【问题标题】:TensorFlow CNN Tutorial: How to edit top layer to be locally connected?TensorFlow CNN 教程:如何编辑顶层以进行本地连接?
【发布时间】:2017-01-19 05:44:43
【问题描述】:

我在机器学习和 python 方面有一些背景,但我只是在学习 TensorFlow。我正在通过tutorial on deep convolutional neural nets 教自己如何使用它进行图像分类。一路上有一个练习,我无法完成。

练习: inference() 中的模型架构与 cuda-convnet 中指定的 CIFAR-10 模型略有不同。特别是,Alex 的原始模型的顶层是局部连接的,而不是全连接的。尝试编辑架构以在顶层精确再现本地连接的架构。

练习参考cifar10.py model 中的 inference() 函数。倒数第二层(称为 local4)的 shape=[384, 192],顶层的 shape=[192, NUM_CLASSES],其中 NUM_CLASSES=10。我认为我们被要求编辑的代码位于定义顶层的代码中:

with tf.variable_scope('softmax_linear') as scope:
    weights = _variable_with_weight_decay('weights', [192, NUM_CLASSES],
                                      stddev=1/192.0, wd=0.0)
    biases = _variable_on_cpu('biases', [NUM_CLASSES],
                          tf.constant_initializer(0.0))
    softmax_linear = tf.add(tf.matmul(local4, weights), biases,name=scope.name
    _activation_summary(softmax_linear)

但是我没有看到任何确定层之间连接概率的代码,所以我不知道我们如何将模型从完全连接更改为本地连接。有人知道怎么做吗?

【问题讨论】:

    标签: python tensorflow conv-neural-network


    【解决方案1】:

    我也在做这个练习。我将尝试正确解释我的方法,而不仅仅是给出解决方案。值得回顾一下全连接层的数学原理 (https://www.tensorflow.org/get_started/mnist/beginners)。

    所以全连接层的线性代数是:

    y = W * x + b

    其中 x 是 n 维输入向量,b 是偏置的 n 维向量,W 是一个 n-by-n 权重矩阵。 y 的第 i 个元素是 W 的第 i 行元素乘以 x 的总和.

    所以....如果你只希望 y[i] 连接到 x[i-1],x[i] , 和 x[i+1],您只需将 W 的第 i 行中的所有值设置为零,除了 (i-1) 列、第 i 列和第 (i+1) 列。因此,要创建一个局部连接层,您只需将 W 强制为带状矩阵 (https://en.wikipedia.org/wiki/Band_matrix),其中带状的大小等于您想要的局部连接邻域的大小。 Tensorflow 有一个设置矩阵的功能(tf.batch_matrix_band_part(input, num_lower, num_upper, name=None))。

    在我看来,这是该练习最简单的数学解法。

    【讨论】:

    • 这个答案不能解决这个问题。 W 矩阵必须是“多带的”。例如,如果滤波器是 3x3,那么应该有 3 个对角带,每个带 3 个元素宽。 tf.matrix_band_part() 只允许一个波段。此外,W 的尺寸会发生变化,我们不能只取原始 W 并将某些元素设置为零。具体来说,W 中的行数必须等于展平输出特征图的长度。我认为 Xyand 的答案是一种更好的方法:提取图像块,并将每个块乘以它自己的内核,因此权重张量获得两个额外的维度(变为 6D)。
    • 很公平。这只是我试图掌握某种数学知识,以提供有关如何解决此练习的线索。我认为他们进行练习的原因是为了让人们自己思考,所以我并不是真的想给出一些可以复制/粘贴的代码,而是帮助基本了解如何在理论上解决这个问题。我发现在使用神经网络时理解一些线性代数很有帮助,而不仅仅是工程。
    • 我已经有一段时间没有处理这个本地连接层了。但是@DavidPickup 的方法实际上可以通过使用完整矩阵乘以常数指示矩阵 I 来模拟多带矩阵。W 的大小应该是 (w_outh_out) X (w_inh_in*d_in )。但是,这似乎很浪费。我错过了什么吗?
    • 当然,我们可以通过定期插入多个单波段矩阵来构造这样的指标矩阵。除了更大(但稀疏)的 W 之外,我们会引入额外的计算:反向传播会尝试更新那些零权重值,因此我们必须在每次权重更新后执行 WI(或 W_gradI每次更新前)。这种开销可能很大:如果我们假设 WI 与 Wx 一样昂贵,那么我们必须多做约 33% 的工作(掩蔽、前向传递、后向传递),而不仅仅是前向和后向传递.
    【解决方案2】:

    我会尽力回答你的问题,虽然我不是 100% 我也答对了。

    查看 cuda-convnet architecture 我们可以看到 TensorFlow 和 cuda-convnet 的实现在第二个池化层之后开始有所不同。

    TensorFlow 实现实现了两个全连接层和 softmax 分类器。

    cuda-convnet 实现了两个本地连接层,一个全连接层和一个 softmax 分类器。

    您包含的代码 sn-p 仅指 softmax 分类器,实际上在两个实现之间共享。要使用 TensorFlow 重现 cuda-convnet 实现,我们必须将现有的全连接层替换为两个本地连接层和一个全连接层。

    由于 Tensor 没有本地连接层作为 SDK 的一部分,我们必须想办法使用现有工具来实现它。这是我实现第一个本地连接层的尝试:

      with tf.variable_scope('local3') as scope:
        shape = pool2.get_shape()
        h = shape[1].value
        w = shape[2].value
    
        sz_local = 3 # kernel size
        sz_patch = (sz_local**2)*shape[3].value
        n_channels = 64
    
        # Extract 3x3 tensor patches
        patches = tf.extract_image_patches(pool2, [1,sz_local,sz_local,1], [1,1,1,1], [1,1,1,1], 'SAME')
        weights = _variable_with_weight_decay('weights', shape=[1,h,w,sz_patch, n_channels], stddev=5e-2, wd=0.0)
        biases = _variable_on_cpu('biases', [h,w,n_channels], tf.constant_initializer(0.1))
    
        # "Filter" each patch with its own kernel 
        mul = tf.multiply(tf.expand_dims(patches, axis=-1), weights)
        ssum = tf.reduce_sum(mul, axis=3)
        pre_activation = tf.add(ssum, biases)
        local3 = tf.nn.relu(pre_activation, name=scope.name)
    

    【讨论】:

    • 权重形状中的 h 和 w 维度应参考输出特征图的高度和宽度,而不是输入特征图。
    猜你喜欢
    • 1970-01-01
    • 2016-02-20
    • 2020-07-22
    • 2018-03-26
    • 2021-06-09
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 2017-12-06
    相关资源
    最近更新 更多