Paddle3D 2 雷达点云CenterPoint模型训练
2 Paddle3D 雷达点云CenterPoint模型训练–包含KITTI格式数据地址
2.0 数据集 百度DAIR-V2X开源路侧数据转kitti格式。
2.0.1 DAIR-V2X-I\velodyne中pcd格式的数据转为bin格式
参考源码:雷达点云数据.pcd格式转.bin格式
def pcd2bin():import numpy as npimport open3d as o3dfrom tqdm import tqdmimport ospcdPath = r'E:\DAIR-V2X-I\velodyne'binPath = r'E:\DAIR-V2X-I\kitti\training\velodyne'files = os.listdir(pcdPath)files = [f for f in files if f[-4:]=='.pcd']for ic in tqdm(range(len(files)), desc='进度 '):f = files[ic]pcdname = os.path.join(pcdPath, f)binname = os.path.join(binPath, f[:-4] + '.bin')# 读取PCD文件# pcd = o3d.io.read_point_cloud("./data/002140.ply")pcd = o3d.io.read_point_cloud(pcdname)# print('==============pcd\n', pcd)# print('==============pcd.points\n', pcd.points)points = np.asarray(pcd.points)# print('==============points\n', points)# print(type(points))# print(points.shape)# 添加全0列point0 = np.zeros((points.shape[0], 1))points = np.column_stack((points,point0))# print(points.shape)# 查看点云图像# o3d.visualization.draw_geometries([pcd])# 将PCD格式保存为BIN格式,使用.tofile实现;# 理论上o3d.io.write_point_cloud也可以实现,但是运行的时候,没有报错,但也并没有保存文件points.tofile(binname)o3d.io.write_point_cloud(os.path.join(binPath, f[:-4]+'.bin'), pcd) # if ic == 1:# break
可视化查看bin文件
def visBinData():"""可视化的形式查看点云数据的Bin文件:return:"""import numpy as npfrom tqdm import tqdmimport mayavi.mlabimport osbinPath = r'D:\lidar3D\data\Lidar0\bin'# binPath = r'./data'files = os.listdir(binPath)files = [f for f in files if f[-4:] == '.bin']for ic in tqdm(range(len(files)), desc='进度 '):f = files[ic]binname = os.path.join(binPath, f)pointcloud = np.fromfile(binname, dtype=np.float32, count=-1).reshape([-1,4])x = pointcloud[:, 0]y = pointcloud[:, 1]z = pointcloud[:, 2]r = pointcloud[:, 3]d = np.sqrt(x ** 2 + y ** 2) # Map Distance from sensordegr = np.degrees(np.arctan(z / d))vals = 'height'if vals == "height":col = zelse:col = dfig = mayavi.mlab.figure(bgcolor=(0, 0, 0), size=(640, 500))mayavi.mlab.points3d(x, y, z,col, # Values used for Colormode="point",colormap='spectral', # 'bone', 'copper', 'gnuplot'# color=(0, 1, 0), # Used a fixed (r,g,b) insteadfigure=fig,)mayavi.mlab.show()break
def visBinData():import open3d as o3dimport numpy as npimport os# 替换为你的 bin 文件路径bin_file_path = r'E:\DAIR-V2X-I\kitti_s\training\velodyne'files = os.listdir(bin_file_path)for f in files[:]:# 读取 bin 文件bin_file = os.path.join(bin_file_path, f)print(bin_file)points_np = np.fromfile(bin_file, dtype=np.float32)print(points_np.shape)points_np = points_np.reshape(-1, 4)print(points_np.shape)# 创建 Open3D 点云对象pcd = o3d.geometry.PointCloud()pcd.points = o3d.utility.Vector3dVector(points_np[:, :3])# 可视化点云o3d.visualization.draw_geometries([pcd])
打印查看bin文件中的数据
def readbinfiles():import numpy as npprint('\n' + '*' * 10 + 'myData' + '*' * 10)path = r'D:\lidar3D\data\mydatas1\kitti_my\training\velodyne\000003.bin'# b1 = np.fromfile(path, dtype=np.float)b2 = np.fromfile(path, dtype=np.float32, count=-1).reshape([-1, 4])print(type(b2))print(b2.shape)print(b2)
2.0.2 先对应training中的所有数据准备好
————————training
______________calib
______________image_2
______________Label_2
______________velodyne
【1】velodyne
这里是所有的.bin格式的点云文件
【2】iamge_2
这里是velodyne中的点云文件对应的图片文件。从原文件里面相同名称的图片复制过来就可以了,这里原图片文件是.jpg的格式,kitti里面查找.png的格式好像是写死的,为避免麻烦,可以先把图片直接重命名为.png的格式。()
def jpg2png():import ospath = r'E:\DAIR-V2X-I\example71\training\image_2'files = os.listdir(path)for f in files:fsrc = os.path.join(path, f)fdes = os.path.join(path, f[:-4]+'.png')os.rename(fsrc, fdes)
【3】calib
两种方式,一种方式是忽略DAIR-V2X数据中的标定,直接复制kitti中calib/000000.txt
if calibFlag:'''copy kitti-mini/training/calib/00000.txt cotent to my calib'''calibPath = r'E:\DAIR-V2X-I\training\calib'binPath = r'E:\DAIR-V2X-I\training\velodyne'kitti_miniCalibPath = r'D:\lidar3D\data\kitti_mini\training\calib/000000.txt'with open(kitti_miniCalibPath, "r") as calib_file:content = calib_file.read()for f in os.listdir(binPath):with open(os.path.join(calibPath, f[:-4]+".txt"), "w") as wf:wf.write(content)
另外一种方式是提取single-infrastructure-side\calib中的标定信息写进calib/xxxxxx.txt文件。因为DAIR-V2X只有一台相机,写到p0: ,R0_rect 和 Tr_velo_to_cam 也从中读取。由于Tr_velo_to_cam 是固定的,所以写死在了代码里面
if calibFlag1:V2XVelodynePath = r'E:\DAIR-V2X-I\training\velodyne'files = os.listdir(V2XVelodynePath)files = [f[:-4]+'.txt' for f in files]for f in files:content=[]cameintriPath = r'E:\DAIR-V2X-I\single-infrastructure-side\calib\camera_intrinsic'with open(os.path.join(cameintriPath,f[:-4]+'.json'), "r") as rf1:data = json.load(rf1)p0 = 'P0:'for d in data["P"]:p0 += ' {}'.format(d)R0_rect = 'R0_rect:'for r in data["R"]:R0_rect += ' {}'.format(r)content.append(p0+'\n')content.append('P1: 1 0 0 0 0 1 0 0 0 0 1 0\n')content.append('P2: 1 0 0 0 0 1 0 0 0 0 1 0\n')content.append('P3: 1 0 0 0 0 1 0 0 0 0 1 0\n')content.append('R0_rect: 1 0 0 0 1 0 0 0 1\n')# vir2camePath = os.path.join(V2XCalibPath, cliblist[1])# with open(os.path.join(vir2camePath,f[:-4]+'.json'), "r") as rf1:# data = json.load(rf1)# R = data["rotation"]# t = data["translation"]Tr_velo_to_cam = 'Tr_velo_to_cam: -0.032055018882740139 -0.9974518923884874 0.020551248965447915 -2.190444561668236 -0.2240930139414797 0.002986041494130043 -0.8756800120708629 5.6360862566491909 0.9737455440255373 -0.041678350017788 -0.2023375046787095 1.4163664770754852\n'content.append(Tr_velo_to_cam)content.append('Tr_imu_to_velo: 1 0 0 0 0 1 0 0 0 0 1 0')fcalibname = os.path.join(mykittiCalibPath, f)# content[-1] = content[-1].replace('\n', '')with open(fcalibname, 'w', encoding='utf-8') as wf:wf.writelines(content)
【4】Label_2
方法{{{见 《 2.1.3中——【4】问题记录3 —— 重新生成label_2文件过程如下》章节}}}
点云的标签文件single-infrastructure-side\label\virtuallidar*.json转为txt文件存储,这里3Class,故只取类型([“Car”, “Cyclist”, “Pedestrian”])([‘Cyclist’, ‘Car’, ‘Truck’])。
这里将每个标签(目标)记作temp, temp [0:16] 共计16列,含义分别为:
类别[0]+是否截断[1]+是否遮挡[2]+观察角度[3]+图像左上右下[4:8]+高宽长[8:11]+相机坐标系xyz[11:14]+方向角[14]+置信度[15]
注意:测试数据集才有最后一列的置信度。
json转txt代码如下,因为只训练点云数据,所以与图片相关的值这里用0代替。
如下代码是直接取json文件中的数据,尺寸取雷达坐标系下的,位置取相机坐标系下的。
if label_2Flag:# 1 创建文件夹 label_2label_2Path = r'E:\DAIR-V2X-I\kitti_s\training\label_22_kitti3clsNewXYZ'judgefolderExit_mkdir(label_2Path)V2XVelodynePath = r'E:\DAIR-V2X-I\kitti_s\training\velodyne'files = os.listdir(V2XVelodynePath)files = [f[:-4] + '.txt' for f in files]V2XLabelPathcamera = r'E:\DAIR-V2X-I\single-infrastructure-side\label\camera'V2XLabelPathlidar = r'E:\DAIR-V2X-I\single-infrastructure-side\label\virtuallidar'# 2 转化生成对应的.txt标签文件labelsList = {}labelsListnew = {}for f in files[:]:# print(f)with open(os.path.join(V2XLabelPathcamera, f[:-4] + '.json'), "r") as rf1:dataca = json.load(rf1)with open(os.path.join(V2XLabelPathlidar, f[:-4] + '.json'), "r") as rf1:datali = json.load(rf1)label_list = []if len(dataca) != len(datali):print('Error: len(dataca) != len(datali)')continuefor oi in range(len(dataca)):obj_ca = dataca[oi]obj_li = datali[oi]label_name = obj_ca["type"]label_nameli = obj_li["type"]if label_name != label_nameli:print('Error: label_name != label_nameli')continue# static labelsif label_name in labelsList.keys():labelsList[label_name] += 1else:labelsList[label_name] = 1# updata label type# Car 、 Cyclist、if label_name == 'Trafficcone' or label_name == 'ScooterRider' or label_name == 'Barrowlist':continueelif label_name == 'Motorcyclist':label_name = 'Cyclist'elif label_name == 'Van':label_name = 'Car'elif label_name == 'Bus':label_name = 'Car'elif label_name == 'Truck':label_name = 'Car'if label_name in labelsListnew.keys():labelsListnew[label_name] += 1else:labelsListnew[label_name] = 1scale = obj_li["3d_dimensions"] # 尺寸取雷达坐标系下的pos = obj_ca["3d_location"] # 位置取相机坐标系下的rot = obj_li["rotation"]alpha = obj_ca["alpha"] # 观察角度[3]cabox = obj_ca["2d_box"] # 图像左上右下[4:8]occluded_state = obj_ca["occluded_state"] # 是否遮挡[2]truncated_state = obj_ca["truncated_state"] # 是否截断[1]tempFlag = True # label_list.append(temp)if tempFlag == True:# 2.1 temp 追加目标类型# temp [0:16] 共计16列# 类别[0]+是否截断[1]+是否遮挡[2]+观察角度[3]+图像左上右下[4:8]+高宽长[8:11]+# 相机坐标系xyz[11:14]+方向角[14]+置信度[15]# 注意:测试数据集才有最后一列的置信度temp = label_name + ' '+ truncated_state +' '+ occluded_state +' 0 ' + \cabox["xmin"] + ' ' + cabox["ymin"] + ' ' + cabox["xmax"] + ' ' + cabox["ymax"] + ' 'temp += (scale['h'].split('.')[0] + "." + scale['h'].split('.')[1][:2] + ' ')temp += (scale['w'].split('.')[0] + "." + scale['w'].split('.')[1][:2] + ' ')temp += (scale['l'].split('.')[0] + "." + scale['l'].split('.')[1][:2] + ' ')# 2.2.1 pos_xyz# temp += (pos['x'].split('.')[0] + "." + pos['x'].split('.')[1][:2] + ' ')# temp += (pos['y'].split('.')[0] + "." + pos['y'].split('.')[1][:2] + ' ')# temp += (pos['z'].split('.')[0] + "." + pos['z'].split('.')[1][:2] + ' ')# 2.2 固定使用转换矩阵lidar_to_cam后# 此处的矩阵目的将lidar转到cam下,再转换到rect下,同样追加到temp中(temp追加pos_xyz)# trans_Mat: calib中的 Tr_velo_to_camtrans_Mat = np.array([[-3.205501888274e-02, -9.974518923885e-01, 2.055124896545e-02, -2.190444561668e+00],[-2.240930139415e-01, 2.986041494130e-03, -8.756800120709e-01, 5.636086256649e+00],[9.737455440255e-01, -4.167835001779e-02, -2.023375046787e-01, 1.416366477075e+00],[0, 0, 0, 1]])# R0_rect: 三维单位矩阵rect_Mat = np.array([[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1, 0],[0, 0, 0, 1]])ptx = str2float(pos["x"])pty = str2float(pos["y"])# print('pos["z"], scale["l"], type(scale["l"])\n', pos["z"], scale["l"], type(scale["l"]))ptz = str2float(pos["z"]) - (0.5 * str2float(scale["l"]))# lidar坐标系下的相机中心点pt_in_lidar = np.array([[ptx],[pty],[ptz],[1.]])pt_in_camera = np.matmul(trans_Mat, pt_in_lidar)pt_in_rect = np.matmul(rect_Mat, pt_in_camera)temp += str(pt_in_rect[0, 0]).split('.')[0] + "." + str(pt_in_rect[0, 0]).split('.')[1][0:2]temp += " "temp += str(pt_in_rect[1, 0]).split('.')[0] + "." + str(pt_in_rect[1, 0]).split('.')[1][0:2]temp += " "temp += str(pt_in_rect[2, 0]).split('.')[0] + "." + str(pt_in_rect[2, 0]).split('.')[1][0:2]temp += " "## 2.3 temp 追加 rot_xyz(先将 rot 航向角 返回到0-360°之间)rot = - str2float(rot) - (np.pi / 2)if rot > np.pi:rot = rot - 2 * np.pielif rot < -np.pi:rot = rot + 2 * np.pitemp += str(rot).split('.')[0] + "." + str(rot).split('.')[1][0:2] + "\n"label_list.append(temp)label_list[-1] = label_list[-1].replace('\n', '')# print(label_list)with open(os.path.join(label_2Path, f[:-4]+'.txt'), "w") as wf:wf.writelines(label_list)print('labels Statics = ', labelsList)print('labels Statics = ', labelsListnew)
如下代码考虑重新计算了位置信息,固定使用转换矩阵lidar_to_cam。[“Car”, “Cyclist”, “Pedestrian”]
if label_2Flag:# 1 创建文件夹 label_2label_2Path = r'E:\DAIR-V2X-I\kitti\training\Label_2'judgefolderExit_mkdir(label_2Path)V2XVelodynePath = r'E:\DAIR-V2X-I\kitti\training\velodyne'files = os.listdir(V2XVelodynePath)files = [f[:-4] + '.txt' for f in files]V2XLabelPathcamera = r'E:\DAIR-V2X-I\single-infrastructure-side\label\camera'V2XLabelPathlidar = r'E:\DAIR-V2X-I\single-infrastructure-side\label\virtuallidar'# 2 转化生成对应的.txt标签文件labelsList = {}labelsListnew = {}for f in files[:]:# print(f)with open(os.path.join(V2XLabelPathcamera, f[:-4] + '.json'), "r") as rf1:dataca = json.load(rf1)with open(os.path.join(V2XLabelPathlidar, f[:-4] + '.json'), "r") as rf1:datali = json.load(rf1)label_list = []if len(dataca) != len(datali):print('Error: len(dataca) != len(datali)')continuefor oi in range(len(dataca)):obj_ca = dataca[oi]obj_li = datali[oi]label_name = obj_ca["type"]label_nameli = obj_li["type"]if label_name != label_nameli:print('Error: label_name != label_nameli')continue# static labelsif label_name in labelsList.keys():labelsList[label_name] += 1else:labelsList[label_name] = 1# updata label type# Car 、 Cyclist、if label_name == 'Trafficcone' or label_name == 'ScooterRider' or label_name == 'Barrowlist':continueelif label_name == 'Motorcyclist':label_name = 'Cyclist'elif label_name == 'Van':label_name = 'Car'elif label_name == 'Bus':label_name = 'Car'elif label_name == 'Truck':label_name = 'Car'if label_name in labelsListnew.keys():labelsListnew[label_name] += 1else:labelsListnew[label_name] = 1scale = obj_li["3d_dimensions"] # 尺寸取雷达坐标系下的pos = obj_ca["3d_location"] # 位置取相机坐标系下的rot = obj_li["rotation"]tempFlag = False # label_list.append(temp)if tempFlag == True:# 2.1 temp 追加目标类型# temp [0:16] 共计16列# 类别[0]+是否截断[1]+是否遮挡[2]+观察角度[3]+图像左上右下[4:8]+高宽长[8:11]+# 相机坐标系xyz[11:14]+方向角[14]+置信度[15]# 注意:测试数据集才有最后一列的置信度temp = label_name + ' 0 0 0 0 0 0 0 'temp += (scale['h'].split('.')[0] + "." + scale['h'].split('.')[1][:2] + ' ')temp += (scale['w'].split('.')[0] + "." + scale['w'].split('.')[1][:2] + ' ')temp += (scale['l'].split('.')[0] + "." + scale['l'].split('.')[1][:2] + ' ')# 2.2.1 pos_xyz# temp += (pos['x'].split('.')[0] + "." + pos['x'].split('.')[1][:2] + ' ')# temp += (pos['y'].split('.')[0] + "." + pos['y'].split('.')[1][:2] + ' ')# temp += (pos['z'].split('.')[0] + "." + pos['z'].split('.')[1][:2] + ' ')# 2.2 固定使用转换矩阵lidar_to_cam后# 此处的矩阵目的将lidar转到cam下,再转换到rect下,同样追加到temp中(temp追加pos_xyz)trans_Mat = np.array([[6.927964000000e-03, -9.999722000000e-01, -2.757829000000e-03, -2.457729000000e-02],[-1.162982000000e-03, 2.749836000000e-03, -9.999955000000e-01, -6.127237000000e-02],[9.999753000000e-01, 6.931141000000e-03, -1.143899000000e-03, -3.321029000000e-01],[0, 0, 0, 1]])rect_Mat = np.array([[9.999128000000e-01, 1.009263000000e-02, -8.511932000000e-03, 0],[-1.012729000000e-02, 9.999406000000e-01, -4.037671000000e-03, 0],[8.470675000000e-03, 4.123522000000e-03, 9.999556000000e-01, 0],[0, 0, 0, 1]])ptx = str2float(pos["x"])pty = str2float(pos["y"])# print('pos["z"], scale["l"], type(scale["l"])\n', pos["z"], scale["l"], type(scale["l"]))ptz = str2float(pos["z"]) - (0.5 * str2float(scale["l"]))# lidar坐标系下的相机中心点pt_in_lidar = np.array([[ptx],[pty],[ptz],[1.]])pt_in_camera = np.matmul(trans_Mat, pt_in_lidar)pt_in_rect = np.matmul(rect_Mat, pt_in_camera)temp += str(pt_in_rect[0, 0]).split('.')[0] + "." + str(pt_in_rect[0, 0]).split('.')[1][0:2]temp += " "temp += str(pt_in_rect[1, 0]).split('.')[0] + "." + str(pt_in_rect[1, 0]).split('.')[1][0:2]temp += " "temp += str(pt_in_rect[2, 0]).split('.')[0] + "." + str(pt_in_rect[2, 0]).split('.')[1][0:2]temp += " "## 2.3 temp 追加 rot_xyz(先将 rot 航向角 返回到0-360°之间)rot = - str2float(rot) - (np.pi / 2)if rot > np.pi:rot = rot - 2 * np.pielif rot < -np.pi:rot = rot + 2 * np.pitemp += str(rot).split('.')[0] + "." + str(rot).split('.')[1][0:2] + "\n"label_list.append(temp)# label_list[-1] = label_list[-1].replace('\n', '')# with open(os.path.join(label_2Path, f[:-4]+'.txt'), "w") as wf:# wf.writelines(label_list)print('labels Statics = ', labelsList )print('labels Statics = ', labelsListnew )
2.0.3 kitti\testing中的数据类似training中数据
仅需移动部分数据作为test是数据即可
————————testing
______________calib
______________image_2
______________Label_2
______________velodyne
2.0.4 写kitti/ImageSets 中的txt文件
注意:如下代码中val.txt 与test.txt中的文件是一致的
def filesPath2txt():import os, randompathtrain = 'E:\DAIR-V2X-I\kitti_s/training/velodyne/'pathtest = 'E:\DAIR-V2X-I\kitti_s/testing/velodyne/'txtPath = 'E:\DAIR-V2X-I\kitti_s/ImageSets/'txt_path_train = os.path.join(txtPath, 'train.txt')txt_path_val = os.path.join(txtPath, 'val.txt')# txt_path_trainval = os.path.join(txtPath, 'trainval.txt')txt_path_test = os.path.join(txtPath, 'test.txt')# mkdirImageSets(txt_path_train, txt_path_val, txt_path_trainval, txt_path_test)files = os.listdir(pathtrain)filesList = [f[:-4] + '\n' for f in files]filestr = filesListfilestr[-1] = filestr[-1].replace('\n', '')with open(txt_path_train, 'w', encoding='utf-8') as wf:wf.writelines(filestr)files = os.listdir(pathtest)filesList = [f[:-4] + '\n' for f in files]filesval = filesList # random.sample(filesList, 700)filesval[-1] = filesval[-1].replace('\n', '')with open(txt_path_val, 'w', encoding='utf-8') as wf:wf.writelines(filesval)# filestest = random.sample(filesList, 400)# filestest[-1] = filestest[-1].replace('\n', '')with open(txt_path_test, 'w', encoding='utf-8') as wf:wf.writelines(filesval)
2.1 paddle3D训练
cd ./Paddle3D
2.1.1 数据
【1】数据
数据存放在Paddle3D/datasets目录下,结构如下:
datasets/
datasets/KITTI/
————datasets/KITTI/ImageSets
————datasets/KITTI/testing
————datasets/KITTI/training
【2】数据预处理
使用如下代码完成数据的预处理操作
python tools/create_det_gt_database.py --dataset_name kitti --dataset_root ./datasets/KITTI --save_dir ./datasets/KITTI
上述过程打印如下,运行结束会生成datasets/KITTI/kitti_train_gt_database目录。
root/anaconda3/envs/pip_paddle_env/lib/python3.8/site-packages/setuptools/sandbox.py:13: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.htmlimport pkg_resources
root/anaconda3/envs/pip_paddle_env/lib/python3.8/site-packages/pkg_resources/__init__.py:2871: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('mpl_toolkits')`.
Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packagesdeclare_namespace(pkg)
root/anaconda3/envs/pip_paddle_env/lib/python3.8/site-packages/pkg_resources/__init__.py:2871: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('google')`.
Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packagesdeclare_namespace(pkg)
ortools not installed, install it by "pip install ortools==9.1.9490" if you run BEVLaneDet model
2023-12-26 17:45:46,823 - INFO - Begin to generate a database for the KITTI dataset.
2023-12-26 17:46:06,774 - INFO - [##################################################] 100.00%
2023-12-26 17:46:07,012 - INFO - The database generation has been done.
2.1.2 模型配置文件
为避免修改原模型配置文件,先复制一份并命名为centerpoint_pillars_016voxel_kitti_my.yml
cp ./configs/centerpoint/centerpoint_pillars_016voxel_kitti.yml ./configs/centerpoint/centerpoint_pillars_016voxel_kitti_my.yml
核对文件中的相关配置信息
train_dataset:type: KittiPCDatasetdataset_root: datasets/KITTI... ...class_names: ["Car", "Cyclist", "Pedestrian"]
2.1.3 训练流程及问题调试
【1】使用如下代码进行训练
# python -m paddle.distributed.launch --gpus 0,1,2,3,4,5,6,7 tools/train.py --config configs/centerpoint/centerpoint_pillars_016voxel_kitti.yml --save_dir ./output_kitti --num_workers 4 --save_interval 5python tools/train.py --config configs/centerpoint/centerpoint_pillars_016voxel_kitti_my.yml --save_dir ./output_kitti --save_interval 5 > 112.log
参数介绍
-m:使用python -m paddle.distributed.launch方法启动分布式训练任务。
参考:https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/distributed/launch_cn.html
> 112.log : 将其中的打印保存在112.log中
【2】问题记录1
【2-1】SystemError: (Fatal) Blocking queue is killed because the data reader raises an exception.
【2-2】KeyError: ‘DataLoader worker(1) caught KeyError with message:\nTraceback (most recent call last):\n File “/home/… …”… … self.sampler_per_class[cls_name].sampling(num_samples)\n KeyError: ‘Car’\n’
【2-1、2-2】解决方法
参考1:SystemError: (Fatal) Blocking queue is killed because the data reader raises an exception : 没找到源码中的相关位置。
参考2:SystemError: (Fatal) Blocking queue is killed (baidu.com)
利用“参考2”中提供的方法, 训练的时候,将num_worker设置为0。如下:
python tools/train.py --config configs/centerpoint/centerpoint_pillars_016voxel_kitti_my.yml --save_dir ./output_kitti --num_workers 0 --save_interval 5
将num_workers 设置为0训练的时候,报如下错误
/Paddle3D/paddle3d/transforms/sampling.py", line 172, in samplingsampling_annos = self.sampler_per_class[cls_name].sampling(num_samples)
KeyError: 'Car'
采用如下代码打印/Paddle3D/paddle3d/transforms/sampling.py", line 172中的信息,结果是{}。
print('self.sampler_per_class', self.sampler_per_class)
》》》》》》self.sampler_per_class {}
发现是配置文件中class_balanced_sampling参数是设置为False的原因。修改class_balanced_sampling为True如下
train_dataset:type: KittiPCDatasetdataset_root: datasets/KITTI... ...mode: trainclass_balanced_sampling: Trueclass_names: ["Car", "Cyclist", "Pedestrian"]
【3】问题记录2
【3-1】ZeroDivisionError: float division by zero
详细报错包含如下
File "/home/mec/hulijuan/Paddle3D/paddle3d/datasets/kitti/kitti_det.py", line 89, in <listcomp>sampling_ratios = [balanced_frac / frac for frac in fracs]
ZeroDivisionError: float division by zero
上述问题打印 print(‘kitti_det.py’, cls_dist) 发现是自己数据集中没有"Pedestrian"类别,而class_names中包含该类别。解决办法是增加包含 "Pedestrian"类 的数据。
【4】问题记录3
【4-1】又报错问题同“【2】问题记录1 SystemError: … KeyError: …”,只能是大概上面的问题没有从根本上解决掉
首先看KeyError的问题。
在paddle3d/transforms/sampling.py/class SamplingDatabase(TransformABC):/def __ init __()中增加打印。如下
def __init__(self,min_num_points_in_box_per_class: Dict[str, int],max_num_samples_per_class: Dict[str, int],database_anno_path: str,database_root: str,class_names: List[str],ignored_difficulty: List[int] = None):self.min_num_points_in_box_per_class = min_num_points_in_box_per_classself.max_num_samples_per_class = max_num_samples_per_classself.database_anno_path = database_anno_pathwith open(database_anno_path, "rb") as f:database_anno = pickle.load(f)print('sampling.py__line58~~~~~~~~~~~~~~~~~~~~58database_anno: ', database_anno)if not osp.exists(database_root):raise ValueError(f"Database root path {database_root} does not exist!!!")self.database_root = database_rootself.class_names = class_namesself.database_anno = self._filter_min_num_points_in_box(database_anno)self.ignored_difficulty = ignored_difficultyif ignored_difficulty is not None:self.database_anno = self._filter_ignored_difficulty(self.database_anno)self.sampler_per_class = dict()print('sampling.py__line70~~~~~~~~~~~~~~~70database_anno: ', self.database_anno)for cls_name, annos in self.database_anno.items():self.sampler_per_class[cls_name] = Sampler(cls_name, annos)
通过打印,可以看出sampling.py–line70的打印是空字典,而sampling.py–line58的打印部分如下:
上图可以看出,num_points_in_box 的值为 0。导致如下代码运行后,database_anno 变成了空字典
self.database_anno = self._filter_min_num_points_in_box(database_anno)
上述问题应该是针对点云文件生成标签文件的时候,方法错了。
重新生成label_2文件过程如下:
1 创建环境
conda create -n pcd2bin_env python=3.8
2 激活环境
conda activate pcd2bin_env
3 安装pypcd
3.1 参考:https://blog.csdn.net/weixin_44450684/article/details/92812746
如下流程:
git clone https://github.com/dimatura/pypcd
cd pypcd
git fetch origin pull/9/head:python3
git checkout python3
python3 setup.py install --user
python3
from pypcd import pypcd
pc = pypcd.PointCloud.from_path('pointcloud.pcd')
利用开源程序重新生成label_2文件过程如下:
源码百度网盘地址:执行程序:
2.2 数据集地址KITTI格式(DAIR-V2X-I(7058帧数据)):(长期有效)
大小:22G
链接:https://pan.baidu.com/s/1gG_S6Vtx4iWAfAVAfOxWWw
提取码:p48l
数据没有问题 但是label_2中的XYZ需要根据前述lanel_2的方法重新生成。需下载该数据集的标签文件single-infrastructure-side-json.zip
2.3 模型
2.3.1 模型评估
2.3.2 模型测试
2.3.3 导出模型
相关文章:
Paddle3D 2 雷达点云CenterPoint模型训练
2 Paddle3D 雷达点云CenterPoint模型训练–包含KITTI格式数据地址 2.0 数据集 百度DAIR-V2X开源路侧数据转kitti格式。 2.0.1 DAIR-V2X-I\velodyne中pcd格式的数据转为bin格式 参考源码:雷达点云数据.pcd格式转.bin格式 def pcd2bin():import numpy as npimport…...
RabbitMQ集群的简单说明
1.普通集群(副本集群) 当集群中某一时刻master主节点宕机,可以对master中Queue中的消息进行备份。而就算master宕机了,从节点不会对外提供服务,等到master节点恢复后,系统才会恢复正常。 主从架构的缺点是队列中的消息只是位于主节…...
支付宝沙箱支付-验签出错之编码集异常
异常信息 invalid-signature 错误 验签出错 错误代码 invalid-signature 错误原因: 验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配,网关生成的验签字符串为: alipay_sdkalipay-sdk-java-dynamicVersionNo&....官方通用…...
图像分割-漫水填充法 floodFill (C#)
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 本文的VB版本请访问:图像分割-漫水填充法 floodFill-CSDN博客 FloodFill方法是一种图像处理算法,它的目的是…...
在pycharm中jupyter连接上了以后显示无此库,但是确实已经安装好了某个库,使用python可以跑,但是使用ipython就跑不了
今天遇到一个事情,就是用pycharm的jupyter时,连接不上,后来手动连接上了以后,发现环境好像不对。 一般来说,这里会是python3,所以里面的环境也是普通python的环境,并没有我下载的库,…...
C++多态性——(3)动态联编的实现——虚函数
归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍 收藏⭐ 留言📝 成功的秘诀就在于多努力一次ÿ…...
docker部署mysql
1.查找mysql镜像 [rootVM-4-5-centos ~]# docker search mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql MySQL is a widely used, open-sourc…...
python代码大全(持续更新)
读写文件 # 读取文件 with open(file.txt, r) as file:content file.read()# 写入文件 with open(file.txt, w) as file:file.write(Hello, World!)HTTP请求 import requestsresponse requests.get(https://api.example.com/data) data response.json()JSON处理 import j…...
C#学习笔记 - C#基础知识 - C#从入门到放弃 - C# 处理程序异常相关技术
C# 入门基础知识 - C# 处理程序异常相关技术 第11节 处理程序异常相关技术11.1 捕获异常11.2 清除、处理所有异常11.3 引发异常11.4 预定义异常类11.5 自定义异常类11.6 异常的综合运用 更多C#基础知识点可查看:C#学习笔记 - C#基础知识 - C#从入门到放弃 第11节 处…...
[python]项目怎么使用第三方库
要在Python项目中使用第三方库,可以按照以下步骤进行: 安装第三方库:使用pip命令安装要使用的第三方库。例如,要安装requests库,可以运行以下命令: pip install requests导入库文件:在Python项…...
java每日一题——双色球系统(答案及编程思路)
前言: 打好基础,daydayup! 题目:要求如下(同时:红球每个号码不可以相同) 编程思路:1,创建一个可以录入数字的数组;2,生成一个可以随机生成数字的数组…...
java的mybatis
一.spring 整合单元测试 二.lombok 三.注解方式开发 四.xml 方式开发 五.动态sql...
Linux驱动开发简易流程
推荐视频: 正点原子【第四期】手把手教你学 Linux之驱动开发篇 小智-学长嵌入式Linux&Android底层开发入门教程 能力矩阵 基础能力矩阵 熟悉c/c、熟悉数据结构 熟悉linux系统,Shell脚本,Makefile/cmake/mk 文件IO、多线程、竞争、并发…...
基于springboot的靓车汽车销售网站
🍅点赞收藏关注 → 私信领取本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅一 、设计说明 1.1 研究背景 随…...
爬取涛声网音频
代码展现: 代码详情: import requests import re import os filename 声音// if not os.path.exists(filename): os.mkdir(filename) def down_load(page): for page in range(page): page page1 url https://www.tosound.…...
如何快速且有效的学习自动化测试?
我写一个学习路线吧: 1.学习python基本语法。 2学习路线图 https://www.processon.com/view/link/64e729486ece22263c3e 学习HTML/CSS下的html、xml、webservice三个教程。 3. 然后下一个python的requests库学习写最简单的网络爬虫。知乎上爬虫教程一大堆。 3是…...
openmmlab大模型实战营01
与环境进行交互——智能体更合适 模型微调常见方式 模型评测 模型部署常见问题你 大语言模型本身不具备最新信息和知识的获取,此时需要搭建包含不同模块的智能体框架 智能体:以大语言模型为核心,进行规划、推理和执行...
HarmonyOS-ArkTS基本语法及声明式UI描述
初识ArkTS语言 ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,继承了TS的所有特性,是TS的超集。因此,在学习ArkTS语言之前,建议开发者具备TS语…...
字符串转成时间的SQL,一个多种数据库通用的函数
select date 2010-10-06 from dual; date 函数,此函数适用于: 1.MySQL数据库 2.Oracle数据库 3.达梦数据库 4.人大金仓数据库...
CMake入门教程【核心篇】查找包(find_package)
😈「CSDN主页」:传送门 😈「Bilibil首页」:传送门 😈「本文的内容」:CMake入门教程 😈「动动你的小手」:点赞👍收藏⭐️评论📝 文章目录 1.使用方法1.1基本用…...
Stable Diffusion好用的显卡推荐
Stable Diffusion 是一款顶级的人工智能艺术生成工具,以其快速的性能、用户友好的界面和显着的效果而闻名。然而,在沉浸体验之前,有必要验证您的计算机(显卡)是否符合最佳功能所需的严格规范。今天我们将介绍三款高性价…...
Spring 对请求参数的优雅处方式(重写序列化方法)
Spring 对请求参数的优雅处方式(重写序列化方法) 描述前端传参方式介绍代码实现:1、重写序列化方式代码2、设置类自动加载到 Spring 中 描述 在我们日常项目开发过程中,往往会遇到前端请求参数中有空格的情况,前端提交…...
2024年中职“网络安全“—数字调查取证(attack817.pcapng)
目录 1.通过分析数据包找出恶意用户最初访问HTTP服务的包号,将该值作为Flag值提交, Flag格式为flag{xxx}; 2.继续查看数据包文件分析出恶意用户扫描了哪些端口,将全部的端口号按照一定顺序作为Flag值,提示:注意端口…...
如何使用VsCode编译C语言?
下载VsCode (1) 解压到D盘跟目录 (2) 运行[vscode.reg],注册右键菜单 (3) 进入[pack]文件夹,运行[install.bat]。安装基本插件。 下载mingw32 (1) 解压任意目录 (2) 我的电脑右键–高级系统设置–高级–环境变量–系统变量–Path(双击)–空白行(双击)–…...
SpringCloud 和 Linux 八股文第三期五问五答
SpringCloud 和 Linux 八股文第三期五问五答 作者:程序员小白条,个人博客 相信看了本文后,对你的面试是有一定帮助的! ⭐点赞⭐收藏⭐不迷路!⭐ 1)Linux常用命令 2)如何查看测试项目的日志 一…...
组件通信方式
组件通信方式有:vuex,ref,父子通信(父传子、子传父),兄弟通信(eventBus), 祖先后代通信(依赖注入) 父传子:父组件内:在子组件标签上设置自定义属…...
kbdnecnt.DLL文件缺失,软件或游戏无法启动运行,怎样快速修复?
不少人都在问“kbdnecnt.DLL文件”是什么?为什么电脑总是报错提示说“kbdnecnt.DLL文件缺失,软件无法启动”? 首先,先来了解“kbdnecnt.DLL文件”是什么? kbdnecnt.DLL是Windows操作系统中的一个动态链接库文件&#…...
Linux账户安全
一.Linux账户与组的基本概念 在Limux操作系统中,每一个文件和程序都归属于一个特定的 “用户”。每个用户都由一个唯一的身份来标识,这个标识称为用户ID (UserID, UID )。系统中的每一个用户也至少需要属于一个“用户分组”,即由系统管理员所…...
深度生成模型之GAN优化目标设计与改进 ->(个人学习记录笔记)
文章目录 深度生成模型之GAN优化目标设计与改进原始GAN优化目标的问题1. JS散度度量问题2. 梯度问题 优化目标的设计与改进1. 最小二乘损失GAN2. Energy-based GAN(EBGAN)3. Wasserstein GAN4. WGAN-GP5. Boundary Equilibrium GAN(BEGAN)6. Loss Sensitive GAN7. Relativeisti…...
程序员如何高效学习技术?
我们相信努力学习一定会有收获,但是方法不当,既让人身心疲惫,也没有切实的回报。 不少朋友每天都阅读技术文章,但是第二天就忘干净了。工作中领导和同事都认可你的沟通和技术能力,但是跳槽面试却屡屡碰壁。面试官问技术…...
网站建设教程 三级分销/湘潭seo快速排名
2019独角兽企业重金招聘Python工程师标准>>> 这里是一个用Eclipse的JUnit4教程: 首先,在项目下建立一个test包,然后再就是新建测试类,右键,选择JUnit Test Case,如下图: 然后选择JUnit4&#…...
怀远建设局门户网站/今日头条最新版
单例模式通常用于保证系统中一个类只有一个单例。 单例模式分为三种:懒汉式、饿汉式、双重锁模式 例1:懒汉式(会产生线程安全问题,需要使用synchronized关键字进行加锁,只有在使用单例模式的时候,实例对象才会被创建) …...
wordpress将首页转成html代码/成功的网络营销案例及分析
一、为什么要使用数据库主从架构一个网站损耗资源最厉害的就是数据库,最易崩溃的也是数据库,而数据库崩溃带来的后果是非常严重的。数据库分为读和写操作,在实际的应用中,读操作的损耗远比写操作多太多,因此读操作是引…...
wordpress看板娘素材/企业网站推广有哪些
先将视频读入后将每帧进行图像二值化处理,然后在子文件夹下生成二值化之后的图片,代码如下 v VideoReader(f25.mp4); ii 1;while hasFrame(v)img readFrame(v);thresh graythresh(img); %自动确定二值化阈值 I2im2bw(img,thresh); %图像二值…...
网站备案工信部/app投放推广
新西兰程序员 ASP.NET网站中设置404自定义错误页面 在用ASP.NET WebForm开发一个网站时,需要自定义404错误页面. 做法是这样的 在网站根目录下建立了一个404.html的错误页面,然后在Global.asax文件中,加入如下代码: <% Applica…...
口红做网站多少钱/微信广告平台推广
解决方法,在改py的头部第一行添加下面的代码即可 # -*- coding: utf-8 -*...