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: 3,950 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 | """
Visual end-to-end check of the SHIPPING path: run the .mlpackage exactly as the
iOS app does (center-square crop -> 512 input -> fp16 logits -> bilinear upsample
-> 19-way argmax -> palette LUT -> alpha mix) and write a contact sheet.
This mirrors SegmentationShaders.metal's math on the CPU, so a good-looking
sheet means the model AND the app's decode contract AND the palette are right.
Usage: verify_coreml_visual.py --model <.mlpackage> --out <dir> [--source <dir>]
"""
import argparse, glob, os
import numpy as np
from PIL import Image, ImageDraw
import coremltools as ct
from palette import CLASS_NAMES, PALETTE
PAL = np.array(PALETTE, dtype=np.float32)
def center_square(im):
w, h = im.size
s = min(w, h)
return im.crop(((w - s) // 2, (h - s) // 2, (w + s) // 2, (h + s) // 2))
def bilinear_upsample(logits, out):
"""(C,g,g) -> (C,out,out), matching the shader's bilinear sampler."""
C, g, _ = logits.shape
# sample centers, same convention as a normalized-UV bilinear sampler
coord = (np.arange(out) + 0.5) / out * g - 0.5
coord = np.clip(coord, 0, g - 1)
i0 = np.floor(coord).astype(int)
i1 = np.minimum(i0 + 1, g - 1)
w1 = (coord - i0).astype(np.float32)
w0 = 1.0 - w1
tmp = logits[:, :, i0] * w0 + logits[:, :, i1] * w1 # x interp
return tmp[:, i0, :] * w0[None, :, None] + tmp[:, i1, :] * w1[None, :, None]
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--model", required=True)
ap.add_argument("--out", default="/private/tmp/claude-501/-Users-ari-Documents-XcodeProjects-facesegmentation/149f7917-f682-4847-ba5b-1e726cecc20c/scratchpad/visual")
ap.add_argument("--source", default="/Users/ari/FaceSegmentation/dataset_celebamaskhq_semantic/images/val")
ap.add_argument("--n", type=int, default=8)
ap.add_argument("--alpha", type=float, default=0.55)
ap.add_argument("--tile", type=int, default=320)
args = ap.parse_args()
os.makedirs(args.out, exist_ok=True)
m = ct.models.MLModel(args.model, compute_units=ct.ComputeUnit.CPU_AND_NE)
spec_in = list(m.input_description)[0]
R = 512
files = sorted(glob.glob(os.path.join(args.source, "**", "*.jpg"), recursive=True))[: args.n]
if not files:
files = sorted(glob.glob(os.path.join(args.source, "**", "*.png"), recursive=True))[: args.n]
tiles, class_hits = [], np.zeros(len(CLASS_NAMES))
for p in files:
im = center_square(Image.open(p).convert("RGB")).resize((R, R), Image.BILINEAR)
out = m.predict({spec_in: im})
logits = np.asarray(out["logits"], dtype=np.float32)[0] # (19,g,g)
up = bilinear_upsample(logits, R) # (19,R,R)
cls = up.argmax(0).astype(np.int32)
class_hits += np.bincount(cls.ravel(), minlength=len(CLASS_NAMES)) / cls.size
rgb = np.asarray(im, dtype=np.float32)
col = PAL[cls]
a = (cls != 0).astype(np.float32)[..., None] * args.alpha
blend = (rgb * (1 - a) + col * a).astype(np.uint8)
pair = Image.new("RGB", (args.tile * 2, args.tile))
pair.paste(im.resize((args.tile, args.tile)), (0, 0))
pair.paste(Image.fromarray(blend).resize((args.tile, args.tile)), (args.tile, 0))
tiles.append(pair)
cols = 2
rows = (len(tiles) + cols - 1) // cols
W, H = tiles[0].size
sheet = Image.new("RGB", (cols * W, rows * H), (16, 16, 16))
for i, t in enumerate(tiles):
sheet.paste(t, ((i % cols) * W, (i // cols) * H))
sheet_path = os.path.join(args.out, "verify_sheet.jpg")
sheet.save(sheet_path, quality=92)
# legend of what the model actually predicted
order = np.argsort(-class_hits)
print("mean class coverage (top 10):")
for i in order[:10]:
if class_hits[i] > 0:
print(f" {CLASS_NAMES[i]:14s} {class_hits[i]/len(tiles):6.2%}")
print("wrote", sheet_path)
if __name__ == "__main__":
main()
|