Apollo 10.0
自动驾驶开放平台
junction_mlp_evaluator.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include <algorithm>
20#include <unordered_map>
21#include <utility>
22
23#include <omp.h>
24
25#include "cyber/common/file.h"
26#include "modules/common/adapters/proto/adapter_config.pb.h"
37
38namespace apollo {
39namespace prediction {
40
43
44namespace {
45
46double ComputeMean(const std::vector<double>& nums, size_t start, size_t end) {
47 int count = 0;
48 double sum = 0.0;
49 for (size_t i = start; i <= end && i < nums.size(); i++) {
50 sum += nums[i];
51 ++count;
52 }
53 return (count == 0) ? 0.0 : sum / count;
54}
55
56} // namespace
57
62
64
66 ObstaclesContainer* obstacles_container) {
67 // Sanity checks.
68 omp_set_num_threads(1);
69 Clear();
70 CHECK_NOTNULL(obstacle_ptr);
71
72 obstacle_ptr->SetEvaluatorType(evaluator_type_);
73
74 int id = obstacle_ptr->id();
75 if (!obstacle_ptr->latest_feature().IsInitialized()) {
76 AERROR << "Obstacle [" << id << "] has no latest feature.";
77 return false;
78 }
79 Feature* latest_feature_ptr = obstacle_ptr->mutable_latest_feature();
80 CHECK_NOTNULL(latest_feature_ptr);
81
82 // Assume obstacle is NOT closed to any junction exit
83 if (!latest_feature_ptr->has_junction_feature() ||
84 latest_feature_ptr->junction_feature().junction_exit_size() < 1) {
85 ADEBUG << "Obstacle [" << id << "] has no junction_exit.";
86 return false;
87 }
88
89 std::vector<double> feature_values;
90 ExtractFeatureValues(obstacle_ptr, obstacles_container, &feature_values);
91
92 // Insert features to DataForLearning
93 if (FLAGS_prediction_offline_mode ==
95 FeatureOutput::InsertDataForLearning(*latest_feature_ptr, feature_values,
96 "junction", nullptr);
97 ADEBUG << "Save extracted features for learning locally.";
98 return true; // Skip Compute probability for offline mode
99 }
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]);
106 }
107 torch_inputs.push_back(std::move(torch_input.to(device_)));
108 std::vector<double> probability;
109 if (latest_feature_ptr->junction_feature().junction_exit_size() > 1) {
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]));
115 }
116 } else {
117 for (int i = 0; i < 12; ++i) {
118 probability.push_back(feature_values[OBSTACLE_FEATURE_SIZE +
119 EGO_VEHICLE_FEATURE_SIZE + 8 * i]);
120 }
121 }
122 for (double prob : probability) {
123 latest_feature_ptr->mutable_junction_feature()
124 ->add_junction_mlp_probability(prob);
125 }
126 // assign all lane_sequence probability
127 LaneGraph* lane_graph_ptr =
128 latest_feature_ptr->mutable_lane()->mutable_lane_graph();
129 CHECK_NOTNULL(lane_graph_ptr);
130 if (lane_graph_ptr->lane_sequence().empty()) {
131 AERROR << "Obstacle [" << id << "] has no lane sequences.";
132 return false;
133 }
134
135 std::unordered_map<std::string, double> junction_exit_prob;
136 for (const JunctionExit& junction_exit :
137 latest_feature_ptr->junction_feature().junction_exit()) {
138 double x =
139 junction_exit.exit_position().x() - latest_feature_ptr->position().x();
140 double y =
141 junction_exit.exit_position().y() - latest_feature_ptr->position().y();
142 double angle =
143 std::atan2(y, x) - std::atan2(latest_feature_ptr->raw_velocity().y(),
144 latest_feature_ptr->raw_velocity().x());
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];
148 }
149
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);
153 for (const LaneSegment& lane_segment : lane_sequence_ptr->lane_segment()) {
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()]);
158 }
159 }
160 }
161 return true;
162}
163
165 Obstacle* obstacle_ptr, ObstaclesContainer* obstacles_container,
166 std::vector<double>* feature_values) {
167 CHECK_NOTNULL(obstacle_ptr);
168 int id = obstacle_ptr->id();
169
170 std::vector<double> obstacle_feature_values;
171 SetObstacleFeatureValues(obstacle_ptr, &obstacle_feature_values);
172
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() << ".";
177 return;
178 }
179
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() << ".";
187 return;
188 }
189
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() << ".";
196 return;
197 }
198
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());
206}
207
208void JunctionMLPEvaluator::SetObstacleFeatureValues(
209 Obstacle* obstacle_ptr, std::vector<double>* feature_values) {
210 feature_values->clear();
211 feature_values->reserve(OBSTACLE_FEATURE_SIZE);
212 const Feature& feature = obstacle_ptr->latest_feature();
213 if (!feature.has_position()) {
214 ADEBUG << "Obstacle [" << obstacle_ptr->id() << "] has no position.";
215 return;
216 }
217 std::pair<double, double> obs_curr_pos =
218 std::make_pair(feature.position().x(), feature.position().y());
219 double obs_curr_heading = feature.velocity_heading();
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));
223
224 if (obstacle_ptr->history_size() > FLAGS_junction_historical_frame_length) {
225 has_history = true;
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()) {
229 has_history = false;
230 break;
231 }
232 if (feature.has_position()) {
233 pos_history[i] = WorldCoordToObjCoord(
234 std::make_pair(feature.position().x(), feature.position().y()),
235 obs_curr_pos, obs_curr_heading);
236 }
237 }
238 }
239
240 feature_values->push_back(feature.speed());
241 feature_values->push_back(feature.acc());
242 feature_values->push_back(feature.junction_feature().junction_range());
243 if (has_history) {
244 feature_values->push_back(1.0);
245 } else {
246 feature_values->push_back(0.0);
247 }
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);
251 }
252}
253
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;
265 return;
266 }
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();
271 apollo::common::math::Vec2d ego_relative_position(
272 ego_position.x() - obstacle_feature.position().x(),
273 ego_position.y() - obstacle_feature.position().y());
274 apollo::common::math::Vec2d ego_relative_velocity(ego_velocity.x(),
275 ego_velocity.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() << "}";
285}
286
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.";
294 return;
295 }
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.";
301 return;
302 }
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);
314 }
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 =
324 apollo::common::math::AngleDiff(heading, junction_exit.exit_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);
338 double t = 0.0;
339 double cost = 0.0;
340 while (t <= exit_time) {
341 double x_1 = EvaluateCubicPolynomial(x_coeffs, t, 1);
342 double x_2 = EvaluateCubicPolynomial(x_coeffs, t, 2);
343 double y_1 = EvaluateCubicPolynomial(y_coeffs, t, 1);
344 double y_2 = EvaluateCubicPolynomial(y_coeffs, t, 2);
345 // cost = curvature * v^2
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;
349 }
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;
359 }
360}
361
362void JunctionMLPEvaluator::LoadModel() {
363 if (FLAGS_use_cuda && torch::cuda::is_available()) {
364 ADEBUG << "CUDA is available";
365 device_ = torch::Device(torch::kCUDA);
366 }
367 torch::set_num_threads(1);
368 torch_model_ =
369 torch::jit::load(FLAGS_torch_vehicle_junction_mlp_file, device_);
370
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_)));
376
377 // warm up to avoid very slow first inference later
378 WarmUp(torch_inputs, &torch_model_, nullptr);
379}
380
381} // namespace prediction
382} // namespace apollo
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
std::pair< double, double > WorldCoordToObjCoord(std::pair< double, double > input_world_coord, std::pair< double, double > obj_world_coord, double obj_world_angle)
Definition evaluator.h:94
ObstacleConf::EvaluatorType evaluator_type_
Definition evaluator.h:156
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
Prediction obstacle.
Definition obstacle.h:52
Feature * mutable_latest_feature()
Get a pointer to the latest feature.
Definition obstacle.cc:88
int id() const
Get the obstacle's ID.
Definition obstacle.cc:60
size_t history_size() const
Get the number of historical features.
Definition obstacle.cc:93
const Feature & feature(const size_t i) const
Get the ith feature from latest to earliest.
Definition obstacle.cc:67
void SetEvaluatorType(const ObstacleConf::EvaluatorType &evaluator_type)
Definition obstacle.cc:1484
const Feature & latest_feature() const
Get the latest feature.
Definition obstacle.cc:78
Use container manager to manage all containers
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
double AngleDiff(const double from, const double to)
Calculate the difference between angle from and to
Definition math_utils.cc:61
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
Definition warm_up.cc:28
double ComputeMean(const std::vector< double > &nums, size_t start, size_t end)
class register implement
Definition arena_queue.h:37
Obstacles container
Holds all global constants for the prediction module.
optional double velocity_heading
Definition feature.proto:93
optional JunctionFeature junction_feature
optional apollo::common::Point3D raw_velocity
Definition feature.proto:91
optional apollo::common::Point3D position
Definition feature.proto:88
repeated JunctionExit junction_exit
Definition feature.proto:53
repeated LaneSequence lane_sequence
repeated LaneSegment lane_segment
Defines the Vec2d class.
warm-up function for torch model to avoid first multiple slowly inference