mirror of
https://gitlvb.teallvbs.xyz/IQ.Lvbs/IQ.Pilot.git
synced 2026-07-16 04:42:05 +08:00
231 lines
8.8 KiB
Bash
Executable File
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"
|