本文的想法来自于https://github.com/open-mmlab/OpenPCDet/issues/771该讨论区下155cannon大佬的想法,但是在训练的最后一步一直出错,希望有大佬可以指点一下,或者遇到同样的问题可以帮助一下,在下不胜感激。
根据自己采集的PCD点云,使用cloudcompare里面的cross section功能,把目标物体的检测框标注出来,在属性栏获取他的中心点坐标和长宽高。
点云文件0000.pcd
标签文件0000.txt 每行x, y, z, dx, dy, dz就是上面说的那6个值,按顺序放,heading统一设为1.57,也就是90°。
先自己创建一个my_dataset.py,此文件和kitti_dataset.py放在同一目录下。
import glob
import numpy as np
from pathlib import Path
from ..dataset import DatasetTemplate
class MyDataset(DatasetTemplate):
def __init__(self,dataset_cfg,class_names,training=True,root_path=None,logger=None):
"""
Args:
root_path:
dataset_cfg:
class_names:
training:
logger:
"""
super().__init__(dataset_cfg=dataset_cfg,class_names=class_names,training=training,root_path=root_path,logger=logger)
point_file_list=glob.glob(str(self.root_path/'training/points/*.bin'))
labels_file_list=glob.glob(str(self.root_path/'training/labels/*.txt'))
point_file_list.sort()
labels_file_list.sort()
self.sample_file_list=point_file_list
self.samplelabel_file_list=labels_file_list
def __len__(self):
return len(self.sample_file_list)
def __getitem__(self, index):
#stem返回的不是整个路径,而是文件名
sample_idx=Path(self.sample_file_list[index]).stem
points=np.fromfile(self.sample_file_list[index],dtype=np.float32).reshape(-1,4)[:,:3]
#在加载点云和标签的同时,将坐标转换成统一坐标系下
points=points[:,[2,0,1]]
points[:,0]=-points[:,0]
points[:,1]=-points[:,1]
points_label=np.loadtxt(self.samplelabel_file_list[index],dtype=np.float32).reshape(-1,7)
points_label=points_label[:,[2,0,1,5,3,4,6]]
gt_names=np.array(['cylinder']*points_label.shape[0])
input_dict={
'points':points,
'frame_id':sample_idx,
'gt_names':gt_names,
'gt_boxes':points_label
}
data_dict = self.prepare_data(data_dict=input_dict)
return data_dict
创建一个my_dataset.yaml,此文件和kitti_dataset.yaml放在同一目录下。
DATASET: 'MyDataset'
DATA_PATH: '../data/cylinder'
POINT_CLOUD_RANGE: [0, -40, -3, 70.4, 40, 1]
DATA_SPLIT: {
'train': train,
'test': val
}
INFO_PATH: {
'train': [kitti_infos_train.pkl],
'test': [kitti_infos_val.pkl],
}
GET_ITEM_LIST: ["points"]
FOV_POINTS_ONLY: True
DATA_AUGMENTOR:
DISABLE_AUG_LIST: ['placeholder']
AUG_CONFIG_LIST:
- NAME: random_world_flip
ALONG_AXIS_LIST: ['x']
- NAME: random_world_rotation
WORLD_ROT_ANGLE: [-0.78539816, 0.78539816]
- NAME: random_world_scaling
WORLD_SCALE_RANGE: [0.95, 1.05]
POINT_FEATURE_ENCODING: {
encoding_type: absolute_coordinates_encoding,
used_feature_list: ['x', 'y', 'z'],
src_feature_list: ['x', 'y', 'z'],
}
DATA_PROCESSOR:
- NAME: mask_points_and_boxes_outside_range
REMOVE_OUTSIDE_BOXES: True
- NAME: shuffle_points
SHUFFLE_ENABLED: {
'train': True,
'test': False
}
- NAME: transform_points_to_voxels
VOXEL_SIZE: [0.05, 0.05, 0.1]
MAX_POINTS_PER_VOXEL: 5
MAX_NUMBER_OF_VOXELS: {
'train': 16000,
'test': 40000
}
创建pointpillar.yaml,此文件放置在tools\cfgs\cylinder_models下面,去掉了gt_sampling数据增强,需要修改POINT_CLOUD_RANGE和VOXEL_SIZE,POINT_CLOUD_RANGE就是你的点云范围,point cloud range along z-axis / voxel_size is 40,point cloud range along x,y -axis / voxel_size is the multiple of 16. 这是必须满足的设置,不然会报错。
CLASS_NAMES: ['cylinder']
DATA_CONFIG:
_BASE_CONFIG_: cfgs/dataset_configs/my_dataset.yaml
POINT_CLOUD_RANGE: [0.9, -2, -2, 3.46, 3.12, 2]
DATA_PROCESSOR:
- NAME: mask_points_and_boxes_outside_range
REMOVE_OUTSIDE_BOXES: True
- NAME: shuffle_points
SHUFFLE_ENABLED: {
'train': True,
'test': False
}
- NAME: transform_points_to_voxels
VOXEL_SIZE: [0.16, 0.16, 4]
MAX_POINTS_PER_VOXEL: 32
MAX_NUMBER_OF_VOXELS: {
'train': 16000,
'test': 40000
}
DATA_AUGMENTOR:
DISABLE_AUG_LIST: ['placeholder']
AUG_CONFIG_LIST:
- NAME: random_world_flip
ALONG_AXIS_LIST: ['x']
- NAME: random_world_rotation
WORLD_ROT_ANGLE: [-0.78539816, 0.78539816]
- NAME: random_world_scaling
WORLD_SCALE_RANGE: [0.95, 1.05]
MODEL:
NAME: PointPillar
VFE:
NAME: PillarVFE
WITH_DISTANCE: False
USE_ABSLOTE_XYZ: True
USE_NORM: True
NUM_FILTERS: [64]
MAP_TO_BEV:
NAME: PointPillarScatter
NUM_BEV_FEATURES: 64
BACKBONE_2D:
NAME: BaseBEVBackbone
LAYER_NUMS: [3, 5, 5]
LAYER_STRIDES: [2, 2, 2]
NUM_FILTERS: [64, 128, 256]
UPSAMPLE_STRIDES: [1, 2, 4]
NUM_UPSAMPLE_FILTERS: [128, 128, 128]
DENSE_HEAD:
NAME: AnchorHeadSingle
CLASS_AGNOSTIC: False
USE_DIRECTION_CLASSIFIER: True
DIR_OFFSET: 0.78539
DIR_LIMIT_OFFSET: 0.0
NUM_DIR_BINS: 2
ANCHOR_GENERATOR_CONFIG: [
{
'class_name': 'cylinder',
'anchor_sizes': [[0.05, 0.05, 0.14]],
'anchor_rotations': [0, 1.57],
'anchor_bottom_heights': [-1.78],
'align_center': False,
'feature_map_stride': 2,
'matched_threshold': 0.6,
'unmatched_threshold': 0.45
}
]
TARGET_ASSIGNER_CONFIG:
NAME: AxisAlignedTargetAssigner
POS_FRACTION: -1.0
SAMPLE_SIZE: 512
NORM_BY_NUM_EXAMPLES: False
MATCH_HEIGHT: False
BOX_CODER: ResidualCoder
LOSS_CONFIG:
LOSS_WEIGHTS: {
'cls_weight': 1.0,
'loc_weight': 2.0,
'dir_weight': 0.2,
'code_weights': [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
}
POST_PROCESSING:
RECALL_THRESH_LIST: [0.3, 0.5, 0.7]
SCORE_THRESH: 0.1
OUTPUT_RAW_SCORE: False
EVAL_METRIC: kitti
NMS_CONFIG:
MULTI_CLASSES_NMS: False
NMS_TYPE: nms_gpu
NMS_THRESH: 0.01
NMS_PRE_MAXSIZE: 4096
NMS_POST_MAXSIZE: 500
OPTIMIZATION:
BATCH_SIZE_PER_GPU: 4
NUM_EPOCHS: 80
OPTIMIZER: adam_onecycle
LR: 0.003
WEIGHT_DECAY: 0.01
MOMENTUM: 0.9
MOMS: [0.95, 0.85]
PCT_START: 0.4
DIV_FACTOR: 10
DECAY_STEP_LIST: [35, 45]
LR_DECAY: 0.1
LR_CLIP: 0.0000001
LR_WARMUP: False
WARMUP_EPOCH: 1
GRAD_NORM_CLIP: 10
在pcdet\datasets\_init_.py里面加上写的MyDataset信息:
from .kitti.my_dataset import MyDataset
all = {
'DatasetTemplate': DatasetTemplate,
'KittiDataset': KittiDataset,
'MyDataset': MyDataset,
'NuScenesDataset': NuScenesDataset,
'WaymoDataset': WaymoDataset,
'PandasetDataset': PandasetDataset,
'LyftDataset': LyftDataset
}
python train.py --cfg_file cfgs/cylinder_models/pointpillar.yaml --batch_size 1 --workers 1 --epochs 40
然后就一直报这个错误。麻了,搞了半个多月了都没解决
2022-09-30 08:57:41,568 INFO **********************Start training cylinder_models/pointpillar(default)**********************
epochs: 0%| | 0/40 [00:05
main()
File "train.py", line 171, in main
merge_all_iters_to_one_epoch=args.merge_all_iters_to_one_epoch
File "/home/wangchen/OpenPCDet/tools/train_utils/train_utils.py", line 118, in train_model
dataloader_iter=dataloader_iter
File "/home/wangchen/OpenPCDet/tools/train_utils/train_utils.py", line 25, in train_one_epoch
batch = next(dataloader_iter)
File "/home/wangchen/anaconda3/envs/pcdet/lib/python3.7/site-packages/torch/utils/data/dataloader.py", line 517, in __next__
data = self._next_data()
File "/home/wangchen/anaconda3/envs/pcdet/lib/python3.7/site-packages/torch/utils/data/dataloader.py", line 557, in _next_data
data = self._dataset_fetcher.fetch(index) # may raise StopIteration
File "/home/wangchen/anaconda3/envs/pcdet/lib/python3.7/site-packages/torch/utils/data/_utils/fetch.py", line 44, in fetch
data = [self.dataset[idx] for idx in possibly_batched_index]
File "/home/wangchen/anaconda3/envs/pcdet/lib/python3.7/site-packages/torch/utils/data/_utils/fetch.py", line 44, in
data = [self.dataset[idx] for idx in possibly_batched_index]
File "../pcdet/datasets/kitti/my_dataset.py", line 49, in __getitem__
data_dict = self.prepare_data(data_dict=input_dict)
File "../pcdet/datasets/dataset.py", line 155, in prepare_data
return self.__getitem__(new_index)
File "../pcdet/datasets/kitti/my_dataset.py", line 49, in __getitem__
data_dict = self.prepare_data(data_dict=input_dict)
。。。。。。。。。。。。。。。。。。。。。。。。中间都是重复的
File "../pcdet/datasets/kitti/my_dataset.py", line 49, in __getitem__
data_dict = self.prepare_data(data_dict=input_dict)
File "../pcdet/datasets/dataset.py", line 155, in prepare_data
return self.__getitem__(new_index)
File "../pcdet/datasets/kitti/my_dataset.py", line 49, in __getitem__
data_dict = self.prepare_data(data_dict=input_dict)
File "../pcdet/datasets/dataset.py", line 155, in prepare_data
return self.__getitem__(new_index)
File "../pcdet/datasets/dataset.py", line 155, in prepare_data
return self.__getitem__(new_index)
File "../pcdet/datasets/kitti/my_dataset.py", line 49, in __getitem__
data_dict = self.prepare_data(data_dict=input_dict)
File "../pcdet/datasets/dataset.py", line 155, in prepare_data
return self.__getitem__(new_index)
File "../pcdet/datasets/kitti/my_dataset.py", line 49, in __getitem__
data_dict = self.prepare_data(data_dict=input_dict)
File "../pcdet/datasets/dataset.py", line 155, in prepare_data
return self.__getitem__(new_index)
File "../pcdet/datasets/kitti/my_dataset.py", line 49, in __getitem__
data_dict = self.prepare_data(data_dict=input_dict)
File "../pcdet/datasets/dataset.py", line 131, in prepare_data
'gt_boxes_mask': gt_boxes_mask
File "../pcdet/datasets/augmentor/data_augmentor.py", line 240, in forward
data_dict = cur_augmentor(data_dict=data_dict)
File "../pcdet/datasets/augmentor/data_augmentor.py", line 50, in random_world_flip
gt_boxes, points,
File "../pcdet/datasets/augmentor/augmentor_utils.py", line 15, in random_flip_along_x
enable = np.random.choice([False, True], replace=False, p=[0.5, 0.5])
File "mtrand.pyx", line 978, in numpy.random.mtrand.RandomState.choice
File "mtrand.pyx", line 1179, in numpy.random.mtrand.RandomState.rand
File "mtrand.pyx", line 425, in numpy.random.mtrand.RandomState.random_sample
File "_common.pyx", line 295, in numpy.random._common.double_fill
RecursionError: maximum recursion depth exceeded while calling a Python object
在my_dataset.py里面我读取标签的时候坐标转换错了,导致一直不行,现在加了两行,终于ok了,哭了。
points=points[:,[2,0,1]]
points[:,0]=-points[:,0]
points[:,1]=-points[:,1]
points_label=np.loadtxt(self.samplelabel_file_list[index],dtype=np.float32).reshape(-1,7)
points_label=points_label[:,[2,0,1,5,3,4,6]]
points_label[:,0]=-points_label[:,0]
points_label[:,1]=-points_label[:,1]
gt_names=np.array(['cylinder']*points_label.shape[0])