来看EfficientLO的网络。网络设计主要是在pwclo_model.py文件里面。
发现自己对cnn的理解不够,先看了这篇文章
1、从if __name__=='__main__'开始
这个我感觉对项目没啥用处?
2、def placeholder_inputs(batch_size, NUM_POINTS)
这里主要是定义了点云数据变量、真实变换矩阵T_gt、估计的变换矩阵T及其逆。
3、def get_loss(l0_q, l0_t, l1_q, l1_t, l2_q, l2_t, l3_q, l3_t, q_gt, t_gt, w_x, w_q)
def get_loss(l0_q, l0_t, l1_q, l1_t, l2_q, l2_t, l3_q, l3_t, q_gt, t_gt, w_x, w_q):#####id
t_gt = tf.squeeze(t_gt, axis = -1)### 8,3 t_gt 的形状从 (8, 3, 1) 变为 (8, 3). 8是因为输入的batch_size是8
batch_size = q_gt.get_shape()[0].value
l0_q_norm = l0_q / (tf.sqrt(tf.reduce_sum(l0_q*l0_q, axis=-1, keep_dims=True)+1e-10) + 1e-10)
l0_loss_q = tf.reduce_mean(tf.sqrt(tf.reduce_sum((q_gt-l0_q_norm)*(q_gt-l0_q_norm), axis=-1, keep_dims=True)+1e-10)) # 计算l0_q与q_gt之间的欧式距离当作loss
l0_loss_x = tf.reduce_mean( tf.sqrt((l0_t-t_gt) * (l0_t-t_gt)+1e-10)) # 计算l0_t与t_gt之间的欧式距离当作loss
l0_loss = l0_loss_x * tf.exp(-w_x) + w_x + l0_loss_q * tf.exp(-w_q) + w_q # 论文中的式(16)
tf.summary.scalar('l0 loss', l0_loss)
省略中间的l1,l2,l3的loss计算过程,和l0是一样的。
loss_sum = 1.6*l3_loss + 0.8*l2_loss + 0.4*l1_loss + 0.2*l0_loss # 按照权重加起来
tf.add_to_collection('losses', loss_sum)
return loss_sum
这里其实就是一个简单的loss计算。但对于loss计算有个问题
1.l3代表的是coarse的pose,误差大,定权大的话使得更快收敛。
2.l0代表的是fine的pose,误差小,定权大的话是否可以更侧重于提升精度。
这里的理解:
4、def get_model
这个get_model函数的原理其实就是论文里面的fig2
for i in range(1, 6):
out_h_list.append(math.ceil(out_h_list[i - 1] / stride_h_list[i]))
out_w_list.append(math.ceil(out_w_list[i - 1] / stride_w_list[i])) # generate the output shape list
先在这里做一个步长提取器,对应着理解就算需要从PC中提取F。
#### the pre2 select bn3 xyz
# get_selected_idx就是根据步长选一些点出来
pre2_selected_idx = get_selected_idx(xyz_f1_input_proj, stride_h_list[1], stride_w_list[1], out_h_list[1], out_w_list[1]) ### b outh outw 3
# 使用索引pre2_selected_idx在xyz_f1_input_proj选取特定位置的元素。
# xyz_f1_input_proj形状为(b, outh, outw, 3),其中 b 是批次大小,outh 和 outw 是输出特征图的高度和宽度,3 是每个位置的元素数量。
pre2_xyz_proj_f1 = tf.gather_nd(xyz_f1_input_proj, pre2_selected_idx) ## b outh outw 3
pre2_xyz_proj_f2 = tf.gather_nd(xyz_f2_input_proj, pre2_selected_idx) ## b outh outw 3
#### the l0 select bn3 xyz
l0_selected_idx = get_selected_idx(pre2_xyz_proj_f1, stride_h_list[2], stride_w_list[2], out_h_list[2], out_w_list[2]) ### b outh outw 3
l0_xyz_proj_f1 = tf.gather_nd(pre2_xyz_proj_f1, l0_selected_idx) ## b outh outw 3
l0_xyz_proj_f2 = tf.gather_nd(pre2_xyz_proj_f2, l0_selected_idx) ## b outh outw 3
#### the l1 select bn3 xyz
l1_selected_idx = get_selected_idx(l0_xyz_proj_f1, stride_h_list[3], stride_w_list[3], out_h_list[3], out_w_list[3]) ### b outh outw 3
l1_xyz_proj_f1 = tf.gather_nd(l0_xyz_proj_f1, l1_selected_idx) ## b outh outw 3
l1_xyz_proj_f2 = tf.gather_nd(l0_xyz_proj_f2, l1_selected_idx) ## b outh outw 3
#### the l2 select bn3 xyz
l2_selected_idx = get_selected_idx(l1_xyz_proj_f1, stride_h_list[4], stride_w_list[4], out_h_list[4], out_w_list[4]) ### b outh outw 3
l2_xyz_proj_f1 = tf.gather_nd(l1_xyz_proj_f1, l2_selected_idx) ## b outh outw 3
l2_xyz_proj_f2 = tf.gather_nd(l1_xyz_proj_f2, l2_selected_idx) ## b outh outw 3
#### the l3 select bn3 xyz
l3_selected_idx = get_selected_idx(l2_xyz_proj_f1, stride_h_list[5], stride_w_list[5], out_h_list[5], out_w_list[5]) ### b outh outw 3
这里就是点数由多到少的进行提取。l0对应的是最多的点、最fine的pose,那么这个就多一些点。l3对应最少的点、最coarse的pose,那么这个就少一点。其实这个从循环:
for i in range(1, 6):
out_h_list.append(math.ceil(out_h_list[i - 1] / stride_h_list[i]))
out_w_list.append(math.ceil(out_w_list[i - 1] / stride_w_list[i])) # generate the output shape list
这里也可以看出来,out_h_list和out_w_list大小都是不断减少的。
with tf.variable_scope('sa1') as scope:
l0_points_f1, l0_xyz_proj_f1 = down_conv(xyz_f1_input_proj, points_f1_input_proj, l0_selected_idx, \
K_sample = 32, kernel_size = [9, 15], distance = Down_conv_dis[0], mlp = [8,8,16], mlp2 = None, flag_add=False, is_training=is_training, bn_decay=bn_decay, scope='layer0')
l0_points_proj_f1 = tf.reshape(l0_points_f1, [batch_size, out_h_list[2], out_w_list[2], -1])
l1_points_f1, l1_xyz_proj_f1 = down_conv(l0_xyz_proj_f1, l0_points_proj_f1, l1_selected_idx, \
K_sample = 32, kernel_size = [7, 11], distance = Down_conv_dis[1], mlp = [16,16,32], mlp2 = None, flag_add=False, is_training=is_training, bn_decay=bn_decay, scope='layer1')
l1_points_proj_f1 = tf.reshape(l1_points_f1, [batch_size, out_h_list[3], out_w_list[3], -1])
############# 接下来的l2、l3同样处理方法,省略 ####################
scope.reuse_variables()
############# 接下来是对f2的处理,与f1处理类似 ####################
l0_points_f2, l0_xyz_proj_f2 = down_conv(xyz_f2_input_proj, points_f2_input_proj, l0_selected_idx, \
K_sample = 32, kernel_size = [9, 15], distance = Down_conv_dis[0], mlp = [8,8,16], mlp2 = None, flag_add=False, is_training=is_training, bn_decay=bn_decay, scope='layer0')
l0_points_proj_f2 = tf.reshape(l0_points_f2, [batch_size, out_h_list[2], out_w_list[2], -1])
l1_points_f2, l1_xyz_proj_f2 = down_conv(l0_xyz_proj_f2, l0_points_proj_f2, l1_selected_idx, \
K_sample = 32, kernel_size = [7, 11], distance = Down_conv_dis[1], mlp = [16,16,32], mlp2 = None, flag_add=False, is_training=is_training, bn_decay=bn_decay, scope='layer1')
l1_points_proj_f2 = tf.reshape(l1_points_f2, [batch_size, out_h_list[3], out_w_list[3], -1])
############# 接下来的l2、l3同样处理方法,省略 ####################
这里分别对f1和f2进行了down_conv的处理,以f1为例。
对第0层:
输入:xyz_f1_input_proj, points_f1_input_proj, l0_selected_idx
其中xyz_f1_input_proj, points_f1_input_proj暂时还是一个东西。l0_selected_idx是选中的H和W的步长所对应的点。
其实在这里就是选取了一个特征图出来。对应做出来的东西就是fig2中的PC和F。
紧接着就是进行cost volume的计算
在这里
l2_points_f1_new = cost_volume(l2_xyz_proj_f1, l2_xyz_proj_f2, l2_points_proj_f1, l2_points_proj_f2, \
kernel_size1 = [3, 5], kernel_size2 = [5, 35] , nsample=4, nsample_q=32, distance = Cost_volume_dis[2], mlp1=[128,64,64], mlp2 = [128,64], \
is_training=is_training, bn_decay=bn_decay, scope='flow_embedding_l2_origin', bn=True, pooling='max', knn=True, corr_func='concat')
l2_xyz_proj_f1和l2_xyz_proj_f2:(8,4,57,3)
l2_points_proj_f1和l2_points_proj_f2:(8,4,57,64)
这里用的是最大池化,更好的提取特征。
这里还对l3进行了为mlp准备的操作
l3_points_f1_cost_volume, _ = down_conv(l2_xyz_proj_f1, l2_points_new_proj_f1, l3_selected_idx, \
K_sample = 16, kernel_size = [5, 9], distance = Down_conv_dis[3], mlp = [128,64,64], mlp2 = None, \
flag_add=False, is_training=is_training, bn_decay=bn_decay, scope='new_layer3')
对应fig2中连接MLP的那个.
接下来的操作就是通过几个warp-refinement来进行pose的精确估计。
最后将每一层估计的q和t输出出来即可。