#!/usr/bin/env bash # mia-run — one-shot Make-It-Animatable v2 auto-rig on fv-ml1 GPU 3 (dread-dev / Dread Naught; # Prime's request, 2026-10-01). Same shape as blender-run: a container starts, rigs, exits, and # hands the GPU back. NOT a seat; nothing stays up between calls. # # scripts/mia-run --job DIR [--seed N | --unseeded] -- = [= ...] # scripts/mia-run --job ~/development/dreadnaught/rig-jobs/j1 -- goblin=in/goblin.glb ogre=in/ogre.glb # # Inputs are paths RELATIVE TO DIR and must be inside it: DIR is the only thing shipped to fv-ml1. # Per mesh, DIR/out/ receives: # _pred.npz predictions in the input's coordinates, WITH `weights_effective` # (the finalize.py formula), so no finalize step is needed afterwards # .fbx .glb _rest.glb MIA's own exports (UI defaults, static rig) # _apose-hint.fbx .glb _rest.glb same predictions, Blender stage with the A-pose hint # _run.json stage timings, model-load time, peak GPU memory, seed, provenance # The model load (~3 x 1 GB checkpoints) is paid once per call, so pass every mesh in one call. # # SEEDED BY DEFAULT (seed 0): before every mesh the driver calls MIA's fix_random(seed) and resets # trimesh's module RNG, which fix_random never reaches (trimesh >= 4 samples surfaces from # trimesh.util._RANDOM_DEFAULT). Without that, runs of the same mesh differ: joints by 0.1-0.27% of # height on dread-dev's CPU noise floor. --unseeded restores upstream behaviour. # # Files: fv-ml1 does NOT mount /mnt/smithy. DIR is mirrored to # fv-ml1:/tank/mia/jobs/-/ (rsync --delete, so a rerun never # inherits leftovers), the driver runs WITH THAT AS ITS WORKING DIRECTORY, and new or changed files # are copied back into DIR afterwards (nothing is ever deleted locally). Running the SAME DIR twice # concurrently shares one remote dir, so don't. Remote job dirs are never swept. # # Image: local/mia (stacks/mia; IMAGE= in fv-ml1:/opt/docker/compose/mia/.env). Weights come from # the read-only /tank/aimodels/huggingface mount at pinned revisions; the run never touches the # network (HF_HUB_OFFLINE=1). The skeleton template is a SUBSTITUTE ("Standard Run.fbx"): the # official one is in a gated HF dataset whose terms were not accepted (see stacks/mia/README.md). # # Budget: GPU 3 (96 GB, borrowed from the vLLM reserve, shared on demand with Blender and Scriberr; # this ends if a full-size seat moves in). Capped at 32 GB RAM / 16 CPUs so a runaway mesh cannot # starve the inference seats on the same host. set -euo pipefail HOST=${MIA_SSH_HOST:-infra-ops@10.251.50.54} ENV_FILE=/opt/docker/compose/mia/.env JOB="" DRIVER_OPTS=() while [ $# -gt 0 ]; do case "$1" in --job) JOB=${2:?--job needs a directory}; shift 2 ;; --seed) DRIVER_OPTS+=(--seed "${2:?--seed needs an integer}"); shift 2 ;; --unseeded) DRIVER_OPTS+=(--unseeded); shift ;; --) shift; break ;; -h|--help) sed -n 2,40p "$0"; exit 0 ;; *) echo "mia-run: unknown option $1 (meshes go after --)" >&2; exit 2 ;; esac done [ -n "$JOB" ] || { echo "mia-run: --job DIR is required (inputs are read from it, out/ is written into it)" >&2; exit 2; } [ $# -gt 0 ] || { echo "mia-run: no meshes; pass = after --" >&2; exit 2; } [ -d "$JOB" ] || { echo "mia-run: --job $JOB is not a directory" >&2; exit 2; } ABS=$(realpath "$JOB") BASE=$(basename "$ABS") [[ $BASE =~ ^[A-Za-z0-9._-]+$ ]] || { echo "mia-run: job dir name '$BASE' must be [A-Za-z0-9._-]" >&2; exit 2; } for m in "$@"; do [[ $m == *=* ]] || { echo "mia-run: '$m' is not =" >&2; exit 2; } f=$(realpath -m "$ABS/${m#*=}") [[ $f == "$ABS"/* && -f $f ]] || { echo "mia-run: input '${m#*=}' is not a file inside $ABS" >&2; exit 2; } done # Keyed on basename + a hash of the ABSOLUTE local path, as blender-run: two dirs that share a # basename never share a remote dir. rsync removes only inside that one remote dir; there is no rm # on a computed path. NAME=$BASE-$(printf '%s' "$ABS" | sha256sum | cut -c1-8) ssh -n -o BatchMode=yes "$HOST" "mkdir -p /tank/mia/jobs/$NAME" rsync -a --delete "$JOB"/ "$HOST:/tank/mia/jobs/$NAME/" # Arguments travel as one shell-quoted string: ssh flattens argv into a remote command line. ARGS=$(printf '%q ' "${DRIVER_OPTS[@]}" "$@") set +e ssh -n -o BatchMode=yes "$HOST" "IMG=\$(grep '^IMAGE=' $ENV_FILE | cut -d= -f2) && \ exec docker run --rm --name mia-run-\$\$ --hostname fv-ml1-mia \ --runtime nvidia -e NVIDIA_VISIBLE_DEVICES=3 -e NVIDIA_DRIVER_CAPABILITIES=compute,utility \ --user 1002:1003 --memory 32g --cpus 16 \ --mount type=bind,src=/tank/aimodels/huggingface,dst=/hf,readonly \ --mount type=bind,src=/tank/mia/jobs/$NAME,dst=/job \ -w /job \"\$IMG\" $ARGS" RC=$? set -e rsync -a --update "$HOST:/tank/mia/jobs/$NAME/" "$JOB"/ exit $RC