IQ.Pilot Release Commit @ d23c019
This commit is contained in:
@@ -60,7 +60,7 @@ def host_tinygrad_flags(*, float16=False):
|
||||
return f"{base} FLOAT16=1" if float16 else base
|
||||
|
||||
# Compile small models
|
||||
for model_name in ['dmonitoring_model']:
|
||||
for model_name in ['dmonitoring_model', 'dmonitoring_model_mici']:
|
||||
# The optimization flags are mandatory on QCOM: without FLOAT16/NOLOCALS/JIT_BATCH_SIZE/OPENPILOT_HACKS these
|
||||
# models compile to unoptimized QCOM kernels and run ~20x slower (dmonitoring_model: ~300ms -> ~14ms),
|
||||
# which starves the driving model on the shared Adreno. IMAGE=2 (not upstream's IMAGE=1) because the
|
||||
|
||||
@@ -20,19 +20,25 @@ from openpilot.selfdrive.locationd.calibration_helpers import get_calibrated_rpy
|
||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext, MonitoringModelFrame
|
||||
from openpilot.selfdrive.modeld.parse_model_outputs import sigmoid, safe_exp
|
||||
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
|
||||
PROCESS_NAME = "selfdrive.modeld.dmonitoringmodeld"
|
||||
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||
MODEL_PKL_PATH = Path(__file__).parent / 'models/dmonitoring_model_tinygrad.pkl'
|
||||
METADATA_PATH = Path(__file__).parent / 'models/dmonitoring_model_metadata.pkl'
|
||||
MODELS_PATH = Path(__file__).parent / 'models'
|
||||
|
||||
|
||||
def get_model_paths(device_type: str) -> tuple[Path, Path]:
|
||||
model_name = 'dmonitoring_model_mici' if device_type == 'mici' else 'dmonitoring_model'
|
||||
return MODELS_PATH / f'{model_name}_tinygrad.pkl', MODELS_PATH / f'{model_name}_metadata.pkl'
|
||||
|
||||
|
||||
class ModelState:
|
||||
inputs: dict[str, np.ndarray]
|
||||
output: np.ndarray
|
||||
|
||||
def __init__(self, cl_ctx):
|
||||
with open(METADATA_PATH, 'rb') as f:
|
||||
def __init__(self, cl_ctx, device_type=None):
|
||||
model_path, metadata_path = get_model_paths(device_type or HARDWARE.get_device_type())
|
||||
with open(metadata_path, 'rb') as f:
|
||||
model_metadata = pickle.load(f)
|
||||
self.input_shapes = model_metadata['input_shapes']
|
||||
self.output_slices = model_metadata['output_slices']
|
||||
@@ -43,7 +49,7 @@ class ModelState:
|
||||
}
|
||||
|
||||
self.tensor_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()}
|
||||
with open(MODEL_PKL_PATH, "rb") as f:
|
||||
with open(model_path, "rb") as f:
|
||||
self.model_run = pickle.load(f)
|
||||
|
||||
def run(self, buf: VisionBuf, calib: np.ndarray, transform: np.ndarray) -> tuple[np.ndarray, float]:
|
||||
@@ -75,8 +81,10 @@ def parse_model_output(model_output):
|
||||
face_descs = model_output[f'face_descs_{ds_suffix}']
|
||||
parsed[f'face_descs_{ds_suffix}'] = face_descs[:, :-6]
|
||||
parsed[f'face_descs_{ds_suffix}_std'] = safe_exp(face_descs[:, -6:])
|
||||
for key in ['face_prob', 'left_eye_prob', 'right_eye_prob','left_blink_prob', 'right_blink_prob', 'sunglasses_prob', 'using_phone_prob']:
|
||||
parsed[f'{key}_{ds_suffix}'] = sigmoid(model_output[f'{key}_{ds_suffix}'])
|
||||
for key in ['face_prob', 'left_eye_prob', 'right_eye_prob','left_blink_prob', 'right_blink_prob', 'sunglasses_prob', 'using_phone_prob', 'sleep_prob']:
|
||||
output_key = f'{key}_{ds_suffix}'
|
||||
if output_key in model_output:
|
||||
parsed[output_key] = sigmoid(model_output[output_key])
|
||||
return parsed
|
||||
|
||||
def fill_driver_data(msg, model_output, ds_suffix):
|
||||
@@ -91,6 +99,8 @@ def fill_driver_data(msg, model_output, ds_suffix):
|
||||
msg.rightBlinkProb = model_output[f'right_blink_prob_{ds_suffix}'][0, 0].item()
|
||||
msg.sunglassesProb = model_output[f'sunglasses_prob_{ds_suffix}'][0, 0].item()
|
||||
msg.phoneProb = model_output[f'using_phone_prob_{ds_suffix}'][0, 0].item()
|
||||
sleep_prob = model_output.get(f'sleep_prob_{ds_suffix}')
|
||||
msg.sleepProb = sleep_prob[0, 0].item() if sleep_prob is not None else 0.
|
||||
|
||||
def get_driverstate_packet(model_output, frame_id: int, location_ts: int, exec_time: float, gpu_exec_time: float):
|
||||
msg = messaging.new_message('driverStateV2', valid=True)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
selfdrive/modeld/models/dmonitoring_model_mici.onnx
Normal file
BIN
selfdrive/modeld/models/dmonitoring_model_mici.onnx
Normal file
Binary file not shown.
BIN
selfdrive/modeld/models/dmonitoring_model_mici_metadata.pkl
Normal file
BIN
selfdrive/modeld/models/dmonitoring_model_mici_metadata.pkl
Normal file
Binary file not shown.
BIN
selfdrive/modeld/models/dmonitoring_model_mici_tinygrad.pkl
Normal file
BIN
selfdrive/modeld/models/dmonitoring_model_mici_tinygrad.pkl
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,8 +1,15 @@
|
||||
{
|
||||
"dmonitoring_model": {
|
||||
"outputs": {
|
||||
"dmonitoring_model_metadata.pkl": "31a86ab7a92dc0af088b15787a440dd3b210aa662e445a15145900e559a1b5c3",
|
||||
"dmonitoring_model_tinygrad.pkl": "806c0ea75df6bf6dfeb81b832314c68e31df5865a52d0359e6eeb76d93ad2b52"
|
||||
"dmonitoring_model_metadata.pkl": "5999c262b1c25c62e485fb4ced5806d20a8ca59e3ae94e0ff499c0fe3497fedc",
|
||||
"dmonitoring_model_tinygrad.pkl": "5aca89a35b42376d56f67ccd28a1080806706d546dd8c63f6e1b4c681f8e2c01"
|
||||
},
|
||||
"signature": "2364ebd4bb95c4b4e539c9b1ba68324b713cbb56617396b73262accf9cdcfbfc"
|
||||
},
|
||||
"dmonitoring_model_mici": {
|
||||
"outputs": {
|
||||
"dmonitoring_model_mici_metadata.pkl": "31a86ab7a92dc0af088b15787a440dd3b210aa662e445a15145900e559a1b5c3",
|
||||
"dmonitoring_model_mici_tinygrad.pkl": "806c0ea75df6bf6dfeb81b832314c68e31df5865a52d0359e6eeb76d93ad2b52"
|
||||
},
|
||||
"signature": "e1eeb5ce45774a816c8da2394e6ee35ebf700b71dff345e0141dbab8ff592349"
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ BASEDIR = MODELD_DIR.parents[1]
|
||||
TINYGRAD_DIR = BASEDIR / 'tinygrad_repo'
|
||||
METADATA_SCRIPT = MODELD_DIR / 'get_model_metadata.py'
|
||||
|
||||
MODEL_NAMES = ['dmonitoring_model']
|
||||
MODEL_NAMES = ['dmonitoring_model', 'dmonitoring_model_mici']
|
||||
|
||||
|
||||
def _hash_file(h, path: Path) -> None:
|
||||
|
||||
37
selfdrive/modeld/test_dmonitoringmodeld.py
Normal file
37
selfdrive/modeld/test_dmonitoringmodeld.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import pickle
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from openpilot.selfdrive.modeld.dmonitoringmodeld import get_driverstate_packet, get_model_paths, parse_model_output, slice_outputs
|
||||
|
||||
|
||||
@pytest.mark.parametrize("device_type, model_name", [
|
||||
("mici", "dmonitoring_model_mici"),
|
||||
("tici", "dmonitoring_model"),
|
||||
("tizi", "dmonitoring_model"),
|
||||
])
|
||||
def test_model_paths(device_type, model_name):
|
||||
model_path, metadata_path = get_model_paths(device_type)
|
||||
|
||||
assert model_path.name == f"{model_name}_tinygrad.pkl"
|
||||
assert metadata_path.name == f"{model_name}_metadata.pkl"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("device_type, expected_sleep_prob", [
|
||||
("mici", 0.),
|
||||
("tici", 0.5),
|
||||
("tizi", 0.5),
|
||||
])
|
||||
def test_sleep_probability_output(device_type, expected_sleep_prob):
|
||||
_, metadata_path = get_model_paths(device_type)
|
||||
with open(metadata_path, 'rb') as f:
|
||||
metadata = pickle.load(f)
|
||||
|
||||
output = np.zeros(metadata['output_shapes']['outputs'][1], dtype=np.float32)
|
||||
parsed = parse_model_output(slice_outputs(output, metadata['output_slices']))
|
||||
parsed['raw_pred'] = b''
|
||||
msg = get_driverstate_packet(parsed, 1, 0, 0., 0.)
|
||||
|
||||
assert msg.driverStateV2.leftDriverData.sleepProb == expected_sleep_prob
|
||||
assert msg.driverStateV2.rightDriverData.sleepProb == expected_sleep_prob
|
||||
@@ -1,51 +1,52 @@
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from openpilot.selfdrive.modeld import prebuilt_models
|
||||
|
||||
|
||||
def write_outputs(models_dir, check_path):
|
||||
outputs = {}
|
||||
for name, contents in {
|
||||
'dmonitoring_model_tinygrad.pkl': b'tinygrad',
|
||||
'dmonitoring_model_metadata.pkl': b'metadata',
|
||||
}.items():
|
||||
(models_dir / name).write_bytes(contents)
|
||||
outputs[name] = hashlib.sha256(contents).hexdigest()
|
||||
check_path.write_text(json.dumps({'dmonitoring_model': {'outputs': outputs}}))
|
||||
def write_outputs(models_dir, check_path, model_names):
|
||||
checks = {}
|
||||
for model_name in model_names:
|
||||
outputs = {}
|
||||
for suffix, contents in {
|
||||
'tinygrad.pkl': b'tinygrad',
|
||||
'metadata.pkl': b'metadata',
|
||||
}.items():
|
||||
name = f'{model_name}_{suffix}'
|
||||
(models_dir / name).write_bytes(contents)
|
||||
outputs[name] = hashlib.sha256(contents).hexdigest()
|
||||
checks[model_name] = {'outputs': outputs}
|
||||
check_path.write_text(json.dumps(checks))
|
||||
|
||||
|
||||
def test_packaged_prebuilt_without_onnx(tmp_path, monkeypatch):
|
||||
@pytest.fixture
|
||||
def packaged_models(tmp_path, monkeypatch):
|
||||
models_dir = tmp_path / 'models'
|
||||
models_dir.mkdir()
|
||||
check_path = models_dir / 'prebuilt_check.json'
|
||||
write_outputs(models_dir, check_path)
|
||||
write_outputs(models_dir, check_path, prebuilt_models.MODEL_NAMES)
|
||||
monkeypatch.setattr(prebuilt_models, 'MODELS_DIR', models_dir)
|
||||
monkeypatch.setattr(prebuilt_models, 'CHECK_PATH', check_path)
|
||||
|
||||
assert prebuilt_models.packaged_prebuilt_matches('dmonitoring_model')
|
||||
assert not prebuilt_models.verify_prebuilt('dmonitoring_model', 'flags')
|
||||
return models_dir
|
||||
|
||||
|
||||
def test_packaged_prebuilt_rejects_corrupt_output(tmp_path, monkeypatch):
|
||||
models_dir = tmp_path / 'models'
|
||||
models_dir.mkdir()
|
||||
check_path = models_dir / 'prebuilt_check.json'
|
||||
write_outputs(models_dir, check_path)
|
||||
(models_dir / 'dmonitoring_model_tinygrad.pkl').write_bytes(b'corrupt')
|
||||
monkeypatch.setattr(prebuilt_models, 'MODELS_DIR', models_dir)
|
||||
monkeypatch.setattr(prebuilt_models, 'CHECK_PATH', check_path)
|
||||
|
||||
assert not prebuilt_models.packaged_prebuilt_matches('dmonitoring_model')
|
||||
@pytest.mark.parametrize("model_name", prebuilt_models.MODEL_NAMES)
|
||||
def test_packaged_prebuilt_without_onnx(packaged_models, model_name):
|
||||
assert prebuilt_models.packaged_prebuilt_matches(model_name)
|
||||
assert not prebuilt_models.verify_prebuilt(model_name, 'flags')
|
||||
|
||||
|
||||
def test_source_checkout_is_not_packaged_prebuilt(tmp_path, monkeypatch):
|
||||
models_dir = tmp_path / 'models'
|
||||
models_dir.mkdir()
|
||||
check_path = models_dir / 'prebuilt_check.json'
|
||||
write_outputs(models_dir, check_path)
|
||||
(models_dir / 'dmonitoring_model.onnx').write_bytes(b'onnx')
|
||||
monkeypatch.setattr(prebuilt_models, 'MODELS_DIR', models_dir)
|
||||
monkeypatch.setattr(prebuilt_models, 'CHECK_PATH', check_path)
|
||||
@pytest.mark.parametrize("model_name", prebuilt_models.MODEL_NAMES)
|
||||
def test_packaged_prebuilt_rejects_corrupt_output(packaged_models, model_name):
|
||||
(packaged_models / f'{model_name}_tinygrad.pkl').write_bytes(b'corrupt')
|
||||
|
||||
assert not prebuilt_models.packaged_prebuilt_matches('dmonitoring_model')
|
||||
assert not prebuilt_models.packaged_prebuilt_matches(model_name)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("model_name", prebuilt_models.MODEL_NAMES)
|
||||
def test_source_checkout_is_not_packaged_prebuilt(packaged_models, model_name):
|
||||
(packaged_models / f'{model_name}.onnx').write_bytes(b'onnx')
|
||||
|
||||
assert not prebuilt_models.packaged_prebuilt_matches(model_name)
|
||||
|
||||
Reference in New Issue
Block a user