2017年8月19日星期六整理第五章部分
此处给出本节的代码:https://github.com/Leechen2014/TensorFlow-for-Machine-Intelligence
相关的文件描述在github中给出。
PS:翻译来源:
http://shop.oreilly.com/product/9781939902351.do
Convolution
顾名思义,卷积运算是卷积神经网络中重要的组成部分。CNN能够精确的匹配多种模式的能力可以归因于卷积计算。正如上一节所示,这些操作需要复杂的输入。在本节中,我们将实验卷积运算和调节他的可用参数。现在要将两个输入的张量(输入和卷积核)卷积为一个输出张量,该输出张量代表每一个输入的信息。
Input and Kernel (输入和卷积核)
在通常情况下Tensorflow中的卷积操作是使用tf.nn.conv2d。还有其他的用例是使用TensorFlow设计的特殊卷积操作。tf.nn.conv2d是开始进行实验的首选卷积运算。例如,我们将两个张量卷积在一起并检查结果。
input_batch=tf.constant([
[# First Input[[0.0], [1.0]],
[[2.0], [3.0]]
],
[# Second Input[[2.0], [4.0]],
[[6.0], [8.0]]
]
])
kernel=tf.constant([
[
[[1.0,2.0]]
]
])
上述代码创建了两个张量。Input_batch张量的形状和上一节见过的image_batch张量的形状类似。第一个张量将会是被卷积的,第二个张量是作为卷积核的。卷积核(Kernel)是一个很重要的术语,其可以与权重(weights)、滤波器(filter)、卷积矩阵(convolution matrix)、掩码(filter)互换。由于这个任务和计算机视觉相关,所以使用术语内核是对的,因为这种东西在计算机视觉中被称为图像内核。当用tensorflow描述功能的时候,术语之间没有实际的差别。
我们在上面的例子中创建了两个张量(tensor).张量Input_batch的形状和上一节中见到的image_batch的形状很像。这第一个张量将会是是被卷积的,第二个tensor将会是卷积核。Kernel是一个很重要的术语,有的时候会被称为权重(weights),过滤器(filter),卷积矩阵(convolution matrix)或者是膜(mask)。由于这个任务(task)与计算机视觉相关,常常被看做image kernel,所以使用kernel这个术语有一定意义。在Tensorflow中描述这个函数的时候,没有本质上的区别。在Tensorflow中的参数被称为filter,它是一个从训练中学习到的一组权重(weights)的集合。(PS:嘿嘿,这个时候看看filter., weights )。
kernel ( filter parameter)中包含的大量不同的权重将会在学习过程中被修改。
在示例代码中,有一个内核是kernel变量的第一个维度。kernel被构建后返回一个张量,其将包括第一个通道与原始输入和原始输入第二个通道加倍(2)。在本文中,通道(channel)用于描述秩(rank)为1的张量(也就是向量)中的元素。通道是计算机视觉中描述输出向量的术语,例如RGB图像具有三个通道,表示为rank为1的张量[红,绿,蓝]。现在,想不讲stride和padding参数,这两个参数将在以后的section中介绍,随后也会集中关注卷积(tf.nn.conv2d)输出。
conv2d = tf.nn.conv2d(input_batch, kernel, strides=[1, 1,1, 1], padding='SAME')
sess.run(conv2d)
示例执行后输出的结果是:
array([[[[ 0., 0.],
[ 1., 2.]],
[[ 2., 4.],
[ 3., 6.]]],
[[[ 2., 4.],
[ 4., 8.]],
[[ 6., 12.],
[ 8., 16.]]]], dtype=float32)
输出的也是一个tensor,它的rank和input_batch一样,而且维度的数量也可以在kernel里面发现.想象一下,如果input_batch代表一个只有一个通道的图像,也就是灰度级图像. Tensor中的每个元素代表图像上的每个像素点.那么,图像右下角的像素值将为3.0。
将卷积操作tf.nn.conv2d看作为图像(用input_batch表示)和张量kernel的结合操作.这两个tensor的卷积会产生一个特征图(a feature map).特征图是一个广泛的术语,不仅仅只在计算机视觉中出现,它涉及与图像内核一起使用的操作的输出。当向output添加新图层的时候,特征图代表了这些张量的卷积.
输入图像和特征图输出之间的关系可以从代码中深入探索.我们可以使用相同的索引,在输入批次和特征图中访问元素。当访问同一个像素下的输入和特征的时候,可以显示出当输入和kernel卷积后的变化.在下面的示例中,可以发现图像中右下角的像素被改变,并可以通过乘法的方式找到改变后的值: 3.0*1.0和3.0*2.0 .相应的像素值以及对应的kernel的值可以用以下方式找到:
lower_right_image_pixel = sess.run(input_batch)[0][1][1]
lower_right_kernel_pixel = sess.run(conv2d)[0][1][1]
lower_right_image_pixel, lower_right_kernel_pixel
上述代码执行后,会输出:
(array([ 3.], dtype=float32), array([ 3., 6.],dtype=float32))
在这个简单的示例中,图像中的每个像素和卷积核中的对象值相乘,并添加到相应的特征图层(layer)中.在上下文中, Layer(层)指的是输出的新维度.在这个例子中很难看到卷积运算过程中的值。
Strides(步长)
卷积在计算机视觉中的价值在于它能够降低输入维度,在本案中输入指的是图像。一个图像(2D图像)的维度是它的宽,高和通道数。对于神经网络来说,扫描一个庞大的图像维度并判断哪些像素重要,这需要消耗大量的时间。使用卷积降低图像的维数是通过改变内核的strides(步长)来完成的。
参数strides可以使得卷积核跳过图像中的像素并在输出的中不包含这些像素。说哪些像素被跳过是不公平的,因为这些像素仍然可能会影响输出。当使用较大的图像和更复杂的内核时,strides参数会突出显示如何与内核一起使用卷积操作。由于卷积是将内核滑过输入,可以使用strides来设置如何在input上行走(walk). strides参数可以配置卷积以跳过某些元素,而不是遍历输入的每个元素。
PS:作者对这个卷积核的操作描述为walk实在是很形象,
例如,采取较大图像和较大内核的卷积。在这种情况下,它是6像素高,6像素宽和1通道深图像(6x6x1)和(3x3x1)内核之间的卷积。
input_batch = tf.constant([
[ # First Input (6x6x1)
[[0.0], [1.0], [2.0], [3.0], [4.0], [5.0]],
[[0.1], [1.1], [2.1], [3.1], [4.1], [5.1]],
[[0.2], [1.2], [2.2], [3.2], [4.2], [5.2]],
[[0.3], [1.3], [2.3], [3.3], [4.3], [5.3]],
[[0.4], [1.4], [2.4], [3.4], [4.4], [5.4]],
[[0.5], [1.5], [2.5], [3.5], [4.5], [5.5]],
],
])
kernel = tf.constant([ # Kernel (3x3x1)
[[[0.0]], [[0.5]], [[0.0]]],
[[[0.0]], [[1.0]], [[0.0]]],
[[[0.0]], [[0.5]], [[0.0]]]
])
# NOTE: the change in the size of the strides parameter.
conv2d = tf.nn.conv2d(input_batch, kernel, strides=[1, 3,3, 1], padding='SAME')
sess.run(conv2d)
代码执行后的输出如下:
array([[[[ 2.20000005],
[ 8.19999981]],
[[ 2.79999995],
[ 8.80000019]]]], dtype=float32)
通过在input_batch上按照步长移动kernel使得inpout_batch变量与kernel变量结合.每次kernel移动后,他会在input_batch中得到确定的元素.然后将重叠值相乘并将结果加在一起。这是一个卷积如何使用所谓的逐点乘法去组合(combines)的两个输入。使用下图可能更直观。
在该图中,遵循代码中的相同的逻辑。将两个张量进行卷积,同时使用跨越(stries)输入。当内核大小允许卷积使用所有的输入值的时候,跨越(strides)会大幅度降低了输出的维度.没有一个输入数据完全从striding中移除,除非输入的张量较小。Strides是调节输入争来那个维度的一种方式.降低维度需要更少的处理能力,并且不会产生完全重叠的接受场(overlap)。strides参数遵循与输入张量相同的格式
[image_batch_size_stride,image_height_stride,image_width_stride,image_channels_stride]。
通常情况下,很少更改stride参数的第一个或最后一个元素,因为这俩元素会使得tf.nn.conv2d操作跳过数据,并且不再考虑输入数据了. image_height_stride和image_width_stride在减少输入维数方面有用.
// ps作者在最后抛出一个问题,并预示着下一节的内容
跨越输入的挑战经常是如何处理不均匀地结束在输入边缘的步幅。这通常是由于图像大小和内核大小不匹配,不均匀的步幅的时候会出现的问题。如果图像大小,内核大小和步幅都不能改变,则填充(padding)可以添加到图像中以处理不均匀区域。
5.2.2 Padding
当内核重叠在图像上时,应将其设置为适合图像的边界。有时,尺寸可能不适合,一个很好的选择是填补图像中的缺失区域。填充图像的缺失区域称为填充图像。
TensorFlow会将用零填充图像,或者当尺寸不允许内核跨越图像而不超过其边界时会引发错误。tf.nn.conv2d的零的数量或错误状态具是由两个参数来控制padding.('VALID','SAME')。
SAME:意味着卷积的输出和输入的大小一样,当计算如何跨越图像时,这不考虑过滤器尺寸;当将所有缺少的值填充为零时,这可能会跨越存在的图像的边界。
VALID:在计算如何跨越图像时要考虑滤镜尺寸。这将尽可能将大量的保持内核在图像的范围内。在某些情况下可能有填充,但会避免。
//PS 作者这是给出了经验贴:
最好考虑输入的大小,但是如果填充是必要的,那么TensorFlow有内置的选项。在大多数简单的情况下,SAME是一个很好的选择。当输入和内核与步幅良好时,优先使用VALID。有关更多信息,TensorFlow在卷积文档中很好地介绍了该话题().
Data Format
Tf.nn.conv2d的另一个参数是Data
Format,在以上的例子中并没有使用到, tf.nn.conv2d的官方文档中解释其是更改数据格式,以便input,kernel和strides遵循迄今为止使用的格式以外的格式。如果输入input tensor不是遵守[bantch_size,
height, width, channel]标准的话,修改数据格式还是很有用的.这种情况出现的话,可以不将输入更改为所匹配的形式,更改data_format参数以使用不同的布局就行了.
DataFormatdata_format: An optional string from: “NHWC”, “NCHW”.Defaults to “NHWC”. Specify the data format of the input and output data. Withthe default format “NHWC”, the data is stored in the order of: [batch,in_height, in_width, in_channels]. Alternatively, the format could be “NCHW”,the data storage order of: [batch, in_channels, in_height, in_width]
-------------------------------------------by 8月8号 --------------------------------
Kernels in Depth(卷积核和深度)
在TensorFlow中,filter参数用于指定与输入进行卷积的内核。过滤器通常是摄影中以调整图像的属性,例如允许到达相机镜头的阳光的量。在摄影中,过滤器允许摄影师彻底改变他们拍摄的照片。摄影师能够使用过滤器改变照片的原因是因为过滤器可以识别进入镜头的光的某些属性。例如,红色透镜滤光片将吸收(阻挡)不是红色的每个频率的频率,只允许红色通过滤光片。
在计算机视觉中,内核(过滤器)用于识别数字图像的重要属性。他们通过使用某些模式来突出显示图像中存在的特征。将复制红色滤镜示例图像的内核通过对除红色以外的所有颜色使用减小值来实现。在这种情况下,红色将保持不变,但所有其他匹配的颜色都会减少。
本章开始的例子使用了一个设计用于执行边缘检测的内核。边缘检测内核在计算机视觉应用中是常见的,并且可以使用基本的TensorFlow操作和单个tf.nn.conv2d操作来实现。
核心代码: 效果图输出是将一个图像和边缘检测核进行卷积产生的,可以看出是检测到边缘的所有区域。
代码中假定一批已经从磁盘中加载的真实图像是可用的(这批图像是image_batch)在本示例中的图像可以从Stanford
Dogs Dataset中找到。Kernel拥有三个通道。这些通道会与[0,255]之间的RGB值同步,255是最大强度。调用tf.minimum和tf.nn.relu是将卷积值保持在有效RGB颜色的范围内,即[0,255]。
在这个简化的例子中可以使用许多其他常用的内核。不同的模式会产生不同的结果。以下内核将通过增加颜色变化的强度来锐化图像。
使用卷积核进行的 锐化处理对比之前的卷积核,我们发现内核中的值被调整,内核的中心强度增加,内核周围的区域强度降低。内核的变化使得可以匹配强烈像素的图案,并增加输出图像的强度。这种变化在视觉上被锐化。注意:请注意,内核的角都全为0,使得以加号形式运行的输出不会受到影响。
这些内核在图像基础上匹配模式。卷积神经网络通过使用在训练期间学到的复杂内核要比之更多。内核的初始值通常是随机的,随着时间的推移,它们(n内核里面的值)会被CNN的学习层训练。当CNN是完整的的时候,开始运行并且发送每个图像与内核的卷积结果,然后根据预测值与图像的label value来对卷积核进行更改。例如:如果一个Sheepdog(是不是应该翻译成牧羊犬?)的图片在训练期间被CNN判断为公牛,那么它(CNN)会修改过滤器(卷积核)的数量以便于更好的尝试匹配SheepDog图片。
用CNN学习负载的模式的时候,往往涉及的不仅仅是一层卷积。即便是我们的代码示例也要包含一个tf.nn.relu层,为可视化输出做准备。卷积层可能在CNN中发生多次,但它们也可能包括其他层类型。这些层的组合成功的成为CNN架构所需的支持网络。
(PS:接下来5.3来会讲解这些内容)
网友评论