在上一篇中,我們介紹了了用TensorflowJS構建一個神經網絡,然後用該模型來進行手寫MINST數據的識別。和之前的基本模型比起來,模型的準確率上升的似乎不是很大。(在我的例子中,驗證部分比較簡單,只是一個大致的統計)甚至有些情況下,如果參數選擇不當,訓練效果還會更差。
卷積網絡,也叫做卷積神經網絡(con-volutional neural network, CNN),是一種專門用來處理具有類似網格結構的數據的神經網絡。例如時間序列數據(可以認爲是在時間軸上有規律地採樣形成的一維網格)和圖像數據(可以看作是二維的像素網格)。對於MINST手寫數據來說,應用卷積網絡會不會是更好的選擇呢?
先上圖:
代碼見Codepen
該圖是我應用CNN對MINST數據進行訓練的結果,準確率在97%,可以說和之前的模型來比較,提高顯著。要知道,要知道在獲得比較高的準確率後,要提高一點都是比較困難的。那我們就簡單的看看卷積網絡是什麼,他爲什麼對於手寫數據的識別做的比其他模型的更好?
CNN的原理實際上是模擬了人類的視覺神經如何識別圖像。每個視覺神經只負責處理不同大小的一小塊畫面,在不同的神經層次處理不同的信息。
卷積和核
大家可能有用過Photoshop的經驗,Photoshop提供很多不同類型的濾鏡來處理圖像,其實那個本質上就是應用不同的核函數對圖像進行卷積的結果。
卷積操作如下圖所示:
左邊的矩形是輸入數據,也就是我們要處理的圖像的張量表示。中間的矩形是核,而右邊的矩形就是卷積的結果。核函數從左至右,從上到下,每次移動一個像素掃描圖像,計算出卷積和的結果矩陣。
卷積的計算過程如下圖:
計算就是乘法和加法,但是上圖的例子計算有個錯誤,看你找不找得到。下面這個圖計算更簡單一點:
如果你能夠理解上圖的數學含義你就能理解,核函數其實是一個權重,對於每一個小塊的圖像,不同的核對不同區域的權重不一樣。
如上圖的兩個核,左面的對於圖像中間的權重爲0,上面的是負向加權,而下面的正向加權。可以想像對應於普通圖像,數據分佈均勻,這個加權計算的結果趨近於零,對應於水平邊緣,上面沒有數據而下面有數據,這個加權的值就比較大,這樣我們就能夠檢測出水平邊緣。同理右邊核函數對應垂直邊緣。
上圖就是應用垂直,水平,垂直加水平的核,對安卓小機器人圖像卷積的結果。我們可以看出對應的核函數是如何識別出邊緣的。
然而在學習的時候要使用什麼樣的核呢?我們看一下網絡結構:
每一個像素都是一個特徵,每一個特徵是一個輸入節點。每一個卷積的結果都輸入到下一層的隱藏節點。核的權重就連接了輸入層和隱藏層。經過0填充的輸入層可以輸出不同形狀的卷積結果。同時可以調整掃描的步幅(stride)。
上圖中,輸入爲7*7,沒有填充,步幅爲1,輸出爲5*5
上圖中,輸入爲5*5,填充1格,步幅爲1,輸出爲5*5
上圖中,輸入爲5*5,填充1格,步幅爲2,輸出爲3*3
上圖中,輸入爲2*2,填充2格,步幅爲1,輸出爲4*4
我們可以看出來,增加填充會導致隱藏層節點數量增加,而增大步幅可以使得隱藏層的節點變少。
通過神經網絡的學習,就能夠確定核的權重。實際的應用,可能會有多個核,因爲有許多的特徵要學習。
就像我們之前看到如果要學習圖像的輪廓,其實是兩個不同的核的組合。
池化
池化層通常是緊跟着卷積的一層,通常是做區域的均值或者最大值操作。如下圖:
如下圖,池化的策略通常是取最大值或者取均值。
池化的作用類似取樣,使得下一層神經網絡要處理的數據極大的縮小。減少整個網絡的參數,防止出現過擬合。
整體結構
通常,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
類似這樣一個結構
訓練的代碼如下:
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是非常流行的深度學習的模型,廣泛用於圖像相關的有關領域,從阿爾法狗到自動駕駛,到處都有他的身影。如果大家希望進一步瞭解,可以研習下面的文章。
參考
- Convolutional Neural Networks - Basics
- 如何理解卷積神經網絡中的卷積?
- Visualizing parts of Convolutional Neural Networks using Keras and Cats
- Essentials of Deep Learning: Visualizing Convolutional Neural Networks in Pytho
- Undrestanding Convolutional Layers in Convolutional Neural Networks (CNNs)