斯坦福TensorFlow課CS20第七講筆記:使用TensorFlow實現CNN
原始課程講義地址
原始課程膠片地址
無特殊說明,筆記內容均來自老師提供的講義和膠片
完整帶圖講義戳我
在MNIST上使用TensorFlow
TensorFlow使用tf.nn.conv2d
來做二維的卷積操作(此時需要輸入是三維)。不同維度輸入的卷積操作可以參考Runhani的StackOverflow回答。函數簽名為
tf.nn.conv2d( input, filter, strides, padding, use_cudnn_on_gpu=True, data_format=NHWC, dilations=[1, 1, 1, 1], name=None)
其中
input
是輸入,默認是四維,每個維度按順序是batch大小(N)、高度(H)、寬度(W)、信道數(C),即shape(input) = (N, H, W, C)
(對應於data_format
參數值NHWC
)filter
對應CNN的卷積核(也就是前面理論部分所講的濾波器),其維度也是四維,不過是高度 x 寬度 x 輸入信道數 x 輸出信道數stride
是長度為4的一維數組,代表在input
四個維度上的步長。通常設為[1, 1, 1, 1]
或[1, 2, 2, 1]
。一般情況下,stride[0] == stride[-1] == 1
,因為不想跳過任何樣本和任何信道padding
是補零的方式而非個數,有兩個選項。- 如果設置為
VALID
,那麼當卷積核和步幅的設置使得卷積過程不能完整覆蓋輸入時,捨棄輸入最右側(或最下側)的內容。根據相關StackOverflow問題的講解,考慮最簡單的1維卷積的情況,假設輸入長度為13,卷積核大小為6,步幅為5,那麼第一次卷積操作所「看」的範圍是1-6,第二次是6-11,此時再移動卷積核不能覆蓋剩下的數據,到此為止,輸入的最後兩個元素被丟棄 - 如果設置為
SAME
,那麼會對輸入補0,使得輸入可以被卷積核按照設定的步幅完整覆蓋。補0的原則是左邊和右邊補的0盡量一樣——如果要補的0是奇數個0,在右側多補一個
- 如果設置為
dilations
是理論講義里提到的膨脹係數。1.4版本里尚未引入這個參數
其它卷積函數,例如depthwise_conv2d
和separable_conv2d
,可以參考文檔
課程講義中給出了一個使用預定義卷積核做計算的例子,不過這種場景在實際應用中估計很難遇到,大部分卷積核都是訓練得出來的(不要忘記卷積核的本質,它就是一組權重)
因此,為了讓例子更加貼近實際,這裡講解對MNIST數據集使用TF構建CNN的方法。這裡使用的體系結構是兩個(卷積+ReLU+最大池)的組合,然後跟兩個全連接。具體的體系結構如下圖所示
由於很多事情(例如最大池、conv)都要做多次,因此需要設計可復用的代碼,而且需要使用變數域來讓我們可以在不同的層使用名字相同的變數。通常是每層都創建自己的變數域
定義卷積層
具體實現時,通常把conv和隨後的非線性變化ReLU實現在一起
def conv_relu(inputs, filters, k_size, stride, padding, scope_name): with tf.variable_scope(scope_name, reuse=tf.AUTO_REUSE) as scope: in_channels = inputs.shape[-1] kernel = tf.get_variable(kernel, [k_size, k_size, in_channels, filters], initializer=tf.truncated_normal_initializer()) biases = tf.get_variable(biases, [filters], initializer=tf.random_normal_initializer()) conv = tf.nn.conv2d(inputs, kernel, strides=[1, stride, stride, 1], padding=padding) return tf.nn.relu(conv + biases, name=scope.name)
個中維度計算可以參考前面的理論講解
定義池化層
可以直接使用TF中的tf.nn.max_pool
來完成
def maxpool(inputs, ksize, stride, padding=VALID, scope_name=pool): with tf.variable_scope(scope_name, reuse=tf.AUTO_REUSE) as scope: pool = tf.nn.max_pool(inputs, ksize=[1, ksize, ksize, 1], strides=[1, stride, stride, 1], padding=padding) return pool
定義全連接
與前面介紹的基本前饋神經網路定義方法無異
def fully_connected(inputs, out_dim, scope_name=fc): with tf.variable_scope(scope_name, reuse=tf.AUTO_REUSE) as scope: in_dim = inputs.shape[-1] w = tf.get_variable(weights, [in_dim, out_dim], initializer=tf.truncated_normal_initializer()) b = tf.get_variable(biases, [out_dim], initializer=tf.constant_initializer(0.0)) out = tf.matmul(inputs, w) + b return out
構成最終代碼
將上面的各個函數組合起來可以得到完整的代碼。講義里給出的是預測的圖,訓練的圖應該是類似的,只不過加了定義loss和優化器的部分(然而GitHub上的代碼並沒有像上面一樣良好地組織)
def inference(self): conv1 = conv_relu(inputs=self.img, filters=32, k_size=5, stride=1, padding=SAME, scope_name=conv1) pool1 = maxpool(conv1, 2, 2, VALID, pool1) conv2 = conv_relu(inputs=pool1, filters=64, k_size=5, stride=1, padding=SAME, scope_name=conv2) pool2 = maxpool(conv2, 2, 2, VALID, pool2) feature_dim = pool2.shape[1] * pool2.shape[2] * pool2.shape[3] pool2 = tf.reshape(pool2, [-1, feature_dim]) fc = tf.nn.relu(fully_connected(pool2, 1024, fc)) dropout = tf.layers.dropout(fc, self.keep_prob, training=self.training, name=dropout) self.logits = fully_connected(dropout, self.n_classes, logits)def eval(self): Count the number of right predictions in a batch with tf.name_scope(predict): preds = tf.nn.softmax(self.logits) correct_preds = tf.equal(tf.argmax(preds, 1), tf.argmax(self.label, 1)) self.accuracy = tf.reduce_sum(tf.cast(correct_preds, tf.float32))
tf.layers
前面的各層定義還是有些麻煩,實際上,TensorFlow提供了一種更簡單的手段,就是直接使用在tf.layers
里定義的各種層
conv1 = tf.layers.conv2d(inputs=self.img, filters=32, kernel_size=[5, 5], padding=SAME, activation=tf.nn.relu, name=conv1)pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2, name=pool1)fc = tf.layers.dense(pool2, 1024, activation=tf.nn.relu, name=fc)
注意在使用tf.layers.dropout
做dropout時,需要指明現在是在訓練還是預測。回憶dropout的核心思想,其僅在訓練時會隨機丟棄一部分神經元,而預測時不會
dropout = tf.layers.dropout(fc, self.keep_prob, training=self.training, name=dropout)
推薦閱讀:
※TensorFlow 到底慢在哪裡?
※手把手教你用TensorFlow實現看圖說話|教程+代碼
※cs20si: tensorflow for research學習筆記4
※TensorFlow官方教程翻譯:導入數據
※TF Boys (TensorFlow Boys ) 養成記(二): TensorFlow 數據讀取
TAG:卷積神經網路CNN | TensorFlow |