77import math
88import time
99import pickle
10- import ctypes
1110import numpy as np
1211from pathlib import Path
1312
1615from msgq .visionipc import VisionIpcClient , VisionStreamType , VisionBuf
1716from openpilot .common .swaglog import cloudlog
1817from openpilot .common .realtime import config_realtime_process
19- from openpilot .common .transformations .model import dmonitoringmodel_intrinsics , DM_INPUT_SIZE
18+ from openpilot .common .transformations .model import dmonitoringmodel_intrinsics
2019from openpilot .common .transformations .camera import _ar_ox_fisheye , _os_fisheye
2120from openpilot .selfdrive .modeld .models .commonmodel_pyx import CLContext , MonitoringModelFrame
2221from openpilot .selfdrive .modeld .parse_model_outputs import sigmoid
2322from openpilot .selfdrive .modeld .runners .tinygrad_helpers import qcom_tensor_from_opencl_address
2423
25- MODEL_WIDTH , MODEL_HEIGHT = DM_INPUT_SIZE
26- CALIB_LEN = 3
27- FEATURE_LEN = 512
28- OUTPUT_SIZE = 83 + FEATURE_LEN
29-
3024PROCESS_NAME = "selfdrive.modeld.dmonitoringmodeld"
3125SEND_RAW_PRED = os .getenv ('SEND_RAW_PRED' )
3226MODEL_PKL_PATH = Path (__file__ ).parent / 'models/dmonitoring_model_tinygrad.pkl'
33-
34- # TODO: slice from meta
35- class DriverStateResult (ctypes .Structure ):
36- _fields_ = [
37- ("face_orientation" , ctypes .c_float * 3 ),
38- ("face_position" , ctypes .c_float * 3 ),
39- ("face_orientation_std" , ctypes .c_float * 3 ),
40- ("face_position_std" , ctypes .c_float * 3 ),
41- ("face_prob" , ctypes .c_float ),
42- ("_unused_a" , ctypes .c_float * 8 ),
43- ("left_eye_prob" , ctypes .c_float ),
44- ("_unused_b" , ctypes .c_float * 8 ),
45- ("right_eye_prob" , ctypes .c_float ),
46- ("left_blink_prob" , ctypes .c_float ),
47- ("right_blink_prob" , ctypes .c_float ),
48- ("sunglasses_prob" , ctypes .c_float ),
49- ("_unused_c" , ctypes .c_float ),
50- ("_unused_d" , ctypes .c_float * 4 ),
51- ("not_ready_prob" , ctypes .c_float * 2 )]
52-
53-
54- class DMonitoringModelResult (ctypes .Structure ):
55- _fields_ = [
56- ("driver_state_lhd" , DriverStateResult ),
57- ("driver_state_rhd" , DriverStateResult ),
58- ("wheel_on_right_prob" , ctypes .c_float ),
59- ("features" , ctypes .c_float * FEATURE_LEN )]
27+ METADATA_PATH = Path (__file__ ).parent / 'models/dmonitoring_model_metadata.pkl'
6028
6129
6230class ModelState :
6331 inputs : dict [str , np .ndarray ]
6432 output : np .ndarray
6533
6634 def __init__ (self , cl_ctx ):
67- assert ctypes .sizeof (DMonitoringModelResult ) == OUTPUT_SIZE * ctypes .sizeof (ctypes .c_float )
35+ with open (METADATA_PATH , 'rb' ) as f :
36+ model_metadata = pickle .load (f )
37+ self .input_shapes = model_metadata ['input_shapes' ]
38+ self .output_slices = model_metadata ['output_slices' ]
6839
6940 self .frame = MonitoringModelFrame (cl_ctx )
7041 self .numpy_inputs = {
71- 'calib' : np .zeros (( 1 , CALIB_LEN ) , dtype = np .float32 ),
42+ 'calib' : np .zeros (self . input_shapes [ 'calib' ] , dtype = np .float32 ),
7243 }
7344
7445 self .tensor_inputs = {k : Tensor (v , device = 'NPY' ).realize () for k ,v in self .numpy_inputs .items ()}
@@ -84,9 +55,9 @@ def run(self, buf: VisionBuf, calib: np.ndarray, transform: np.ndarray) -> tuple
8455 if TICI :
8556 # The imgs tensors are backed by opencl memory, only need init once
8657 if 'input_img' not in self .tensor_inputs :
87- self .tensor_inputs ['input_img' ] = qcom_tensor_from_opencl_address (input_img_cl .mem_address , ( 1 , MODEL_WIDTH * MODEL_HEIGHT ) , dtype = dtypes .uint8 )
58+ self .tensor_inputs ['input_img' ] = qcom_tensor_from_opencl_address (input_img_cl .mem_address , self . input_shapes [ 'input_img' ] , dtype = dtypes .uint8 )
8859 else :
89- self .tensor_inputs ['input_img' ] = Tensor (self .frame .buffer_from_cl (input_img_cl ).reshape (( 1 , MODEL_WIDTH * MODEL_HEIGHT ) ), dtype = dtypes .uint8 ).realize ()
60+ self .tensor_inputs ['input_img' ] = Tensor (self .frame .buffer_from_cl (input_img_cl ).reshape (self . input_shapes [ 'input_img' ] ), dtype = dtypes .uint8 ).realize ()
9061
9162
9263 output = self .model_run (** self .tensor_inputs ).contiguous ().realize ().uop .base .buffer .numpy ()
@@ -95,31 +66,31 @@ def run(self, buf: VisionBuf, calib: np.ndarray, transform: np.ndarray) -> tuple
9566 return output , t2 - t1
9667
9768
98- def fill_driver_state (msg , ds_result : DriverStateResult ):
99- msg . faceOrientation = list ( ds_result . face_orientation )
100- msg . faceOrientationStd = [ math . exp ( x ) for x in ds_result . face_orientation_std ]
101- msg .facePosition = list ( ds_result . face_position [: 2 ])
102- msg .facePositionStd = [math .exp (x ) for x in ds_result . face_position_std [: 2 ]]
103- msg .faceProb = float (sigmoid ( ds_result . face_prob ))
104- msg .leftEyeProb = float ( sigmoid ( ds_result . left_eye_prob ))
105- msg .rightEyeProb = float (sigmoid (ds_result . right_eye_prob ))
106- msg .leftBlinkProb = float (sigmoid (ds_result . left_blink_prob ))
107- msg .rightBlinkProb = float (sigmoid (ds_result . right_blink_prob ))
108- msg .sunglassesProb = float (sigmoid (ds_result . sunglasses_prob ))
109- msg .notReadyProb = [ float (sigmoid (x )) for x in ds_result . not_ready_prob ]
110-
111-
112- def get_driverstate_packet ( model_output : np . ndarray , frame_id : int , location_ts : int , execution_time : float , gpu_execution_time : float ):
113- model_result = ctypes . cast (model_output . ctypes . data , ctypes . POINTER ( DMonitoringModelResult )). contents
69+ def fill_driver_state (msg , model_output , output_slices , ds_suffix ):
70+ face_descs = model_output [ output_slices [ f'face_descs_ { ds_suffix } ' ]]
71+ face_descs_std = face_descs [ - 6 : ]
72+ msg .faceOrientation = [ float ( x ) for x in face_descs [: 3 ]]
73+ msg .faceOrientationStd = [math .exp (x ) for x in face_descs_std [: 3 ]]
74+ msg .facePosition = [ float (x ) for x in face_descs [ 3 : 5 ]]
75+ msg .facePositionStd = [ math . exp ( x ) for x in face_descs_std [ 3 : 5 ]]
76+ msg .faceProb = float (sigmoid (model_output [ output_slices [ f'face_prob_ { ds_suffix } ' ]][ 0 ] ))
77+ msg .leftEyeProb = float (sigmoid (model_output [ output_slices [ f'left_eye_prob_ { ds_suffix } ' ]][ 0 ] ))
78+ msg .rightEyeProb = float (sigmoid (model_output [ output_slices [ f'right_eye_prob_ { ds_suffix } ' ]][ 0 ] ))
79+ msg .leftBlinkProb = float (sigmoid (model_output [ output_slices [ f'left_blink_prob_ { ds_suffix } ' ]][ 0 ] ))
80+ msg .rightBlinkProb = float (sigmoid (model_output [ output_slices [ f'right_blink_prob_ { ds_suffix } ' ]][ 0 ]))
81+ msg . sunglassesProb = float ( sigmoid ( model_output [ output_slices [ f'sunglasses_prob_ { ds_suffix } ' ]][ 0 ]))
82+ msg . phoneProb = float ( sigmoid ( model_output [ output_slices [ f'using_phone_prob_ { ds_suffix } ' ]][ 0 ]))
83+
84+ def get_driverstate_packet (model_output : np . ndarray , output_slices : dict [ str , slice ], frame_id : int , location_ts : int , exec_time : float , gpu_exec_time : float ):
11485 msg = messaging .new_message ('driverStateV2' , valid = True )
11586 ds = msg .driverStateV2
11687 ds .frameId = frame_id
117- ds .modelExecutionTime = execution_time
118- ds .gpuExecutionTime = gpu_execution_time
119- ds .wheelOnRightProb = float (sigmoid (model_result . wheel_on_right_prob ))
88+ ds .modelExecutionTime = exec_time
89+ ds .gpuExecutionTime = gpu_exec_time
90+ ds .wheelOnRightProb = float (sigmoid (model_output [ output_slices [ 'wheel_on_right' ]][ 0 ] ))
12091 ds .rawPredictions = model_output .tobytes () if SEND_RAW_PRED else b''
121- fill_driver_state (ds .leftDriverData , model_result . driver_state_lhd )
122- fill_driver_state (ds .rightDriverData , model_result . driver_state_rhd )
92+ fill_driver_state (ds .leftDriverData , model_output , output_slices , 'lhd' )
93+ fill_driver_state (ds .rightDriverData , model_output , output_slices , 'rhd' )
12394 return msg
12495
12596
@@ -140,7 +111,7 @@ def main():
140111 sm = SubMaster (["liveCalibration" ])
141112 pm = PubMaster (["driverStateV2" ])
142113
143- calib = np .zeros (CALIB_LEN , dtype = np .float32 )
114+ calib = np .zeros (model . numpy_inputs [ 'calib' ]. size , dtype = np .float32 )
144115 model_transform = None
145116
146117 while True :
@@ -160,7 +131,8 @@ def main():
160131 model_output , gpu_execution_time = model .run (buf , calib , model_transform )
161132 t2 = time .perf_counter ()
162133
163- pm .send ("driverStateV2" , get_driverstate_packet (model_output , vipc_client .frame_id , vipc_client .timestamp_sof , t2 - t1 , gpu_execution_time ))
134+ msg = get_driverstate_packet (model_output , model .output_slices , vipc_client .frame_id , vipc_client .timestamp_sof , t2 - t1 , gpu_execution_time )
135+ pm .send ("driverStateV2" , msg )
164136
165137
166138if __name__ == "__main__" :
0 commit comments