Image Segmentation
ultralytics
Core ML
mask-generation
face-parsing
semantic-segmentation
yolo26
ios
on-device
celebamask-hq
Instructions to use a-ml/yolo26-face with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- ultralytics
How to use a-ml/yolo26-face with ultralytics:
# Couldn't find a valid YOLO version tag. # Replace XX with the correct version. from ultralytics import YOLOvXX model = YOLOvXX.from_pretrained("a-ml/yolo26-face") source = 'http://images.cocodataset.org/val2017/000000039769.jpg' model.predict(source=source, save=True) - Notebooks
- Google Colab
- Kaggle
File size: 4,546 Bytes
e2f3b24 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | """
Train YOLO26 semantic segmentation on CelebAMask-HQ (19-class face parsing).
Variants: nano (realtime, ships in the iOS app) and large (accuracy reference).
imgsz=512 == deploy resolution (masks are natively 512). ENet inverse-log class
weighting is automatic in the semantic trainer (rare classes: glasses/hat/
earring/necklace).
Augmentation notes:
* fliplr=0.0 -- CRITICAL. RandomFlip flips geometry WITHOUT swapping the
left/right class labels, so any hflip corrupts l_eye/r_eye, l_brow/r_brow,
l_ear/r_ear. Must stay disabled.
* mosaic + degrees/translate/scale -- scale/position/tilt robustness to close
the aligned-crop (CelebA-HQ) -> live-selfie domain gap.
Throughput: uses MPSWorkersTrainer to undo ultralytics' forced workers=0 on MPS.
Timing probe: ml/train.py --epochs 1 --fraction 0.04 --no-val --name bench_X
Full run: ml/train.py --model yolo26l-sem.pt --epochs 60 --name celeba_large
"""
import argparse
from ultralytics import YOLO
from fast_trainer import MPSWorkersTrainer
DATA = "/Users/ari/FaceSegmentation/dataset_celebamaskhq_semantic/data.yaml"
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--data", default=DATA)
ap.add_argument("--model", default="yolo26n-sem.pt")
ap.add_argument("--epochs", type=int, default=100)
ap.add_argument("--imgsz", type=int, default=512)
ap.add_argument("--batch", type=int, default=32)
ap.add_argument("--fraction", type=float, default=1.0)
ap.add_argument("--device", default="mps")
ap.add_argument("--workers", type=int, default=8)
ap.add_argument("--name", default="celeba_face")
ap.add_argument("--project", default="/Users/ari/FaceSegmentation/runs_semantic")
ap.add_argument("--patience", type=int, default=30)
ap.add_argument("--cache", default="False")
ap.add_argument("--mosaic", type=float, default=0.5)
ap.add_argument("--val", action=argparse.BooleanOptionalAction, default=True)
ap.add_argument("--plots", action=argparse.BooleanOptionalAction, default=True)
# deterministic=True (ultralytics default) forces slow MPS kernels in the
# semantic loss -- measured 5037 -> 2293 ms/iter when disabled.
ap.add_argument("--deterministic", action=argparse.BooleanOptionalAction, default=False)
ap.add_argument("--amp", action=argparse.BooleanOptionalAction, default=True)
ap.add_argument("--val-period", type=int, default=1,
help="validate every Nth epoch (plus the final epoch)")
# ENet weights are (1/ln(1.02+p))**cls_pw. Ultralytics defaults cls_pw=0.0,
# which makes every weight exactly 1.0 -- i.e. class weighting silently OFF.
# At 1.0 the rare classes (necklace/eyes/glasses/earring) get ~45-50x the
# weight of hair/background/skin (~3.4-4.2), a 14.6x dynamic range.
ap.add_argument("--cls-pw", type=float, default=1.0,
help="ENet class-weight exponent; 0 disables class weighting")
# The stock loss upsamples stride-8 logits to full mask resolution (159M
# elements at 512/b32). Evaluating it lower is much cheaper but gives up
# some sub-grid boundary supervision. 0 = stock behaviour.
ap.add_argument("--loss-size", type=int, default=0,
help="compute the loss at this resolution instead of full mask res")
args = ap.parse_args()
if args.loss_size:
import loss_patch
loss_patch.apply(args.loss_size)
print(f"loss_patch: computing semantic loss at {args.loss_size}px")
MPSWorkersTrainer.val_period = args.val_period
model = YOLO(args.model)
model.train(
trainer=MPSWorkersTrainer,
data=args.data,
epochs=args.epochs,
imgsz=args.imgsz,
batch=args.batch,
device=args.device,
workers=args.workers,
project=args.project,
name=args.name,
fraction=args.fraction,
patience=args.patience,
cache=args.cache,
deterministic=args.deterministic,
amp=args.amp,
cls_pw=args.cls_pw,
# --- augmentation tuned for face parsing ---
fliplr=0.0, # CRITICAL: preserves left/right class semantics
flipud=0.0,
degrees=10.0, # head tilt
translate=0.1,
scale=0.5,
mosaic=args.mosaic,
close_mosaic=10,
mixup=0.0,
copy_paste=0.0,
# default hsv_* kept for lighting robustness
val=args.val,
plots=args.plots,
seed=0,
exist_ok=True,
)
if __name__ == "__main__":
main()
|