[翻译 chapter 5 ]
PS: 有一部分在另外一台电脑上, 明天稍后给出
Input and Kernel
我们在上面的例子中创建了两个张量(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)可以添加到图像中以处理不均匀区域。
Padding
当内核重叠在图像上时,应将其设置为适合图像的边界。 有时,尺寸可能不适合,一个很好的选择是填补图像中的缺失区域。 填充图像的缺失区域称为填充图像。
TensorFlow会将用零填充图像,或者当尺寸不允许内核跨越图像而不超过其边界时会引发错误。 tf.nn.conv2d的零的数量或错误状态具是由两个参数来控制padding. ('VALID','SAME')。
SAME: 意味着卷积的输出和输入的大小一样, 当计算如何跨越图像时,这不考虑过滤器尺寸; 当将所有缺少的值填充为零时,这可能会跨越存在的图像的边界。
VALID: 在计算如何跨越图像时要考虑滤镜尺寸。 这将尽可能将大量的保持内核在图像的范围内。在某些情况下可能有填充,但会避免。
// 给出了经验贴
最好考虑输入的大小,但是如果填充是必要的,那么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参数以使用不同的布局就行了.
data_format: An optional string from: “NHWC”, “NCHW”. Defaults to “NHWC”. Specify the data format of the input and output data. With the 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操作来实现。