CNN是把未知图案和标准X图案一个局部一个局部的对比
A ConvNet is made up of Layers. Every Layer has a simple API: It transforms an input 3D volume to an output 3D volume with some differentiable function that may or may not have parameters.(卷积神经网络是由层组成的。每一层都有一个简单的API:用一些含或者不含参数的可导的函数,将输入的3D数据变换为3D的输出数据)
In particular, the CONV/FC layers perform transformations that are a function of not only the activations in the input volume, but also of the parameters (the weights and biases of the neurons). On the other hand, the RELU/POOL layers will implement a fixed function. The parameters in the CONV/FC layers will be trained with gradient descent so that the class scores that the ConvNet computes are consistent with the labels in the training set for each image.
翻译:
每个层的输入是3D数据,然后使用一个可导的函数将其变换为3D的输出数据。
有的层有参数,有的没有(卷积层和全连接层有,ReLU层和汇聚层没有)。
有的层有额外的超参数,有的没有(卷积层、全连接层和汇聚层有,ReLU层没有)
详细描述CNN里面的各个层。
概述和直观介绍:首先讨论的是,在没有大脑和生物意义上的神经元之类的比喻下,卷积层到底在计算什么。卷积层的参数是有一些可学习的滤波器集合构成的。每个滤波器在空间上(宽度和高度)都比较小,但是深度和输入数据一致。举例来说,卷积神经网络第一层的一个典型的滤波器的尺寸可以是5x5x3(宽高都是5像素,深度是3是因为图像应为颜色通道,所以有3的深度)。在前向传播的时候,让每个滤波器都在输入数据的宽度和高度上滑动(更精确地说是卷积),然后计算整个滤波器和输入数据任一处的内积。当滤波器沿着输入数据的宽度和高度滑过后,会生成一个2维的激活图(activation map),激活图给出了在每个空间位置处滤波器的反应。直观地来说,网络会让滤波器学习到当它看到某些类型的视觉特征时就激活,具体的视觉特征可能是某些方位上的边界,或者在第一层上某些颜色的斑点,甚至可以是网络更高层上的蜂巢状或者车轮状图案。
计算过程:
计算方式就是通过点乘(dot product)的方式,对于每个通道都与分类器(filter)点乘后相加,然后再加上偏差(bias)
输出数据体的深度是一个超参数:它和使用的滤波器的数量一致,而每个滤波器在输入数据中寻找一些不同的东西。
卷积神经网络最常见的形式就是将一些卷积层和ReLU层放在一起,其后紧跟汇聚层,然后重复如此直到图像在空间上被缩小到一个足够小的尺寸,在某个地方过渡成成全连接层也较为常见。最后的全连接层得到输出,比如分类评分等。换句话说,最常见的卷积神经网络结构如下:
INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC
其中*指的是重复次数,POOL?指的是一个可选的汇聚层。其中N >=0,通常N<=3,M>=0,K>=0,通常K<3。例如,下面是一些常见的网络结构规律:
几个小滤波器卷积层的组合比一个大滤波器卷积层好:假设你一层一层地重叠了3个3x3的卷积层(层与层之间有非线性激活函数)。在这个排列下,第一个卷积层中的每个神经元都对输入数据体有一个3x3的视野。第二个卷积层上的神经元对第一个卷积层有一个3x3的视野,也就是对输入数据体有5x5的视野。同样,在第三个卷积层上的神经元对第二个卷积层有3x3的视野,也就是对输入数据体有7x7的视野。假设不采用这3个3x3的卷积层,二是使用一个单独的有7x7的感受野的卷积层,那么所有神经元的感受野也是7x7,但是就有一些缺点。首先,多个卷积层与非线性的激活层交替的结构,比单一卷积层的结构更能提取出深层的更好的特征。其次,假设所有的数据有C个通道,那么单独的7x7卷积层将会包含C×(7×7×C)=49C2C\times (7\times 7\times C)=49C^2C×(7×7×C)=49C2个参数,而3个3x3的卷积层的组合仅有3×(C×(3×3×C))=27C23\times (C\times (3\times 3\times C))=27C^23×(C×(3×3×C))=27C2个参数。直观说来,最好选择带有小滤波器的卷积层组合,而不是用一个带有大的滤波器的卷积层。前者可以表达出输入数据中更多个强力特征,使用的参数也更少。唯一的不足是,在进行反向传播时,中间的卷积层可能会导致占用更多的内存。
到现在为止,我们都没有提及卷积神经网络中每层的超参数的使用。现在先介绍设置结构尺寸的一般性规则,然后根据这些规则进行讨论:
输入层(包含图像的)应该能被2整除很多次。常用数字包括32(比如CIFAR-10),64,96(比如STL-10)或224(比如ImageNet卷积神经网络),384和512。
卷积层应该使用小尺寸滤波器(比如3x3或最多5x5),使用步长S=1。还有一点非常重要,就是对输入数据进行零填充,这样卷积层就不会改变输入数据在空间维度上的尺寸。比如,当F=3,那就使用P=1来保持输入尺寸。当F=5,P=2,一般对于任意F,当P=(F-1)/2的时候能保持输入尺寸。如果必须使用更大的滤波器尺寸(比如7x7之类),通常只用在第一个面对原始图像的卷积层上。
汇聚层负责对输入数据的空间维度进行降采样。最常用的设置是用用2x2感受野(即F=2)的最大值汇聚,步长为2(S=2)。注意这一操作将会把输入数据中75%的激活数据丢弃(因为对宽度和高度都进行了2的降采样)。另一个不那么常用的设置是使用3x3的感受野,步长为2。最大值汇聚的感受野尺寸很少有超过3的,因为汇聚操作过于激烈,易造成数据信息丢失,这通常会导致算法性能变差。
减少尺寸设置的问题:上文中展示的两种设置是很好的,因为所有的卷积层都能保持其输入数据的空间尺寸,汇聚层只负责对数据体从空间维度进行降采样。如果使用的步长大于1并且不对卷积层的输入数据使用零填充,那么就必须非常仔细地监督输入数据体通过整个卷积神经网络结构的过程,确认所有的步长和滤波器都尺寸互相吻合,卷积神经网络的结构美妙对称地联系在一起。
为什么在卷积层使用1的步长?在实际应用中,更小的步长效果更好。上文也已经提过,步长为1可以让空间维度的降采样全部由汇聚层负责,卷积层只负责对输入数据体的深度进行变换。
为何使用零填充?使用零填充除了前面提到的可以让卷积层的输出数据保持和输入数据在空间维度的不变,还可以提高算法性能。如果卷积层值进行卷积而不进行零填充,那么数据体的尺寸就会略微减小,那么图像边缘的信息就会过快地损失掉。
因为内存限制所做的妥协:在某些案例(尤其是早期的卷积神经网络结构)中,基于前面的各种规则,内存的使用量迅速飙升。例如,使用64个尺寸为3x3的滤波器对224x224x3的图像进行卷积,零填充为1,得到的激活数据体尺寸是[224x224x64]。这个数量就是一千万的激活数据,或者就是72MB的内存(每张图就是这么多,激活函数和梯度都是)。因为GPU通常因为内存导致性能瓶颈,所以做出一些妥协是必须的。在实践中,人们倾向于在网络的第一个卷积层做出妥协。例如,可以妥协可能是在第一个卷积层使用步长为2,尺寸为7x7的滤波器(比如在ZFnet中)。在AlexNet中,滤波器的尺寸的11x11,步长为4。
对一个思维的输入数据 input 和四维的卷积核filter 进行操作,然后对输入的数据进行二维的卷积操作,得到卷积之后的结果,也是我们最常用的卷积函数。主要用在图像卷积方面
函数原型:tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
参数介绍:
除去name参数用以指定该操作的name,与方法有关的一共五个参数:(一般需要指定的前四个参数)
input
:指需要做卷积的输入图像,它要求是一个Tensor,具有[batch, in_height
,in_width
, in_channels
]这样的shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数]filter
:相当于CNN中的卷积核,它要求是一个Tensor,具有[filter_height
, filter_width
, in_channels
, out_channels
]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,有一个地方需要注意,第一、二、三维filter_height
, filter_width
,in_channels
,就是参数input的第二、三、四维[in_height,in_width, in_channels
]。padding
:string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式。tensorflow padding之SAME和VALIDuse_cudnn_on_gpu
:bool类型,是否使用cudnn加速,默认为true一般input
的in_channels
和filter里面的in_channels
应该保持一致
示例代码:
input_data = tf.Variable(np.random.rand(10, 9, 9, 3), dtype=np.float32)
filter_data = tf.Variable(np.random.rand(2, 2, 3, 2), dtype=np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides=[1, 1, 1, 1], padding='SAME')
print('tf.nn.conv2d : ', y)
# tf.nn.conv2d : Tensor("Conv2D:0", shape=(10, 9, 9, 2), dtype=float32)
# 在padding='SAME'时输入输出的图像大小是一致的
相关参考可参阅:Tensorflow:卷积函数
如果说tf.nn.conv1d主要用在图像处理上,那么tf.nn.conv1d则是主要用于NLP对向量进行处理,当然tf.nn.conv1d完全可以用在CV方面。
函数原型:tf.nn.conv1d(inputs, filters, stride, padding, use_cudnn_on_gpu=None, data_format=None,name=None)
参数介绍:((以NHWC格式为例,即,通道维在最后))
inputs
: [batch, in_width, in_channels] 是一个3-D张量,batch为样本维,表示多少个样本,in_width为宽度维,表示样本的宽度,in_channels维通道维,表示样本有多少个通道。 (事实上,也可以把格式看作如下:[batch, 行数, 列数],把每一个样本看作一个平铺开的二维数组。这样的话可以方便理解。)filters
: [filter_width, in_channels, out_channels] 是一个3-D张量,filter_width可以看作每次与value进行卷积的行数,in_channels表示value一共有多少列(与value中的in_channels相对应)。out_channels表示输出通道,可以理解为一共有多少个卷积核,即卷积核的数目。stride
: 一个整数,表示步长,每次(向下及在行
的维度上)移动的距离(TensorFlow中解释是向右移动的距离,这里可以看作向下移动的距离)。padding
:SAME or VALID 是否用0填充,SAME用0填充,VALID不使用0填充。tensorflow padding之SAME和VALIDuse_cudnn_on_gpu
:是否使用gpu加速,True or Flasedata_format
: [batch, in_channels, in_width]name
:名称。可省略。一般input
的in_channels
和filter里面的in_channels
应该保持一致。
示例代码:
import tensorflow as tf
import numpy as np
# 定义一个矩阵a,表示需要被卷积的矩阵。
a = np.array(np.arange(1, 1 + 20).reshape([1, 10, 2]), dtype=np.float32)
# 卷积核,此处卷积核的数目为1
kernel = np.array(np.arange(1, 1 + 4), dtype=np.float32).reshape([2, 2, 1])
# 进行conv1d卷积
conv1d = tf.nn.conv1d(a, kernel, 1, 'VALID')
with tf.Session() as sess:
# 初始化
tf.global_variables_initializer().run()
# 输出卷积值
print(sess.run(conv1d))
结果:
[[[ 30.]
[ 50.]
[ 70.]
[ 90.]
[110.]
[130.]
[150.]
[170.]
[190.]]]
参考链接
参考链接
相关参考: