|
|
|
@ -35,8 +35,10 @@ from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, |
|
|
|
|
PROCESS_NAME = "selfdrive.modeld.modeld" |
|
|
|
|
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') |
|
|
|
|
|
|
|
|
|
MODEL_PKL_PATH = Path(__file__).parent / 'models/supercombo_tinygrad.pkl' |
|
|
|
|
METADATA_PATH = Path(__file__).parent / 'models/supercombo_metadata.pkl' |
|
|
|
|
VISION_PKL_PATH = Path(__file__).parent / 'models/driving_vision_tinygrad.pkl' |
|
|
|
|
POLICY_PKL_PATH = Path(__file__).parent / 'models/driving_policy_tinygrad.pkl' |
|
|
|
|
VISION_METADATA_PATH = Path(__file__).parent / 'models/driving_vision_metadata.pkl' |
|
|
|
|
POLICY_METADATA_PATH = Path(__file__).parent / 'models/driving_policy_metadata.pkl' |
|
|
|
|
|
|
|
|
|
class FrameMeta: |
|
|
|
|
frame_id: int = 0 |
|
|
|
@ -57,32 +59,42 @@ class ModelState: |
|
|
|
|
self.frames = {'input_imgs': DrivingModelFrame(context), 'big_input_imgs': DrivingModelFrame(context)} |
|
|
|
|
self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32) |
|
|
|
|
|
|
|
|
|
# img buffers are managed in openCL transform code |
|
|
|
|
# policy inputs |
|
|
|
|
self.numpy_inputs = { |
|
|
|
|
'desire': np.zeros((1, (ModelConstants.FULL_HISTORY_BUFFER_LEN+1), ModelConstants.DESIRE_LEN), dtype=np.float32), |
|
|
|
|
'desire': np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32), |
|
|
|
|
'traffic_convention': np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32), |
|
|
|
|
'lateral_control_params': np.zeros((1, ModelConstants.LATERAL_CONTROL_PARAMS_LEN), dtype=np.float32), |
|
|
|
|
'prev_desired_curv': np.zeros((1, (ModelConstants.FULL_HISTORY_BUFFER_LEN+1), ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32), |
|
|
|
|
'prev_desired_curv': np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32), |
|
|
|
|
'features_buffer': np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
with open(METADATA_PATH, 'rb') as f: |
|
|
|
|
model_metadata = pickle.load(f) |
|
|
|
|
self.input_shapes = model_metadata['input_shapes'] |
|
|
|
|
with open(VISION_METADATA_PATH, 'rb') as f: |
|
|
|
|
vision_metadata = pickle.load(f) |
|
|
|
|
self.vision_input_shapes = vision_metadata['input_shapes'] |
|
|
|
|
self.vision_output_slices = vision_metadata['output_slices'] |
|
|
|
|
vision_output_size = vision_metadata['output_shapes']['outputs'][1] |
|
|
|
|
|
|
|
|
|
with open(POLICY_METADATA_PATH, 'rb') as f: |
|
|
|
|
policy_metadata = pickle.load(f) |
|
|
|
|
self.policy_input_shapes = policy_metadata['input_shapes'] |
|
|
|
|
self.policy_output_slices = policy_metadata['output_slices'] |
|
|
|
|
policy_output_size = policy_metadata['output_shapes']['outputs'][1] |
|
|
|
|
|
|
|
|
|
self.output_slices = model_metadata['output_slices'] |
|
|
|
|
net_output_size = model_metadata['output_shapes']['outputs'][1] |
|
|
|
|
self.output = np.zeros(net_output_size, dtype=np.float32) |
|
|
|
|
# img buffers are managed in openCL transform code |
|
|
|
|
self.vision_inputs: dict[str, Tensor] = {} |
|
|
|
|
self.vision_output = np.zeros(vision_output_size, dtype=np.float32) |
|
|
|
|
self.policy_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()} |
|
|
|
|
self.policy_output = np.zeros(policy_output_size, dtype=np.float32) |
|
|
|
|
self.parser = Parser() |
|
|
|
|
|
|
|
|
|
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: |
|
|
|
|
self.model_run = pickle.load(f) |
|
|
|
|
with open(VISION_PKL_PATH, "rb") as f: |
|
|
|
|
self.vision_run = pickle.load(f) |
|
|
|
|
|
|
|
|
|
def slice_outputs(self, model_outputs: np.ndarray) -> dict[str, np.ndarray]: |
|
|
|
|
parsed_model_outputs = {k: model_outputs[np.newaxis, v] for k,v in self.output_slices.items()} |
|
|
|
|
if SEND_RAW_PRED: |
|
|
|
|
parsed_model_outputs['raw_pred'] = model_outputs.copy() |
|
|
|
|
with open(POLICY_PKL_PATH, "rb") as f: |
|
|
|
|
self.policy_run = pickle.load(f) |
|
|
|
|
|
|
|
|
|
def slice_outputs(self, model_outputs: np.ndarray, output_slices: dict[str, slice]) -> dict[str, np.ndarray]: |
|
|
|
|
parsed_model_outputs = {k: model_outputs[np.newaxis, v] for k,v in output_slices.items()} |
|
|
|
|
return parsed_model_outputs |
|
|
|
|
|
|
|
|
|
def run(self, buf: VisionBuf, wbuf: VisionBuf, transform: np.ndarray, transform_wide: np.ndarray, |
|
|
|
@ -103,29 +115,34 @@ class ModelState: |
|
|
|
|
if TICI: |
|
|
|
|
# The imgs tensors are backed by opencl memory, only need init once |
|
|
|
|
for key in imgs_cl: |
|
|
|
|
if key not in self.tensor_inputs: |
|
|
|
|
self.tensor_inputs[key] = qcom_tensor_from_opencl_address(imgs_cl[key].mem_address, self.input_shapes[key], dtype=dtypes.uint8) |
|
|
|
|
if key not in self.vision_inputs: |
|
|
|
|
self.vision_inputs[key] = qcom_tensor_from_opencl_address(imgs_cl[key].mem_address, self.vision_input_shapes[key], dtype=dtypes.uint8) |
|
|
|
|
else: |
|
|
|
|
for key in imgs_cl: |
|
|
|
|
self.numpy_inputs[key] = self.frames[key].buffer_from_cl(imgs_cl[key]).reshape(self.input_shapes[key]) |
|
|
|
|
self.tensor_inputs[key] = Tensor(self.numpy_inputs[key], dtype=dtypes.uint8).realize() |
|
|
|
|
|
|
|
|
|
frame_input = self.frames[key].buffer_from_cl(imgs_cl[key]).reshape(self.vision_input_shapes[key]) |
|
|
|
|
self.vision_inputs[key] = Tensor(frame_input, dtype=dtypes.uint8).realize() |
|
|
|
|
|
|
|
|
|
if prepare_only: |
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
self.output = self.model_run(**self.tensor_inputs).numpy().flatten() |
|
|
|
|
|
|
|
|
|
outputs = self.parser.parse_outputs(self.slice_outputs(self.output)) |
|
|
|
|
self.vision_output = self.vision_run(**self.vision_inputs).numpy().flatten() |
|
|
|
|
vision_outputs_dict = self.parser.parse_vision_outputs(self.slice_outputs(self.vision_output, self.vision_output_slices)) |
|
|
|
|
|
|
|
|
|
self.numpy_inputs['features_buffer'][0,:-1] = self.numpy_inputs['features_buffer'][0,1:] |
|
|
|
|
self.numpy_inputs['features_buffer'][0,-1] = outputs['hidden_state'][0, :] |
|
|
|
|
self.numpy_inputs['features_buffer'][0,-1] = vision_outputs_dict['hidden_state'][0, :] |
|
|
|
|
|
|
|
|
|
self.policy_output = self.policy_run(**self.policy_inputs).numpy().flatten() |
|
|
|
|
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices)) |
|
|
|
|
|
|
|
|
|
# TODO model only uses last value now |
|
|
|
|
self.numpy_inputs['prev_desired_curv'][0,:-1] = self.numpy_inputs['prev_desired_curv'][0,1:] |
|
|
|
|
self.numpy_inputs['prev_desired_curv'][0,-1,:] = outputs['desired_curvature'][0, :] |
|
|
|
|
return outputs |
|
|
|
|
self.numpy_inputs['prev_desired_curv'][0,-1,:] = policy_outputs_dict['desired_curvature'][0, :] |
|
|
|
|
|
|
|
|
|
combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict} |
|
|
|
|
if SEND_RAW_PRED: |
|
|
|
|
combined_outputs_dict['raw_pred'] = np.concatenate([self.vision_output.copy(), self.policy_output.copy()]) |
|
|
|
|
|
|
|
|
|
return combined_outputs_dict |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(demo=False): |
|
|
|
|