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