avanishd commited on
Commit
fb552e4
·
verified ·
1 Parent(s): 32d3642

Create README.md

Browse files
Files changed (1) hide show
  1. README.md +242 -0
README.md ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ metrics:
3
+ - pAUC
4
+ model-index:
5
+ - name: >-
6
+ avanishd/avanishd/vit-base-patch16-dinov3-finetuned-skin-lesion-classification
7
+ results:
8
+ - task:
9
+ name: Image Classification
10
+ type: image-classification
11
+ metrics:
12
+ - name: pAUC
13
+ type: pAUC
14
+ value: 0.1441070826953209
15
+ base_model:
16
+ - timm/vit_base_patch16_dinov3.lvd1689m
17
+ ---
18
+
19
+ # vit-base-patch16-dinov3-finetuned-skin-lesion-classification
20
+
21
+ This model is a finetuned for skin lesion classification.
22
+
23
+ ## Intended Uses & Limitations
24
+
25
+ ### Intended Use
26
+
27
+ This model is intended for dermoscopic skin lesion classification using a 224x224 image size.
28
+
29
+ ### Limitations
30
+
31
+ This model was only trained for 1 epoch and has not seen many malignant examples (due to large class imbalance in ISIC 2024 dataset).
32
+
33
+ ## How to Get Started with the Model
34
+
35
+ ```Python
36
+ class DinoSkinLesionClassifier(nn.Module, PyTorchModelHubMixin):
37
+ """
38
+ PytorchModelHubMixin adds push to Hugging Face Hub
39
+
40
+ See: https://huggingface.co/docs/hub/models-uploading#upload-a-pytorch-model-using-huggingfacehub
41
+ """
42
+ def __init__(self, num_classes=1, freeze_backbone=True):
43
+ super(DinoSkinLesionClassifier, self).__init__()
44
+
45
+ # Initialize Dino v3 backbone
46
+ self.backbone = timm.create_model('vit_base_patch16_dinov3', pretrained=True, num_classes=0, global_pool='avg')
47
+
48
+ # Freeze backbone weights if requested
49
+ # This makes training much faster
50
+ if freeze_backbone:
51
+ for param in self.backbone.parameters():
52
+ param.requires_grad = False
53
+
54
+ # Get feature dimension from the backbone
55
+ feat_dim = self.backbone.num_features
56
+
57
+ # Define the classification head
58
+ self.head = nn.Linear(feat_dim, num_classes) # Should be 768 in, 1 out
59
+
60
+ def forward(self, x):
61
+ out = self.backbone(x)
62
+ out = self.head(out)
63
+
64
+ return out
65
+
66
+ from huggingface_hub import hf_hub_download
67
+
68
+ weights_path = hf_hub_download(
69
+ repo_id="avanishd/vit-base-patch16-dinov3-finetuned-skin-lesion-classification",
70
+ filename="model.safetensors"
71
+ )
72
+
73
+ from safetensors.torch import load_file
74
+
75
+ model = EfficientNetSkinLesionClassifier()
76
+ state = load_file(weights_path)
77
+ model.load_state_dict(state, strict=True)
78
+
79
+ model.eval() # Set model to evaluation mode
80
+
81
+ model.to(device) # Don't forget to put on GPU
82
+
83
+
84
+ # Example with PH2 Dataset
85
+
86
+ class PH2Dataset(Dataset):
87
+ """
88
+ Dataset for PH2 images, which are in png format.
89
+
90
+ PH2 contains skin lesions images classified as
91
+
92
+ - Common Nevus (benign)
93
+ - Atypical Nevus (benign)
94
+ - Melanoma (malignant)
95
+
96
+ No need for is real label here, since this is purely for testing
97
+ """
98
+
99
+ def __init__(self, dir_path, metadata, transform=None):
100
+ super(PH2Dataset, self).__init__()
101
+
102
+ self.dir_path = dir_path
103
+ self.transform = transform
104
+
105
+ self.image_files = [os.path.join(dir_path, f) for f in os.listdir(dir_path)
106
+ if f.lower().endswith(('.jpg', '.jpeg', '.png'))]
107
+
108
+ # Load metadata w/ polars (only 2 columns)
109
+ self.metadata = pl.read_csv(metadata)
110
+
111
+ self.diagnostic_mapping = {
112
+ "Common Nevus": 0,
113
+ "Atypical Nevus": 0,
114
+ "Melanoma": 1,
115
+ }
116
+
117
+ def __len__(self):
118
+ return len(self.image_files)
119
+
120
+ def __getitem__(self, idx):
121
+ # The image name in the metadata csv are like IMD003
122
+ image_id = self.image_files[idx].split('/')[-1].split('.')[0]
123
+
124
+ # Still need the entire path to open the image
125
+ image = Image.open(self.image_files[idx]).convert('RGB')
126
+
127
+ if self.transform: # Apply transform if it exists
128
+ image = self.transform(image)
129
+
130
+ diagnosis = self.metadata.filter(pl.col("image_name") == image_id).select("diagnosis").item()
131
+
132
+ label = torch.tensor(self.diagnostic_mapping[diagnosis], dtype=torch.int16)
133
+
134
+ return image, label
135
+
136
+
137
+ transform = transforms.Compose([
138
+ transforms.ToTensor(),
139
+ transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), # Image net mean and std
140
+ transforms.Resize((224, 224)), # Dimensions for Efficient Net v2
141
+ ])
142
+
143
+ ph_2_images = "/content/data/ph2_data/images"
144
+ ph_2_metadata = "/content/data/ph2_data/ph_2_dataset.csv"
145
+
146
+ ex_dataset = PH2Dataset(ph_2_images, ph_2_metadata, transform)
147
+
148
+ ex_loader = DataLoader(ex_dataset, batch_size=64, shuffle=False)
149
+
150
+ for (images, labels) in test_loader:
151
+ images = images.to(device)
152
+ labels = labels.to(device)
153
+ output = model(images)
154
+
155
+ y_pred_prob = torch.sigmoid(output).cpu().numpy().ravel()
156
+ y_pred = np.where(y_pred_prob < 0.5, 0, 1)
157
+
158
+ return y_pred
159
+
160
+ ```
161
+
162
+ ## Training and evaluation data
163
+
164
+ This model was trained with the [ISIC 2024 challenge](https://www.kaggle.com/competitions/isic-2024-challenge) and [ISIC 2024 synthetic](https://www.kaggle.com/datasets/ilya9711nov/isic-2024-synthetic) datasets.
165
+
166
+ For the ISIC 2024 Challenge data, an 80-20 train test split was applied, and the test split was used to evaluate the model.
167
+
168
+ ## Training Procedure
169
+
170
+ ### Training hyperparameters
171
+ - learning_rate: 1e-4
172
+ - train_batch_size: 64
173
+ - eval_batch_size: 64
174
+ - seed: 42
175
+ - optimizer: Use OptimizerNames.ADAMW_TORCH with weight decay=1e-2 and optimizer_args=No additional optimizer arguments
176
+ - num_epochs: 1
177
+
178
+ ### Training results
179
+
180
+ | Training Loss | Epoch | Step |
181
+ |---------------|-------|------|
182
+ | 0.5027 | 1 | 100 |
183
+ | 0.5672 | 1 | 200 |
184
+ | 0.5373 | 1 | 300 |
185
+ | 0.4693 | 1 | 400 |
186
+ | 5.3829 | 1 | 500 |
187
+ | 0.4872 | 1 | 600 |
188
+ | 0.4717 | 1 | 700 |
189
+ | 0.4550 | 1 | 800 |
190
+ | 0.4185 | 1 | 900 |
191
+ | 0.4142 | 1 | 1000 |
192
+ | 0.3570 | 1 | 1100 |
193
+ | 0.3877 | 1 | 1200 |
194
+ | 0.4282 | 1 | 1300 |
195
+ | 8.8676 | 1 | 1400 |
196
+ | 0.3732 | 1 | 1500 |
197
+ | 0.3522 | 1 | 1600 |
198
+ | 0.3065 | 1 | 1700 |
199
+ | 0.3732 | 1 | 1800 |
200
+ | 0.3965 | 1 | 1900 |
201
+ | 0.4727 | 1 | 2000 |
202
+ | 0.3407 | 1 | 2100 |
203
+ | 0.3421 | 1 | 2200 |
204
+ | 0.3847 | 1 | 2300 |
205
+ | 0.3911 | 1 | 2400 |
206
+ | 0.4006 | 1 | 2500 |
207
+ | 0.2836 | 1 | 2600 |
208
+ | 0.3968 | 1 | 2700 |
209
+ | 0.3796 | 1 | 2800 |
210
+ | 0.3317 | 1 | 2900 |
211
+ | 0.2762 | 1 | 3000 |
212
+ | 0.3027 | 1 | 3100 |
213
+ | 0.3002 | 1 | 3200 |
214
+ | 0.3672 | 1 | 3300 |
215
+ | 0.2660 | 1 | 3400 |
216
+ | 0.3145 | 1 | 3500 |
217
+ | 0.4098 | 1 | 3600 |
218
+ | 0.3156 | 1 | 3700 |
219
+ | 0.2762 | 1 | 3800 |
220
+ | 0.2557 | 1 | 3900 |
221
+ | 0.3204 | 1 | 4000 |
222
+ | 0.3097 | 1 | 4100 |
223
+ | 0.2790 | 1 | 4200 |
224
+ | 0.3395 | 1 | 4300 |
225
+ | 0.2888 | 1 | 4400 |
226
+ | 0.3002 | 1 | 4500 |
227
+ | 0.3388 | 1 | 4600 |
228
+ | 0.3744 | 1 | 4700 |
229
+ | 0.3143 | 1 | 4800 |
230
+ | 0.3501 | 1 | 4900 |
231
+ | 0.2923 | 1 | 5000 |
232
+ | 0.3152 | 1 | 5100 |
233
+ | 0.3380 | 1 | 5200 |
234
+
235
+
236
+ ### Framework versions
237
+
238
+ - Pytorch 2.9.0+cu126
239
+ - torchvision: 0.24.0+cu126
240
+ - timm: 1.0.22
241
+ - numpy: 2.0.2
242
+ - safetensors: 0.7.0