MSG1999 commited on
Commit
445d72e
·
verified ·
1 Parent(s): 9636a1c
Files changed (1) hide show
  1. README.md +255 -36
README.md CHANGED
@@ -4,72 +4,291 @@ license: apache-2.0
4
  tags:
5
  - image-classification
6
  - vit
 
7
  - lora
8
  - peft
9
  - cifar100
10
  - pytorch
 
 
11
  datasets:
12
  - cifar100
13
  metrics:
14
  - accuracy
15
  base_model: WinKawaks/vit-small-patch16-224
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  ---
17
 
18
- # ViT-Small + LoRA Fine-tuned on CIFAR-100
19
 
20
- **Assignment:** DLOps A5Q1 | **Date:** 2026-04-08
21
- **Best Model:** exp10_r8_a8 | **Val Acc: 90.46%** | **Test Acc: 90.44%**
22
 
23
- ## Experiment Grid
24
 
25
- | Exp | LoRA | Rank | Alpha | Val Acc |
26
- |-----|------|------|-------|---------|
27
- | exp01_no_lora | ❌ | — | — | 80.77% |
28
- | exp02_r2_a2 | ✅ | 2 | 2 | 89.65% |
29
- | exp03_r2_a4 | ✅ | 2 | 4 | 90.03% |
30
- | exp04_r2_a8 | ✅ | 2 | 8 | 89.98% |
31
- | exp05_r4_a2 | ✅ | 4 | 2 | 89.91% |
32
- | exp06_r4_a4 | ✅ | 4 | 4 | 90.11% |
33
- | exp07_r4_a8 | ✅ | 4 | 8 | 90.28% |
34
- | exp08_r8_a2 | ✅ | 8 | 2 | 90.09% |
35
- | exp09_r8_a4 | ✅ | 8 | 4 | 90.17% |
36
- | **exp10_r8_a8** ⭐ | ✅ | **8** | **8** | **90.46%** |
37
 
38
- ## Best Config
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  | Parameter | Value |
41
  |-----------|-------|
42
- | Base model | `WinKawaks/vit-small-patch16-224` |
43
- | LoRA rank | 8 |
44
- | LoRA alpha | 8 |
45
- | LoRA dropout | 0.1 |
46
- | Target modules | query, key, value |
47
- | Trainable params | 259,684 / 21,925,348 (1.18%) |
48
- | Val accuracy | **90.46%** |
49
- | Test accuracy | **90.44%** |
50
- | Epochs | 10 |
51
- | Batch size | 128 |
 
 
 
52
  | Learning rate | 3e-4 |
 
 
 
 
 
 
 
53
 
54
- ## Usage
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  ```python
 
57
  from transformers import ViTForImageClassification, ViTImageProcessor
58
- from peft import PeftModel
 
59
  from PIL import Image
60
- import torch
61
 
 
62
  BASE = "WinKawaks/vit-small-patch16-224"
63
 
64
- processor = ViTImageProcessor.from_pretrained(BASE)
65
- base = ViTForImageClassification.from_pretrained(
66
- BASE, num_labels=100, ignore_mismatched_sizes=True)
67
- model = PeftModel.from_pretrained(base, "MSG1999/vit-lora-cifar100")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  model.eval()
 
69
 
 
 
70
  image = Image.open("your_image.jpg").convert("RGB")
71
  inputs = processor(images=image, return_tensors="pt")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  with torch.no_grad():
73
- pred = model(**inputs).logits.argmax(-1).item()
74
- print(model.config.id2label[pred])
 
 
 
75
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  tags:
5
  - image-classification
6
  - vit
7
+ - vit-small
8
  - lora
9
  - peft
10
  - cifar100
11
  - pytorch
12
+ - fine-tuning
13
+ - parameter-efficient
14
  datasets:
15
  - cifar100
16
  metrics:
17
  - accuracy
18
  base_model: WinKawaks/vit-small-patch16-224
19
+ model-index:
20
+ - name: vit-lora-cifar100
21
+ results:
22
+ - task:
23
+ type: image-classification
24
+ name: Image Classification
25
+ dataset:
26
+ name: CIFAR-100
27
+ type: cifar100
28
+ metrics:
29
+ - type: accuracy
30
+ value: 0.9046
31
+ name: Validation Accuracy
32
+ - type: accuracy
33
+ value: 0.9044
34
+ name: Test Accuracy
35
  ---
36
 
37
+ <div align="center">
38
 
39
+ # ViT-Small + LoRA CIFAR-100
 
40
 
41
+ **Parameter-efficient fine-tuning of ViT-S/16 on CIFAR-100 · Val Acc: 90.46% · Test Acc: 90.44%**
42
 
43
+ [![Model](https://img.shields.io/badge/🤗_Model-MSG1999%2Fvit--lora--cifar100-yellow)](https://huggingface.co/MSG1999/vit-lora-cifar100)
44
+ [![Dataset](https://img.shields.io/badge/Dataset-CIFAR--100-blue)](https://www.cs.toronto.edu/~kriz/cifar.html)
45
+ [![Val Acc](https://img.shields.io/badge/Val%20Acc-90.46%25-brightgreen)]()
46
+ [![Test Acc](https://img.shields.io/badge/Test%20Acc-90.44%25-brightgreen)]()
47
+ [![Framework](https://img.shields.io/badge/Framework-PyTorch-orange)](https://pytorch.org/)
48
+ [![PEFT](https://img.shields.io/badge/PEFT-LoRA-purple)](https://github.com/huggingface/peft)
49
+ [![License](https://img.shields.io/badge/License-Apache%202.0-lightgrey)](https://www.apache.org/licenses/LICENSE-2.0)
 
 
 
 
 
50
 
51
+ </div>
52
+
53
+ ---
54
+
55
+ ## Overview
56
+
57
+ This repository contains `best_model.pt` — the **full merged state dict** of a ViT-Small/16 model fine-tuned on CIFAR-100 using Low-Rank Adaptation (LoRA). Only the Q, K, V attention projections and classification head were updated during training. All other weights remain frozen.
58
+
59
+ | | |
60
+ |---|---|
61
+ | **Base model** | `WinKawaks/vit-small-patch16-224` (ImageNet pre-trained) |
62
+ | **Dataset** | CIFAR-100 (50,000 train · 10,000 test · 100 classes) |
63
+ | **Method** | LoRA on Query, Key, Value attention projections + trainable head |
64
+ | **Best config** | rank=8, alpha=8, dropout=0.1 |
65
+ | **Trainable params** | 259,684 / 21,925,348 **(1.18%)** |
66
+ | **Val accuracy** | **90.46%** (+9.69 pp over frozen-backbone baseline) |
67
+ | **Test accuracy** | **90.44%** |
68
+ | **Hardware** | NVIDIA GTX 1080 Ti (11.7 GB VRAM) |
69
+
70
+ ---
71
+
72
+ ## Architecture
73
+
74
+ ```
75
+ ViT-Small/16 (patch=16, dim=384, heads=6, layers=12)
76
+ ├── Patch Embedding [frozen]
77
+ ├── Transformer Encoder × 12
78
+ │ ├── Multi-Head Self-Attention
79
+ │ │ ├── Query ── LoRA(A·B, r=8) ✅ trained
80
+ │ │ ├── Key ── LoRA(A·B, r=8) ✅ trained
81
+ │ │ └── Value ── LoRA(A·B, r=8) ✅ trained
82
+ │ ├── LayerNorm [frozen]
83
+ │ └── MLP (FFN) [frozen]
84
+ └── Classification Head (384 → 100) ✅ trained
85
+ ```
86
+
87
+ LoRA update rule: `W' = W + (α/r) · B·A`
88
+ where `W` is frozen, `A ∈ ℝ^{r×d}` and `B ∈ ℝ^{d×r}` are learned.
89
+ With r=8 and α=8, the scaling factor α/r = **1.0**.
90
+
91
+ ---
92
+
93
+ ## Hyperparameters
94
+
95
+ ### LoRA (best configuration)
96
 
97
  | Parameter | Value |
98
  |-----------|-------|
99
+ | Rank (r) | **8** |
100
+ | Alpha (α) | **8** |
101
+ | Scaling (α/r) | 1.0 |
102
+ | Dropout | 0.1 |
103
+ | Target modules | `query`, `key`, `value` |
104
+ | Bias | none |
105
+ | Trainable params | 259,684 (1.18%) |
106
+
107
+ ### Training
108
+
109
+ | Parameter | Value |
110
+ |-----------|-------|
111
+ | Optimizer | AdamW |
112
  | Learning rate | 3e-4 |
113
+ | Weight decay | 1e-4 |
114
+ | LR scheduler | CosineAnnealingLR |
115
+ | Batch size | 128 |
116
+ | Epochs | 10 |
117
+ | Input resolution | 224 × 224 |
118
+
119
+ ### Data augmentation (train)
120
 
121
+ | Transform | Setting |
122
+ |-----------|---------|
123
+ | RandomHorizontalFlip | p = 0.5 |
124
+ | RandomCrop | 224 × 224, padding = 28 |
125
+ | ColorJitter | brightness=0.3, contrast=0.3, saturation=0.3, hue=0.05 |
126
+ | Normalize mean | (0.5071, 0.4867, 0.4408) |
127
+ | Normalize std | (0.2675, 0.2565, 0.2761) |
128
+
129
+ ---
130
+
131
+ ## Experiment Results
132
+
133
+ ### Grid search — all 10 runs
134
+
135
+ | Experiment | Rank | Alpha | Dropout | Val Acc | Test Acc | Trainable Params |
136
+ |------------|:----:|:-----:|:-------:|:-------:|:--------:|:----------------:|
137
+ | exp01 — no LoRA (baseline) | — | — | 0.1 | 80.77% | 80.77% | 38,500 |
138
+ | exp02 | 2 | 2 | 0.1 | 89.65% | 89.65% | 93,796 |
139
+ | exp03 | 2 | 4 | 0.1 | 90.03% | 90.03% | 93,796 |
140
+ | exp04 | 2 | 8 | 0.1 | 89.98% | 89.97% | 93,796 |
141
+ | exp05 | 4 | 2 | 0.1 | 89.91% | 89.91% | 149,092 |
142
+ | exp06 | 4 | 4 | 0.1 | 90.11% | 90.11% | 149,092 |
143
+ | exp07 | 4 | 8 | 0.1 | 90.28% | 90.28% | 149,092 |
144
+ | exp08 | 8 | 2 | 0.1 | 90.09% | 89.97% | 259,684 |
145
+ | exp09 | 8 | 4 | 0.1 | 90.17% | 90.17% | 259,684 |
146
+ | **exp10 ⭐ BEST** | **8** | **8** | **0.1** | **90.46%** | **90.44%** | **259,684** |
147
+
148
+ ### Optuna hyperparameter search — 10 trials
149
+
150
+ Optuna searched over rank ∈ {2, 4, 8}, alpha ∈ {2, 4, 8}, and dropout ∈ [0.05, 0.30].
151
+
152
+ | Trial | Rank | Alpha | Dropout | Val Acc |
153
+ |-------|:----:|:-----:|:-------:|:-------:|
154
+ | t0 | 2 | 4 | 0.15 | 90.06% |
155
+ | t1 | 4 | 8 | 0.30 | 90.32% |
156
+ | t2 | 4 | 2 | 0.15 | 90.03% |
157
+ | t3 | 4 | 8 | 0.25 | 90.08% |
158
+ | t4 | 4 | 2 | 0.15 | 90.10% |
159
+ | **t5 ⭐** | **8** | **8** | **0.30** | **90.39%** |
160
+ | t6 | 4 | 4 | 0.05 | 90.27% |
161
+ | t7 | 2 | 2 | 0.10 | 89.90% |
162
+ | t8 | 8 | 2 | 0.20 | 90.01% |
163
+ | t9 | 8 | 4 | 0.15 | 90.06% |
164
+
165
+ **Key findings:**
166
+ - rank=8, alpha=8 consistently tops the leaderboard across both search phases.
167
+ - Higher dropout (0.30 vs 0.10) with the best config yields nearly identical accuracy (90.39% vs 90.46%), confirming robustness.
168
+ - Increasing rank beyond 8 or alpha beyond 8 was not explored but is unlikely to yield significant gains given the plateau.
169
+ - LoRA provides **+9.69 pp** over the frozen-backbone baseline at just 1.18% parameter cost.
170
+
171
+ ---
172
+
173
+ ## Quickstart
174
+
175
+ ### Install dependencies
176
+
177
+ ```bash
178
+ pip install torch torchvision transformers peft huggingface_hub Pillow
179
+ ```
180
+
181
+ ### Load the model and run inference
182
 
183
  ```python
184
+ import torch
185
  from transformers import ViTForImageClassification, ViTImageProcessor
186
+ from peft import LoraConfig, get_peft_model
187
+ from huggingface_hub import hf_hub_download
188
  from PIL import Image
 
189
 
190
+ REPO = "MSG1999/vit-lora-cifar100"
191
  BASE = "WinKawaks/vit-small-patch16-224"
192
 
193
+ CIFAR100_CLASSES = [
194
+ "apple", "aquarium_fish", "baby", "bear", "beaver", "bed", "bee", "beetle",
195
+ "bicycle", "bottle", "bowl", "boy", "bridge", "bus", "butterfly", "camel",
196
+ "can", "castle", "caterpillar", "cattle", "chair", "chimpanzee", "clock",
197
+ "cloud", "cockroach", "couch", "crab", "crocodile", "cup", "dinosaur",
198
+ "dolphin", "elephant", "flatfish", "forest", "fox", "girl", "hamster",
199
+ "house", "kangaroo", "keyboard", "lamp", "lawn_mower", "leopard", "lion",
200
+ "lizard", "lobster", "man", "maple_tree", "motorcycle", "mountain", "mouse",
201
+ "mushroom", "oak_tree", "orange", "orchid", "otter", "palm_tree", "pear",
202
+ "pickup_truck", "pine_tree", "plain", "plate", "poppy", "porcupine",
203
+ "possum", "rabbit", "raccoon", "ray", "road", "rocket", "rose", "sea",
204
+ "seal", "shark", "shrew", "skunk", "skyscraper", "snail", "snake", "spider",
205
+ "squirrel", "streetcar", "sunflower", "sweet_pepper", "table", "tank",
206
+ "telephone", "television", "tiger", "tractor", "train", "trout", "tulip",
207
+ "turtle", "wardrobe", "whale", "willow_tree", "wolf", "woman", "worm",
208
+ ]
209
+ id2label = {i: c for i, c in enumerate(CIFAR100_CLASSES)}
210
+ label2id = {c: i for i, c in id2label.items()}
211
+
212
+ # 1. Reconstruct model with the same LoRA config used during training
213
+ base_model = ViTForImageClassification.from_pretrained(
214
+ BASE,
215
+ num_labels=100,
216
+ id2label=id2label,
217
+ label2id=label2id,
218
+ ignore_mismatched_sizes=True,
219
+ )
220
+ lora_config = LoraConfig(
221
+ r=8,
222
+ lora_alpha=8,
223
+ lora_dropout=0.1,
224
+ target_modules=["query", "key", "value"],
225
+ bias="none",
226
+ )
227
+ model = get_peft_model(base_model, lora_config)
228
+
229
+ # 2. Download and load best_model.pt
230
+ ckpt_path = hf_hub_download(repo_id=REPO, filename="best_model.pt")
231
+ state_dict = torch.load(ckpt_path, map_location="cpu")
232
+ model.load_state_dict(state_dict, strict=False)
233
  model.eval()
234
+ print("Model loaded successfully.")
235
 
236
+ # 3. Inference
237
+ processor = ViTImageProcessor.from_pretrained(BASE)
238
  image = Image.open("your_image.jpg").convert("RGB")
239
  inputs = processor(images=image, return_tensors="pt")
240
+
241
+ with torch.no_grad():
242
+ logits = model(**inputs).logits
243
+
244
+ pred_id = logits.argmax(-1).item()
245
+ confidence = logits.softmax(-1)[0, pred_id].item()
246
+ print(f"Predicted class : {id2label[pred_id]}")
247
+ print(f"Confidence : {confidence * 100:.1f}%")
248
+ ```
249
+
250
+ ### Batch inference
251
+
252
+ ```python
253
+ images = [Image.open(p).convert("RGB") for p in image_paths]
254
+ inputs = processor(images=images, return_tensors="pt")
255
+
256
  with torch.no_grad():
257
+ logits = model(**inputs).logits
258
+
259
+ preds = logits.argmax(-1).tolist()
260
+ for path, pred in zip(image_paths, preds):
261
+ print(f"{path} → {id2label[pred]}")
262
  ```
263
+
264
+ ---
265
+
266
+ ## Repository files
267
+
268
+ | File | Description |
269
+ |------|-------------|
270
+ | `best_model.pt` | Full state dict of the best ViT-S + LoRA model (exp10, r=8 α=8) |
271
+ | `README.md` | This model card |
272
+
273
+ Training code, logs, and all experiment weights are available in the [GitHub repository](https://github.com/MSG1999/DLOps-A5).
274
+
275
+ ---
276
+
277
+ ## Citation
278
+
279
+ ```bibtex
280
+ @misc{gadiya2026vitlora,
281
+ title = {ViT-Small + LoRA Fine-tuning on CIFAR-100},
282
+ author = {Mahek Gadiya},
283
+ year = {2026},
284
+ note = {DLOps Assignment 5 — Q1, IIT Jodhpur},
285
+ url = {https://huggingface.co/MSG1999/vit-lora-cifar100},
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ <div align="center">
292
+ DLOps Assignment 5 &nbsp;|&nbsp; IIT Jodhpur &nbsp;|&nbsp;
293
+ <a href="https://huggingface.co/MSG1999">MSG1999</a>
294
+ </div>