From 752c07f9e4aa2a2a4812e0c7206685589572b9c8 Mon Sep 17 00:00:00 2001 From: James Vecellio-Grant <159560811+Discountchubbs@users.noreply.github.com> Date: Thu, 3 Sep 2026 05:22:43 -0700 Subject: [PATCH 1/5] ci: Replace hf oath with token (#1986) replace oauth with token --- .github/workflows/build-all-tinygrad-models.yaml | 1 + .github/workflows/build-default-models.yaml | 4 ++-- .github/workflows/build-single-tinygrad-model.yaml | 13 ++++--------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build-all-tinygrad-models.yaml b/.github/workflows/build-all-tinygrad-models.yaml index 7bddeab2b..8c2bcad0a 100644 --- a/.github/workflows/build-all-tinygrad-models.yaml +++ b/.github/workflows/build-all-tinygrad-models.yaml @@ -78,6 +78,7 @@ jobs: - name: Get next recompiled dir number id: create-recompiled-dir env: + HF_TOKEN: ${{ secrets.HF_TOKEN }} HF_REPO: ${{ github.event.inputs.hf_repo }} run: | pip install huggingface_hub diff --git a/.github/workflows/build-default-models.yaml b/.github/workflows/build-default-models.yaml index f2cb00767..d748d3ac1 100644 --- a/.github/workflows/build-default-models.yaml +++ b/.github/workflows/build-default-models.yaml @@ -341,7 +341,7 @@ jobs: - name: Upload model to HF if: ${{ inputs.target == 'small' || inputs.target == 'big' }} env: - HF_OIDC_RESOURCE: datasets/${{ env.HF_REPO }} + HF_TOKEN: ${{ secrets.HF_TOKEN }} ARTIFACT_NAME: ${{ steps.artifact.outputs.artifact_name }} run: | rm -f output/artifact_name.txt @@ -367,7 +367,7 @@ jobs: - name: Generate DM metadata and upload to HF if: ${{ inputs.target == 'dm' }} env: - HF_OIDC_RESOURCE: datasets/${{ env.HF_REPO }} + HF_TOKEN: ${{ secrets.HF_TOKEN }} run: | export PYTHONPATH=$(pwd) python3 -c " diff --git a/.github/workflows/build-single-tinygrad-model.yaml b/.github/workflows/build-single-tinygrad-model.yaml index c9d495c15..c795541e6 100644 --- a/.github/workflows/build-single-tinygrad-model.yaml +++ b/.github/workflows/build-single-tinygrad-model.yaml @@ -146,7 +146,7 @@ jobs: - name: Validate hf_repo and JSON version env: - HF_OIDC_RESOURCE: datasets/${{ inputs.hf_repo }} + HF_TOKEN: ${{ secrets.HF_TOKEN }} run: | if [ ! -f "$JSON_FILE" ]; then echo "JSON file $JSON_FILE does not exist!" @@ -155,13 +155,8 @@ jobs: python3 -c " import sys from huggingface_hub import HfApi - try: - api = HfApi() - api.repo_info(repo_id=sys.argv[1], repo_type='dataset') - print(f'Success: Repo {sys.argv[1]} exists.') - except Exception as e: - print('HF validation failed:', e) - sys.exit(1) + HfApi().repo_info(repo_id=sys.argv[1], repo_type='dataset') + print(f'Success: Repo {sys.argv[1]} exists.') " "${{ inputs.hf_repo }}" - name: Download artifact name file @@ -192,7 +187,7 @@ jobs: - name: Upload to Hugging Face env: - HF_OIDC_RESOURCE: datasets/${{ inputs.hf_repo }} + HF_TOKEN: ${{ secrets.HF_TOKEN }} ARTIFACT_NAME: ${{ steps.read-artifact-name.outputs.artifact_name }} run: | hf upload ${{ inputs.hf_repo }} \ From 132b31f4cf7b52a5a7e69f98afaba68ca0d43d62 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Thu, 3 Sep 2026 10:10:21 -0400 Subject: [PATCH 2/5] ci: poll GH API in prepare model jobs (#1987) --- .../workflows/sunnypilot-build-prebuilt.yaml | 114 ++++++++++++++---- 1 file changed, 90 insertions(+), 24 deletions(-) diff --git a/.github/workflows/sunnypilot-build-prebuilt.yaml b/.github/workflows/sunnypilot-build-prebuilt.yaml index c93dbe02c..dfcc7068e 100644 --- a/.github/workflows/sunnypilot-build-prebuilt.yaml +++ b/.github/workflows/sunnypilot-build-prebuilt.yaml @@ -216,6 +216,9 @@ jobs: needs: [ prepare_strategy ] runs-on: ubuntu-24.04 if: ${{ needs.prepare_strategy.outputs.include_big_model == 'true' }} + concurrency: + group: prepare-chestnut + cancel-in-progress: false outputs: onnx_sha256: ${{ steps.resolve.outputs.onnx_sha256 }} env: @@ -228,8 +231,10 @@ jobs: run: | REF="${{ github.head_ref || github.ref_name }}" - ONNX_HASH=$(gh api "repos/${GH_REPO}/contents/openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx?ref=${REF}" --jq '.content' | base64 -d | grep '^oid sha256:' | cut -d: -f2) + BLOB_SHA=$(gh api "repos/${GH_REPO}/contents/openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx?ref=${REF}" --jq '.sha') + ONNX_HASH=$(gh api "repos/${GH_REPO}/git/blobs/${BLOB_SHA}" --jq '.content' | base64 -d | grep '^oid sha256:' | cut -d: -f2) echo "ONNX hash: $ONNX_HASH" + [ -n "$ONNX_HASH" ] || { echo "::error::Failed to extract ONNX hash"; exit 1; } echo "onnx_sha256=$ONNX_HASH" >> $GITHUB_OUTPUT TINYGRAD_REF=$(gh api "repos/${GH_REPO}/contents/tinygrad_repo?ref=${REF}" --jq '.sha') @@ -238,7 +243,7 @@ jobs: JSON_URL="https://huggingface.co/datasets/${HF_REPO}/resolve/main/${HF_DEFAULTS_PATH}/default_models.json" check_defaults() { - DEFAULTS=$(curl -fsSL "$JSON_URL" 2>/dev/null) || return 1 + DEFAULTS=$(curl -fsSL "${JSON_URL}?t=$(date +%s)" 2>/dev/null) || return 1 TINYGRAD_MATCH=$(echo "$DEFAULTS" | jq -r --arg ref "$TINYGRAD_REF" '.tinygrad_ref == $ref' 2>/dev/null) [ "$TINYGRAD_MATCH" = "true" ] || return 1 BUNDLE=$(echo "$DEFAULTS" | jq --arg hash "$ONNX_HASH" '.bundles[] | select(.onnx_sha256 == $hash)' 2>/dev/null) @@ -252,18 +257,35 @@ jobs: echo "No matching model on HF — dispatching build" gh workflow run build-default-models.yaml --ref "$REF" -f target=big + sleep 10 - echo "Polling HF for big model availability..." + BUILD_RUN_ID=$(gh run list --workflow build-default-models.yaml --branch "$REF" --limit 1 --json databaseId --jq '.[0].databaseId') + echo "Dispatched build run: $BUILD_RUN_ID" + + echo "Waiting for build run to complete..." for i in $(seq 1 90); do sleep 30 - if check_defaults; then - echo "Big model available on HF after $((i * 30))s" - exit 0 + STATUS=$(gh api "repos/${GH_REPO}/actions/runs/${BUILD_RUN_ID}" --jq '.status') + CONCLUSION=$(gh api "repos/${GH_REPO}/actions/runs/${BUILD_RUN_ID}" --jq '.conclusion') + echo "Poll $i/90: status=$STATUS conclusion=$CONCLUSION" + if [ "$STATUS" = "completed" ]; then + if [ "$CONCLUSION" = "success" ]; then + echo "Build run succeeded, verifying HF..." + sleep 10 + if check_defaults; then + echo "Big model verified on HF" + exit 0 + fi + echo "::error::Build succeeded but model not found on HF" + exit 1 + else + echo "::error::Build run failed with conclusion=$CONCLUSION" + exit 1 + fi fi - echo "Poll $i/90: not yet available" done - echo "::error::Big model not available on HF after 45 minutes" + echo "::error::Build run did not complete within 45 minutes" exit 1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -277,6 +299,9 @@ jobs: prepare_small_model: needs: [ prepare_strategy ] runs-on: ubuntu-24.04 + concurrency: + group: prepare-small-model + cancel-in-progress: false outputs: driving_onnx_sha256: ${{ steps.resolve.outputs.driving_onnx_sha256 }} env: @@ -289,8 +314,10 @@ jobs: run: | REF="${{ github.head_ref || github.ref_name }}" - DRIVING_HASH=$(gh api "repos/${GH_REPO}/contents/openpilot/selfdrive/modeld/models/driving_supercombo.onnx?ref=${REF}" --jq '.content' | base64 -d | grep '^oid sha256:' | cut -d: -f2) + BLOB_SHA=$(gh api "repos/${GH_REPO}/contents/openpilot/selfdrive/modeld/models/driving_supercombo.onnx?ref=${REF}" --jq '.sha') + DRIVING_HASH=$(gh api "repos/${GH_REPO}/git/blobs/${BLOB_SHA}" --jq '.content' | base64 -d | grep '^oid sha256:' | cut -d: -f2) echo "Driving ONNX hash: $DRIVING_HASH" + [ -n "$DRIVING_HASH" ] || { echo "::error::Failed to extract driving ONNX hash"; exit 1; } echo "driving_onnx_sha256=$DRIVING_HASH" >> $GITHUB_OUTPUT TINYGRAD_REF=$(gh api "repos/${GH_REPO}/contents/tinygrad_repo?ref=${REF}" --jq '.sha') @@ -299,7 +326,7 @@ jobs: JSON_URL="https://huggingface.co/datasets/${HF_REPO}/resolve/main/${HF_DEFAULTS_PATH}/default_models.json" check_defaults() { - DEFAULTS=$(curl -fsSL "$JSON_URL" 2>/dev/null) || return 1 + DEFAULTS=$(curl -fsSL "${JSON_URL}?t=$(date +%s)" 2>/dev/null) || return 1 TINYGRAD_MATCH=$(echo "$DEFAULTS" | jq -r --arg ref "$TINYGRAD_REF" '.tinygrad_ref == $ref' 2>/dev/null) [ "$TINYGRAD_MATCH" = "true" ] || return 1 DRIVING=$(echo "$DEFAULTS" | jq --arg hash "$DRIVING_HASH" '.bundles[] | select(.onnx_sha256 == $hash)' 2>/dev/null) @@ -313,18 +340,35 @@ jobs: echo "No matching model on HF — dispatching build" gh workflow run build-default-models.yaml --ref "$REF" -f target=small + sleep 10 - echo "Polling HF for model availability..." + BUILD_RUN_ID=$(gh run list --workflow build-default-models.yaml --branch "$REF" --limit 1 --json databaseId --jq '.[0].databaseId') + echo "Dispatched build run: $BUILD_RUN_ID" + + echo "Waiting for build run to complete..." for i in $(seq 1 60); do sleep 30 - if check_defaults; then - echo "Model available on HF after $((i * 30))s" - exit 0 + STATUS=$(gh api "repos/${GH_REPO}/actions/runs/${BUILD_RUN_ID}" --jq '.status') + CONCLUSION=$(gh api "repos/${GH_REPO}/actions/runs/${BUILD_RUN_ID}" --jq '.conclusion') + echo "Poll $i/60: status=$STATUS conclusion=$CONCLUSION" + if [ "$STATUS" = "completed" ]; then + if [ "$CONCLUSION" = "success" ]; then + echo "Build run succeeded, verifying HF..." + sleep 10 + if check_defaults; then + echo "Small model verified on HF" + exit 0 + fi + echo "::error::Build succeeded but model not found on HF" + exit 1 + else + echo "::error::Build run failed with conclusion=$CONCLUSION" + exit 1 + fi fi - echo "Poll $i/60: not yet available" done - echo "::error::Small driving model not available on HF after 30 minutes" + echo "::error::Small model build did not complete within 30 minutes" exit 1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -338,6 +382,9 @@ jobs: prepare_dm_model: needs: [ prepare_strategy ] runs-on: ubuntu-24.04 + concurrency: + group: prepare-dm-model + cancel-in-progress: false outputs: dm_onnx_sha256: ${{ steps.resolve.outputs.dm_onnx_sha256 }} env: @@ -350,8 +397,10 @@ jobs: run: | REF="${{ github.head_ref || github.ref_name }}" - DM_HASH=$(gh api "repos/${GH_REPO}/contents/openpilot/selfdrive/modeld/models/dmonitoring_model.onnx?ref=${REF}" --jq '.content' | base64 -d | grep '^oid sha256:' | cut -d: -f2) + BLOB_SHA=$(gh api "repos/${GH_REPO}/contents/openpilot/selfdrive/modeld/models/dmonitoring_model.onnx?ref=${REF}" --jq '.sha') + DM_HASH=$(gh api "repos/${GH_REPO}/git/blobs/${BLOB_SHA}" --jq '.content' | base64 -d | grep '^oid sha256:' | cut -d: -f2) echo "DM ONNX hash: $DM_HASH" + [ -n "$DM_HASH" ] || { echo "::error::Failed to extract DM ONNX hash"; exit 1; } echo "dm_onnx_sha256=$DM_HASH" >> $GITHUB_OUTPUT TINYGRAD_REF=$(gh api "repos/${GH_REPO}/contents/tinygrad_repo?ref=${REF}" --jq '.sha') @@ -360,7 +409,7 @@ jobs: JSON_URL="https://huggingface.co/datasets/${HF_REPO}/resolve/main/${HF_DEFAULTS_PATH}/default_models.json" check_defaults() { - DEFAULTS=$(curl -fsSL "$JSON_URL" 2>/dev/null) || return 1 + DEFAULTS=$(curl -fsSL "${JSON_URL}?t=$(date +%s)" 2>/dev/null) || return 1 TINYGRAD_MATCH=$(echo "$DEFAULTS" | jq -r --arg ref "$TINYGRAD_REF" '.tinygrad_ref == $ref' 2>/dev/null) [ "$TINYGRAD_MATCH" = "true" ] || return 1 DM=$(echo "$DEFAULTS" | jq --arg hash "$DM_HASH" '.bundles[] | select(.onnx_sha256 == $hash)' 2>/dev/null) @@ -374,18 +423,35 @@ jobs: echo "No matching DM model on HF — dispatching build" gh workflow run build-default-models.yaml --ref "$REF" -f target=dm + sleep 10 - echo "Polling HF for DM model availability..." + BUILD_RUN_ID=$(gh run list --workflow build-default-models.yaml --branch "$REF" --limit 1 --json databaseId --jq '.[0].databaseId') + echo "Dispatched build run: $BUILD_RUN_ID" + + echo "Waiting for build run to complete..." for i in $(seq 1 60); do sleep 30 - if check_defaults; then - echo "DM model available on HF after $((i * 30))s" - exit 0 + STATUS=$(gh api "repos/${GH_REPO}/actions/runs/${BUILD_RUN_ID}" --jq '.status') + CONCLUSION=$(gh api "repos/${GH_REPO}/actions/runs/${BUILD_RUN_ID}" --jq '.conclusion') + echo "Poll $i/60: status=$STATUS conclusion=$CONCLUSION" + if [ "$STATUS" = "completed" ]; then + if [ "$CONCLUSION" = "success" ]; then + echo "Build run succeeded, verifying HF..." + sleep 10 + if check_defaults; then + echo "DM model verified on HF" + exit 0 + fi + echo "::error::Build succeeded but DM model not found on HF" + exit 1 + else + echo "::error::Build run failed with conclusion=$CONCLUSION" + exit 1 + fi fi - echo "Poll $i/60: not yet available" done - echo "::error::DM model not available on HF after 30 minutes" + echo "::error::DM model build did not complete within 30 minutes" exit 1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 302f3ad892038144edabc5626bda2294a4ff9b11 Mon Sep 17 00:00:00 2001 From: James Vecellio-Grant <159560811+Discountchubbs@users.noreply.github.com> Date: Fri, 4 Sep 2026 16:52:09 -0700 Subject: [PATCH 3/5] ci: compile dm warp (#1989) --- .github/workflows/build-default-models.yaml | 18 ++++++++++++++++++ .../download-hf-model-chunks/action.yml | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/.github/workflows/build-default-models.yaml b/.github/workflows/build-default-models.yaml index d748d3ac1..4f22002ae 100644 --- a/.github/workflows/build-default-models.yaml +++ b/.github/workflows/build-default-models.yaml @@ -484,11 +484,29 @@ jobs: print(f'Chunked {pkl} into {len(targets)} chunks') " + - name: Compile DM warp + run: | + source ${UV_PROJECT_ENVIRONMENT}/bin/activate + export PYTHONPATH="${PYTHONPATH}:${{ github.workspace }}/tinygrad_repo:${{ github.workspace }}" + + TG_FLAGS="DEV=QCOM IMAGE=1 FLOAT16=1 NOLOCALS=1 JIT_BATCH_SIZE=0 OPENPILOT_HACKS=1" + MODEL_DIR="${{ github.workspace }}/openpilot/selfdrive/modeld" + DM_SIZE=$(python3 -c "from openpilot.common.transformations.model import DM_INPUT_SIZE as s; print(f'{s[0]}x{s[1]}')") + + for res in $(python3 -c "from openpilot.common.transformations.camera import _ar_ox_fisheye as a, _os_fisheye as o; print(f'{a.width}x{a.height} {o.width}x{o.height}')"); do + WARP_PKL="${MODEL_DIR}/models/dm_warp_${res}_tinygrad.pkl" + taskset -c 7 env ${TG_FLAGS} python3 ${MODEL_DIR}/compile_dm_warp.py \ + --camera-resolution ${res} \ + --warp-to ${DM_SIZE} \ + --output ${WARP_PKL} + done + - name: Prepare DM output run: | mkdir -p dm_output cp ${{ github.workspace }}/${{ env.DM_PKL }}.chunk* dm_output/ cp ${{ github.workspace }}/${{ env.DM_PKL }}.chunkmanifest dm_output/ + cp ${{ github.workspace }}/openpilot/selfdrive/modeld/models/dm_warp_* dm_output/ - name: Upload DM artifact uses: actions/upload-artifact@v4 diff --git a/.github/workflows/download-hf-model-chunks/action.yml b/.github/workflows/download-hf-model-chunks/action.yml index 01ab5385d..677385f1d 100644 --- a/.github/workflows/download-hf-model-chunks/action.yml +++ b/.github/workflows/download-hf-model-chunks/action.yml @@ -46,6 +46,13 @@ runs: printf '%s\t%s\n' "$ENCODED_URL" "${DEST_DIR}/${CANONICAL}.chunk${CHUNK_IDX}" >> "$DOWNLOAD_LIST" done < <(echo "$ARTIFACT" | jq -r '.chunks[].file_name') echo "$NUM_CHUNKS" > "${DEST_DIR}/${CANONICAL}.chunkmanifest" + + if [ "$CANONICAL" = "dmonitoring_model_tinygrad.pkl" ]; then + for warp in dm_warp_1928x1208_tinygrad.pkl dm_warp_1344x760_tinygrad.pkl; do + ENCODED_URL=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${BASE_URL}/${warp}', safe=':/'))") + printf '%s\t%s\n' "$ENCODED_URL" "${DEST_DIR}/${warp}" >> "$DOWNLOAD_LIST" + done + fi } echo "$MODELS_JSON" | jq -c '.[]' | while IFS= read -r model; do From 7eb457f6c474a8fe50a9319de507d532cd61aaf6 Mon Sep 17 00:00:00 2001 From: Nayan Date: Fri, 4 Sep 2026 22:50:12 -0400 Subject: [PATCH 4/5] chaos (#1991) burn it all --- .github/CODEOWNERS | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index e8f1b7eb8..000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,11 +0,0 @@ -* @sunnypilot/dev-internal -/.github/ @devtekve @sunnyhaibin -/release/ci/ @devtekve @sunnyhaibin -/tinygrad_repo @devtekve @Discountchubbs -/tinygrad/ @devtekve @Discountchubbs -/selfdrive/controls/lib/longitudinal_planner.py @devtekve @Discountchubbs -/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @devtekve @Discountchubbs -/selfdrive/modeld/ @devtekve @Discountchubbs -/sunnypilot/model* @devtekve @Discountchubbs -/sunnypilot/sunnylink/ @devtekve -/system/athena/ @devtekve \ No newline at end of file From 047ae41c0d9fe3ae5656d1541a376d6fbf17c9a3 Mon Sep 17 00:00:00 2001 From: James Vecellio-Grant <159560811+Discountchubbs@users.noreply.github.com> Date: Fri, 4 Sep 2026 21:15:00 -0700 Subject: [PATCH 5/5] modeld_v2: one dev warp and enqueue (#1990) --- .github/workflows/sunnypilot-build-model.yaml | 2 +- .../sunnypilot/modeld_v2/compile_modeld.py | 16 +++--- openpilot/sunnypilot/modeld_v2/modeld.py | 56 +++++++------------ openpilot/sunnypilot/models/fetcher.py | 2 +- 4 files changed, 32 insertions(+), 44 deletions(-) diff --git a/.github/workflows/sunnypilot-build-model.yaml b/.github/workflows/sunnypilot-build-model.yaml index 10be63ee2..837c53be6 100644 --- a/.github/workflows/sunnypilot-build-model.yaml +++ b/.github/workflows/sunnypilot-build-model.yaml @@ -188,7 +188,7 @@ jobs: if [ "${{ inputs.target_hardware }}" == "chestnut" ]; then echo "CHESTNUT build" export CHESTNUT=1 - TG_FLAGS="DEBUG=1 DEV=USB+AMD:LLVM WARP_DEV=QCOM FLOAT16=1 JIT_BATCH_SIZE=0 GMMU=0 TC_OPT=2" + TG_FLAGS="DEBUG=1 DEV=USB+AMD:LLVM FLOAT16=1 JIT_BATCH_SIZE=0 GMMU=0 TC_OPT=2 TC_OCCUPANCY_OPT=1" OUTPUT_PKL="${{ env.MODELS_DIR }}/big_driving_tinygrad.pkl" else echo "QCOM build" diff --git a/openpilot/sunnypilot/modeld_v2/compile_modeld.py b/openpilot/sunnypilot/modeld_v2/compile_modeld.py index 7a58352c3..a27409756 100755 --- a/openpilot/sunnypilot/modeld_v2/compile_modeld.py +++ b/openpilot/sunnypilot/modeld_v2/compile_modeld.py @@ -41,7 +41,6 @@ from tinygrad.tensor import Tensor MODEL_TYPES = ('vision_policy', 'supercombo', 'vision_multi_policy') WARP_INPUTS = ['tfm', 'big_tfm'] POLICY_INPUTS = ['img_q', 'big_img_q', 'feat_q', 'desire_q', 'packed_npy_inputs'] -WARP_DEV = os.getenv('WARP_DEV') def _detect_desire_key(shapes: dict) -> str | None: @@ -154,12 +153,13 @@ def make_warp_queues(device=Device.DEFAULT): def make_warp(nv12: NV12Frame, model_w: int, model_h: int): frame_prepare = make_frame_prepare(nv12, model_w, model_h) - WARP_DEV = os.getenv('WARP_DEV', Device.DEFAULT) def warp(tfm, big_tfm, frame, big_frame): - tfm = tfm.to(WARP_DEV) - big_tfm = big_tfm.to(WARP_DEV) - Tensor.realize(tfm, big_tfm) + tfm = tfm.to(Device.DEFAULT) + big_tfm = big_tfm.to(Device.DEFAULT) + frame = frame.to(Device.DEFAULT) + big_frame = big_frame.to(Device.DEFAULT) + Tensor.realize(tfm, big_tfm, frame, big_frame) warped_frame = frame_prepare(frame, tfm).unsqueeze(0) warped_big_frame = frame_prepare(big_frame, big_tfm).unsqueeze(0) @@ -368,16 +368,18 @@ if __name__ == "__main__": run_policy_func = make_run_policy(vision_runner, policy_runners, features_slice, derived_frame_skip, all_shapes) run_policy_jit = TinyJit(run_policy_func, prune=True) make_policy_queues = partial(generate_queues_and_npy, all_shapes, derived_frame_skip, is_supercombo=is_supercombo) - make_random_model_inputs = partial(make_random_images, keys=['warped'], shape=(2, 6, model_h // 2, model_w // 2), device=WARP_DEV) + make_random_model_inputs = partial(make_random_images, keys=['warped'], shape=(2, 6, model_h // 2, model_w // 2), device=Device.DEFAULT) output_data['run_policy'] = compile_jit(run_policy_jit, make_random_model_inputs, POLICY_INPUTS, make_policy_queues) for cam_w, cam_h in args.camera_resolutions: print(f"Compiling warp JIT for {cam_w}x{cam_h}...") nv12 = NV12Frame(cam_w, cam_h, *get_nv12_info(cam_w, cam_h)) - make_random_warp_inputs = partial(make_random_images, keys=['frame', 'big_frame'], shape=nv12.size, device=WARP_DEV) + make_random_warp_inputs = partial(make_random_images, keys=['frame', 'big_frame'], shape=nv12.size, device=Device.DEFAULT) warp = TinyJit(make_warp(nv12, model_w, model_h), prune=True) output_data[(cam_w, cam_h)] = compile_jit(warp, make_random_warp_inputs, WARP_INPUTS, make_warp_queues) + output_data['metadata']['warp_dev'] = Device.DEFAULT + with open(args.output, "wb") as file: dump_oob(output_data, file) diff --git a/openpilot/sunnypilot/modeld_v2/modeld.py b/openpilot/sunnypilot/modeld_v2/modeld.py index cd421d70d..2ab96934e 100755 --- a/openpilot/sunnypilot/modeld_v2/modeld.py +++ b/openpilot/sunnypilot/modeld_v2/modeld.py @@ -6,6 +6,7 @@ This file is part of sunnypilot and is licensed under the MIT License. See the LICENSE.md file in the root directory for more details. """ +from collections.abc import Callable import os os.environ['GMMU'] = '0' import numpy as np @@ -110,18 +111,12 @@ class ModelState(ModelStateBase): cloudlog.warning(f"loading combined pkl: {pkl_path}") jits = load_oob(open_file_chunked(pkl_path)) - self.WARP_DEV = 'QCOM' if COMMA_HARDWARE else 'CPU' - self.DEV = 'AMD' if self.chestnut else self.WARP_DEV - self.QUEUE_DEV = self.DEV metadata = jits['metadata'] - - self.is_legacy_model = 'run_policy' not in jits # remove after next recompile - if self.is_legacy_model: - self.warp = jits[(cam_w, cam_h)]['warp_enqueue'] - self.run_policy = jits[(cam_w, cam_h)]['run_policy'] - else: - self.run_policy = jits['run_policy'] - self.warp = jits[(cam_w, cam_h)] + self.WARP_DEV = metadata.get('warp_dev', 'QCOM' if COMMA_HARDWARE else 'CPU') + self.DEV = 'AMD' if self.chestnut else ('QCOM' if COMMA_HARDWARE else 'CPU') + self.QUEUE_DEV = self.DEV + self.run_policy = jits['run_policy'] + self.warp = jits[(cam_w, cam_h)] if 'model' in metadata: model_metadata = metadata['model'] @@ -180,11 +175,7 @@ class ModelState(ModelStateBase): yuv_size = self.frame_buf_params[self._road_key][3] frame_tensor = Tensor(np.zeros(yuv_size, dtype=np.uint8), device=self.WARP_DEV).contiguous().realize() big_frame_tensor = Tensor(np.zeros(yuv_size, dtype=np.uint8), device=self.WARP_DEV).contiguous().realize() - - if self.is_legacy_model: # Remove this conditional hack after recompile - self.warp(**self.input_queues, frame=frame_tensor, big_frame=big_frame_tensor) - else: - self.warp(**{k: self.input_queues[k] for k in WARP_INPUTS}, frame=frame_tensor, big_frame=big_frame_tensor) + self.warp(**{k: self.input_queues[k] for k in WARP_INPUTS}, frame=frame_tensor, big_frame=big_frame_tensor) def warmup(self) -> None: dummy_frames = {k: np.zeros(self.frame_buf_params[k][3], dtype=np.uint8) for k in self._vision_input_names} @@ -217,7 +208,8 @@ class ModelState(ModelStateBase): return self._desire_key def run(self, bufs: dict[str, VisionBuf], transforms: dict[str, np.ndarray], - inputs: dict[str, np.ndarray], prepare_only: bool) -> dict[str, np.ndarray] | None: + inputs: dict[str, np.ndarray], prepare_only: bool, + after_enqueue: Callable[[], None] | None = None) -> dict[str, np.ndarray] | None: for key in bufs.keys(): ptr = np.frombuffer(bufs[key].data, dtype=np.uint8).ctypes.data yuv_size = self.frame_buf_params[key][3] @@ -239,20 +231,18 @@ class ModelState(ModelStateBase): self.numpy_inputs['tfm'][:, :] = transforms[road_key].reshape(3, 3) self.numpy_inputs['big_tfm'][:, :] = transforms[wide_key].reshape(3, 3) - if self.is_legacy_model: # remove after next recompile - if prepare_only: - self.warp(**self.input_queues, frame=self.full_frames[road_key], big_frame=self.full_frames[wide_key]) - return None - raw_outputs = self.run_policy(**self.input_queues, frame=self.full_frames[road_key], big_frame=self.full_frames[wide_key]) - else: - if prepare_only: - self.warp(**{k: self.input_queues[k] for k in WARP_INPUTS}, frame=self.full_frames[road_key], big_frame=self.full_frames[wide_key]) - return None - warped = self.warp(**{k: self.input_queues[k] for k in WARP_INPUTS}, frame=self.full_frames[road_key], big_frame=self.full_frames[wide_key]) - raw_outputs = self.run_policy(**{k: self.input_queues[k] for k in POLICY_INPUTS if k in self.input_queues}, warped=warped) + if prepare_only: + self.warp(**{k: self.input_queues[k] for k in WARP_INPUTS}, frame=self.full_frames[road_key], big_frame=self.full_frames[wide_key]) + return None + warped = self.warp(**{k: self.input_queues[k] for k in WARP_INPUTS}, frame=self.full_frames[road_key], big_frame=self.full_frames[wide_key]) + raw_outputs = self.run_policy(**{k: self.input_queues[k] for k in POLICY_INPUTS if k in self.input_queues}, warped=warped) + if after_enqueue is not None: + after_enqueue() if self._combined_model_type == 'supercombo': model_output = raw_outputs.numpy().flatten() + if self.chestnut and not np.all(np.isfinite(model_output)): + raise RuntimeError("model output not finite") sliced = {k: model_output[np.newaxis, v] for k, v in self.vision_output_slices.items()} outputs = self.parser.parse_outputs(sliced) if 'prev_feat' in self.numpy_inputs: @@ -285,9 +275,6 @@ class ModelState(ModelStateBase): buf[0, :-1] = buf[0, 1:] buf[0, -1, :] = outputs['desired_curvature'][0, :] if not self.mlsim else 0 - if self.chestnut and not np.all(np.isfinite(outputs.get('plan', np.array([0.])))): - raise RuntimeError("model output not finite") - return outputs def get_action_from_model(self, model_output: dict[str, np.ndarray], prev_action: log.ModelDataV2.Action, @@ -512,7 +499,9 @@ def main(demo=False): mt1 = time.perf_counter() try: - model_output = model.run(bufs, transforms, inputs, prepare_only) + send_chestnut = (chestnut_state is not None and + run_count % round(model.constants.MODEL_FREQ / SERVICE_LIST['chestnutState'].frequency) == 0) + model_output = model.run(bufs, transforms, inputs, prepare_only, chestnut_state.send if send_chestnut else None) except Exception: if not params.get_bool("ChestnutActive"): raise @@ -559,9 +548,6 @@ def main(demo=False): pm.send('modelDataV2SP', mdv2sp_send) last_vipc_frame_id = meta_main.frame_id - if chestnut_state is not None and run_count % round(model.constants.MODEL_FREQ / SERVICE_LIST['chestnutState'].frequency) == 0: - chestnut_state.send() - if __name__ == "__main__": try: import argparse diff --git a/openpilot/sunnypilot/models/fetcher.py b/openpilot/sunnypilot/models/fetcher.py index f997dbbc5..810b9b7e4 100644 --- a/openpilot/sunnypilot/models/fetcher.py +++ b/openpilot/sunnypilot/models/fetcher.py @@ -139,7 +139,7 @@ class ModelCache: class ModelFetcher: """Handles fetching and caching of model data from remote source""" MODEL_URL = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-models/refs/heads/gh-pages/docs/driving_models_v22.json" - MODEL_URL_CHESTNUT = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-models/refs/heads/gh-pages/docs/driving_models_chestnut_v23.json" + MODEL_URL_CHESTNUT = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-models/refs/heads/gh-pages/docs/driving_models_chestnut_v24.json" MODEL_SOURCES = { "qcom": (MODEL_URL, ""),