Apollo 11.0
自动驾驶开放平台
pointwise_unet.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2023 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 "cyber/common/file.h"
24
25namespace apollo {
26namespace perception {
27namespace lidar {
28
30
32 std::string config_file = GetConfigFile(options.config_path, options.config_file);
33 ACHECK(apollo::cyber::common::GetProtoFromFile(config_file, &model_param_));
34 AINFO << "PointWise unet Configs: " << model_param_.DebugString();
35 // gpu
36 use_gpu_ = model_param_.use_gpu();
37
38 // Unet params
39 auto unet_params = model_param_.unet_params();
40 resolution_ = unet_params.resolution();
41 unet_width_ = unet_params.unet_width();
42 unet_length_ = unet_params.unet_length();
43 min_height_ = unet_params.min_height();
44 max_height_ = unet_params.max_height();
45 min_x_ = unet_params.min_x();
46 max_x_ = unet_params.max_x();
47 min_y_ = unet_params.min_y();
48 max_y_ = unet_params.max_y();
49 z_offset_ = model_param_.z_offset();
50 max_point_number_ = unet_params.max_point_number();
51
52 // unet nodes init
53 unet_nodes_.clear();
54 unet_nodes_.resize(unet_width_ * unet_length_);
55
56 // Init model
57 if (!InitModel()) {
58 AERROR << "Init model error.";
59 return false;
60 }
61 // create cuda stream
62 cudaStreamCreate(&stream_);
63
64 // semantic class mapping
65 motion_class_mapping_.push_back(static_cast<uint8_t>(PointMotionLabel::STATIONARY));
66 motion_class_mapping_.push_back(static_cast<uint8_t>(PointMotionLabel::STATIONARY));
67 motion_class_mapping_.push_back(static_cast<uint8_t>(PointMotionLabel::MOVING));
68 motion_class_mapping_.push_back(static_cast<uint8_t>(PointMotionLabel::UNKNOWN));
69 CHECK_EQ(motion_class_mapping_.size(), 4) << "class num and motion map size not match";
70
71 return true;
72}
73
75 // check input
76 if (frame == nullptr) {
77 AERROR << "Input null frame ptr.";
78 return false;
79 }
80 if (frame->cloud == nullptr || frame->world_cloud == nullptr) {
81 AERROR << "Input null frame cloud.";
82 return false;
83 }
84 if (frame->cloud->size() == 0 || frame->world_cloud->size() == 0) {
85 AERROR << "Input none points.";
86 return false;
87 }
88
89 // record input cloud and lidar frame
90 original_cloud_ = frame->cloud;
91 original_world_cloud_ = frame->world_cloud;
92 double timestamp = frame->timestamp;
93
94 while (!prev_world_clouds_.empty()
95 && timestamp - prev_world_clouds_.front().first > model_param_.fuse_time_interval()) {
96 prev_world_clouds_.pop_front();
97 }
98
99 // check cached pointcloud
100 if (prev_world_clouds_.size() == 0) {
101 AINFO << "No cached point cloud available, skip.";
102 prev_world_clouds_.push_back(std::make_pair(timestamp, frame->world_cloud));
103 return false;
104 }
105
106 if (cudaSetDevice(model_param_.preprocess().gpu_id()) != cudaSuccess) {
107 AERROR << "Failed to set device to " << model_param_.preprocess().gpu_id();
108 return false;
109 }
110
111 lidar_frame_ref_ = frame;
112 base::PointFCloudPtr prev_cloud(new base::PointFCloud());
113 TransformCloud(prev_cloud, prev_world_clouds_.front().second);
114
115 Timer timer;
116
117 GeneratePfnFeature(prev_cloud);
118 pfn_inference_->Infer();
119 GenerateBackboneFeature(prev_bev_feature_);
120 double prev_pfn_feature_time = timer.toc(true);
121
122 GeneratePfnFeature(original_cloud_);
123 pfn_inference_->Infer();
124 GenerateBackboneFeature(bev_feature_);
125 double cur_pfn_feature_time = timer.toc(true);
126
127 seg_pred_blob_->Reshape({max_point_number_, 4});
128 inference_->Infer();
129 double backbone_infer_time = timer.toc(true);
130
131 LabelToPointCloud(frame);
132 double label_pointcloud_time = timer.toc(true);
133
134 AINFO << "MotionNet time: "
135 << "previous pfn feature time: " << prev_pfn_feature_time << "ms, "
136 << "current pfn feature time: " << cur_pfn_feature_time << "ms, "
137 << "backbone infer time: " << backbone_infer_time << "ms, "
138 << "pointcloud label time: " << label_pointcloud_time << "ms.";
139
140 prev_world_clouds_.push_back(std::make_pair(timestamp, frame->world_cloud));
141
142 return true;
143}
144
145bool MotionUnet::InitModel() {
146 // fpn name:blob maps
147 std::map<std::string, std::vector<int>> pfn_blob_maps;
148 // pfn model
149 auto pfn_info = model_param_.pfn_info();
150 auto preprocess = model_param_.preprocess();
151
152 // pfn model file
153 std::string model_path = GetModelPath(pfn_info.name());
154 std::string pfn_proto_file = GetModelFile(model_path, pfn_info.proto_file().file());
155 std::vector<std::string> pfn_input_names = inference::GetBlobNames(pfn_info.inputs());
156 std::vector<std::string> pfn_output_names = inference::GetBlobNames(pfn_info.outputs());
158 "apollo::perception::inference::" + pfn_info.infer_plugin());
159 pfn_inference_->set_model_info(pfn_proto_file, pfn_input_names, pfn_output_names);
160 pfn_inference_->set_gpu_id(preprocess.gpu_id());
161 pfn_inference_->set_max_batch_size(max_point_number_ * 2);
162
163 inference::AddShape(&pfn_blob_maps, pfn_info.inputs());
164 inference::AddShape(&pfn_blob_maps, pfn_info.outputs());
165
166 pfn_inference_->Init(pfn_blob_maps);
167 // init pfn input blob
168 if (pfn_input_names.size() == 1) {
169 voxels_ = pfn_inference_->get_blob(pfn_input_names.at(0));
170 CHECK_NOTNULL(voxels_.get());
171 } else {
172 AERROR << "Init pfn_inferece input blob error.";
173 return false;
174 }
175 // init pfn output blobs
176 if (pfn_output_names.size() == 1) {
177 pfn_point_feats_ = pfn_inference_->get_blob(pfn_output_names.at(0));
178 CHECK_NOTNULL(pfn_point_feats_.get());
179 } else {
180 AERROR << "Init pfn_inferece output blob error.";
181 return false;
182 }
183 AINFO << "Init pointwise unet pfn model success.";
184
185 // backbone name:blob maps
186 std::map<std::string, std::vector<int>> blob_maps;
187 // backbone info
188 auto info = model_param_.info();
189 // backbone model file
190 std::string proto_file = GetModelFile(model_path, info.proto_file().file());
191 std::vector<std::string> input_names = inference::GetBlobNames(info.inputs());
192 std::vector<std::string> output_names = inference::GetBlobNames(info.outputs());
194 "apollo::perception::inference::" + info.infer_plugin());
195 inference_->set_model_info(proto_file, input_names, output_names);
196 inference_->set_gpu_id(preprocess.gpu_id());
197 inference_->set_max_batch_size(max_point_number_ * 2);
198
199 inference::AddShape(&blob_maps, info.inputs());
200 inference::AddShape(&blob_maps, info.outputs());
201
202 inference_->Init(blob_maps);
203 // init backbone input blobs
204 // Caution: the order of input-names between pointwise_unet.h
205 // and pointwise_unet_param.pb.txt should be the same.
206 if (input_names.size() == 4) {
207 coors_ = inference_->get_blob(input_names.at(0));
208 point_feats_ = inference_->get_blob(input_names.at(1));
209 bev_feature_ = inference_->get_blob(input_names.at(2));
210 prev_bev_feature_ = inference_->get_blob(input_names.at(3));
211
212 CHECK_NOTNULL(coors_.get());
213 CHECK_NOTNULL(point_feats_.get());
214 CHECK_NOTNULL(bev_feature_.get());
215 CHECK_NOTNULL(prev_bev_feature_.get());
216 } else {
217 AERROR << "Init inferece input blobs error.";
218 return false;
219 }
220 // init output blob
221 if (output_names.size() == 1) {
222 seg_pred_blob_ = inference_->get_blob(output_names.at(0));
223 CHECK_NOTNULL(seg_pred_blob_.get());
224 } else {
225 AERROR << "Init inferece output blobs error.";
226 return false;
227 }
228 AINFO << "Init pointwise unet backbone model success.";
229
230 return true;
231}
232
233
234void MotionUnet::GeneratePfnFeatureCPU(base::PointFCloudPtr cloud) {
235 // clear unet nodes
236 unet_nodes_.clear();
237 std::vector<Unode>().swap(unet_nodes_);
238 unet_nodes_.resize(unet_width_ * unet_length_);
239
240 // valid point index
241 valid_point_index_.clear();
242 valid_point_index_.reserve(cloud->size());
243
244 // valid node of unet
245 valid_node_index_.clear();
246 valid_node_index_.reserve(unet_width_ * unet_length_);
247
248 // generate pfn model feature
249 for (size_t i = 0; i < cloud->size(); i++) {
250 auto pt = cloud->at(i);
251 // check valid range
252 if (pt.x < min_x_ || pt.x > max_x_ || pt.y < min_y_ || pt.y > max_y_ || pt.z + z_offset_ < min_height_
253 || pt.z + z_offset_ > max_height_) {
254 continue;
255 }
256 // get coordinate of pointcloud bev
257 int grid_x = (pt.x - min_x_) / resolution_;
258 int grid_y = (pt.y - min_y_) / resolution_;
259 if (grid_x >= 0 && grid_x < unet_width_ && grid_y >= 0 && grid_y < unet_length_) {
260 // unet bev grid_x and grid_y
261 int pillar_idx = grid_y * unet_length_ + grid_x;
262 // valid point index
263 valid_point_index_.push_back(i);
264 // valid node index
265 valid_node_index_.push_back(pillar_idx);
266
267 // unet bev node
268 // gravity center
269 unet_nodes_.at(pillar_idx).sum_x += pt.x;
270 unet_nodes_.at(pillar_idx).sum_y += pt.y;
271 unet_nodes_.at(pillar_idx).sum_z += pt.z;
272 if (unet_nodes_.at(pillar_idx).point_size == 0) {
273 // geometric center
274 unet_nodes_.at(pillar_idx).geometric_x
275 = static_cast<float>(grid_x) * resolution_ + 0.5 * resolution_ + min_x_;
276 unet_nodes_.at(pillar_idx).geometric_y
277 = static_cast<float>(grid_y) * resolution_ + 0.5 * resolution_ + min_y_;
278 unet_nodes_.at(pillar_idx).geometric_z = 0;
279 // grid coordinate
280 unet_nodes_.at(pillar_idx).grid_x = grid_x;
281 unet_nodes_.at(pillar_idx).grid_y = grid_y;
282 }
283 unet_nodes_.at(pillar_idx).point_size += 1;
284
285 // max point number
286 if (static_cast<int>(valid_point_index_.size()) >= max_point_number_) {
287 break;
288 }
289 }
290 }
291
292 // pfn input feature
293 voxels_->Reshape({valid_point_index_.size(), 10});
294 auto voxel_cpu_data = voxels_->mutable_cpu_data();
295 // output
296 pfn_point_feats_->Reshape({valid_point_index_.size(), 64});
297 // backbone input feature
298 coors_->Reshape({valid_point_index_.size(), 4});
299 auto coors_cpu_data = coors_->mutable_cpu_data();
300 for (size_t i = 0; i < valid_point_index_.size(); i++) {
301 auto pt = cloud->at(valid_point_index_.at(i));
302 Unode node = unet_nodes_.at(valid_node_index_.at(i));
303 // generate voxels feature
304 voxel_cpu_data[i * 10 + 0] = pt.x;
305 voxel_cpu_data[i * 10 + 1] = pt.y;
306 voxel_cpu_data[i * 10 + 2] = pt.z + z_offset_;
307 voxel_cpu_data[i * 10 + 3] = pt.intensity / 255.;
308 voxel_cpu_data[i * 10 + 4] = pt.x - node.sum_x / (node.point_size + 1e-6);
309 voxel_cpu_data[i * 10 + 5] = pt.y - node.sum_y / (node.point_size + 1e-6);
310 voxel_cpu_data[i * 10 + 6] = pt.z - node.sum_z / (node.point_size + 1e-6);
311 voxel_cpu_data[i * 10 + 7] = pt.x - node.geometric_x;
312 voxel_cpu_data[i * 10 + 8] = pt.y - node.geometric_y;
313 voxel_cpu_data[i * 10 + 9] = pt.z + z_offset_ - node.geometric_z;
314
315 // generate coors feauture
316 coors_cpu_data[i * 4 + 0] = 0;
317 coors_cpu_data[i * 4 + 1] = 0;
318 coors_cpu_data[i * 4 + 2] = node.grid_y;
319 coors_cpu_data[i * 4 + 3] = node.grid_x;
320 }
321}
322
323void MotionUnet::GenerateBackboneFeatureCPU(std::shared_ptr<base::Blob<float>> feature) {
324 // generate point_feats feature
325 point_feats_->Reshape(pfn_point_feats_->shape());
326 point_feats_->set_gpu_data(pfn_point_feats_->mutable_gpu_data());
327
328 // get pfn model output
329 auto point_feats_cpu = pfn_point_feats_->mutable_cpu_data();
330
331 // generate voxel_features_ and feature_coors_
332 feature->Reshape({1, 64, unet_length_, unet_width_});
333 auto feature_data = feature->mutable_cpu_data();
334 memset(feature_data, 0, sizeof(float) * 64 * unet_length_ * unet_width_);
335
336 for (size_t i = 0; i < valid_node_index_.size(); i++) {
337 int pillar_idx = valid_node_index_.at(i);
338 Unode node = unet_nodes_.at(pillar_idx);
339 // voxel_features_
340 for (int j = 0; j < 64; j++) {
341 int index = j * unet_length_ * unet_width_ + node.grid_y * unet_length_ + node.grid_x;
342 float value = feature_data[index];
343 float max_val = point_feats_cpu[i * 64 + j];
344 max_val = std::max(max_val, value);
345 feature_data[index] = max_val;
346 }
347 }
348}
349
350void MotionUnet::LabelToPointCloud(LidarFrame* frame) {
351 // check input
352 if (!original_cloud_ || !original_world_cloud_) {
353 AERROR << "Fail to labeling, original_cloud_ or original_world_cloud_ is empty !";
354 return;
355 }
356
357 auto sematic_result = seg_pred_blob_->mutable_cpu_data();
358 for (size_t i = 0; i < valid_point_index_.size(); i++) {
359 int max_index = 0;
360 float max_prob = std::numeric_limits<float>::min();
361 for (int n = 0; n < 4; n++) {
362 float prob = sematic_result[i * 4 + n];
363 if (max_prob < prob) {
364 max_prob = prob;
365 max_index = n;
366 }
367 }
368 int point_index = valid_point_index_.at(i);
370 static_cast<PointMotionLabel>(motion_class_mapping_[max_index]),
371 &original_cloud_->points_semantic_label(point_index));
373 static_cast<PointMotionLabel>(motion_class_mapping_[max_index]),
374 &original_world_cloud_->points_semantic_label(point_index));
375 }
376}
377
378void MotionUnet::TransformCloud(
379 base::PointFCloudPtr &cloud_ptr,
380 const base::PointDCloudPtr &world_cloud_ptr) {
381 cloud_ptr->clear();
382 cloud_ptr->reserve(world_cloud_ptr->size());
383 for (size_t i = 0; i < world_cloud_ptr->size(); ++i) {
384 auto &point = world_cloud_ptr->at(i);
385 Eigen::Vector3d trans_point(point.x, point.y, point.z);
386 trans_point = lidar_frame_ref_->lidar2world_pose.inverse() * trans_point;
387 base::PointF pt;
388 pt.x = static_cast<float>(trans_point(0));
389 pt.y = static_cast<float>(trans_point(1));
390 pt.z = static_cast<float>(trans_point(2));
391 pt.intensity = static_cast<float>(point.intensity);
392 cloud_ptr->push_back(pt);
393 }
394 }
395
397
398} // namespace lidar
399} // namespace perception
400} // namespace apollo
#define PERCEPTION_REGISTER_POINTCLOUDPARSER(name)
static PluginManager * Instance()
get singleton instance of PluginManager
std::shared_ptr< Base > CreateInstance(const std::string &derived_class)
create plugin instance of derived class based on Base
bool Parse(const PointCloudParserOptions &options, LidarFrame *frame)
Detect foreground objects
bool Init(const PointCloudParserInitOptions &options=PointCloudParserInitOptions())
Init the Base PointCloud Parser object
double toc(bool reset=false)
Definition lidar_timer.h:28
#define ACHECK(cond)
Definition log.h:80
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
bool GetProtoFromFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as a representation of protobufs,...
Definition file.cc:132
Point< float > PointF
Definition point.h:56
std::shared_ptr< PointDCloud > PointDCloudPtr
std::shared_ptr< PointFCloud > PointFCloudPtr
std::vector< std::string > GetBlobNames(const google::protobuf::RepeatedPtrField< common::ModelBlob > &model_blobs)
Definition model_util.cc:23
void AddShape(std::map< std::string, std::vector< int > > *shape_map, const google::protobuf::RepeatedPtrField< common::ModelBlob > &model_blobs)
Definition model_util.cc:32
void SetMotionLabel(PointMotionLabel label, uint8_t *value)
std::string GetModelFile(const std::string &model_name, const std::string &file_name)
Get the model file path by model path and file name
Definition util.cc:55
std::string GetConfigFile(const std::string &config_path, const std::string &config_file)
Definition util.cc:80
std::string GetModelPath(const std::string &model_name)
Get the model path by model name, search from APOLLO_MODEL_PATH
Definition util.cc:44
class register implement
Definition arena_queue.h:37
std::shared_ptr< base::AttributePointCloud< base::PointD > > world_cloud
Definition lidar_frame.h:37
std::shared_ptr< base::AttributePointCloud< base::PointF > > cloud
Definition lidar_frame.h:35