20#include <unordered_map>
26#include "modules/common/adapters/proto/adapter_config.pb.h"
46double ComputeMean(
const std::vector<double>& nums,
size_t start,
size_t end) {
49 for (
size_t i = start; i <= end && i < nums.size(); i++) {
53 return (count == 0) ? 0.0 : sum / count;
68 omp_set_num_threads(1);
70 CHECK_NOTNULL(obstacle_ptr);
74 int id = obstacle_ptr->
id();
76 AERROR <<
"Obstacle [" <<
id <<
"] has no latest feature.";
80 CHECK_NOTNULL(latest_feature_ptr);
83 if (!latest_feature_ptr->has_junction_feature() ||
85 ADEBUG <<
"Obstacle [" <<
id <<
"] has no junction_exit.";
89 std::vector<double> feature_values;
93 if (FLAGS_prediction_offline_mode ==
97 ADEBUG <<
"Save extracted features for learning locally.";
100 std::vector<torch::jit::IValue> torch_inputs;
101 int input_dim =
static_cast<int>(
102 OBSTACLE_FEATURE_SIZE + EGO_VEHICLE_FEATURE_SIZE + JUNCTION_FEATURE_SIZE);
103 torch::Tensor torch_input = torch::zeros({1, input_dim});
104 for (
size_t i = 0; i < feature_values.size(); ++i) {
105 torch_input[0][i] =
static_cast<float>(feature_values[i]);
107 torch_inputs.push_back(std::move(torch_input.to(device_)));
108 std::vector<double> probability;
110 at::Tensor torch_output_tensor =
111 torch_model_.forward(torch_inputs).toTensor().to(torch::kCPU);
112 auto torch_output = torch_output_tensor.accessor<float, 2>();
113 for (
int i = 0; i < torch_output.size(1); ++i) {
114 probability.push_back(
static_cast<double>(torch_output[0][i]));
117 for (
int i = 0; i < 12; ++i) {
118 probability.push_back(feature_values[OBSTACLE_FEATURE_SIZE +
119 EGO_VEHICLE_FEATURE_SIZE + 8 * i]);
122 for (
double prob : probability) {
123 latest_feature_ptr->mutable_junction_feature()
124 ->add_junction_mlp_probability(prob);
128 latest_feature_ptr->mutable_lane()->mutable_lane_graph();
129 CHECK_NOTNULL(lane_graph_ptr);
131 AERROR <<
"Obstacle [" <<
id <<
"] has no lane sequences.";
135 std::unordered_map<std::string, double> junction_exit_prob;
139 junction_exit.exit_position().x() - latest_feature_ptr->
position().
x();
141 junction_exit.exit_position().y() - latest_feature_ptr->
position().
y();
143 std::atan2(y, x) - std::atan2(latest_feature_ptr->
raw_velocity().
y(),
145 double d_idx = (angle / (2.0 * M_PI) + 1.0 / 24.0) * 12.0;
146 int idx =
static_cast<int>(floor(d_idx >= 0 ? d_idx : d_idx + 12));
147 junction_exit_prob[junction_exit.exit_lane_id()] = probability[idx];
150 for (
int i = 0; i < lane_graph_ptr->lane_sequence_size(); ++i) {
151 LaneSequence* lane_sequence_ptr = lane_graph_ptr->mutable_lane_sequence(i);
152 CHECK_NOTNULL(lane_sequence_ptr);
154 if (junction_exit_prob.find(lane_segment.lane_id()) !=
155 junction_exit_prob.end()) {
156 lane_sequence_ptr->set_probability(
157 junction_exit_prob[lane_segment.lane_id()]);
166 std::vector<double>* feature_values) {
167 CHECK_NOTNULL(obstacle_ptr);
168 int id = obstacle_ptr->
id();
170 std::vector<double> obstacle_feature_values;
171 SetObstacleFeatureValues(obstacle_ptr, &obstacle_feature_values);
173 if (obstacle_feature_values.size() != OBSTACLE_FEATURE_SIZE) {
174 AERROR <<
"Obstacle [" <<
id <<
"] has fewer than "
175 <<
"expected obstacle feature_values "
176 << obstacle_feature_values.size() <<
".";
180 std::vector<double> ego_vehicle_feature_values;
181 SetEgoVehicleFeatureValues(obstacle_ptr, obstacles_container,
182 &ego_vehicle_feature_values);
183 if (ego_vehicle_feature_values.size() != EGO_VEHICLE_FEATURE_SIZE) {
184 AERROR <<
"Obstacle [" <<
id <<
"] has fewer than "
185 <<
"expected ego vehicle feature_values"
186 << ego_vehicle_feature_values.size() <<
".";
190 std::vector<double> junction_feature_values;
191 SetJunctionFeatureValues(obstacle_ptr, &junction_feature_values);
192 if (junction_feature_values.size() != JUNCTION_FEATURE_SIZE) {
193 AERROR <<
"Obstacle [" <<
id <<
"] has fewer than "
194 <<
"expected junction feature_values"
195 << junction_feature_values.size() <<
".";
199 feature_values->insert(feature_values->end(), obstacle_feature_values.begin(),
200 obstacle_feature_values.end());
201 feature_values->insert(feature_values->end(),
202 ego_vehicle_feature_values.begin(),
203 ego_vehicle_feature_values.end());
204 feature_values->insert(feature_values->end(), junction_feature_values.begin(),
205 junction_feature_values.end());
208void JunctionMLPEvaluator::SetObstacleFeatureValues(
209 Obstacle* obstacle_ptr, std::vector<double>* feature_values) {
210 feature_values->clear();
211 feature_values->reserve(OBSTACLE_FEATURE_SIZE);
213 if (!feature.has_position()) {
214 ADEBUG <<
"Obstacle [" << obstacle_ptr->
id() <<
"] has no position.";
217 std::pair<double, double> obs_curr_pos =
220 bool has_history =
false;
221 std::vector<std::pair<double, double>> pos_history(
222 FLAGS_junction_historical_frame_length, std::make_pair(0.0, 0.0));
224 if (obstacle_ptr->
history_size() > FLAGS_junction_historical_frame_length) {
226 for (std::size_t i = 0; i < FLAGS_junction_historical_frame_length; ++i) {
227 const Feature& feature = obstacle_ptr->
feature(i + 1);
228 if (!feature.IsInitialized()) {
232 if (feature.has_position()) {
234 std::make_pair(feature.position().x(), feature.position().y()),
235 obs_curr_pos, obs_curr_heading);
240 feature_values->push_back(feature.speed());
241 feature_values->push_back(feature.acc());
242 feature_values->push_back(feature.junction_feature().junction_range());
244 feature_values->push_back(1.0);
246 feature_values->push_back(0.0);
248 for (std::size_t i = 0; i < FLAGS_junction_historical_frame_length; i++) {
249 feature_values->push_back(pos_history[i].first);
250 feature_values->push_back(pos_history[i].second);
254void JunctionMLPEvaluator::SetEgoVehicleFeatureValues(
255 Obstacle* obstacle_ptr, ObstaclesContainer* obstacles_container,
256 std::vector<double>*
const feature_values) {
257 feature_values->clear();
258 *feature_values = std::vector<double>(4, 0.0);
259 auto ego_pose_obstacle_ptr =
260 obstacles_container->GetObstacle(FLAGS_ego_vehicle_id);
261 if (ego_pose_obstacle_ptr ==
nullptr ||
262 ego_pose_obstacle_ptr->history_size() == 0) {
263 (*feature_values)[0] = 100.0;
264 (*feature_values)[1] = 100.0;
267 const auto ego_position = ego_pose_obstacle_ptr->latest_feature().position();
268 const auto ego_velocity = ego_pose_obstacle_ptr->latest_feature().velocity();
269 CHECK_GT(obstacle_ptr->history_size(), 0U);
270 const Feature& obstacle_feature = obstacle_ptr->latest_feature();
272 ego_position.x() - obstacle_feature.position().x(),
273 ego_position.y() - obstacle_feature.position().y());
276 ego_relative_velocity.rotate(-obstacle_feature.velocity_heading());
277 (*feature_values)[0] = ego_relative_position.x();
278 (*feature_values)[1] = ego_relative_position.y();
279 (*feature_values)[2] = ego_relative_velocity.x();
280 (*feature_values)[3] = ego_relative_velocity.y();
281 ADEBUG <<
"ego relative pos = {" << ego_relative_position.x() <<
", "
282 << ego_relative_position.y() <<
"} "
283 <<
"ego_relative_velocity = {" << ego_relative_velocity.x() <<
", "
284 << ego_relative_velocity.y() <<
"}";
287void JunctionMLPEvaluator::SetJunctionFeatureValues(
288 Obstacle* obstacle_ptr, std::vector<double>* feature_values) {
289 feature_values->clear();
290 feature_values->reserve(JUNCTION_FEATURE_SIZE);
291 Feature* feature_ptr = obstacle_ptr->mutable_latest_feature();
292 if (!feature_ptr->has_position()) {
293 ADEBUG <<
"Obstacle [" << obstacle_ptr->id() <<
"] has no position.";
296 double heading = std::atan2(feature_ptr->raw_velocity().y(),
297 feature_ptr->raw_velocity().x());
298 if (!feature_ptr->has_junction_feature()) {
299 AERROR <<
"Obstacle [" << obstacle_ptr->id()
300 <<
"] has no junction_feature.";
303 std::string junction_id = feature_ptr->junction_feature().junction_id();
304 double junction_range = feature_ptr->junction_feature().junction_range();
305 for (
int i = 0; i < 12; ++i) {
306 feature_values->push_back(0.0);
307 feature_values->push_back(0.0);
308 feature_values->push_back(0.0);
309 feature_values->push_back(1.0);
310 feature_values->push_back(1.0);
311 feature_values->push_back(1.0);
312 feature_values->push_back(0.0);
313 feature_values->push_back(0.0);
315 int num_junction_exit = feature_ptr->junction_feature().junction_exit_size();
316 for (
int i = 0; i < num_junction_exit; ++i) {
317 const JunctionExit& junction_exit =
318 feature_ptr->junction_feature().junction_exit(i);
319 double x = junction_exit.exit_position().x() - feature_ptr->position().x();
320 double y = junction_exit.exit_position().y() - feature_ptr->position().y();
321 double diff_x = std::cos(-heading) * x - std::sin(-heading) * y;
322 double diff_y = std::sin(-heading) * x + std::cos(-heading) * y;
323 double diff_heading =
325 double angle = std::atan2(diff_y, diff_x);
326 double d_idx = (angle / (2.0 * M_PI) + 1.0 / 24.0) * 12.0;
327 int idx =
static_cast<int>(floor(d_idx >= 0 ? d_idx : d_idx + 12));
328 double speed = std::max(0.1, feature_ptr->speed());
329 double exit_time = std::hypot(diff_x, diff_y) / speed;
330 std::array<double, 2> start_x = {0, speed};
331 std::array<double, 2> end_x = {diff_x, std::cos(diff_heading) * speed};
332 std::array<double, 2> start_y = {0, 0};
333 std::array<double, 2> end_y = {diff_y, std::sin(diff_heading) * speed};
334 std::array<double, 4> x_coeffs =
335 ComputePolynomial<3>(start_x, end_x, exit_time);
336 std::array<double, 4> y_coeffs =
337 ComputePolynomial<3>(start_y, end_y, exit_time);
340 while (t <= exit_time) {
346 cost = std::max(cost,
347 std::abs(x_1 * y_2 - y_1 * x_2) / std::hypot(x_1, y_1));
348 t += FLAGS_prediction_trajectory_time_resolution;
350 feature_values->operator[](idx * 8) = 1.0;
351 feature_values->operator[](idx * 8 + 1) = diff_x / junction_range;
352 feature_values->operator[](idx * 8 + 2) = diff_y / junction_range;
353 feature_values->operator[](idx * 8 + 3) =
354 std::sqrt(diff_x * diff_x + diff_y * diff_y) / junction_range;
355 feature_values->operator[](idx * 8 + 4) = diff_x;
356 feature_values->operator[](idx * 8 + 5) = diff_y;
357 feature_values->operator[](idx * 8 + 6) = diff_heading;
358 feature_values->operator[](idx * 8 + 7) = cost;
362void JunctionMLPEvaluator::LoadModel() {
363 if (FLAGS_use_cuda && torch::cuda::is_available()) {
364 ADEBUG <<
"CUDA is available";
365 device_ = torch::Device(torch::kCUDA);
367 torch::set_num_threads(1);
369 torch::jit::load(FLAGS_torch_vehicle_junction_mlp_file, device_);
371 std::vector<torch::jit::IValue> torch_inputs;
372 int input_dim =
static_cast<int>(
373 OBSTACLE_FEATURE_SIZE + EGO_VEHICLE_FEATURE_SIZE + JUNCTION_FEATURE_SIZE);
374 torch::Tensor torch_input = torch::randn({1, input_dim});
375 torch_inputs.push_back(std::move(torch_input.to(device_)));
378 WarmUp(torch_inputs, &torch_model_,
nullptr);
Implements a class of 2-dimensional vectors.
std::pair< double, double > WorldCoordToObjCoord(std::pair< double, double > input_world_coord, std::pair< double, double > obj_world_coord, double obj_world_angle)
ObstacleConf::EvaluatorType evaluator_type_
static void InsertDataForLearning(const Feature &feature, const std::vector< double > &feature_values, const std::string &category, const LaneSequence *lane_sequence_ptr)
Insert a data_for_learning
bool Evaluate(Obstacle *obstacle_ptr, ObstaclesContainer *obstacles_container) override
Override Evaluate
void ExtractFeatureValues(Obstacle *obstacle_ptr, ObstaclesContainer *obstacles_container, std::vector< double > *feature_values)
Extract feature vector
JunctionMLPEvaluator()
Constructor
void Clear()
Clear obstacle feature map
Feature * mutable_latest_feature()
Get a pointer to the latest feature.
int id() const
Get the obstacle's ID.
size_t history_size() const
Get the number of historical features.
const Feature & feature(const size_t i) const
Get the ith feature from latest to earliest.
void SetEvaluatorType(const ObstacleConf::EvaluatorType &evaluator_type)
const Feature & latest_feature() const
Get the latest feature.
static const int kDumpDataForLearning
Use container manager to manage all containers
double AngleDiff(const double from, const double to)
Calculate the difference between angle from and to
double EvaluateCubicPolynomial(const std::array< double, 4 > &coefs, const double t, const uint32_t order, const double end_t, const double end_v)
Evaluate cubic polynomial.
std::array< double, 2 *N - 2 > ComputePolynomial(const std::array< double, N - 1 > &start_state, const std::array< double, N - 1 > &end_state, const double param)
void WarmUp(const std::vector< torch::jit::IValue > &torch_inputs, torch::jit::script::Module *model, at::Tensor *default_output_ptr)
warm up function to avoid slowly inference of torch model
double ComputeMean(const std::vector< double > &nums, size_t start, size_t end)
Holds all global constants for the prediction module.
optional double velocity_heading
optional JunctionFeature junction_feature
optional apollo::common::Point3D raw_velocity
optional apollo::common::Point3D position
repeated JunctionExit junction_exit
repeated LaneSequence lane_sequence
repeated LaneSegment lane_segment
warm-up function for torch model to avoid first multiple slowly inference