Voxelnet
的时候,没有初始化的名字,如何找到对应的网络函数的:使用:
net = get_voxelnet_class(model_cfg.network_class_name)(。。。)
函数定义:
def get_voxelnet_class(name):
global REGISTERED_NETWORK_CLASSES
assert name in REGISTERED_NETWORK_CLASSES, f"available class: {REGISTERED_NETWORK_CLASSES}"
return REGISTERED_NETWORK_CLASSES[name]
被调用:
@register_voxelnet
class VoxelNet(nn.Module):
def __init__(self,
output_shape,
num_class=2,
。。。
问题:
REGISTERED_NETWORK_CLASSES
初始化是空集,如何出来了两个元素的。
可能原因:
(1)在被调用函数前是一个函数修饰器(@):
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。装饰器的作用就是为已经存在的对象添加额外的功能。
@register_voxelnet
class VoxelNet(nn.Module):
也就是说,上面的这个结构也就是 VoxelNet=register_voxelnet(VoxelNet),其中在VoxelNet被调用之前,register_voxelnet函数就已经被调用了。
register_voxelnet
如下:
def register_voxelnet(cls, name=None):
global REGISTERED_NETWORK_CLASSES
if name is None:
name = cls.__name__
assert name not in REGISTERED_NETWORK_CLASSES, f"exist class: {REGISTERED_NETWORK_CLASSES}"
REGISTERED_NETWORK_CLASSES[name] = cls
return cls
debug发现,所以运行的过程是:
第一,
register_voxelnet
函数预先生成REGISTERED_NETWORK_CLASSES
集合。
第二,运行加载名称函数net = get_voxelnet_class(model_cfg.network_class_name)
第三,运行网络构造函数VoxelNet
自己新建的函数名称,需要在__iniy__.py文件中加入进去。
这一步是在create_data的操作。不细看了。
(1)过程:
voxel_builder.build
–>VoxelGeneratorV2
(一些参数)–>points_to_voxel
(把点划分到格子中)
-------------------------------VoxelGeneratorV2过程的参数定义-------------------------------------------
属性 | shape | 含义 |
---|---|---|
_coor_to_voxelidx | [400,1280,1056] | |
_voxel_size | 3 | = [0.05,0.05,0.1] |
_point_cloud_range | 6 | = [0.0,-32,-3,52.8,32,1.0] |
_max_num_points | 1 | =5 |
_max_voxels | 1 | =20000 |
_grid_size | 3 | =[1056,1280,40] |
_full_mean | bool | = False |
_block_filtering | bool | = False |
_block_factor | 1 | =0 |
_height_threshold | 1 | =0.0 |
_block_size | 1 | =0.0 |
_height_high_threshold | 1 | =0.0 |
-------------------------------points_to_voxel -把点划分到格子中-------------------------------------------
函数定义如下
def points_to_voxel(points,
voxel_size,
coors_range,
coor_to_voxelidx,
max_points=35,
max_voxels=20000,
full_mean=False,
block_filtering=True,
block_factor=1,
block_size=8,
height_threshold=0.2,
height_high_threshold=3.0,
pad_output=False):
关于参数的解释如下:
输入参数 | 解释 |
---|---|
points | [N, ndim] float tensor. 前3个维度表示(x,y,z),后面的为其他信息 |
voxel_size | voxel size |
coors_range | voxel range |
coor_to_voxelidx | |
max_points | int array. used as a dense map. 密集表示[40,1056,1280] |
max_voxels | for voxelnet, 20000 is a good choice |
full_mean | bool. if true, all empty points in voxel will be filled with mean of exist points. |
block_filtering | filter voxels by height. used for lidar point cloud. |
返回参数 | 解释 |
---|---|
voxels | [M, max_points, ndim] float tensor. only contain points.注意到只有含有点的voxels,M表示的在一个batch中含有点的voxel的个数.max_points=5。也就是 [含有点的voxel个数,5,4] |
coordinates | [M, 3] int32 tensor. zyx format,点云中所有点的个数的坐标 |
num_points_per_voxel | [M] int32 tensor。每一个含有点的voxel中含有点的个数,最大为5 |
好吧,这一个函数并没有多大的用处,看下一个吧!!!
prep_pointcloud
函数convert point cloud to voxels, create targets if ground truths exists.
也就是把点放入voxel中,以及得到gt的targets方便用于Loss的计算
考察如何建立起voxel和gt之间的关系的.
重要的代码在target_assigner.py
文件中的generate_anchors_dict
for anchor_generator, match_thresh, unmatch_thresh, fsize in zip(
self._anchor_generators, matched_thresholds,
unmatched_thresholds, feature_map_sizes):
。。。
设置了一堆>0.6和小于0.4IOU参数,应该是用于判定pos和neg的。
dataset 也就是训练数据集。包含四个主要部分:
(1)_class_names:也就是car,pedestrain,cyclist和van
(2)_kitti+infos:在creat_data.py文件运行时建立的数据信息整合,每一个子项对应着该个item的pc位置,image位置,cliab位置和对应的annos标注.
(3)_prep_func:一些参数,比如需要shuffe,voxel_generater等,如下:
尤其是anchor_cache感觉内容挺多的:
(4)root_path
(1)每一个类别都分别对应anchor,matched_threshold和unmatch_threshold.
(2)每一种都是42240对应的大小.
(3)对于IOU:car[0.6,0.45],cyclist[0.35,0.2],pedestrain[0.35,0.2],Van[0.6,0.45]
(4)目前的anchor应该只有anchor的形式,没有内容.
在计算loss的时候,如下:
loc_losses = loc_loss_ftor(
box_preds, reg_targets, weights=reg_weights) # [N, M]
这里的reg_targets
和box——pred大小都是 [ b s , 160 ∗ 132 ∗ 8 , 7 ] [bs,160∗132∗8,7] [bs,160∗132∗8,7],问题是:
1.作者又是如何把gt从三维降到二维。
2.reg_targets
是gt的feature,对于[1601328]个anchor,里边肯定具有很多不是pos的anchor,那么这些不是pos的anchor对应的内容又是什么呢?
不用从三维降到二维,初始化anchor时,是在xy平面上每隔(0.4,0.4)则得到一个anchor(7个维度),最终也就是[160,132,7]而不是[1280,1056,7]。然后再根据anchor和gt之间分别的IOU来确定对应的labels和reg。
是pos的gt的anchor的7个维度是[x,y,z,w,h,l,yaw],而neg则全是-1.
(1)voxel是划分格子提取特征的,其每个格子的size是[0.05,0.05,0.1],在一块点云中划分出来的size是[1280,1056,40],同时在z轴方向上也是有格子的;anchor划分时是根据
feature_map_size
的大小来设定的,其中feature_map_size
大小是根据config中的下采样因子(=8)来的,该feature_map_size
要对应到后面经过rpn之后的feature_map大小[bs,160,132,2*channel],同时,anchor在z轴上是没有的,仅仅在xy平面上存在。
对Non-empty的voxel提取特征后,scatter回[bs,1280,1056,channels]的voxel中,然后使用稀疏卷积mid_spconv进行3D特征提取,到[bs,2,160,132,cahnnes]–>[bs,2*channel,160,132](这个经过3D稀疏卷积的fea-map就是featuremapsize,大小刚好和anchor的一样,只是anchor是在原始点云的空间中根据这里的feature-map的大小生成的,但是在实际中,这里的feature实际上是和mid_cov相关的而不是和config的
downsample_factor
没有关系,因此如果修改anchor的feature_map,也要相应的修改mid_cov的层次结构),后再通过rpnhead的处理得到上采样的组合的fea-map[bs,256,160,132],然后进行回归和预测。