我已经用Python实现了一个简单的CNN程序,可以通过机器学习MNIST数据集。我实施了3层:
我在ConvPoolLayer中实现了平均池化。这是在前向传播期间意味着汇集的代码行:
# 'activation' is a numpy array of 3D activations from the convolutional code (not shown here)
skimage.measure.block_reduce(activation, block_size=(1, 1, 2, 2), func=np.mean)
这里是等效的反向传播代码:
# delta is a numpy array of 3D error matrices back-propagated from the upper layers
delta = delta.repeat(2, axis=2).repeat(2, axis=3)
它所做的只是提升错误。
我的问题是,如何在不损失性能的情况下实现最大池化的反向传播?或者,没有函数调用有更好的方法吗?在使用平均池进行几次迭代后,我得到了约90-95%的准确度,因此我想看看最大池对性能的影响。
如果有任何可以在这里应用的NumPy技巧,我很乐意学习它们。我想了解自己在CNN中发生了什么,为什么事情按照他们的方式工作,以及操作是否可以优化,所以使用框架对我来说不是一个选择。
感谢您的帮助!
答案 0 :(得分:3)
[updated]对于最大池使用的前向传播:
skimage.measure.block_reduce(activation, block_size=(1, 1, 2, 2), func=np.max)
您对平均合并的反向传播并不完全正确。您应该根据合并单元格的数量来划分delta(在您的情况下为4)。请参阅http://www.slideshare.net/kuwajima/cnnbp
要传播最大池,您只需将delta指定给前向传递中具有最高值的单元格。因此,在汇集层的正向通过期间,通常跟踪最大激活的索引(有时也称为开关),使得梯度路由在反向传播期间是有效的。请参阅http://cs231n.github.io/convolutional-networks/#pool
实现此目的的效率非常低:
#forward
activationPrevious = np.copy(activation)
skimage.measure.block_reduce(activation, block_size=(1, 1, 2, 2), func=np.max)
maxs = activations.repeat(2, axis=2).repeat(2, axis=3)
mask = np.equal(activationPrevious, maxs).astype(int)
#backward
delta = delta.repeat(2, axis=2).repeat(2, axis=3)
delta = np.multiply(delta, mask)