mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-08-22 17:43:47 +08:00
Compare commits
5 Commits
tn
...
spatial-feat
| Author | SHA1 | Date | |
|---|---|---|---|
| e9bafbd353 | |||
| e372046ff1 | |||
| 07558166c8 | |||
| ca9338812e | |||
| 4667241fe7 |
@@ -0,0 +1,78 @@
|
|||||||
|
name: Build default big model
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
HF_REPO: sunnypilot/sunnypilot_models_v1
|
||||||
|
HF_DEFAULTS_PATH: models/defaults/big
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_model:
|
||||||
|
uses: ./.github/workflows/sunnypilot-build-model.yaml
|
||||||
|
with:
|
||||||
|
upstream_branch: ${{ github.sha }}
|
||||||
|
custom_name: default-big-model
|
||||||
|
target_hardware: usbgpu
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
upload_defaults:
|
||||||
|
needs: build_model
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- run: git lfs pull -I "openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx"
|
||||||
|
|
||||||
|
- name: Install huggingface_hub
|
||||||
|
run: pip install --upgrade "huggingface_hub>=0.22.0"
|
||||||
|
|
||||||
|
- name: Download artifact name
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: artifact-name-default-big-model
|
||||||
|
path: artifact_name
|
||||||
|
|
||||||
|
- name: Read artifact name
|
||||||
|
id: artifact
|
||||||
|
run: |
|
||||||
|
ARTIFACT_NAME=$(cat artifact_name/artifact_name.txt)
|
||||||
|
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Download model artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ steps.artifact.outputs.artifact_name }}
|
||||||
|
path: output
|
||||||
|
|
||||||
|
- name: Upload model to HF defaults
|
||||||
|
env:
|
||||||
|
HF_OIDC_RESOURCE: datasets/${{ env.HF_REPO }}
|
||||||
|
ARTIFACT_NAME: ${{ steps.artifact.outputs.artifact_name }}
|
||||||
|
run: |
|
||||||
|
rm -f output/artifact_name.txt
|
||||||
|
hf upload ${{ env.HF_REPO }} \
|
||||||
|
output/ \
|
||||||
|
"${HF_DEFAULTS_PATH}/${ARTIFACT_NAME}/" \
|
||||||
|
--repo-type=dataset
|
||||||
|
|
||||||
|
- name: Get tinygrad ref and ONNX hash
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
export PYTHONPATH=$(pwd)
|
||||||
|
echo "tinygrad_ref=$(python3 openpilot/sunnypilot/models/tinygrad_ref.py)" >> $GITHUB_OUTPUT
|
||||||
|
echo "onnx_sha256=$(sha256sum openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx | cut -d' ' -f1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Update default_models.json on HF
|
||||||
|
env:
|
||||||
|
HF_OIDC_RESOURCE: datasets/${{ env.HF_REPO }}
|
||||||
|
ARTIFACT_NAME: ${{ steps.artifact.outputs.artifact_name }}
|
||||||
|
run: |
|
||||||
|
python3 release/ci/upload_default_model.py \
|
||||||
|
--hf-repo "${{ env.HF_REPO }}" \
|
||||||
|
--hf-defaults-path "${{ env.HF_DEFAULTS_PATH }}" \
|
||||||
|
--artifact-name "$ARTIFACT_NAME" \
|
||||||
|
--metadata-path "output/metadata.json" \
|
||||||
|
--onnx-sha256 "${{ steps.meta.outputs.onnx_sha256 }}" \
|
||||||
|
--tinygrad-ref "${{ steps.meta.outputs.tinygrad_ref }}"
|
||||||
@@ -192,7 +192,7 @@ class ModelRenderer(Widget, ChevronMetrics, ModelRendererSP):
|
|||||||
|
|
||||||
max_idx = self._get_path_length_idx(path_x_array, max_distance)
|
max_idx = self._get_path_length_idx(path_x_array, max_distance)
|
||||||
self._path.projected_points = self._map_line_to_polygon(
|
self._path.projected_points = self._map_line_to_polygon(
|
||||||
self._path.raw_points, 0.9, self._path_offset_z, max_idx, max_distance, allow_invert=False
|
self._path.raw_points, self._get_path_half_width(), self._path_offset_z, max_idx, max_distance, allow_invert=False
|
||||||
)
|
)
|
||||||
|
|
||||||
self._update_experimental_gradient()
|
self._update_experimental_gradient()
|
||||||
@@ -292,7 +292,7 @@ class ModelRenderer(Widget, ChevronMetrics, ModelRendererSP):
|
|||||||
allow_throttle = sm['longitudinalPlan'].allowThrottle or not self._longitudinal_control
|
allow_throttle = sm['longitudinalPlan'].allowThrottle or not self._longitudinal_control
|
||||||
self._blend_filter.update(int(allow_throttle))
|
self._blend_filter.update(int(allow_throttle))
|
||||||
|
|
||||||
if ui_state.rainbow_path:
|
if ui_state.rainbow_path and self._lateral_active:
|
||||||
self.rainbow_path.draw_rainbow_path(self._rect, self._path)
|
self.rainbow_path.draw_rainbow_path(self._rect, self._path)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,23 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
|||||||
This file is part of sunnypilot and is licensed under the MIT License.
|
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.
|
See the LICENSE.md file in the root directory for more details.
|
||||||
"""
|
"""
|
||||||
|
from openpilot.common.filter_simple import FirstOrderFilter
|
||||||
|
from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus
|
||||||
from openpilot.selfdrive.ui.sunnypilot.onroad.chevron_metrics import ChevronMetrics
|
from openpilot.selfdrive.ui.sunnypilot.onroad.chevron_metrics import ChevronMetrics
|
||||||
from openpilot.selfdrive.ui.sunnypilot.onroad.rainbow_path import RainbowPath
|
from openpilot.selfdrive.ui.sunnypilot.onroad.rainbow_path import RainbowPath
|
||||||
|
from openpilot.system.ui.lib.application import gui_app
|
||||||
|
|
||||||
|
|
||||||
class ModelRendererSP:
|
class ModelRendererSP:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.rainbow_path = RainbowPath()
|
self.rainbow_path = RainbowPath()
|
||||||
self.chevron_metrics = ChevronMetrics()
|
self.chevron_metrics = ChevronMetrics()
|
||||||
|
self._width_filter = FirstOrderFilter(0.9, 0.1, 1 / gui_app.target_fps)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _lateral_active(self) -> bool:
|
||||||
|
return ui_state.status in (UIStatus.ENGAGED, UIStatus.LAT_ONLY)
|
||||||
|
|
||||||
|
def _get_path_half_width(self) -> float:
|
||||||
|
target = 0.9 if self._lateral_active else 0.40
|
||||||
|
return self._width_filter.update(target)
|
||||||
|
|||||||
@@ -186,14 +186,14 @@ def make_run_policy(vision_runner, policy_runners: list, features_slice: slice,
|
|||||||
warped_dev = warped.to(Device.DEFAULT)
|
warped_dev = warped.to(Device.DEFAULT)
|
||||||
Tensor.realize(packed_npy_inputs_dev, warped_dev)
|
Tensor.realize(packed_npy_inputs_dev, warped_dev)
|
||||||
|
|
||||||
img = shift_and_sample(img_q, warped_dev[0:1], sample_skip_fn).realize()
|
img = shift_and_sample(img_q, warped_dev[0:1], sample_skip_fn)
|
||||||
big_img = shift_and_sample(big_img_q, warped_dev[1:2], sample_skip_fn).realize()
|
big_img = shift_and_sample(big_img_q, warped_dev[1:2], sample_skip_fn)
|
||||||
|
|
||||||
unpacked_tensors = [tensor.reshape(shape) for tensor, shape in zip(packed_npy_inputs_dev.split(npy_sizes), npy_shapes.values(), strict=True)]
|
unpacked_tensors = [tensor.reshape(shape) for tensor, shape in zip(packed_npy_inputs_dev.split(npy_sizes), npy_shapes.values(), strict=True)]
|
||||||
unpacked_dict = dict(zip(npy_shapes.keys(), unpacked_tensors, strict=True))
|
unpacked_dict = dict(zip(npy_shapes.keys(), unpacked_tensors, strict=True))
|
||||||
|
|
||||||
desire_dev = unpacked_dict['desire']
|
desire_dev = unpacked_dict['desire']
|
||||||
desire_buf = shift_and_sample(desire_q, desire_dev.reshape(1, 1, -1), sample_desire_fn).realize()
|
desire_buf = shift_and_sample(desire_q, desire_dev.reshape(1, 1, -1), sample_desire_fn)
|
||||||
|
|
||||||
inputs = {desire_key: desire_buf}
|
inputs = {desire_key: desire_buf}
|
||||||
for key, tensor_val in unpacked_dict.items():
|
for key, tensor_val in unpacked_dict.items():
|
||||||
@@ -202,22 +202,22 @@ def make_run_policy(vision_runner, policy_runners: list, features_slice: slice,
|
|||||||
|
|
||||||
if 'prev_feat' in unpacked_dict:
|
if 'prev_feat' in unpacked_dict:
|
||||||
prev_feat_dev = unpacked_dict['prev_feat']
|
prev_feat_dev = unpacked_dict['prev_feat']
|
||||||
feat_buf = shift_and_sample(feat_q, prev_feat_dev.reshape(1, 1, -1), sample_skip_fn).realize()
|
feat_buf = shift_and_sample(feat_q, prev_feat_dev.reshape(1, 1, -1), sample_skip_fn)
|
||||||
inputs['features_buffer'] = feat_buf.reshape(input_shapes['features_buffer'])
|
inputs['features_buffer'] = feat_buf if len(fb := input_shapes['features_buffer']) <= 3 else feat_buf.reshape(fb)
|
||||||
|
|
||||||
if vision_runner:
|
if vision_runner:
|
||||||
vision_out_cast = next(iter(vision_runner({road_key: img, wide_key: big_img}).values())).cast('float32').realize()
|
vision_out_cast = next(iter(vision_runner({road_key: img, wide_key: big_img}).values())).cast('float32').realize()
|
||||||
if 'features_buffer' not in inputs:
|
if 'features_buffer' not in inputs:
|
||||||
new_feat = vision_out_cast[:, features_slice].reshape(1, -1).unsqueeze(0)
|
new_feat = vision_out_cast[:, features_slice].reshape(1, -1).unsqueeze(0)
|
||||||
feat_buf = shift_and_sample(feat_q, new_feat, sample_skip_fn).realize()
|
feat_buf = shift_and_sample(feat_q, new_feat, sample_skip_fn).realize()
|
||||||
inputs['features_buffer'] = feat_buf.reshape(input_shapes['features_buffer'])
|
inputs['features_buffer'] = feat_buf if len(fb := input_shapes['features_buffer']) <= 3 else feat_buf.reshape(fb)
|
||||||
policy_outs = [next(iter(pol_runner(inputs).values())).cast('float32').realize() for pol_runner in policy_runners]
|
policy_outs = [next(iter(pol_runner(inputs).values())).cast('float32').realize() for pol_runner in policy_runners]
|
||||||
return (vision_out_cast, *policy_outs) if len(policy_outs) > 1 else (vision_out_cast, policy_outs[0])
|
return (vision_out_cast, *policy_outs) if len(policy_outs) > 1 else (vision_out_cast, policy_outs[0])
|
||||||
|
|
||||||
inputs.update({road_key: img, wide_key: big_img})
|
inputs.update({road_key: img, wide_key: big_img})
|
||||||
if 'features_buffer' not in inputs:
|
if 'features_buffer' not in inputs:
|
||||||
feat_buf = sample_skip_fn(feat_q)
|
feat_buf = sample_skip_fn(feat_q)
|
||||||
inputs['features_buffer'] = feat_buf.reshape(input_shapes['features_buffer'])
|
inputs['features_buffer'] = feat_buf if len(fb := input_shapes['features_buffer']) <= 3 else feat_buf.reshape(fb)
|
||||||
|
|
||||||
policy_out = next(iter(policy_runners[0](inputs).values())).cast('float32').realize()
|
policy_out = next(iter(policy_runners[0](inputs).values())).cast('float32').realize()
|
||||||
if 'features_buffer' not in inputs and features_slice is not None:
|
if 'features_buffer' not in inputs and features_slice is not None:
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from huggingface_hub import HfApi, hf_hub_download
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--hf-repo", required=True)
|
||||||
|
parser.add_argument("--hf-defaults-path", required=True)
|
||||||
|
parser.add_argument("--artifact-name", required=True)
|
||||||
|
parser.add_argument("--metadata-path", required=True)
|
||||||
|
parser.add_argument("--onnx-sha256", required=True)
|
||||||
|
parser.add_argument("--tinygrad-ref", required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
with open(args.metadata_path) as f:
|
||||||
|
metadata = json.load(f)
|
||||||
|
|
||||||
|
bundle = metadata['bundles'][0]
|
||||||
|
bundle['onnx_sha256'] = args.onnx_sha256
|
||||||
|
|
||||||
|
artifact = bundle['models'][0]['artifact']
|
||||||
|
hf_base = f"https://huggingface.co/datasets/{args.hf_repo}/resolve/main/{args.hf_defaults_path}/{args.artifact_name}"
|
||||||
|
artifact['download_uri']['url'] = f"{hf_base}/{artifact['file_name']}"
|
||||||
|
for chunk in artifact.get('chunks', []):
|
||||||
|
chunk['url'] = f"{hf_base}/{chunk['file_name']}"
|
||||||
|
|
||||||
|
json_filename = f"{args.hf_defaults_path}/default_models.json"
|
||||||
|
try:
|
||||||
|
local_path = hf_hub_download(repo_id=args.hf_repo, repo_type='dataset', filename=json_filename)
|
||||||
|
with open(local_path) as f:
|
||||||
|
defaults_json = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
defaults_json = {"tinygrad_ref": args.tinygrad_ref, "bundles": []}
|
||||||
|
|
||||||
|
defaults_json['tinygrad_ref'] = args.tinygrad_ref
|
||||||
|
|
||||||
|
existing_idx = next((i for i, b in enumerate(defaults_json['bundles'])
|
||||||
|
if b.get('display_name') == bundle.get('display_name')), None)
|
||||||
|
if existing_idx is not None:
|
||||||
|
defaults_json['bundles'][existing_idx] = bundle
|
||||||
|
else:
|
||||||
|
defaults_json['bundles'].append(bundle)
|
||||||
|
|
||||||
|
print(json.dumps(defaults_json, indent=2))
|
||||||
|
|
||||||
|
api = HfApi()
|
||||||
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
|
||||||
|
json.dump(defaults_json, f, indent=2)
|
||||||
|
tmp_path = f.name
|
||||||
|
|
||||||
|
api.upload_file(
|
||||||
|
path_or_fileobj=tmp_path,
|
||||||
|
path_in_repo=json_filename,
|
||||||
|
repo_id=args.hf_repo,
|
||||||
|
repo_type="dataset",
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Updated {json_filename}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user