Views
No views yet
1!pip install geopy > delete.txt
2!pip install datasets > delete.txt
3!pip install torch torchvision datasets > delete.txt
4!pip install huggingface_hub > delete.txt
5!rm delete.txt1!pip install transformers
2import transformers!huggingface-cli login --token [your_token]1lat_mean = 39.95156937654321
2lat_std = 0.0005992518588323268
3lon_mean = -75.19136795987654
4lon_std = 0.00070303952533189591from transformers import AutoModelForImageClassification, PretrainedConfig, PreTrainedModel
2import torch
3import torch.nn as nn
4import os
5from huggingface_hub import PyTorchModelHubMixin, hf_hub_download
6from safetensors.torch import load_file
7
8class CustomConvNeXtConfig(PretrainedConfig):
9 model_type = "custom-convnext"
10
11 def __init__(self, num_labels=2, **kwargs):
12 super().__init__(**kwargs)
13 self.num_labels = num_labels # Register number of labels (output dimensions)
14
15class CustomConvNeXtModel(PreTrainedModel):
16 config_class = CustomConvNeXtConfig
17
18 def __init__(self, config, model_name="facebook/convnext-tiny-224",
19 num_classes=2, train_final_layer_only=False):
20 super().__init__(config)
21
22 # Load pre-trained ConvNeXt model from Hugging Face
23 self.convnext = AutoModelForImageClassification.from_pretrained(model_name)
24
25 # Access the input features of the existing classifier
26 in_features = self.convnext.classifier.in_features
27
28 # Modify the classifier layer to match the number of output classes
29 self.convnext.classifier = nn.Linear(in_features, num_classes)
30
31 # Freeze previous weights if only training the final layer
32 if train_final_layer_only:
33 for name, param in self.convnext.named_parameters():
34 if "classifier" not in name:
35 param.requires_grad = False
36 else:
37 print(f"Unfrozen layer: {name}")
38
39 def forward(self, x):
40 return self.convnext(x)
41
42 @classmethod
43 def from_pretrained(cls, repo_id, model_name="facebook/convnext-tiny-224", **kwargs):
44 """Load model weights and configuration from Hugging Face Hub."""
45 # Download model.safetensors from Hugging Face Hub
46 model_path = hf_hub_download(repo_id=repo_id, filename="model.safetensors")
47
48 # Download config.json from Hugging Face Hub
49 config_path = hf_hub_download(repo_id=repo_id, filename="config.json")
50
51 # Load configuration
52 config = CustomConvNeXtConfig.from_pretrained(config_path)
53
54 # Create the model
55 model = cls(config=config, model_name=model_name, num_classes=config.num_labels)
56
57 # Load state_dict from safetensors file
58 state_dict = load_file(model_path)
59 model.load_state_dict(state_dict)
60
61 return model
62
63
64class CustomResNetConfig(PretrainedConfig):
65 model_type = "custom-resnet"
66
67 def __init__(self, num_labels=2, **kwargs):
68 super().__init__(**kwargs)
69 self.num_labels = num_labels # Register number of labels (output dimensions)
70
71class CustomResNetModel(nn.Module, PyTorchModelHubMixin):
72 config_class = CustomResNetConfig
73
74 def __init__(self, model_name="microsoft/resnet-18",
75 num_classes=2,
76 train_final_layer_only=False):
77 super().__init__()
78
79 # Load pre-trained ResNet model from Hugging Face
80 self.resnet = AutoModelForImageClassification.from_pretrained(model_name)
81
82 # Access the Linear layer within the Sequential classifier
83 in_features = self.resnet.classifier[1].in_features # Accessing the Linear layer within the Sequential
84
85 # Modify the classifier layer to have the desired number of output classes
86 self.resnet.classifier = nn.Sequential(
87 nn.Flatten(),
88 nn.Linear(in_features, num_classes)
89 )
90
91 self.config = CustomResNetConfig(num_labels=num_classes)
92
93 # Freeze previous weights
94 if train_final_layer_only:
95 for name, param in self.resnet.named_parameters():
96 if "classifier" not in name:
97 param.requires_grad = False
98 else:
99 print(f"Unfrozen layer: {name}")
100
101 def forward(self, x):
102 return self.resnet(x)
103
104 def save_pretrained(self, save_directory, **kwargs):
105 """Save model weights and custom configuration in Hugging Face format."""
106 os.makedirs(save_directory, exist_ok=True)
107
108 # Save model weights
109 torch.save(self.state_dict(), os.path.join(save_directory, "pytorch_model.bin"))
110
111 # Save configuration
112 self.config.save_pretrained(save_directory)
113
114 @classmethod
115 def from_pretrained(cls, repo_id, model_name="microsoft/resnet-18", **kwargs):
116 """Load model weights and configuration from Hugging Face Hub or local directory."""
117 # Download pytorch_model.bin from Hugging Face Hub
118 model_path = hf_hub_download(repo_id=repo_id, filename="pytorch_model.bin")
119
120 # Download config.json from Hugging Face Hub
121 config_path = hf_hub_download(repo_id=repo_id, filename="config.json")
122
123 # Load configuration
124 config = CustomResNetConfig.from_pretrained(config_path)
125
126 # Create the model
127 model = cls(model_name=model_name, num_classes=config.num_labels)
128
129 # Load state_dict
130 model.load_state_dict(torch.load(model_path, map_location=torch.device("cpu")))
131
132 return model
133
134
135class CustomEfficientNetConfig(PretrainedConfig):
136 model_type = "custom-efficientnet"
137
138 def __init__(self, num_labels=2, **kwargs):
139 super().__init__(**kwargs)
140 self.num_labels = num_labels # Register number of labels (output dimensions)
141
142class CustomEfficientNetModel(PreTrainedModel):
143 config_class = CustomEfficientNetConfig
144
145 def __init__(self, config, model_name="google/efficientnet-b0",
146 num_classes=2, train_final_layer_only=False):
147 super().__init__(config)
148
149 # Load pre-trained EfficientNet model from Hugging Face
150 self.efficientnet = AutoModelForImageClassification.from_pretrained(model_name)
151
152 # Access the input features of the existing classifier
153 in_features = self.efficientnet.classifier.in_features
154
155 # Modify the classifier layer to match the number of output classes
156 self.efficientnet.classifier = nn.Sequential(
157 nn.Linear(in_features, num_classes)
158 )
159
160 # Freeze previous weights if only training the final layer
161 if train_final_layer_only:
162 for name, param in self.efficientnet.named_parameters():
163 if "classifier" not in name:
164 param.requires_grad = False
165 else:
166 print(f"Unfrozen layer: {name}")
167
168 def forward(self, x):
169 return self.efficientnet(x)
170
171 @classmethod
172 def from_pretrained(cls, repo_id, model_name="google/efficientnet-b0", **kwargs):
173 """Load model weights and configuration from Hugging Face Hub."""
174 # Attempt to download the safetensors model file
175 try:
176 model_path = hf_hub_download(repo_id=repo_id, filename="model.safetensors")
177 state_dict = load_file(model_path)
178 except Exception as e:
179 raise ValueError(
180 f"Failed to download or load 'model.safetensors' from {repo_id}. Ensure the file exists."
181 ) from e
182
183 # Download config.json from Hugging Face Hub
184 config_path = hf_hub_download(repo_id=repo_id, filename="config.json")
185
186 # Load configuration
187 config = CustomEfficientNetConfig.from_pretrained(config_path)
188
189 # Create the model
190 model = cls(config=config, model_name=model_name, num_classes=config.num_labels)
191
192 # Load the state_dict into the model
193 model.load_state_dict(state_dict)
194
195 return model
196
197
198class CustomViTConfig(PretrainedConfig):
199 model_type = "custom-vit"
200
201 def __init__(self, num_labels=2, **kwargs):
202 super().__init__(**kwargs)
203 self.num_labels = num_labels # Register number of labels (output dimensions)
204
205class CustomViTModel(PreTrainedModel):
206 config_class = CustomViTConfig
207
208 def __init__(self, config, model_name="google/vit-base-patch16-224",
209 num_classes=2, train_final_layer_only=False):
210 super().__init__(config)
211
212 # Load pre-trained ViT model from Hugging Face
213 self.vit = AutoModelForImageClassification.from_pretrained(model_name)
214
215 # Access the input features of the existing classifier
216 in_features = self.vit.classifier.in_features
217
218 # Modify the classifier layer to match the number of output classes
219 self.vit.classifier = nn.Linear(in_features, num_classes)
220
221 # Freeze previous weights if only training the final layer
222 if train_final_layer_only:
223 for name, param in self.vit.named_parameters():
224 if "classifier" not in name:
225 param.requires_grad = False
226 else:
227 print(f"Unfrozen layer: {name}")
228
229 def forward(self, x):
230 return self.vit(x)
231
232 @classmethod
233 def from_pretrained(cls, repo_id, model_name="google/vit-base-patch16-224", **kwargs):
234 # Attempt to download the safetensors model file
235 try:
236 model_path = hf_hub_download(repo_id=repo_id, filename="model.safetensors")
237 state_dict = load_file(model_path)
238 except Exception as e:
239 raise ValueError(
240 f"Failed to download or load 'model.safetensors' from {repo_id}. Ensure the file exists."
241 ) from e
242
243 # Download config.json from Hugging Face Hub
244 config_path = hf_hub_download(repo_id=repo_id, filename="config.json")
245
246 # Load configuration
247 config = CustomViTConfig.from_pretrained(config_path)
248
249 # Create the model
250 model = cls(config=config, model_name=model_name, num_classes=config.num_labels)
251
252 # Load the state_dict into the model
253 model.load_state_dict(state_dict)
254
255 return model
256
257
258# Define the WeightedEnsembleModel class
259class WeightedEnsembleModel(nn.Module):
260 def __init__(self, models, weights):
261 """
262 Initialize the ensemble model with individual models and their weights.
263 """
264 super(WeightedEnsembleModel, self).__init__()
265 self.models = nn.ModuleList(models) # Wrap models in ModuleList
266 self.weights = weights
267
268 def forward(self, images):
269 """
270 Forward pass for the ensemble model.
271 Performs weighted averaging of logits from individual models.
272 """
273 ensemble_logits = torch.zeros((images.size(0), 2)).to(images.device) # Initialize logits
274 for model, weight in zip(self.models, self.weights):
275 outputs = model(images)
276 logits = outputs.logits if hasattr(outputs, "logits") else outputs # Extract logits
277 ensemble_logits += weight * logits # Weighted sum of logits
278 return ensemble_logits
279
280
2811from transformers import AutoModelForImageClassification
2import torch
3from sklearn.metrics import mean_absolute_error, mean_squared_error
4import matplotlib.pyplot as plt
5import numpy as np
6
7device = torch.device("cuda" if torch.cuda.is_available() else "cpu")1#resnet
2resnet = CustomResNetModel.from_pretrained(
3 "final-project-5190/model-resnet-50-base",
4 model_name="microsoft/resnet-50"
5)
6
7#convnext
8convnext=CustomConvNeXtModel.from_pretrained(
9 "final-project-5190/model-convnext-tiny-reducePlateau",
10 model_name="facebook/convnext-tiny-224")
11
12#vit
13vit = CustomViTModel.from_pretrained(
14 "final-project-5190/model-ViT-base",
15 model_name="google/vit-base-patch16-224"
16)
17
18#efficientnet
19efficientnet = CustomEfficientNetModel.from_pretrained(
20 "final-project-5190/model-efficientnet-b0-base",
21 model_name="google/efficientnet-b0"
22)
23
24models = [convnext, resnet, vit, efficientnet]
25weights = [0.28, 0.26, 0.20, 0.27]1# Download
2from datasets import load_dataset, Image1import torch
2import torch.nn as nn
3import torchvision.models as models
4import torchvision.transforms as transforms
5from torch.utils.data import DataLoader, Dataset
6from transformers import AutoImageProcessor, AutoModelForImageClassification, AutoConfig
7from huggingface_hub import PyTorchModelHubMixin, hf_hub_download
8from PIL import Image
9import os
10import numpy as np
11
12class GPSImageDataset(Dataset):
13 def __init__(self, hf_dataset, transform=None, lat_mean=None, lat_std=None, lon_mean=None, lon_std=None):
14 self.hf_dataset = hf_dataset
15 self.transform = transform
16
17 # Compute mean and std from the dataframe if not provided
18 self.latitude_mean = lat_mean if lat_mean is not None else np.mean(np.array(self.hf_dataset['Latitude']))
19 self.latitude_std = lat_std if lat_std is not None else np.std(np.array(self.hf_dataset['Latitude']))
20 self.longitude_mean = lon_mean if lon_mean is not None else np.mean(np.array(self.hf_dataset['Longitude']))
21 self.longitude_std = lon_std if lon_std is not None else np.std(np.array(self.hf_dataset['Longitude']))
22
23 def __len__(self):
24 return len(self.hf_dataset)
25
26 def __getitem__(self, idx):
27 # Extract data
28 example = self.hf_dataset[idx]
29
30 # Load and process the image
31 image = example['image']
32 latitude = example['Latitude']
33 longitude = example['Longitude']
34 # image = image.rotate(-90, expand=True)
35 if self.transform:
36 image = self.transform(image)
37
38 # Normalize GPS coordinates
39 latitude = (latitude - self.latitude_mean) / self.latitude_std
40 longitude = (longitude - self.longitude_mean) / self.longitude_std
41 gps_coords = torch.tensor([latitude, longitude], dtype=torch.float32)
42
43 return image, gps_coords1# Dataloader + Visualize
2transform = transforms.Compose([
3 transforms.RandomResizedCrop(224), # Random crop and resize to 224x224
4 transforms.RandomHorizontalFlip(), # Random horizontal flip
5 # transforms.RandomRotation(degrees=15), # Random rotation between -15 and 15 degrees
6 transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1), # Random color jitter
7 # transforms.GaussianBlur(kernel_size=(3, 5), sigma=(0.1, 2.0)),
8 # transforms.RandomPerspective(distortion_scale=0.5, p=0.5),
9 transforms.ToTensor(),
10
11 transforms.Normalize(mean=[0.485, 0.456, 0.406],
12 std=[0.229, 0.224, 0.225])
13])
14
15# Optionally, you can create a separate transform for inference without augmentations
16inference_transform = transforms.Compose([
17 transforms.Resize((224, 224)),
18 transforms.ToTensor(),
19 transforms.Normalize(mean=[0.485, 0.456, 0.406],
20 std=[0.229, 0.224, 0.225])
21])1# Load test data
2release_data = load_dataset("gydou/released_img", split="train")1# Create dataset and dataloader using training mean and std
2rel_dataset = GPSImageDataset(
3 hf_dataset=release_data,
4 transform=inference_transform,
5 lat_mean=lat_mean,
6 lat_std=lat_std,
7 lon_mean=lon_mean,
8 lon_std=lon_std
9)
10rel_dataloader = DataLoader(rel_dataset, batch_size=32, shuffle=False)1# ensemble
2ensemble_model = WeightedEnsembleModel(models=models, weights=weights).to(device)
3
4# Validation
5all_preds = []
6all_actuals = []
7
8ensemble_model.eval()
9with torch.no_grad():
10 for images, gps_coords in rel_dataloader:
11 images, gps_coords = images.to(device), gps_coords.to(device)
12
13 # Weighted ensemble prediction using the new model
14 ensemble_logits = ensemble_model(images)
15
16 # Denormalize predictions and actual values
17 preds = ensemble_logits.cpu() * torch.tensor([lat_std, lon_std]) + torch.tensor([lat_mean, lon_mean])
18 actuals = gps_coords.cpu() * torch.tensor([lat_std, lon_std]) + torch.tensor([lat_mean, lon_mean])
19
20 all_preds.append(preds)
21 all_actuals.append(actuals)
22
23# Concatenate all batches
24all_preds = torch.cat(all_preds).numpy()
25all_actuals = torch.cat(all_actuals).numpy()
26
27# Compute error metrics
28mae = mean_absolute_error(all_actuals, all_preds)
29rmse = mean_squared_error(all_actuals, all_preds, squared=False)
30
31print(f'Mean Absolute Error: {mae}')
32print(f'Root Mean Squared Error: {rmse}')
33
34# Convert predictions and actuals to meters
35latitude_mean_radians = np.radians(lat_mean) # Convert to radians for cosine
36meters_per_degree_latitude = 111000 # Constant
37meters_per_degree_longitude = 111000 * np.cos(latitude_mean_radians) # Adjusted for latitude mean
38
39all_preds_meters = all_preds.copy()
40all_preds_meters[:, 0] *= meters_per_degree_latitude # Latitude to meters
41all_preds_meters[:, 1] *= meters_per_degree_longitude # Longitude to meters
42
43all_actuals_meters = all_actuals.copy()
44all_actuals_meters[:, 0] *= meters_per_degree_latitude # Latitude to meters
45all_actuals_meters[:, 1] *= meters_per_degree_longitude # Longitude to meters
46
47# Compute error metrics in meters
48mae_meters = mean_absolute_error(all_actuals_meters, all_preds_meters)
49rmse_meters = mean_squared_error(all_actuals_meters, all_preds_meters, squared=False)
50
51print(f"Mean Absolute Error (meters): {mae_meters:.2f}")
52print(f"Root Mean Squared Error (meters): {rmse_meters:.2f}")
53