Views
No views yet
1## Training Data Statistics
2lat_mean = 39.951537011424264
3lat_std = 0.0006940325318781937
4lon_mean = -75.19152009539549
5lon_std = 0.00076077169646552421# install dependencies
2pip install geopy datasets torch torchvision huggingface_hub
3
4# import packages
5import numpy as np
6from geopy.distance import geodesic
7import torch
8from torch.utils.data import DataLoader, Dataset
9from torchvision import transforms
10import torch.nn as nn
11from torchvision.models import mobilenet_v2, MobileNet_V2_Weights, convnext_tiny, ConvNeXt_Tiny_Weights
12from datasets import load_dataset
13from huggingface_hub import hf_hub_download
14
15# load the model
16repo_id = "cis519projectA/ImageToGPSproject_convnext_mobilenet"
17filename = "convnext_mobilenet_ensemble_model.pth"
18model_path = hf_hub_download(repo_id=repo_id, filename=filename)
19
20# define models
21class CustomConvNeXtModel(nn.Module):
22 def __init__(self, weights=ConvNeXt_Tiny_Weights.DEFAULT, num_classes=2):
23 super().__init__()
24
25 # Load pre-trained ConvNeXt model
26 self.convnext = convnext_tiny(weights=weights)
27 in_features = self.convnext.classifier[2].in_features
28
29 self.convnext.classifier = nn.Sequential(
30 nn.AdaptiveAvgPool2d(1),
31 nn.Flatten(),
32 nn.Linear(in_features, 512),
33 nn.BatchNorm1d(512),
34 nn.ReLU(),
35 nn.Dropout(p=0.3),
36 nn.Linear(512, num_classes)
37 )
38
39 # Freeze early layers
40 for param in self.convnext.features[:4].parameters():
41 param.requires_grad = False
42
43 def forward(self, x):
44 return self.convnext(x)
45
46class CustomMobileNetModel(nn.Module):
47 def __init__(self, weights=MobileNet_V2_Weights.DEFAULT, num_classes=2):
48 super().__init__()
49
50 # Load pre-trained MobileNet model
51 self.mobilenet = mobilenet_v2(weights=weights)
52 in_features = self.mobilenet.classifier[1].in_features
53
54 self.mobilenet.classifier = nn.Sequential(
55 nn.Linear(in_features, 1024),
56 nn.ReLU(),
57 nn.Dropout(p=0.5),
58 nn.Linear(1024, 512),
59 nn.ReLU(),
60 nn.Dropout(p=0.5),
61 nn.Linear(512, num_classes)
62 )
63
64 # Freeze early layers
65 for param in self.mobilenet.features[:5].parameters():
66 param.requires_grad = False
67
68 def forward(self, x):
69 return self.mobilenet(x)
70
71class EnsembleModel(nn.Module):
72 def __init__(self, resnet_model, mobilenet_model, num_classes=2):
73 super().__init__()
74 self.resnet = resnet_model
75 self.mobilenet = mobilenet_model
76 self.fc = nn.Sequential(
77 nn.Linear(num_classes * 2, 512),
78 nn.ReLU(),
79 nn.Dropout(p=0.3),
80 nn.Linear(512, num_classes)
81 )
82
83 def forward(self, x):
84 resnet_out = self.resnet(x)
85 mobilenet_out = self.mobilenet(x)
86 combined = torch.cat((resnet_out, mobilenet_out), dim=1)
87 output = self.fc(combined)
88 return output
89
90convnext_model = CustomConvNeXtModel()
91mobilenet_model = CustomMobileNetModel()
92ensemble_model = EnsembleModel(convnext_model, mobilenet_model)
93
94# load the model weights
95device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
96state_dict = torch.load(model_path, map_location=device)
97ensemble_model.load_state_dict(state_dict)
98ensemble_model.to(device)
99ensemble_model.eval()
100
101
102# load the dataset
103dataset_test = load_dataset("gydou/released_img", split="train")
104
105# define transformers
106inference_transform = transforms.Compose([
107 transforms.Resize((224, 224)),
108 transforms.ToTensor(),
109 transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
110])
111
112# Parameters for denormalization
113lat_mean = 39.951537011424264
114lat_std = 0.0006940325318781937
115lon_mean = -75.19152009539549
116lon_std = 0.0007607716964655242
117
118class GPSImageDataset(Dataset):
119 def __init__(self, hf_dataset, transform=None, lat_mean=None, lat_std=None, lon_mean=None, lon_std=None):
120 self.hf_dataset = hf_dataset
121 self.transform = transform
122 self.latitude_mean = lat_mean
123 self.latitude_std = lat_std
124 self.longitude_mean = lon_mean
125 self.longitude_std = lon_std
126
127 def __len__(self):
128 return len(self.hf_dataset)
129
130 def __getitem__(self, idx):
131 example = self.hf_dataset[idx]
132 image = example['image']
133 latitude = example['Latitude']
134 longitude = example['Longitude']
135 if self.transform:
136 image = self.transform(image)
137 latitude = (latitude - self.latitude_mean) / self.latitude_std
138 longitude = (longitude - self.longitude_mean) / self.longitude_std
139 gps_coords = torch.tensor([latitude, longitude], dtype=torch.float32)
140 return image, gps_coords
141
142# transform test data
143test_dataset = GPSImageDataset(
144 hf_dataset=dataset_test,
145 transform=inference_transform,
146 lat_mean=lat_mean,
147 lat_std=lat_std,
148 lon_mean=lon_mean,
149 lon_std=lon_std
150)
151test_dataloader = DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4)
152
153# evaluate
154def evaluate_model_single_batch(model, dataloader, lat_mean, lat_std, lon_mean, lon_std):
155 all_distances = []
156 model.eval()
157 with torch.no_grad():
158 for batch_idx, (images, gps_coords) in enumerate(dataloader):
159 images, gps_coords = images.to(device), gps_coords.to(device)
160 outputs = model(images)
161 preds_denorm = outputs.cpu().numpy() * np.array([lat_std, lon_std]) + np.array([lat_mean, lon_mean])
162 actuals_denorm = gps_coords.cpu().numpy() * np.array([lat_std, lon_std]) + np.array([lat_mean, lon_mean])
163 for pred, actual in zip(preds_denorm, actuals_denorm):
164 distance = geodesic((actual[0], actual[1]), (pred[0], pred[1])).meters
165 all_distances.append(distance)
166 break
167
168 mean_error = np.mean(all_distances)
169 rmse_error = np.sqrt(np.mean(np.square(all_distances)))
170 return mean_error, rmse_error
171
172
173# Evaluate using only one batch
174mean_error, rmse_error = evaluate_model_single_batch(
175 ensemble_model, test_dataloader, lat_mean, lat_std, lon_mean, lon_std
176)
177print(f"Mean Error (meters): {mean_error:.2f}, RMSE (meters): {rmse_error:.2f}")