在瀏覽器中進行深度學習:TensorFlow.js (六)構建一個卷積網絡 Convolutional Network 原 薦

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

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

先上圖:

代碼見Codepen

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

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

卷積和核

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

卷積操作如下圖所示:

“cnn deep learning gif”的图片搜索结果

左邊的矩形是輸入數據,也就是我們要處理的圖像的張量表示。中間的矩形是核,而右邊的矩形就是卷積的結果。核函數從左至右,從上到下,每次移動一個像素掃描圖像,計算出卷積和的結果矩陣。

卷積的計算過程如下圖:

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

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

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

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

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

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

相关图片

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

“cnn deep learning gif”的图片搜索结果

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

“cnn deep learning gif”的图片搜索结果

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

“cnn deep learning gif”的图片搜索结果

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

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

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

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

池化

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

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

“cnn pooling”的图片搜索结果

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

 

整體結構

通常,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

類似這樣一個結構

“cnn deep learning”的图片搜索结果

訓練的代碼如下:

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

參考

 

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