Spaces:
Sleeping
Sleeping
Habeeb Okunade commited on
Commit ·
9633807
1
Parent(s): e2b01e7
Fine-tuning the Beit pre-trained model
Browse files- .gitattributes +6 -0
- Dockerfile +3 -30
- app.py +3 -48
- requirements.txt +3 -12
- startup.sh +3 -4
- 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 |
-
|
| 2 |
-
|
| 3 |
-
|
| 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 |
-
|
| 2 |
-
|
| 3 |
-
|
| 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 |
-
|
| 2 |
-
|
| 3 |
-
|
| 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 |
-
|
| 2 |
-
|
| 3 |
-
|
| 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 |
-
|
| 2 |
-
|
| 3 |
-
|
| 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|