The weights were in two places: face detection and recognition in `models/face/`, segmentation in `core/dr-segment/models/`. Nothing was wrong with either path, but between them there was nowhere to look to answer "how much model does this application carry", and that number is about to start growing. So the crate-local copy moves up beside the other. `models/` now holds `face/` and `segment/`, and a `du -sh` of one directory is the whole answer. No content changes: the .onnx and its vocabulary are byte-identical, and `LICENCE.md` moves up a level to cover the tree rather than one crate. The LFS pattern in `.gitattributes` is `*.onnx` and already matched both locations, so only its comment needed the new path. `include_bytes!` is relative to the source file and `build.rs` runs with the crate root as its working directory, which is why the two paths climb a different number of levels. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
65 lines
2.3 KiB
Bash
Executable File
65 lines
2.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Re-export the segmentation model that ships in models/ at the repository root.
|
|
#
|
|
# The .onnx is committed (D14), so this is not part of any build — it exists so
|
|
# the committed artefact is reproducible rather than a binary someone once
|
|
# produced and nobody can regenerate. Run it when bumping the model.
|
|
#
|
|
# ./tools/export-seg-model.sh
|
|
#
|
|
# Requires `uv`. Everything else is fetched into a throwaway venv.
|
|
#
|
|
# ## Why these export flags
|
|
#
|
|
# `dynamic=False` is not a default we failed to change: **tract cannot parse
|
|
# the dynamic-shape graph at all**, failing shape inference on the neck's
|
|
# Concat. A fixed input shape is a hard requirement of the pure-Rust backend
|
|
# (see the workspace manifest for why that backend was chosen), and it is what
|
|
# makes the tiling option in `semantic.rs` the only route to more resolution.
|
|
#
|
|
# `imgsz` square rather than a rectangle matched to 3:2: one graph has to
|
|
# serve portrait, landscape, square crops and panoramas. A landscape-shaped
|
|
# graph trades letterbox waste on 3:2 for worse waste on everything else.
|
|
set -euo pipefail
|
|
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO="$(cd "${HERE}/.." && pwd)"
|
|
OUT="${REPO}/models/segment"
|
|
|
|
MODEL="${1:-yolo26n-seg}"
|
|
IMGSZ="${2:-640}"
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "${WORK}"' EXIT
|
|
|
|
echo "==> exporting ${MODEL} at imgsz=${IMGSZ} in ${WORK}"
|
|
cd "${WORK}"
|
|
uv venv --python 3.12 venv
|
|
VIRTUAL_ENV="${WORK}/venv" uv pip install ultralytics onnx onnxslim
|
|
|
|
VIRTUAL_ENV="${WORK}/venv" "${WORK}/venv/bin/python" - "${MODEL}" "${IMGSZ}" <<'PY'
|
|
import sys, json
|
|
from ultralytics import YOLO
|
|
|
|
name = sys.argv[1]
|
|
imgsz = int(sys.argv[2])
|
|
m = YOLO(f"{name}.pt")
|
|
path = m.export(format="onnx", opset=17, simplify=True, imgsz=imgsz, dynamic=False)
|
|
print("ONNX:", path)
|
|
|
|
# The class names travel with the model rather than being retyped into Rust —
|
|
# a hand-copied vocabulary is a silent mismatch waiting to happen when the
|
|
# model is bumped.
|
|
with open("classes.json", "w") as f:
|
|
json.dump([m.names[i] for i in range(len(m.names))], f, indent=1)
|
|
print("classes:", len(m.names))
|
|
PY
|
|
|
|
mkdir -p "${OUT}"
|
|
cp "${WORK}/${MODEL}.onnx" "${OUT}/${MODEL}.onnx"
|
|
cp "${WORK}/classes.json" "${OUT}/${MODEL}.classes.json"
|
|
|
|
echo "==> wrote:"
|
|
ls -la "${OUT}"
|
|
echo
|
|
echo "Remember: these weights are AGPL-3.0 (see ${OUT}/LICENCE.md)."
|