parent
e030a701fa
commit
c2ecf7ab7c
4 changed files with 259 additions and 13 deletions
@ -0,0 +1,113 @@ |
|||||||
|
import capnp |
||||||
|
import numpy as np |
||||||
|
from typing import List, Dict |
||||||
|
from openpilot.selfdrive.modeld.models.driving_pyx import PublishState |
||||||
|
from openpilot.selfdrive.modeld.constants import T_IDXS, X_IDXS, lEAD_T_IDXS, META_T_IdXS |
||||||
|
|
||||||
|
def fill_xyzt(builder, t, x, y, z, x_std=None, y_std=None, z_std=None): |
||||||
|
builder.t = t |
||||||
|
builder.x = x.tolist() |
||||||
|
builder.y = y.tolist() |
||||||
|
builder.z = z.tolist() |
||||||
|
if x_std is not None: builder.xStd = x_std.tolist() |
||||||
|
if y_std is not None: builder.yStd = y_std.tolist() |
||||||
|
if z_std is not None: builder.zStd = z_std.tolist() |
||||||
|
|
||||||
|
def fill_xyvat(builder, t, x, y, v, a, x_std=None, y_std=None, v_std=None, a_std=None): |
||||||
|
builder.t = t |
||||||
|
builder.x = x.tolist() |
||||||
|
builder.y = y.tolist() |
||||||
|
builder.v = v.tolist() |
||||||
|
builder.a = a.tolist() |
||||||
|
if x_std is not None: builder.xStd = x_std.tolist() |
||||||
|
if y_std is not None: builder.yStd = y_std.tolist() |
||||||
|
if v_std is not None:builder.vStd = v_std.tolist() |
||||||
|
if a_std is not None:builder.aStd = a_std.tolist() |
||||||
|
|
||||||
|
def fill_model_msg(msg: capnp._DynamicStructBuilder, net_output_data: Dict[str, np.ndarray], ps: PublishState, |
||||||
|
vipc_frame_id: int, vipc_frame_id_extra: int, frame_id: int, frame_drop: float, |
||||||
|
timestamp_eof: int, timestamp_llk: int, model_execution_time: float, |
||||||
|
nav_enabled: bool, valid: bool) -> None: |
||||||
|
frame_age = frame_id - vipc_frame_id if frame_id > vipc_frame_id else 0 |
||||||
|
msg.valid = valid |
||||||
|
|
||||||
|
modelV2 = msg.modelV2 |
||||||
|
modelV2.frameId = vipc_frame_id |
||||||
|
modelV2.frameIdExtra = vipc_frame_id_extra |
||||||
|
modelV2.frameAge = frame_age |
||||||
|
modelV2.frameDropPerc = frame_drop * 100 |
||||||
|
modelV2.timestampEof = timestamp_eof |
||||||
|
modelV2.locationMonoTime = timestamp_llk |
||||||
|
modelV2.modelExecutionTime = model_execution_time |
||||||
|
modelV2.navEnabled = nav_enabled |
||||||
|
|
||||||
|
# plan |
||||||
|
fill_xyzt(modelV2.position, T_IDXS, net_output_data['plan'][0,0], net_output_data['plan'][0,1], net_output_data['plan'][0,2], |
||||||
|
net_output_data['plan_stds'][0,0], net_output_data['plan_stds'][0,1], net_output_data['plan_stds'][0,2]) |
||||||
|
fill_xyzt(modelV2.velocity, T_IDXS, net_output_data['plan'][0,3], net_output_data['plan'][0,4], net_output_data['plan'][0,5]) |
||||||
|
fill_xyzt(modelV2.acceleration, T_IDXS, net_output_data['plan'][0,6], net_output_data['plan'][0,7], net_output_data['plan'][0,9]) |
||||||
|
fill_xyzt(modelV2.orientation, T_IDXS, net_output_data['plan'][0,10], net_output_data['plan'][0,11], net_output_data['plan'][0,12]) |
||||||
|
fill_xyzt(modelV2.orientationRate, T_IDXS, net_output_data['plan'][0,13], net_output_data['plan'][0,14], net_output_data['plan'][0,15]) |
||||||
|
|
||||||
|
# lane lines |
||||||
|
modelV2.init('laneLines', 4) |
||||||
|
for i in range(4): |
||||||
|
fill_xyzt(modelV2.laneLines[i], T_IDXS, np.array(X_IDXS), net_output_data['lane_lines'][0,i,:,0], net_output_data['lane_lines'][0,i,:,1]) |
||||||
|
modelV2.laneLineProbs = net_output_data['lane_lines_prob'][0].tolist() |
||||||
|
|
||||||
|
# road edges |
||||||
|
modelV2.init('roadEdges', 2) |
||||||
|
for i in range(2): |
||||||
|
fill_xyzt(modelV2.roadEdges[i], T_IDXS, np.array(X_IDXS), net_output_data['road_edges'][0,i,:,0], net_output_data['road_edges'][0,i,:,1]) |
||||||
|
modelV2.roadEdgeStds = net_output_data['road_edges_stds'][0,:,0,0].tolist() |
||||||
|
|
||||||
|
# leads |
||||||
|
modelV2.init('leadsV3', 2) |
||||||
|
for i in range(2): |
||||||
|
fill_xyvat(modelV2.leadsV3[i], lEAD_T_IDXS, net_output_data['lead'][0,i,:,0], net_output_data['lead'][0,i,:,1], net_output_data['lead'][0,i,:,2], net_output_data['lead'][0,i,:,3], |
||||||
|
net_output_data['lead_stds'][0,i,:,0], net_output_data['lead_stds'][0,i,:,1], net_output_data['lead_stds'][0,i,:,2], net_output_data['lead_stds'][0,i,:,3]) |
||||||
|
|
||||||
|
# leads probs |
||||||
|
# TODO |
||||||
|
|
||||||
|
# confidence |
||||||
|
# TODO |
||||||
|
modelV2.confidence = 0 |
||||||
|
|
||||||
|
# meta |
||||||
|
# TODO |
||||||
|
modelV2.meta.engagedProb = 0. |
||||||
|
modelV2.meta.hardBrakePredicted = False |
||||||
|
modelV2.meta.init('disengagePredictions') |
||||||
|
modelV2.meta.disengagePredictions.t = META_T_IdXS |
||||||
|
modelV2.meta.disengagePredictions.brakeDisengageProbs = np.zeros(5, dtype=np.float32).tolist() |
||||||
|
modelV2.meta.disengagePredictions.gasDisengageProbs = np.zeros(5, dtype=np.float32).tolist() |
||||||
|
modelV2.meta.disengagePredictions.steerOverrideProbs = np.zeros(5, dtype=np.float32).tolist() |
||||||
|
modelV2.meta.disengagePredictions.brake3MetersPerSecondSquaredProbs = np.zeros(5, dtype=np.float32).tolist() |
||||||
|
modelV2.meta.disengagePredictions.brake4MetersPerSecondSquaredProbs = np.zeros(5, dtype=np.float32).tolist() |
||||||
|
modelV2.meta.disengagePredictions.brake5MetersPerSecondSquaredProbs = np.zeros(5, dtype=np.float32).tolist() |
||||||
|
modelV2.meta.desirePrediction = np.zeros(4*8, dtype=np.float32).tolist() |
||||||
|
|
||||||
|
# temporal pose |
||||||
|
modelV2.temporalPose.trans = net_output_data['sim_pose'][0,:3].tolist() |
||||||
|
modelV2.temporalPose.transStd = net_output_data['sim_pose_stds'][0,:3].tolist() |
||||||
|
modelV2.temporalPose.rot = net_output_data['sim_pose'][0,3:].tolist() |
||||||
|
modelV2.temporalPose.rotStd = net_output_data['sim_pose_stds'][0,3:].tolist() |
||||||
|
|
||||||
|
|
||||||
|
def fill_pose_msg(msg: capnp._DynamicStructBuilder, net_output_data: Dict[str, np.ndarray], |
||||||
|
vipc_frame_id: int, vipc_dropped_frames: int, timestamp_eof: int, live_calib_seen: bool) -> None: |
||||||
|
msg.valid = live_calib_seen & (vipc_dropped_frames < 1) |
||||||
|
cameraOdometry = msg.cameraOdometry |
||||||
|
|
||||||
|
cameraOdometry.frameId = vipc_frame_id |
||||||
|
cameraOdometry.timestampEof = timestamp_eof |
||||||
|
|
||||||
|
cameraOdometry.trans = net_output_data['pose'][0,:3].tolist() |
||||||
|
cameraOdometry.rot = net_output_data['pose'][0,3:].tolist() |
||||||
|
cameraOdometry.wideFromDeviceEuler = net_output_data['wide_from_device_euler'][0,:].tolist() |
||||||
|
cameraOdometry.roadTransformTrans = net_output_data['road_transform'][0,:3].tolist() |
||||||
|
cameraOdometry.transStd = net_output_data['pose_stds'][0,:3].tolist() |
||||||
|
cameraOdometry.rotStd = net_output_data['pose_stds'][0,3:].tolist() |
||||||
|
cameraOdometry.wideFromDeviceEulerStd = net_output_data['wide_from_device_euler_stds'][0,:].tolist() |
||||||
|
cameraOdometry.roadTransformTransStd = net_output_data['road_transform_stds'][0,:3].tolist() |
@ -0,0 +1,113 @@ |
|||||||
|
import numpy as np |
||||||
|
from typing import Dict |
||||||
|
from openpilot.selfdrive.modeld.constants import IDX_N |
||||||
|
|
||||||
|
POSE_WIDTH = 6 |
||||||
|
SIM_POSE_WIDTH = 6 |
||||||
|
LEAD_WIDTH = 4 |
||||||
|
LANE_LINES_WIDTH = 2 |
||||||
|
ROAD_EDGES_WIDTH = 2 |
||||||
|
PLAN_WIDTH = 15 |
||||||
|
DESIRE_PRED_WIDTH = 4 |
||||||
|
|
||||||
|
NUM_LANE_LINES = 4 |
||||||
|
NUM_ROAD_EDGES = 2 |
||||||
|
|
||||||
|
LEAD_TRAJ_LEN = 6 |
||||||
|
|
||||||
|
PLAN_MHP_N = 5 |
||||||
|
LEAD_MHP_N = 2 |
||||||
|
PLAN_MHP_SELECTION = 1 |
||||||
|
LEAD_MHP_SELECTION = 3 |
||||||
|
|
||||||
|
FCW_THRESHOLD_5MS2_HIGH = 0.15 |
||||||
|
FCW_THRESHOLD_5MS2_LOW = 0.05 |
||||||
|
FCW_THRESHOLD_3MS2 = 0.7 |
||||||
|
|
||||||
|
def sigmoid(x): |
||||||
|
return 1. / (1. + np.exp(-x)) |
||||||
|
|
||||||
|
def softmax(x, axis=-1): |
||||||
|
x -= np.max(x, axis=axis, keepdims=True) |
||||||
|
if x.dtype == np.float32 or x.dtype == np.float64: |
||||||
|
np.exp(x, out=x) |
||||||
|
else: |
||||||
|
x = np.exp(x) |
||||||
|
x /= np.sum(x, axis=axis, keepdims=True) |
||||||
|
return x |
||||||
|
|
||||||
|
def parse_mdn(name, outs, in_N=0, out_N=1, out_shape=None): |
||||||
|
if name not in outs: |
||||||
|
return |
||||||
|
raw = outs[name] |
||||||
|
raw = raw.reshape((raw.shape[0], max(in_N, 1), -1)) |
||||||
|
|
||||||
|
pred_mu = raw[:,:,:(raw.shape[2] - out_N)//2] |
||||||
|
n_values = (raw.shape[2] - out_N)//2 |
||||||
|
pred_mu = raw[:,:,:n_values] |
||||||
|
pred_std = np.exp(raw[:,:,n_values: 2*n_values]) |
||||||
|
|
||||||
|
if in_N > 1: |
||||||
|
weights = np.zeros((raw.shape[0], in_N, out_N), dtype=raw.dtype) |
||||||
|
for i in range(out_N): |
||||||
|
weights[:,:,i - out_N] = softmax(raw[:,:,i - out_N], axis=-1) |
||||||
|
|
||||||
|
if out_N == 1: |
||||||
|
for fidx in range(weights.shape[0]): |
||||||
|
idxs = np.argsort(weights[fidx][:,0])[::-1] |
||||||
|
weights[fidx] = weights[fidx][idxs] |
||||||
|
pred_mu[fidx] = pred_mu[fidx][idxs] |
||||||
|
pred_std[fidx] = pred_std[fidx][idxs] |
||||||
|
full_shape = tuple([raw.shape[0], in_N] + list(out_shape)) |
||||||
|
outs[name + '_weights'] = weights |
||||||
|
outs[name + '_hypotheses'] = pred_mu.reshape(full_shape) |
||||||
|
outs[name + '_stds_hypotheses'] = pred_std.reshape(full_shape) |
||||||
|
|
||||||
|
pred_mu_final = np.zeros((raw.shape[0], out_N, n_values), dtype=raw.dtype) |
||||||
|
pred_std_final = np.zeros((raw.shape[0], out_N, n_values), dtype=raw.dtype) |
||||||
|
for fidx in range(weights.shape[0]): |
||||||
|
for hidx in range(out_N): |
||||||
|
idxs = np.argsort(weights[fidx,:,hidx])[::-1] |
||||||
|
pred_mu_final[fidx, hidx] = pred_mu[fidx, idxs[0]] |
||||||
|
pred_std_final[fidx, hidx] = pred_std[fidx, idxs[0]] |
||||||
|
else: |
||||||
|
pred_mu_final = pred_mu |
||||||
|
pred_std_final = pred_std |
||||||
|
|
||||||
|
if out_N > 1: |
||||||
|
final_shape = tuple([raw.shape[0], out_N] + list(out_shape)) |
||||||
|
else: |
||||||
|
final_shape = tuple([raw.shape[0],] + list(out_shape)) |
||||||
|
outs[name] = pred_mu_final.reshape(final_shape) |
||||||
|
outs[name + '_stds'] = pred_std_final.reshape(final_shape) |
||||||
|
return |
||||||
|
|
||||||
|
def parse_binary_crossentropy(name, outs): |
||||||
|
if name not in outs: |
||||||
|
return |
||||||
|
raw = outs[name] |
||||||
|
outs[name] = sigmoid(raw) |
||||||
|
return |
||||||
|
|
||||||
|
def parse_categorical_crossentropy(name, outs, size=1): |
||||||
|
if name not in outs: |
||||||
|
return |
||||||
|
raw = outs[name] |
||||||
|
if size > 1: |
||||||
|
raw = raw.reshape((raw.shape[0], size, -1)) |
||||||
|
outs[name] = softmax(raw, axis=-1) |
||||||
|
return |
||||||
|
|
||||||
|
def parse_outputs(outs: Dict[str, np.ndarray]) -> Dict[str, np.ndarray]: |
||||||
|
parse_mdn('plan', outs, in_N=PLAN_MHP_N, out_N=PLAN_MHP_SELECTION, out_shape=(IDX_N,PLAN_WIDTH)) |
||||||
|
parse_mdn('lane_lines', outs, in_N=0, out_N=0, out_shape=(NUM_LANE_LINES,IDX_N,LANE_LINES_WIDTH)) |
||||||
|
parse_mdn('road_edges', outs, in_N=0, out_N=0, out_shape=(NUM_ROAD_EDGES,IDX_N,LANE_LINES_WIDTH)) |
||||||
|
parse_mdn('pose', outs, in_N=0, out_N=0, out_shape=(POSE_WIDTH,)) |
||||||
|
parse_mdn('road_transform', outs, in_N=0, out_N=0, out_shape=(POSE_WIDTH,)) |
||||||
|
parse_mdn('sim_pose', outs, in_N=0, out_N=0, out_shape=(POSE_WIDTH,)) |
||||||
|
parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(POSE_WIDTH // 2,)) |
||||||
|
parse_mdn('lead', outs, in_N=LEAD_MHP_N, out_N=LEAD_MHP_SELECTION, out_shape=(LEAD_TRAJ_LEN,LEAD_WIDTH)) |
||||||
|
for k in ['lead_prob', 'lane_lines_prob', 'meta']: |
||||||
|
parse_binary_crossentropy(k, outs) |
||||||
|
parse_categorical_crossentropy('desire_pred', outs, size=DESIRE_PRED_WIDTH) |
||||||
|
return outs |
Loading…
Reference in new issue