Habeeb Okunade commited on
Commit
9633807
·
1 Parent(s): e2b01e7

Fine-tuning the Beit pre-trained model

Browse files
Files changed (6) hide show
  1. .gitattributes +6 -0
  2. Dockerfile +3 -30
  3. app.py +3 -48
  4. requirements.txt +3 -12
  5. startup.sh +3 -4
  6. train.py +3 -71
.gitattributes CHANGED
@@ -1,3 +1,9 @@
 
 
 
 
 
 
1
  *.png filter=lfs diff=lfs merge=lfs -text
2
  *.jpg filter=lfs diff=lfs merge=lfs -text
3
  *.jpeg filter=lfs diff=lfs merge=lfs -text
 
1
+ app.py filter=lfs diff=lfs merge=lfs -text
2
+ data filter=lfs diff=lfs merge=lfs -text
3
+ Dockerfile filter=lfs diff=lfs merge=lfs -text
4
+ requirements.txt filter=lfs diff=lfs merge=lfs -text
5
+ startup.sh filter=lfs diff=lfs merge=lfs -text
6
+ train.py filter=lfs diff=lfs merge=lfs -text
7
  *.png filter=lfs diff=lfs merge=lfs -text
8
  *.jpg filter=lfs diff=lfs merge=lfs -text
9
  *.jpeg filter=lfs diff=lfs merge=lfs -text
Dockerfile CHANGED
@@ -1,30 +1,3 @@
1
- FROM python:3.10-slim
2
-
3
- # Create non-root user
4
- RUN adduser --disabled-password --gecos '' user
5
- USER user
6
-
7
- # Environment variables
8
- ENV HOME=/home/user \
9
- PATH=/home/user/.local/bin:$PATH \
10
- PORT=7860
11
-
12
- WORKDIR $HOME/app
13
-
14
- # Copy requirements first (better for Docker layer caching)
15
- COPY --chown=user requirements.txt ./
16
- RUN pip install --no-cache-dir -r requirements.txt
17
-
18
- # Copy the rest of the application
19
- COPY --chown=user . .
20
-
21
- # Expose FastAPI default port for Hugging Face Spaces
22
- EXPOSE 7860
23
-
24
- # HF auth picked automatically from env (Spaces provides HF_TOKEN)
25
- ENV HF_HOME=/root/.cache/huggingface \
26
- TRANSFORMERS_CACHE=/root/.cache/huggingface/transformers \
27
- TORCH_HOME=/root/.cache/torch
28
-
29
- # Start API
30
- CMD ["bash", "startup.sh"]
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5c22cda261116e37bfe0d54cd627c4bae393711ecf9241ae0bcb0708505de385
3
+ size 771
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -1,48 +1,3 @@
1
- # app.py
2
- import os, json
3
- from fastapi import FastAPI, UploadFile
4
- from transformers import AutoImageProcessor, BeitForImageClassification
5
- from PIL import Image
6
- import torch
7
-
8
- MODEL_DIR = "outputs/beit-retina"
9
- CLASSES = ["AMD","DMO","DR","GLC","HR","Normal"]
10
-
11
- app = FastAPI(title="Retina Disease Classifier")
12
-
13
- # Lazy load model & processor
14
- processor = None
15
- model = None
16
-
17
- def load_model():
18
- global processor, model, CLASSES
19
- processor = AutoImageProcessor.from_pretrained(MODEL_DIR)
20
- model = BeitForImageClassification.from_pretrained(MODEL_DIR)
21
- with open(os.path.join(MODEL_DIR, "labels.json")) as f:
22
- CLASSES = json.load(f)
23
-
24
- @app.on_event("startup")
25
- def startup_event():
26
- if os.path.exists(MODEL_DIR):
27
- load_model()
28
-
29
- @app.post("/predict")
30
- async def predict(file: UploadFile):
31
- if model is None:
32
- return {"error": "Model not trained yet"}
33
- img = Image.open(file.file).convert("RGB")
34
- inputs = processor(images=img, return_tensors="pt")
35
- with torch.no_grad():
36
- logits = model(**inputs).logits
37
- probs = torch.softmax(logits, dim=1)[0].tolist()
38
- pred_id = int(torch.argmax(logits, dim=1).item())
39
- return {
40
- "class_id": CLASSES[pred_id],
41
- "probabilities": [{CLASSES[i]: float(p) for i, p in enumerate(probs)}]
42
- }
43
-
44
- @app.post("/train")
45
- async def train_endpoint():
46
- os.system("python train.py") # blocking training run
47
- load_model()
48
- return {"status": "Training complete and model reloaded"}
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4af62f87d886a945ea83769a8503175aa3223acce7bc67bf04dc77b7466fec56
3
+ size 1522
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,12 +1,3 @@
1
- torch
2
- torchvision
3
- transformers
4
- datasets
5
- accelerate
6
- scikit-learn
7
- fastapi
8
- uvicorn[standard]
9
- pillow
10
- pydantic==2.8.2
11
- python-multipart==0.0.9
12
- huggingface_hub==0.24.6
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:64cfb5f9134f154569f48ce0aa7eafa9030ca81176aa3fc6194d385e36cd8bfb
3
+ size 173
 
 
 
 
 
 
 
 
 
startup.sh CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- # In HF Spaces with Docker, CUDA is available if a GPU is provisioned.
4
- exec uvicorn app:app --host 0.0.0.0 --port ${PORT:-7860}
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e2ddf251bb3ea2548afe28f1275b333f1c01dcc6ed0d8f248faa7f2b24c1dda9
3
+ size 165
 
train.py CHANGED
@@ -1,71 +1,3 @@
1
- # train.py
2
- import os, json
3
- from transformers import AutoImageProcessor, BeitForImageClassification, TrainingArguments, Trainer
4
- from datasets import load_dataset
5
- from sklearn.metrics import accuracy_score, f1_score
6
- import numpy as np
7
-
8
- CLASSES = ["AMD","DMO","DR","GLC","HR","Normal"]
9
- MODEL_NAME = "microsoft/beit-base-patch16-224"
10
-
11
- print("HOME dir:", os.environ.get("HOME"))
12
- print("HF cache:", os.environ.get("HF_HOME", os.path.join(os.environ["HOME"], ".cache", "huggingface")))
13
-
14
-
15
- def compute_metrics(eval_pred):
16
- logits, labels = eval_pred
17
- preds = np.argmax(logits, axis=1)
18
- return {
19
- "accuracy": accuracy_score(labels, preds),
20
- "f1_weighted": f1_score(labels, preds, average="weighted")
21
- }
22
-
23
- def train(output_dir="/outputs/beit-retina", train_dir="data/train", val_dir="data/val", epochs=5, batch_size=16):
24
- processor = AutoImageProcessor.from_pretrained(MODEL_NAME)
25
- dataset = load_dataset("imagefolder", data_dir={"train": train_dir, "validation": val_dir})
26
-
27
- def transform(examples):
28
- images = [processor(Image.open(p).convert("RGB"), return_tensors="pt")["pixel_values"][0] for p in examples["image"]]
29
- return {"pixel_values": images}
30
-
31
- dataset = dataset.cast_column("label", dataset["train"].features["label"].cast(type="ClassLabel", names=CLASSES))
32
-
33
- model = BeitForImageClassification.from_pretrained(
34
- MODEL_NAME,
35
- num_labels=len(CLASSES),
36
- id2label={i: c for i, c in enumerate(CLASSES)},
37
- label2id={c: i for i, c in enumerate(CLASSES)}
38
- )
39
-
40
- args = TrainingArguments(
41
- output_dir=output_dir,
42
- per_device_train_batch_size=batch_size,
43
- per_device_eval_batch_size=batch_size,
44
- num_train_epochs=epochs,
45
- evaluation_strategy="epoch",
46
- save_strategy="epoch",
47
- load_best_model_at_end=True,
48
- metric_for_best_model="f1_weighted",
49
- logging_steps=50,
50
- report_to="none"
51
- )
52
-
53
- trainer = Trainer(
54
- model=model,
55
- args=args,
56
- train_dataset=dataset["train"],
57
- eval_dataset=dataset["validation"],
58
- tokenizer=processor,
59
- compute_metrics=compute_metrics
60
- )
61
-
62
- trainer.train()
63
- model.save_pretrained(output_dir)
64
- processor.save_pretrained(output_dir)
65
-
66
- with open(os.path.join(output_dir, "labels.json"), "w") as f:
67
- json.dump(CLASSES, f)
68
- print("✅ Training complete. Model saved at:", output_dir)
69
-
70
- if __name__ == "__main__":
71
- train()
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:09b73a425fc928a3220b6e598bd618b454ca8b8d34cba277608dcd01baf3ea73
3
+ size 2529