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是無界函數,利用某些形式的歸一化來識別那些高頻特徵通常是十分有用的。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章