Files
IQ.Pilot/iqpilot/scripts/model_compile/model_compile_optimized.sh
T
2026-07-11 09:58:33 -05:00

231 lines
8.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Optimized add-model pipeline: compiles the supercombo pkl for QCOM
# OFF-DEVICE (~17s in an arm64 docker via the tinydreno NULL:QCOMCL backend)
# instead of 5-10min on the SD845; the device only runs a ~90s finalize
# (one-time/weight-prep kernel replay + local-size rebake) and smoke
# validation, then the artifact is staged into the IQModels vault.
# Edit the MODEL_* / COMMA_COMMIT / ONNX_SHA block below per model.
# Companion tools live alongside this script.
set -euo pipefail
DEVICE_IP="${DEVICE_IP:-192.168.173.125}"
DEVICE_USER="${DEVICE_USER:-iq}"
IQPILOT_LOCAL="${IQPILOT_LOCAL:-/Users/t/Developer/iqpilot/iqpilot}"
IQMODELS="${IQMODELS:-/Volumes/New New Vault/IQModels}"
MODEL_SLUG="drlv17exp"
MODEL_LABEL="DRLV17EXP"
MODEL_DISPLAY="DeepRL v17 Exp (July 10, 2026)"
ARTIFACT="driving_supercombo_${MODEL_SLUG}.pkl"
COMMA_COMMIT="81cea09207ca94de867b7f0ddd0a3ea9540bb62b"
ONNX_SHA="b4b454d0816eb3019c3696caebeb1e72e49f982048d519285a87ab77a08ac48e"
CONTAINER="qcomcompile"
HC="$IQPILOT_LOCAL/iqpilot/scripts/model_compile"
COMMA_TMP="/tmp/comma-openpilot-${MODEL_SLUG}"
WORK="$(mktemp -d /tmp/hostcompile-${MODEL_SLUG}.XXXX)"
trap 'rm -rf "$WORK" "$COMMA_TMP"' EXIT
export IQMODELS MODEL_LABEL MODEL_DISPLAY ARTIFACT COMMA_COMMIT
# --- 1. fetch + pin the onnx ---
rm -rf "$COMMA_TMP"
git init -q "$COMMA_TMP"
git -C "$COMMA_TMP" remote add origin https://github.com/commaai/openpilot.git
git -C "$COMMA_TMP" fetch --depth 1 origin "$COMMA_COMMIT"
GIT_LFS_SKIP_SMUDGE=1 git -C "$COMMA_TMP" checkout -q FETCH_HEAD
git -C "$COMMA_TMP" lfs install --local
git -C "$COMMA_TMP" lfs pull --include="openpilot/selfdrive/modeld/models/driving_supercombo.onnx"
ONNX_LOCAL="$COMMA_TMP/openpilot/selfdrive/modeld/models/driving_supercombo.onnx"
ACTUAL_ONNX_SHA="$(shasum -a 256 "$ONNX_LOCAL" | awk '{print $1}')"
echo "ONNX SHA: $ACTUAL_ONNX_SHA"
test "$ACTUAL_ONNX_SHA" = "$ONNX_SHA"
cp "$ONNX_LOCAL" "$WORK/model.onnx"
# --- 2. ensure the arm64 compile container ---
if [ "$(docker inspect -f '{{.State.Running}}' "$CONTAINER" 2>/dev/null)" != "true" ]; then
docker rm -f "$CONTAINER" 2>/dev/null || true
docker run -d --name "$CONTAINER" --platform linux/arm64 --shm-size=2g \
-v "$IQPILOT_LOCAL":/op -e PYTHONDONTWRITEBYTECODE=1 \
python:3.12-bookworm sleep infinity
# tinydreno compiler: same binary the device itself compiles with
scp -q "$DEVICE_USER@$DEVICE_IP:/usr/lib/aarch64-linux-gnu/libllvm-qcom.so" "$WORK/libllvm-qcom.so"
docker cp "$WORK/libllvm-qcom.so" "$CONTAINER":/usr/lib/libllvm-qcom.so
docker exec "$CONTAINER" bash -c "apt-get update -qq && apt-get install -y -qq clang && \
pip install -q numpy zstandard pycapnp requests smbus2 pyserial pyzmq cryptography"
fi
docker exec "$CONTAINER" mkdir -p /work-"$MODEL_SLUG"
docker cp "$WORK/model.onnx" "$CONTAINER":/work-"$MODEL_SLUG"/model.onnx
# --- 3. compile off-device (scheduling + Adreno codegen, ~20s) ---
docker exec "$CONTAINER" bash -c "cd /op && env \
DEV='NULL:QCOMCL:a630,IMAGE_PITCH_ALIGNMENT=64' \
WARP_DEV=NULL NULL_ALLOW_COPYOUT=1 \
IMAGE=2 FLOAT16=1 NOLOCALS=1 JIT_BATCH_SIZE=0 OPENPILOT_HACKS=1 \
PYTHONPATH=/op:/op/tinygrad_repo \
python /op/iqpilot/scripts/model_compile/host_compile_shim.py \
--model-size 512x256 --camera-resolutions 1344x760 1928x1208 \
--onnx /work-$MODEL_SLUG/model.onnx --output /work-$MODEL_SLUG/host.pkl --frame-skip 4"
docker cp "$CONTAINER":/work-"$MODEL_SLUG"/host.pkl "$WORK/host.pkl"
docker exec "$CONTAINER" rm -rf /work-"$MODEL_SLUG"
# --- 4. remap device strings NULL -> QCOM ---
python3 "$HC/remap_pkl.py" "$WORK/host.pkl" "$WORK/qcom.pkl"
# --- 5. device: rebake local sizes (~30s) + smoke validate ---
DEVICE_ENV="HOME=/data/root-home XDG_CACHE_HOME=/data/root-cache TMPDIR=/data/root-tmp \
PYTHONPATH=/data/openpilot:/data/openpilot/tinygrad_repo \
PATH=/usr/local/venv/bin:/usr/sbin:/usr/bin:/sbin:/bin VIRTUAL_ENV=/usr/local/venv \
DEV=QCOM WARP_DEV=QCOM IMAGE=2 FLOAT16=1 NOLOCALS=1 JIT_BATCH_SIZE=0 OPENPILOT_HACKS=1"
scp -q "$WORK/qcom.pkl" "$DEVICE_USER@$DEVICE_IP:/data/media/0/models/${MODEL_SLUG}.unbaked.pkl"
scp -q "$HC/finalize_pkl.py" "$HC/smoke_validate_pkl.py" "$DEVICE_USER@$DEVICE_IP:/data/media/0/"
ssh "$DEVICE_USER@$DEVICE_IP" "sudo mkdir -p /data/root-home /data/root-cache /data/root-tmp && \
sudo env $DEVICE_ENV /usr/local/venv/bin/python /data/media/0/finalize_pkl.py \
/data/media/0/models/${MODEL_SLUG}.unbaked.pkl /data/media/0/models/${ARTIFACT} && \
sudo env $DEVICE_ENV /usr/local/venv/bin/python /data/media/0/smoke_validate_pkl.py \
/data/media/0/models/${ARTIFACT} && \
sudo rm /data/media/0/models/${MODEL_SLUG}.unbaked.pkl"
# --- 6. pull artifact, checksum, stage into IQModels vault ---
scp -q "$DEVICE_USER@$DEVICE_IP:/data/media/0/models/${ARTIFACT}" "/tmp/${ARTIFACT}"
LOCAL_SHA="$(shasum -a 256 "/tmp/${ARTIFACT}" | awk '{print $1}')"
LOCAL_SIZE="$(stat -f%z "/tmp/${ARTIFACT}")"
test "$LOCAL_SIZE" -gt 100000000
export MODEL_SHA="$LOCAL_SHA"
mkdir -p "$IQMODELS/models/recompiled16/model-${MODEL_LABEL}"
cp "/tmp/${ARTIFACT}" "$IQMODELS/models/recompiled16/model-${MODEL_LABEL}/${ARTIFACT}"
chmod 644 "$IQMODELS/models/recompiled16/model-${MODEL_LABEL}/${ARTIFACT}" 2>/dev/null || true
python3 <<'PY'
import copy
import json
import os
from datetime import datetime, timezone
from pathlib import Path
root = Path(os.environ["IQMODELS"])
short = os.environ["MODEL_LABEL"]
display = os.environ["MODEL_DISPLAY"]
filename = os.environ["ARTIFACT"]
sha = os.environ["MODEL_SHA"]
ref = os.environ["COMMA_COMMIT"]
url = (
"https://git.konn3kt.com/teal/IQModels/raw/branch/main/"
f"models/recompiled16/model-{short}/{filename}"
)
def walk(value):
if isinstance(value, dict):
yield value
for child in value.values():
yield from walk(child)
elif isinstance(value, list):
for child in value:
yield from walk(child)
def find(value, name):
if isinstance(value, list):
for i, item in enumerate(value):
if isinstance(item, dict) and item.get("short_name") == name:
return value, i
for item in value:
result = find(item, name)
if result:
return result
elif isinstance(value, dict):
for child in value.values():
result = find(child, name)
if result:
return result
return None
def patch(value):
if isinstance(value, dict):
for key, child in list(value.items()):
if key.lower() in {"sha", "sha256", "hash", "checksum"} and isinstance(child, str):
value[key] = sha
elif key == "file_name" and isinstance(child, str) and "driving_supercombo" in child:
value[key] = filename
elif key == "url" and isinstance(child, str) and "driving_supercombo" in child:
value[key] = url
else:
patch(child)
elif isinstance(value, list):
for child in value:
patch(child)
for relative in ("docs/model_selector_b.json", "docs/model_fetcher_b.json"):
path = root / relative
data = json.loads(path.read_text())
if any(
isinstance(item, dict) and item.get("short_name") == short
for item in walk(data)
):
raise SystemExit(f"{relative}: {short} already exists")
template = (
find(data, "DRLV16")
or find(data, "DIVRLV4")
or find(data, "DIVRLV3")
or find(data, "DIVRL")
or find(data, "DRLV7")
)
if not template:
raise SystemExit(f"{relative}: template not found")
parent, index = template
entry = copy.deepcopy(parent[index])
max_index = max(
(
item["index"]
for item in walk(data)
if isinstance(item, dict) and isinstance(item.get("index"), int)
),
default=0,
)
entry["short_name"] = short
entry["display_name"] = display
entry["ref"] = ref
entry["index"] = max_index + 1
if "build_time" in entry:
entry["build_time"] = (
datetime.now(timezone.utc)
.replace(microsecond=0)
.isoformat()
.replace("+00:00", "Z")
)
patch(entry)
parent.insert(index + 1, entry)
path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n")
print(f"{relative}: inserted {short}, index={entry['index']}, sha={sha}")
PY
python3 -m json.tool "$IQMODELS/docs/model_selector_b.json" >/dev/null
python3 -m json.tool "$IQMODELS/docs/model_fetcher_b.json" >/dev/null
REL="models/recompiled16/model-${MODEL_LABEL}/${ARTIFACT}"
git -C "$IQMODELS" add -- \
"$REL" \
docs/model_selector_b.json \
docs/model_fetcher_b.json
STAGED_SIZE="$(git -C "$IQMODELS" cat-file -s ":${REL}")"
test "$STAGED_SIZE" -gt 100000000
git -C "$IQMODELS" diff --staged --stat
git -C "$IQMODELS" commit -m "Add ${MODEL_LABEL} model (host-compiled)"
echo
echo "DONE — artifact SHA: $MODEL_SHA"
echo "Push with: git -C \"$IQMODELS\" push"