Habeeb Okunade commited on
Commit
4e7f56d
·
1 Parent(s): 5bbbe03

Update Training script

Browse files
Files changed (2) hide show
  1. Dockerfile +21 -13
  2. train.py +50 -18
Dockerfile CHANGED
@@ -1,5 +1,11 @@
1
  FROM python:3.10-slim
2
 
 
 
 
 
 
 
3
  # Create non-root user
4
  RUN adduser --disabled-password --gecos '' user
5
  USER user
@@ -7,27 +13,29 @@ USER user
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=/home/user/.cache/huggingface \
26
- TRANSFORMERS_CACHE=/home/user/.cache/huggingface/transformers \
27
- TORCH_HOME=/home/user/.cache/torch
28
-
29
- RUN mkdir -p $HF_HOME $TRANSFORMERS_CACHE $TORCH_HOME
30
  RUN chmod +x startup.sh
31
 
 
 
 
32
  # Start API
33
- CMD ["bash", "startup.sh"]
 
1
  FROM python:3.10-slim
2
 
3
+ # Install system dependencies (for Pillow and general Python packages)
4
+ USER root
5
+ RUN apt-get update && \
6
+ apt-get install -y libjpeg-dev zlib1g-dev git && \
7
+ rm -rf /var/lib/apt/lists/*
8
+
9
  # Create non-root user
10
  RUN adduser --disabled-password --gecos '' user
11
  USER user
 
13
  # Environment variables
14
  ENV HOME=/home/user \
15
  PATH=/home/user/.local/bin:$PATH \
16
+ PORT=7860 \
17
+ HF_HOME=/home/user/.cache/huggingface \
18
+ TRANSFORMERS_CACHE=/home/user/.cache/huggingface/transformers \
19
+ TORCH_HOME=/home/user/.cache/torch \
20
+ OUTPUT_DIR=/home/user/outputs/beit-retina
21
 
22
  WORKDIR $HOME/app
23
 
24
+ # Create necessary directories
25
+ RUN mkdir -p $HF_HOME $TRANSFORMERS_CACHE $TORCH_HOME $OUTPUT_DIR
26
+
27
+ # Copy requirements first for caching
28
  COPY --chown=user requirements.txt ./
29
  RUN pip install --no-cache-dir -r requirements.txt
30
 
31
+ # Copy app
32
  COPY --chown=user . .
33
 
34
+ # Make startup script executable
 
 
 
 
 
 
 
 
35
  RUN chmod +x startup.sh
36
 
37
+ # Expose port
38
+ EXPOSE 7860
39
+
40
  # Start API
41
+ CMD ["bash", "startup.sh"]
train.py CHANGED
@@ -1,17 +1,27 @@
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)
@@ -20,16 +30,21 @@ def compute_metrics(eval_pred):
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),
@@ -37,8 +52,18 @@ def train(output_dir="/outputs/beit-retina", train_dir="data/train", val_dir="da
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,
@@ -50,6 +75,7 @@ def train(output_dir="/outputs/beit-retina", train_dir="data/train", val_dir="da
50
  report_to="none"
51
  )
52
 
 
53
  trainer = Trainer(
54
  model=model,
55
  args=args,
@@ -59,13 +85,19 @@ def train(output_dir="/outputs/beit-retina", train_dir="data/train", val_dir="da
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
+ import os
2
+ import json
3
+ from PIL import Image
4
  from transformers import AutoImageProcessor, BeitForImageClassification, TrainingArguments, Trainer
5
  from datasets import load_dataset
6
  from sklearn.metrics import accuracy_score, f1_score
7
  import numpy as np
8
 
9
+ # -------------------------------
10
+ # Config
11
+ # -------------------------------
12
  CLASSES = ["AMD","DMO","DR","GLC","HR","Normal"]
13
  MODEL_NAME = "microsoft/beit-base-patch16-224"
14
 
15
+ # Output directory (from env or default)
16
+ OUTPUT_DIR = os.environ.get("OUTPUT_DIR", os.path.join(os.environ["HOME"], "outputs/beit-retina"))
17
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
18
 
19
+ print("HOME dir:", os.environ.get("HOME"))
20
+ print("HF cache:", os.environ.get("HF_HOME"))
21
 
22
+ # -------------------------------
23
+ # Metrics
24
+ # -------------------------------
25
  def compute_metrics(eval_pred):
26
  logits, labels = eval_pred
27
  preds = np.argmax(logits, axis=1)
 
30
  "f1_weighted": f1_score(labels, preds, average="weighted")
31
  }
32
 
33
+ # -------------------------------
34
+ # Preprocessing function
35
+ # -------------------------------
36
+ def transform(examples, processor):
37
+ """Converts image paths to pixel_values tensors."""
38
+ images = [processor(Image.open(p).convert("RGB"), return_tensors="pt")["pixel_values"][0]
39
+ for p in examples["image"]]
40
+ return {"pixel_values": images}
 
41
 
42
+ # -------------------------------
43
+ # Training function
44
+ # -------------------------------
45
+ def train(train_dir="data/train", val_dir="data/val", epochs=5, batch_size=16):
46
+ # Load processor and model
47
+ processor = AutoImageProcessor.from_pretrained(MODEL_NAME)
48
  model = BeitForImageClassification.from_pretrained(
49
  MODEL_NAME,
50
  num_labels=len(CLASSES),
 
52
  label2id={c: i for i, c in enumerate(CLASSES)}
53
  )
54
 
55
+ # Load dataset
56
+ dataset = load_dataset("imagefolder", data_dir={"train": train_dir, "validation": val_dir})
57
+
58
+ # Map transform over dataset
59
+ dataset = dataset.map(lambda x: transform(x, processor), batched=True)
60
+
61
+ # Ensure dataset returns PyTorch tensors
62
+ dataset.set_format(type="torch", columns=["pixel_values", "label"])
63
+
64
+ # Training arguments
65
  args = TrainingArguments(
66
+ output_dir=OUTPUT_DIR,
67
  per_device_train_batch_size=batch_size,
68
  per_device_eval_batch_size=batch_size,
69
  num_train_epochs=epochs,
 
75
  report_to="none"
76
  )
77
 
78
+ # Trainer
79
  trainer = Trainer(
80
  model=model,
81
  args=args,
 
85
  compute_metrics=compute_metrics
86
  )
87
 
88
+ # Train
89
  trainer.train()
 
 
90
 
91
+ # Save model and processor
92
+ model.save_pretrained(OUTPUT_DIR)
93
+ processor.save_pretrained(OUTPUT_DIR)
94
+
95
+ # Save labels
96
+ with open(os.path.join(OUTPUT_DIR, "labels.json"), "w") as f:
97
  json.dump(CLASSES, f)
98
+
99
+ print("✅ Training complete. Model saved at:", OUTPUT_DIR)
100
+
101
 
102
  if __name__ == "__main__":
103
  train()