Views
No views yet
1class DinoSkinLesionClassifier(nn.Module, PyTorchModelHubMixin):
2 """
3 PytorchModelHubMixin adds push to Hugging Face Hub
4
5 See: https://huggingface.co/docs/hub/models-uploading#upload-a-pytorch-model-using-huggingfacehub
6 """
7 def __init__(self, num_classes=1, freeze_backbone=True):
8 super(DinoSkinLesionClassifier, self).__init__()
9
10 # Initialize Dino v3 backbone
11 self.backbone = timm.create_model('vit_base_patch16_dinov3', pretrained=True, num_classes=0, global_pool='avg')
12
13 # Freeze backbone weights if requested
14 # This makes training much faster
15 if freeze_backbone:
16 for param in self.backbone.parameters():
17 param.requires_grad = False
18
19 # Get feature dimension from the backbone
20 feat_dim = self.backbone.num_features
21
22 # Define the classification head
23 self.head = nn.Linear(feat_dim, num_classes) # Should be 768 in, 1 out
24
25 def forward(self, x):
26 out = self.backbone(x)
27 out = self.head(out)
28
29 return out
30
31from huggingface_hub import hf_hub_download
32
33weights_path = hf_hub_download(
34 repo_id="avanishd/vit-base-patch16-dinov3-finetuned-skin-lesion-classification",
35 filename="model.safetensors"
36 )
37
38from safetensors.torch import load_model
39
40model = EfficientNetSkinLesionClassifier()
41load_model(model, filename=weights_path, strict=True)
42
43model.to(device) # Don't forget to put on GPU
44
45model.eval() # Set model to evaluation mode
46
47
48# Example with PH2 Dataset
49
50class PH2Dataset(Dataset):
51 """
52 Dataset for PH2 images, which are in png format.
53
54 PH2 contains skin lesions images classified as
55
56 - Common Nevus (benign)
57 - Atypical Nevus (benign)
58 - Melanoma (malignant)
59
60 No need for is real label here, since this is purely for testing
61 """
62
63 def __init__(self, dir_path, metadata, transform=None):
64 super(PH2Dataset, self).__init__()
65
66 self.dir_path = dir_path
67 self.transform = transform
68
69 self.image_files = [os.path.join(dir_path, f) for f in os.listdir(dir_path)
70 if f.lower().endswith(('.jpg', '.jpeg', '.png'))]
71
72 # Load metadata w/ polars (only 2 columns)
73 self.metadata = pl.read_csv(metadata)
74
75 self.diagnostic_mapping = {
76 "Common Nevus": 0,
77 "Atypical Nevus": 0,
78 "Melanoma": 1,
79 }
80
81 def __len__(self):
82 return len(self.image_files)
83
84 def __getitem__(self, idx):
85 # The image name in the metadata csv are like IMD003
86 image_id = self.image_files[idx].split('/')[-1].split('.')[0]
87
88 # Still need the entire path to open the image
89 image = Image.open(self.image_files[idx]).convert('RGB')
90
91 if self.transform: # Apply transform if it exists
92 image = self.transform(image)
93
94 diagnosis = self.metadata.filter(pl.col("image_name") == image_id).select("diagnosis").item()
95
96 label = torch.tensor(self.diagnostic_mapping[diagnosis], dtype=torch.int16)
97
98 return image, label
99
100
101transform = transforms.Compose([
102 transforms.ToTensor(),
103 transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), # Image net mean and std
104 transforms.Resize((224, 224)), # Dimensions for Efficient Net v2
105])
106
107ph_2_images = "/content/data/ph2_data/images"
108ph_2_metadata = "/content/data/ph2_data/ph_2_dataset.csv"
109
110ex_dataset = PH2Dataset(ph_2_images, ph_2_metadata, transform)
111
112ex_loader = DataLoader(ex_dataset, batch_size=64, shuffle=False)
113
114for (images, labels) in test_loader:
115 images = images.to(device)
116 labels = labels.to(device)
117 output = model(images)
118
119 y_pred_prob = torch.sigmoid(output).cpu().numpy().ravel()
120 y_pred = np.where(y_pred_prob < 0.5, 0, 1)
121
122 return y_pred
123| Training Loss | Epoch | Step |
|---|---|---|
| 0.5027 | 1 | 100 |
| 0.5672 | 1 | 200 |
| 0.5373 | 1 | 300 |
| 0.4693 | 1 | 400 |
| 5.3829 | 1 | 500 |
| 0.4872 | 1 | 600 |
| 0.4717 | 1 | 700 |
| 0.4550 | 1 | 800 |
| 0.4185 | 1 | 900 |
| 0.4142 | 1 | 1000 |
| 0.3570 | 1 | 1100 |
| 0.3877 | 1 | 1200 |
| 0.4282 | 1 | 1300 |
| 8.8676 | 1 | 1400 |
| 0.3732 | 1 | 1500 |
| 0.3522 | 1 | 1600 |
| 0.3065 | 1 | 1700 |
| 0.3732 | 1 | 1800 |
| 0.3965 | 1 | 1900 |
| 0.4727 | 1 | 2000 |
| 0.3407 | 1 | 2100 |
| 0.3421 | 1 | 2200 |
| 0.3847 | 1 | 2300 |
| 0.3911 | 1 | 2400 |
| 0.4006 | 1 | 2500 |
| 0.2836 | 1 | 2600 |
| 0.3968 | 1 | 2700 |
| 0.3796 | 1 | 2800 |
| 0.3317 | 1 | 2900 |
| 0.2762 | 1 | 3000 |
| 0.3027 | 1 | 3100 |
| 0.3002 | 1 | 3200 |
| 0.3672 | 1 | 3300 |
| 0.2660 | 1 | 3400 |
| 0.3145 | 1 | 3500 |
| 0.4098 | 1 | 3600 |
| 0.3156 | 1 | 3700 |
| 0.2762 | 1 | 3800 |
| 0.2557 | 1 | 3900 |
| 0.3204 | 1 | 4000 |
| 0.3097 | 1 | 4100 |
| 0.2790 | 1 | 4200 |
| 0.3395 | 1 | 4300 |
| 0.2888 | 1 | 4400 |
| 0.3002 | 1 | 4500 |
| 0.3388 | 1 | 4600 |
| 0.3744 | 1 | 4700 |
| 0.3143 | 1 | 4800 |
| 0.3501 | 1 | 4900 |
| 0.2923 | 1 | 5000 |
| 0.3152 | 1 | 5100 |
| 0.3380 | 1 | 5200 |