Manar55 commited on
Commit
bddca5d
·
verified ·
1 Parent(s): 611c278

Deploy 3a26184

Browse files
Files changed (1) hide show
  1. server/train_plate_chars.py +55 -0
server/train_plate_chars.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Trains the Saudi plate character detector (YOLOv8) and writes
3
+ plate_chars.pt. Used by .github/workflows/train-plate-chars.yml (CPU runner,
4
+ so a time budget keeps it inside GitHub's 6-hour job limit) and runnable by
5
+ hand: python server/train_plate_chars.py <folder with data.yaml> [hours]
6
+ """
7
+ import glob
8
+ import os
9
+ import shutil
10
+ import sys
11
+
12
+ import yaml
13
+ from ultralytics import YOLO
14
+
15
+
16
+ def fix_yaml(root):
17
+ yp = glob.glob(os.path.join(root, "**", "data.yaml"), recursive=True)[0]
18
+ base = os.path.dirname(os.path.abspath(yp))
19
+ d = yaml.safe_load(open(yp))
20
+ d["path"] = base
21
+ for k, cands in (("train", ["train"]), ("val", ["valid", "val"]), ("test", ["test"])):
22
+ for c in cands:
23
+ p = os.path.join(base, c, "images")
24
+ if os.path.isdir(p):
25
+ d[k] = p
26
+ break
27
+ else:
28
+ d.pop(k, None)
29
+ d.setdefault("val", d["train"])
30
+ yaml.safe_dump(d, open(yp, "w"), allow_unicode=True)
31
+ print(f"classes ({d['nc']}): {d['names']}", flush=True)
32
+ return yp
33
+
34
+
35
+ def main():
36
+ root = sys.argv[1] if len(sys.argv) > 1 else "data"
37
+ hours = float(sys.argv[2]) if len(sys.argv) > 2 else 4.5
38
+ yp = fix_yaml(root)
39
+ import torch
40
+ gpu = torch.cuda.is_available()
41
+ model = YOLO("yolov8s.pt" if gpu else "yolov8n.pt")
42
+ model.train(data=yp, imgsz=640 if gpu else 512, epochs=80 if gpu else 40, patience=15,
43
+ batch=16, workers=4, time=hours, # stop (and keep best) within the budget
44
+ fliplr=0.0, # never mirror characters
45
+ degrees=8, perspective=0.0005, hsv_v=0.5, name="plate_chars", exist_ok=True)
46
+ best = sorted(glob.glob("runs/detect/plate_chars*/weights/best.pt"), key=os.path.getmtime)[-1]
47
+ r = YOLO(best).val(data=yp, imgsz=640 if gpu else 512)
48
+ print(f"mAP50 = {r.box.map50:.3f}", flush=True)
49
+ shutil.copy(best, "plate_chars.pt")
50
+ with open("train_summary.txt", "w") as f:
51
+ f.write(f"mAP50={r.box.map50:.3f}\nclasses={YOLO(best).names}\n")
52
+
53
+
54
+ if __name__ == "__main__":
55
+ main()