前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分类VS分割——从原理和代码角度来分析对比

分类VS分割——从原理和代码角度来分析对比

作者头像
点云乐课堂
发布2020-05-18 14:23:41
2K0
发布2020-05-18 14:23:41
举报
文章被收录于专栏:3D点云深度学习

分类任务与分割任务有什么联系吗?

答案是肯定的。

分割其实就是对每一个像素进行分类。在代码上,分割与分类的区别就更小了,都是用全连接层输出一定的数目,这个数目就是你要分类/分割的个数。

以PointNet为例,先看看网络架构:

可以看到网络在得到global feature之前,分类和分割是公用一套网络的。它们的代码自然也一样。这部分代码位于pointnet_cls.py和pointnet_seg.py中,完全相同。

代码语言:javascript
复制
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)

再往后看,就出现一些区别了。

分类任务:

代码语言:javascript
复制
    # 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

代码布局如同网络中描绘的一样。池化操作后,做全连接层,最后输出40,对应40类物体分类。

再来看分割:

代码语言:javascript
复制
    global_feat = tf_util.max_pool2d(net, [num_point,1],
                                    padding='VALID', scope='maxpool')
   print(global_feat)   global_feat_expand = tf.tile(global_feat, [1, num_point, 1, 1])
   concat_feat = tf.concat(3, [point_feat, global_feat_expand])
   print(concat_feat)   net = tf_util.conv2d(concat_feat, 512, [1,1],
                        padding='VALID', stride=[1,1],
                        bn=True, is_training=is_training,
                        scope='conv6', bn_decay=bn_decay)
   net = tf_util.conv2d(net, 256, [1,1],
                        padding='VALID', stride=[1,1],
                        bn=True, is_training=is_training,
                        scope='conv7', bn_decay=bn_decay)
   net = tf_util.conv2d(net, 128, [1,1],
                        padding='VALID', stride=[1,1],
                        bn=True, is_training=is_training,
                        scope='conv8', bn_decay=bn_decay)
   net = tf_util.conv2d(net, 128, [1,1],
                        padding='VALID', stride=[1,1],
                        bn=True, is_training=is_training,
                        scope='conv9', bn_decay=bn_decay)   net = tf_util.conv2d(net, 50, [1,1],
                        padding='VALID', stride=[1,1], activation_fn=None,
                        scope='conv10')
   net = tf.squeeze(net, [2]) # BxNxC   return net, end_points

除了增加全局特征与点特征的拼接外,也是做了全连接操作,注意此处的全连接使用1*1的卷积实现的,但是本质上和使用fully_connect效果一样。最后的输出是50,对应的是分割任务的50个parts。

最后的损失函数也是一样的。这里就不贴出来了。

所以,总的来说,分割就是一种特殊的分类。当然,为了提高分割效果,可以对损失函数做相应的改进,如平滑等。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 3D点云深度学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档