Geo_CNN代码解释与说明

Geo_CNN代码解释与说明

1.tf_geoconv.py注释

''' 
tf_geoconv.py注释
'''

from __future__ import print_function
import tensorflow as tf
from tensorflow.python.framework import ops
import sys
import os

import numpy as np

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(BASE_DIR)
geoconv_module = tf.load_op_library(os.path.join(BASE_DIR, 'tf_geoconv_so.so'))
# so文件就是常说的动态链接库(共享库), 都是C或C++编译出来的。


# 该aggregate函数是采用tf的c++端定义的aggregate
def aggregate(feat, xyz, radius, decay_radius, delta=0):
    '''
    inputs:
        feature: batch_size * num_points * num_channels     float32
        xyz: batch_size * num_points * 3                    float32
        radius:                                             float32
        decay_radius:                                       float32
        delta                                               int
    returns:
        output feature: batch_size * num_points * num_channels  float32
        # 从.cpp文件可以看出output feature中的num_channels=输入的num_channels/6
        # 6为论文中的6个基向量
        norm feature: batch_size * num_points
    '''
    return geoconv_module.aggregate(feat, xyz, radius, decay_radius, delta)


# 使用修饰器, @ops.RegisterGradient("OpName"),建立梯度反向传播函数。
# 这里涉及到使用重写梯度的方法tf.RegisterGradient()
@tf.RegisterGradient('Aggregate')
def _aggregate_grad(op, *out_g):   # 梯度函数的签名是 def _computer_gradient(op, grad)
    # 其中第一个op用来接收当前操作的输入值/张量等,op.input包含输入值、输出值
    # 第二个gard用来接收从反向而言的上一层的梯度。
    # grad,这里为*out_g包含上层传来的梯度
    feat = op.inputs[0]  # 取出feature=batch_size*num_points*num_channels
    xyz  = op.inputs[1]  # 取出xyz=batch_size * num_points * 3
    top_g = out_g[0]     # 取出反向而言的上一层的梯度第1个参数
    norm_buffer = out_g[1]  # 取出反向而言的上一层的梯度第2个参数
    # 属性的信息可以通过 op.get_attr 获取.
    radius = op.get_attr("radius")  # 获取radius属性信息
    decay_radius = op.get_attr("decayradius")
    delta = op.get_attr("delta")
    return [geoconv_module.aggregate_grad(feat, xyz, top_g, radius, decay_radius, delta)[0], None]


# 验证梯度差异
# tf.test.TestCase继承了 unittest.TestCase,但添加了一些额外的方法
# 可以添加与 TensorFlow 测试相关的方法
class AggregateTest(tf.test.TestCase):
    def test(self):
        pass

    def test_grad(self):
        with tf.device('/gpu:0'):
            # features : batch_size=8, num_points=128, num_channels = 192
            feats = tf.constant(np.random.random((8, 128, 192)).astype('float32'))
            # xyz : batch_size=8, num_points=128, num_channels = 3(xyz)
            xyz   = tf.constant(np.random.random((8, 128, 3)).astype('float32'))
            # radius = 0.3, decay_radius = 0.6
            ag, _ = aggregate(feats, xyz, 0.3, 0.6)
            # ag为output feature: batch_size * num_points * num_channels
            # 通过论文,我们可以知道ag=[8,128,192/6=32],因为6个通道将空间分为8个空间
            print(ag)

        # tf的测试格式
        with self.test_session():
            print("------ Going to compute gradient error")
            # compute_gradient_error()数值化地计算梯度,返回与理论上的梯度的差别,我们所期望的是一个非常小的差别
            # 注意这个函数计算的并不是梯度,而是输出对输入的Jacobian
            # tf.test.compute_gradient_error(x, x_shape, y, y_shape, x_init_value=None, delta=0.001, init_targets=None)
            # 计算梯度的error。在计算所得的与数值估计的Jacobian中 为dy/dx计算最大的error
            err = tf.test.compute_gradient_error(feats, (8, 128, 192), ag, (8, 128, 32))
            # 参考链接:https://blog.csdn.net/lenbow/article/details/52218551#reply
            print(err)
            # python比较断言assertLess (first, second, msg = None)
            # 验证first < second,否则fail,抛出异常
            # 其他断言类型:https://blog.csdn.net/weixin_34237596/article/details/93426712
            self.assertLess(err, 1e-4)


if __name__ == "__main__":
    tf.test.main()

2.geoconv_utils.py的geoconv注释

def geoconv(feat, xyz, num_outputs, bypass_num_outputs,
            radius, decay_radius, bn=True, is_training=False,
            scope=None, bn_decay=None, activation_fn=tf.nn.relu,
            delta=False):

    ''' GeoCNN Geo-Conv
        Input:
            feat: (batch_size, num_point, input_channels) TF tensor
            points: (batch_size, num_point, 3) TF tensor
            num_outputs: the count of output channels
            bypass_num_outputs: the count of output channels of bypass
            radius: the inner radius of local ball of each point.
            decay radius: the outer radius of local ball of each point
            ...
    '''

    # TensorFlow提供了variable_scope 这种独特的机制来共享变量。
    with tf.variable_scope(scope) as sc:
        # perceptron为感知机
        self = perceptron(feat, num_outputs, scope='self', is_training=is_training, bn=False, activation_fn=None)
        # mutal
        mutual = perceptron(feat, bypass_num_outputs * 6, scope='mutual', is_training=is_training, bn=False, activation_fn=None)
        # ag为输出的特征,其中mutual为输入特征
        ag, _ = aggregate(mutual, xyz, radius, decay_radius, delta)

        # b=batch_size, n=num_points, bc=bypass_num_outputs
        b, n, bc = ag.get_shape().as_list()
        # c=num_outputs
        _, _, c  = self.get_shape().as_list()
        # ag=[batch_size * num_points, bypass_num_outputs]
        # -1 代表的含义是不用我们自己指定这一维的大小,函数会自动计算,
        # 但列表中只能存在一个-1
        ag   = tf.reshape(ag, (-1, bc))
        # self=[Batchsize * Num_points, num_outputs]
        self = tf.reshape(self, (-1, c))

        if bn:
            ag = batch_norm_for_fc(ag, is_training, bn_decay, scope='mutual_bn')
        if activation_fn is not None:
            ag = activation_fn(ag)

        # ag=[b=batch_size, n=num_points, bc=bypass_num_outputs]
        ag = tf.reshape(ag, (b, n, bc))
        # ag=[batch_size , num_points, num_outputs]
        ag = perceptron(ag, num_outputs, scope='enlarge', is_training=is_training, bn=False, activation_fn=None)
        # ag=[batch_size * num_points, num_outputs]
        ag = tf.reshape(ag, (-1, c))

        # outputs=[batch_size * num_points, num_outputs]
        outputs = self + ag

        if bn:
            outputs = batch_norm_for_fc(outputs, is_training, bn_decay, scope='enlarge_bn')
        if activation_fn is not None:
            outputs = activation_fn(outputs)

        # [batch_size , num_points, num_outputs]
        outputs = tf.reshape(outputs, (b, n, c))

        return outputs

3.tf_utils.py的geoconv注释

# 实现感知机
# tf的data_format有NHWC[batch, in_height, in_width, in_channels]
# 和NCHW[batch, in_channels, in_height, in_width]两种
def perceptron(inputs,  # 输入
               num_output_channels,  # 输出通道数
               scope,
               is_training=None,
               data_format='NHWC',
               user_xavier=True,
               stddev=1e-3,
               weight_decay=None,
               activation_fn=tf.nn.relu,
               use_xavier=True,
               bn=False,
               bn_decay=None):

    # variable_scope变量作用范围
    # 通过捕获范围并设置重用来共享变量sc
    with tf.variable_scope(scope) as sc:

        assert(data_format=='NHWC' or data_format=='NCHW')

        # 获取输入格式[B, N, C]
        b, n, c = inputs.get_shape().as_list()
        # inputs=[B*N,C]
        inputs = tf.reshape(inputs, (-1, c))

        # _variable_with_weight_decay 为变量添加weight decay
        # weights=[C,num_output_channels]
        weights = _variable_with_weight_decay('weights',
                                            shape=[c, num_output_channels],
                                            use_xavier=use_xavier,
                                            stddev=stddev,
                                            wd=weight_decay)

        # tf.matmul()将矩阵a乘以矩阵b,生成a * b。与矩阵各元素相乘不一样,tf.atmul为矩阵乘法
        # tf.multiply()两个矩阵中对应元素各自相乘
        outputs = tf.matmul(inputs, weights)  # outputs=[B*N,num_output_channels]
        biases = _variable_on_cpu('biases', [num_output_channels],
                                tf.constant_initializer(0.0))

        # 添加偏置项
        outputs = tf.nn.bias_add(outputs, biases)

        # outputs=[B,N,num_output_channels]
        outputs = tf.reshape(outputs, (b, n, -1))

        # bn为True时,添加相应的bn层归一化
        if bn:  # 如果bn归一化
            # batch_norm_for_fc(inputs, is_training, bn_decay, scope)
            # 返回值为batch_norm_template(inputs, is_training, scope, [0,], bn_decay, data_format='NHWC')
            # outputs = [inputs, is_training, scope, [0,], bn_decay, data_format='NHWC']
            outputs = batch_norm_for_fc(outputs, is_training, bn_decay, 'bn')

        # 若有激活函数,则添加相应的激活函数层,这里默认为Relu
        if activation_fn is not None:
            outputs = activation_fn(outputs)

        return outputs

其他待更

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaobai_Ry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值