卷积运算
<nobr> s(t)=∫x(a)w(t−a)da </nobr>
这种操作叫做卷积。卷积运算通常用星号表示:
<nobr> s(t)=(x∗w)(t) </nobr>
卷积的第一个参数通常叫做输入,第二个参数叫做核函数。输出有时被称为特征映射。
如果假设 <nobr> x </nobr>和 <nobr> w </nobr>都定义在整数t上,可定义离散形式的卷积:
<nobr> s(t)=(x∗w)(t)=∑a=−∞∞x(a)w(t−a) </nobr>
动机
卷积运算通过三个重要思想帮助改进机器学习系统:稀疏连接,参数共享,等变表示。
稀疏连接
传统神经网络使用矩阵乘法建立输入与输出的连接关系。参数矩阵的每一个单独的参数都描述了一个输入单元与一个输出单元间的交互。卷积网络通过使核的大小远小于输入的大小来达到稀疏连接的目的。
如果有m个输入和n个输出,矩阵乘法需要m*n个参数。如果限制每一个输出拥有的连接数为k,那么稀疏的连接方法只需k*n个参数。
参数共享
参数共享是指在一个模型的多个函数中使用相同的参数。
在卷积网络中,核的每一个元素都作用在输入的每一个位置上。
等变表示
对于卷积,参数共享的特殊形式使得神经网络具有对平移等变的性质。如果一个函数满足输入改变,输出也以同样的方式改变,就说它是等变的。
卷积对其他的一些变换并不是天然等变的,例如对于图像的放缩或旋转变换,需要其他的机制来处理这些变换。
池化
池化函数使用某一位置的相邻输出的总体统计特征来代替网络在该位置的输出。例如最大池化,平均池化,L2范数,基于距中心像素距离的加权平均函数等。
当输入做出少量平移时,池化能够帮助输入的表示近似不变。局部平移不变性是一个很有用的性质,尤其是当我们关心某个特征是否出现而不关心它出现的具***置时。
使用池化可以看作是增加了一个无限强的先验:这一层学得的函数必须具有对少量平移的不变性。
池化综合了全部邻居的反馈,使得池化单元少于探测单元成为可能。
卷积与池化作为一种无限强的先验
一个无限强的先验需要对一些参数的概率置零并且完全禁止对这些参数赋值,无论数据对于这些参数的值给出了多大的支持。
卷积和池化可能导致欠拟合。与任何其他先验类似,卷积和池化只有当先验的假设合理且正确时才有用。
当一项任务涉及到要对输入中相隔较远的信息进行合并时,那么卷积所利用的先验可能就不正确了。
池化后的维度计算公式为
<nobr> 1+(W−F)/S </nobr>
基本卷积函数的变体
我们通常希望网络的每一层能够在多个位置提取多种类型的特征。
我们可以对全卷积函数输出进行下采样来降低计算开销(代价是提取的特征没有先前那么好)。在输出的每个方向上,每间隔s个像素进行采样。s称为下采样卷积的步幅stride。
任何卷积网络的实现都有一个重要的性质,能够隐含地对输入V用零进行填充(pad)使得它加宽。如果没有这个性质,标识的宽度在每一层就会缩减,缩减的幅度是比核少一个像素这么多。
相关计算
卷积输出维度的计算
输入层维度是 <nobr> W </nobr>,滤波器的维度为 <nobr> F(height∗width∗depth) </nobr>,stride为 <nobr> S </nobr>,padding的数量为 <nobr> P </nobr>,则下一层的维度为
<nobr> 1+(W−F+2P)/S </nobr>
对于无法整除情况,一般卷积操作向下取整,池化操作向上取整。
TensorFlow维度计算
input = tf.placeholder(tf.float32, (None, 32, 32, 3))
filter_weights = tf.Variable(tf.truncated_normal((8, 8, 3, 20))) # (height, width, input_depth, output_depth)
filter_bias = tf.Variable(tf.zeros(20))
strides = [1, 2, 2, 1] # (batch, height, width, depth)
padding = 'VALID'
conv = tf.nn.conv2d(input, filter_weights, strides, padding) + filter_bias
当使用SAME Padding时
out_height
= ceil(float(in_height)/flaot(strides[1]))
out_width
= ceil(float(in_width)/flaot(strides[2]))
当使用VALID Padding时
out_height
=ceil(float(in_height-filter_height+1)/float(strides[1]))
out_width
=ceil(float(in_width-filter_width+1)/float(strides[2]))
参数数量计算
- 输入为32*32*3(H*W*D)
- 20个滤波器8*8*3(H*W*D)
- 步长高和宽均为2(S)
- padding大小为1(P)
则输出层为1+(32-8+2)/2=14
14*14*20(H*W*D) - 无参数共享
若没有参数共享,每个输出层的神经元必须连接到滤波器的每个神经元,此外,每个输出层的神经元必须连接到一个偏置单元,
则卷积层参数为(8*8*3+1)*(14*14*20)=756560 - 有参数共享
有了参数共享,每个输出通道的神经元与相同通道的其它神经元共享权值。参数的数量与滤波器神经元的数量相同,加上偏置,再乘以输出层的通道数。
(8 * 8 * 3 + 1) * 20 = 3840 + 20 = 3860