05.16 如何構建卷積網絡 Convolutional Network?

在上一篇中,我們介紹了了用TensorflowJS構建一個神經網絡,然後用該模型來進行手寫MINST數據的識別。和之前的基本模型比起來,模型的準確率上升的似乎不是很大。(在我的例子中,驗證部分比較簡單,只是一個大致的統計)甚至有些情況下,如果參數選擇不當,訓練效果還會更差。

卷積網絡,也叫做卷積神經網絡(con-volutional neural network, CNN),是一種專門用來處理具有類似網格結構的數據的神經網絡。例如時間序列數據(可以認為是在時間軸上有規律地採樣形成的一維網格)和圖像數據(可以看作是二維的像素網格)。對於MINST手寫數據來說,應用卷積網絡會不會是更好的選擇呢?

先上圖:

如何構建卷積網絡 Convolutional Network?

代碼見Codepen

該圖是我應用CNN對MINST數據進行訓練的結果,準確率在97%,可以說和之前的模型來比較,提高顯著。要知道,要知道在獲得比較高的準確率後,要提高一點都是比較困難的。那我們就簡單的看看卷積網絡是什麼,他為什麼對於手寫數據的識別做的比其他模型的更好?

CNN的原理實際上是模擬了人類的視覺神經如何識別圖像。每個視覺神經只負責處理不同大小的一小塊畫面,在不同的神經層次處理不同的信息。

卷積和核

大家可能有用過Photoshop的經驗,Photoshop提供很多不同類型的濾鏡來處理圖像,其實那個本質上就是應用不同的核函數對圖像進行卷積的結果。

卷積操作如下圖所示:

如何構建卷積網絡 Convolutional Network?

卷積的計算過程如下圖:

如何構建卷積網絡 Convolutional Network?

計算就是乘法和加法,但是上圖的例子計算有個錯誤,看你找不找得到。下面這個圖計算更簡單一點:

如果你能夠理解上圖的數學含義你就能理解,核函數其實是一個權重,對於每一個小塊的圖像,不同的核對不同區域的權重不一樣。

如何構建卷積網絡 Convolutional Network?

如何構建卷積網絡 Convolutional Network?

如上圖的兩個核,左面的對於圖像中間的權重為0,上面的是負向加權,而下面的正向加權。可以想像對應於普通圖像,數據分佈均勻,這個加權計算的結果趨近於零,對應於水平邊緣,上面沒有數據而下面有數據,這個加權的值就比較大,這樣我們就能夠檢測出水平邊緣。同理右邊核函數對應垂直邊緣。

如何構建卷積網絡 Convolutional Network?

如何構建卷積網絡 Convolutional Network?

上圖就是應用垂直,水平,垂直加水平的核,對安卓小機器人圖像卷積的結果。我們可以看出對應的核函數是如何識別出邊緣的。

然而在學習的時候要使用什麼樣的核呢?我們看一下網絡結構:

如何構建卷積網絡 Convolutional Network?

每一個像素都是一個特徵,每一個特徵是一個輸入節點。每一個卷積的結果都輸入到下一層的隱藏節點。核的權重就連接了輸入層和隱藏層。經過0填充的輸入層可以輸出不同形狀的卷積結果。同時可以調整掃描的步幅(stride)。

上圖中,輸入為7*7,沒有填充,步幅為1,輸出為5*5

如何構建卷積網絡 Convolutional Network?

上圖中,輸入為5*5,填充1格,步幅為1,輸出為5*5

上圖中,輸入為5*5,填充1格,步幅為2,輸出為3*3

如何構建卷積網絡 Convolutional Network?

上圖中,輸入為2*2,填充2格,步幅為1,輸出為4*4

我們可以看出來,增加填充會導致隱藏層節點數量增加,而增大步幅可以使得隱藏層的節點變少。

通過神經網絡的學習,就能夠確定核的權重。實際的應用,可能會有多個核,因為有許多的特徵要學習。

如何構建卷積網絡 Convolutional Network?

就像我們之前看到如果要學習圖像的輪廓,其實是兩個不同的核的組合。

池化

池化層通常是緊跟著卷積的一層,通常是做區域的均值或者最大值操作。如下圖:

如何構建卷積網絡 Convolutional Network?

如下圖,池化的策略通常是取最大值或者取均值。

池化的作用類似取樣,使得下一層神經網絡要處理的數據極大的縮小。減少整個網絡的參數,防止出現過擬合。


整體結構

如何構建卷積網絡 Convolutional Network?

通常,CNN網絡的由如上圖所示的層次構成:

  • 輸入層 Input Layer

  • 卷積層 Convolution Layer

  • 池化層 Pooling Layer

  • 全連接層 Fully Connected (Dense) Layer

  • 分類層 Softmax Classification Layer

  • 輸出層 Output Layer

在瞭解的基本的卷積網絡的概念後,我們來看看如何在TensorflowJS中實現一個CNN。

下面是模型的代碼:

function cnn() {
const model = tf.sequential();
model.add(tf.layers.conv2d({
inputShape: [28, 28, 1],
kernelSize: 5,
filters: 8,
strides: 1,
activation: 'relu',
kernelInitializer: 'varianceScaling'
}));
model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [2, 2]}));
model.add(tf.layers.conv2d({
kernelSize: 5,
filters: 16,
strides: 1,
activation: 'relu',
kernelInitializer: 'varianceScaling'
}));
model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [2, 2]}));
model.add(tf.layers.flatten());
model.add(tf.layers.dense(
{units: 10, kernelInitializer: 'varianceScaling', activation: 'softmax'}));
return model;
}
  • tf.sequential() 創建一個連續的神經網絡,自動創建輸入層

  • tf.layers.conv2d 是第一層的卷積層,輸入28*28*1是圖像的長,高,顏色通道。核的大小是5*5,步幅是1。我們先忽略其它參數。

  • tf.layers.maxPooling2d是下一個池化層,就是以2*2的小窗口對卷積結果做池化。

  • 接著又是一個卷積和一個池化層。

  • tf.layers.flatten() 是把之前的結果打平。

  • 最後是一個softmax分類層 tf.layers.dense

類似這樣一個結構

如何構建卷積網絡 Convolutional Network?

訓練的代碼如下:

const model = cnn();
const LEARNING_RATE = 0.15;
const optimizer = tf.train.sgd(LEARNING_RATE);
model.compile({
optimizer: optimizer,
loss: 'categoricalCrossentropy',
metrics: ['accuracy'],
});
async function train() {
const BATCH_SIZE = 16;
const TRAIN_BATCHES = 1000;
const TEST_BATCH_SIZE = 100;
const TEST_ITERATION_FREQUENCY = 5;
for (let i = 0; i < TRAIN_BATCHES; i++) {
const batch = data.nextTrainBatch(BATCH_SIZE);
let testBatch;
let validationData;
// Every few batches test the accuracy of the mode.
if (i % TEST_ITERATION_FREQUENCY === 0 && i > 0 ) {
testBatch = data.nextTestBatch(TEST_BATCH_SIZE);
validationData = [
testBatch.xs.reshape([TEST_BATCH_SIZE, 28, 28, 1]), testBatch.labels
];
}
// The entire dataset doesn't fit into memory so we call fit repeatedly
// with batches.
const history = await model.fit(
batch.xs.reshape([BATCH_SIZE, 28, 28, 1]), batch.labels,
{batchSize: BATCH_SIZE, validationData, epochs: 1});
const loss = history.history.loss[0];
const accuracy = history.history.acc[0];
batch.xs.dispose();
batch.labels.dispose();
if (testBatch != null) {
testBatch.xs.dispose();
testBatch.labels.dispose();
}
await tf.nextFrame();
}
}

如果和之前的神經網絡的訓練的代碼比較,這裡唯一的變化就是輸入數據的形狀。

// For CNN
batch.xs.reshape([BATCH_SIZE, 28, 28, 1])
// For NN
batch.xs.reshape([BATCH_SIZE, 784])

這是由兩個網絡輸入層的形狀來決定的。

大家在選取模型的時候可以考慮CNN的優缺點。

優點:

  • 共享卷積核,對高維數據處理無壓力

  • 無需手動選取特徵,訓練好權重,即得特徵

  • 分類效果好

缺點:

  • 需要調參,需要大樣本量,訓練最好要用GPU

  • 物理含義不明確,隨著 Convolution 的堆疊,Feature Map 變得越來越抽象,人類已經很難去理解了

CNN是非常流行的深度學習的模型,廣泛用於圖像相關的有關領域,從阿爾法狗到自動駕駛,到處都有他的身影。如果大家希望進一步瞭解,可以研習下面的文章。


分享到:


相關文章: