第七句
tf.summary.scalar('bn_decay', bn_decay)
查看pointnet学习(二)tf.summary.scalar含义
第八句
pred, end_points = MODEL.get_model(pointclouds_pl, is_training_pl, bn_decay=bn_decay)
字面意思是获取模型。调用的是配置模型的get_model,这里解读配置的是pointnet_cls.py文件里的model,主要神经网络的搭建,初始化。具体实现为
def get_model(point_cloud, is_training, bn_decay=None):
""" Classification PointNet, input is BxNx3, output Bx40 """
batch_size = point_cloud.get_shape()[0].value
num_point = point_cloud.get_shape()[1].value
end_points = {}
with tf.variable_scope('transform_net1') as sc:
transform = input_transform_net(point_cloud, is_training, bn_decay, K=3)
point_cloud_transformed = tf.matmul(point_cloud, transform)
input_image = tf.expand_dims(point_cloud_transformed, -1)
net = tf_util.conv2d(input_image, 64, [1,3],
padding='VALID', stride=[1,1],
bn=True, is_training=is_training,
scope='conv1', bn_decay=bn_decay)
net = tf_util.conv2d(net, 64, [1,1],
padding='VALID', stride=[1,1],
bn=True, is_training=is_training,
scope='conv2', bn_decay=bn_decay)
with tf.variable_scope('transform_net2') as sc:
transform = feature_transform_net(net, is_training, bn_decay, K=64)
end_points['transform'] = transform
net_transformed = tf.matmul(tf.squeeze(net, axis=[2]), transform)
net_transformed = tf.expand_dims(net_transformed, [2])
net = tf_util.conv2d(net_transformed, 64, [1,1],
padding='VALID', stride=[1,1],
bn=True, is_training=is_training,
scope='conv3', bn_decay=bn_decay)
net = tf_util.conv2d(net, 128, [1,1],
padding='VALID', stride=[1,1],
bn=True, is_training=is_training,
scope='conv4', bn_decay=bn_decay)
net = tf_util.conv2d(net, 1024, [1,1],
padding='VALID', stride=[1,1],
bn=True, is_training=is_training,
scope='conv5', bn_decay=bn_decay)
# Symmetric function: max pooling
net = tf_util.max_pool2d(net, [num_point,1],
padding='VALID', scope='maxpool')
net = tf.reshape(net, [batch_size, -1])
net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training,
scope='fc1', bn_decay=bn_decay)
net = tf_util.dropout(net, keep_prob=0.7, is_training=is_training,
scope='dp1')
net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training,
scope='fc2', bn_decay=bn_decay)
net = tf_util.dropout(net, keep_prob=0.7, is_training=is_training,
scope='dp2')
net = tf_util.fully_connected(net, 40, activation_fn=None, scope='fc3')
return net, end_points
从返回值来看,model就是net以及end_points
然后看看输入参数,第一个是pointcloud=pointclouds_pl,第二个是istrainning=is_training_pl,第三个是bn_decay=bn_decay。回想学习,pointnet学习(五)train函数,第五、六句
则可知,pointcloud是一个shape(32x1024x3)的三维的tensor,里面存放点云数据,istrainning是一个bool类型的tensor,shape没有指定,
现在看getmodel函数体内code:
第一句,获取bitchsize即为32,第二句为获取点数量1024,第三句为声明一个endpoint为dict字典
第四第五句,为加载transformnet,因为pointnet网络在进行分类之前先进入transformnet将点云旋转为正向方位,虽然有后续文章之处此net对后续分类并没有什么影响,但是还是照旧加上了。
tf.variable_scope('transform_net1') as sc
设置transformnet名字为transform_net1。
transform = input_transform_net(point_cloud, is_training, bn_decay, K=3)
下面来看transform_net的构建,也是包括了跟model一样的三个参数,除此之外添加了一个K参数。
定义另一维的kernel的值,此工程返回的transform_net的shape为[32,3,3]输出对应bitchsize个3x3旋转矩阵,根据卷积,池化得到的大量特征点的旋转矩阵,有点类似图像处理中提取特征点,然后对比源和目标特征点计算的旋转矩阵的原理,参考pointnet学习(七)input_transform_net,
得到transformnet的输出之后,与inputcloud进行叉乘,得到
第六句
point_cloud_transformed = tf.matmul(point_cloud, transform)
旋转矩阵求得之后,那么就应该让我们的input的point_cloud经过相乘得到正向的点云模型了,后面
第七句
input_image = tf.expand_dims(point_cloud_transformed, -1)
为了卷积,继续对旋转后的32个batch的点云模型进行卷积
第八、九句,
net = tf_util.conv2d(input_image, 64, [1,3],
padding='VALID', stride=[1,1],
bn=True, is_training=is_training,
scope='conv1', bn_decay=bn_decay)
net = tf_util.conv2d(net, 64, [1,1],
padding='VALID', stride=[1,1],
bn=True, is_training=is_training,
scope='conv2', bn_decay=bn_decay)
这两句就很熟悉了,参考pointnet学习(八)tf_util.conv2d,也是对我旋转后的点云模型,xyz进行卷积,因为输出为64,所以有64个1x3的核验numpoint方向以及xyz方向,1,1步幅进行卷积,得到了32,1024,1,64的tensor,因为没有maxpolling所以依然是1024个点的每个点的xyz卷积和分为64个channel存储因为同一个点让64个1,3卷积kernel进行了卷积。
第九句,继续进行卷积,依然出来32,1024,1,64的tensor这里相当于对于这卷积后的xyz继续乘以一个w+b的到的值
第十,十一句
with tf.variable_scope('transform_net2') as sc:
transform = feature_transform_net(net, is_training, bn_decay, K=64)
第二个transform的网络层。是对特征值进行旋转偏移,参考pointnet input_transform_net
第十二句
net_transformed = tf.matmul(tf.squeeze(net, axis=[2]), transform)
先看tf.squeeze(net, axis=[2]),功能是,移除tensor中所有维度为1的数据或者指定某一维的数据移除,这句是指移除32,1024,1,64中第三维数据,变为32,1024,64的tensor。跟feature transform64*64进行矩阵相乘,旋转,偏移。得到新的卷积得到特征值之后的input、
第十三句
net_transformed = tf.expand_dims(net_transformed, [2])
重新将之前删除的第三维拓展方便后续的卷积运算
十四~十八句。对32,1024,1,64的tensor进行卷积,分别输出[32,1024,1,64]tensor,[32,1024,1,126]tensor,[32,1024,1,1024]tensor,最后maxpolling输出得到[32,1,1,1024]tensor,重新reshape为[32,1024]tensor.
十九句,初始化一个1024,512的weighttensor以及512,512的biastensor进行运算得到32,512的tensor
第二十句
net = tf_util.dropout(net, keep_prob=0.7, is_training=is_training,
scope='dp1')
第二十一二十二句与第十九二十句一样,转换为32,256tensor,
第二十三句,最后一层fullyconnect,乘以weight+你、bias,最后得到32,40tensor,
至此,net与transformnet搭建完成