CNN架构

简单的CNN架构通常包含卷积层(tf.nn.conv2d)、非线性变换层(tf.nn.relu)、池化层(tf.nn.max_pool)及全连接层(tf.nn.matmul)。如果没有这些层,模型便很难与复杂的模式匹配,因为网络将被填充过多的信息。一个设计良好的CNN架构会突出那些重要的信息,而将噪声忽略。

1.get_shape

TensorFlow的输入流水线(用于读取和解码文件)拥有一种为使用一个批数据中的多幅图像而设计的专门格式,它包括了任意一幅图像所需的信息([image_batch_size,image_height,image_width,image_channels])

import tensorflow as tf
import numpy as np
sess = tf.InteractiveSession()
image_batch = tf.constant([
        [  # First Image
            [[0, 255, 0], [0, 255, 0], [0, 255, 0]],
            [[0, 255, 0], [0, 255, 0], [0, 255, 0]]
        ],
        [  # Second Image
            [[0, 0, 255], [0, 0, 255], [0, 0, 255]],
            [[0, 0, 255], [0, 0, 255], [0, 0, 255]]
        ]
    ])
#image_batch.get_shape
#sess.run(image_batch)[0][0][0]
print(image_batch) # Tensor("Const:0", shape=(2, 2, 3, 3), dtype=int32)
print(sess.run(image_batch)[0][0][0]) # [  0 255   0]

上述代码创建了一个包含两幅图像的图像批数据。每幅图像的高为2个像素,宽为3个像素,且颜色空间为RGB。执行后的输出的第1组维度表明了图像数量,第2组维度对应图像的高度,第3组维度表明了图像的宽度,而颜色通道数量对应于最后一组维度。

变量image_batch并不会从磁盘直接加载图像,而是将自身当成作为输入流水线的一部分而被加载的图像。使用输入流水线从磁盘加载的图像拥有相同的格式和行为。一种常见的做法是创建一些与上述image_batch实例相似的假数据对CNN的输入和输出进行测试。这种简化的输入会使诊断和调试一些简单问题更加容易。简化调试过程非常重要,因为CNN架构极为复杂,训练经常需要耗费数日。

2.卷积

import tensorflow as tf
import numpy as np
sess = tf.InteractiveSession()
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]]
        ]
    ])
conv2d = tf.nn.conv2d(input_batch, kernel, strides=[1, 1, 1, 1], padding='SAME')
sess.run(conv2d)

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

设置跨度是一种调整输入张量维数的方法。降维可减少所需的运算量,并可避免创建一些完全重叠的感受域。strides参数的格式与输入向量相同,即(image_batch_size_stride、image_height_stride、image_width_stride、image_channels_stride)。第1个和最后一个跨度参数通常很少修改,因为它们会在tf.nn.conv2d运算中跳过一些数据,从而不将这部分数据予以考虑。如果希望降低输入的维数,可修改image_height_stride和image_width_stride参数。

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]]]
    ])
conv2d = tf.nn.conv2d(input_batch, kernel, strides=[1, 3, 3, 1], padding='SAME')
sess.run(conv2d)
print(conv2d.eval())

tf.nn.conv2d的零填充数量或错误状态是由参数padding控制的,它的取值可以是SAME或VALID。

·SAME :卷积输出与输入的尺寸相同。这里在计算如何跨越图像时,并不考虑滤波器的尺寸。选用该设置时,缺失的像素将用0填充,卷积核扫过的像素数将超过图像的实际像素数。

·VALID :在计算卷积核如何在图像上跨越时,需要考虑滤波器的尺寸。这会使卷积核尽量不越过图像的边界。在某些情形下,可能边界也会被填充。

3.池化层

池化层能够减少过拟合,并通过减小输入的尺寸来提高性能。它们可用于对输入降采样,但会为后续层保留重要的信息。只使用tf.nn.conv2d来减小输入的尺寸也是可以的,但池化层的效率更高。

4.归一化

归一化层并非CNN所独有。在使用tf.nn.relu时,考虑输出的归一化是有价值的。由于ReLU是无界函数,利用某些形式的归一化来识别那些高频特征通常是十分有用的。




猜你喜欢

转载自blog.csdn.net/qq_25366173/article/details/80227425
CNN