Tensorflow_08A_Keras 助攻下的 Sequential 模型

Brief 概述

使用 keras 搭建模型時讓人們感受到的簡潔性與設計者的用心非常直觀的能夠在過程中留下深刻的印象,這個模塊幫可以讓呈現出來的代碼極爲人性化且一目瞭然,使用 Tensorflow 模塊搭建神經網絡模型通常需要百行的代碼,自定義模型和函數,唯一受到 tf 封裝的厲害功能只有梯度下降的自動取極值,如果是一個初出入門的人,沒有一定的基礎背景累積,更遑論使用 tf 搭建神經網絡。

其大量封裝了一系列的複雜深度學習原理成爲一個又一個簡潔的函數模塊,構建的時候即便基礎知識差一些也可以非常快的上手搭建工作,是一個對初學者非常友好的接口。不過其封裝的函數總量適用的對象遠遠不止初學者這麼簡單,其內部還有非常完整的高級功能,同時也滿足高級框架的搭建!

keras 模塊原本並非是 Tensorflow 的高級 API,而是一個身在 Google 工作的工程師基於 Tensorflow 和 Theano 開發出來的第三方模塊,讓其他人也能夠快速的構建屬於自己的模型,到了後來此模塊逐漸受到大衆青睞後,Google 於是把它收邊進了 Tensorflow high level API 中,現在已經逐漸形成了使用者社羣,並有許多巨頭以此模塊作爲基礎開發基於他們熟悉的底層框架對應的 API 接口,相信不久的未來 Keras 將成爲每種框架的統一接口,讓熟悉 Keras 的人們能夠在各種框架中根據性能的優劣自由切換。

p.s. 點擊此 進入 keras 官網,點擊此 進入 keras 的 GitHub 源代碼。

 

Import Data 導入數據

構建神經網絡之前,最重要的還是數據本身,而這裏將繼續沿用前面面幾個章節中所使用的兩個模型 MNIST 與 CIFAR10,和與其對應的函數代碼,並簡單打印出引入數據集圖像對應標籤的結果。

import gzip
from Code_Session.TF_04 import mnist as M
import pickle
from Code_Session.TF_05 import cifar2cnn as cc

MNIST Dataset

path_mnist = '/Users/kcl/Documents/Python_Projects/01_AI_Tutorials/_2_Image_Datasets/MNIST_data'
mnist = M.MNIST(val_ratio=0.0, data_dir=path_mnist)
print(mnist.img_train.shape)
(60000, 784)
mnist_img_train = M.format_images(mnist.img_train)
mnist_lab_train = mnist.lab_train
mnist_cls_name = [i for i in range(10)]
cc.plot_images(mnist_img_train, mnist.lab_train, mnist_cls_name, size=[3, 4])

 

CIFAR10 Dataset

path_cifar = '/Users/kcl/Documents/Python_Projects/cifar-10-batches-py'
img_train = cc.merge_batches('data', file_dir=path_cifar)
print(img_train.shape)
(50000, 3072)
file_dir = path_cifar + '/' + 'batches.meta'
def get_class_name(file_dir=file_dir):
    with open(file_dir, 'rb') as file:
        dic = pickle.load(file, encoding='bytes')
    return [w.decode('utf-8') for w in dic[b'label_names']]


cifar_img_train = cc.format_images(img_train)
cifar_lab_train = cc.merge_batches('labels', file_dir=path_cifar)
cc.plot_images(cifar_img_train, cifar_lab_train, 
               get_class_name(), size=[3, 4])

 

p.s. 如果對其中的代碼有任何不熟悉,請詳見前面幾回合的內容。

接下來就可以從 Tensorflow 模塊中呼叫 keras 搭建一個非常迅捷且輕便的神經網絡模型。類似 keras 的 API 模塊也有 PrettyTensor 與 layers,不過從 Tensorflow 官網的態度來看,它很可能將在未來被刪減,而主推 keras,同時很多更新的功能 keras 也持續同步着,是一個相對穩健的高級 API,故值得一探究竟。

 

Keras Insight

此 API 主要有兩種模式可以讓我們建構神經網絡:

  1. Sequential Model
  2. Functional Model

他們彼此之間在背後代碼上的運算過程是一樣的,差別主要在於我們使用者書寫上的差異,Sequential 的代碼看起來和一般的代碼沒什麼區別,基本山看到代碼就能瞭解其含義,而 Functional 方法寫起來是讓參數帶入函數裏面的函數,等下面內容提及到代碼就會知曉。

既然是搭建神經網絡專用的 API,那麼整個框架主要的功能也就只圍繞着相關的機制操作,主要的機制如下陳列:

  1. .add: 添加一層新的神經網絡
  2. .compile: 把上面呢所有添加好的神經網絡全部打包
  3. .fit: 訓練設定好的神經網絡
  4. .evaluate: 計算神經網絡的損失值和驗證集正確率
  5. .predict: 計算新的數據在此模型的正確率
  6. .save: 把更新到一定階段的神經網絡參數儲存起來,如同 checkpoint
  7. .load_model: 重新載入儲存好的神經網絡參數文檔

不論是哪一個神經網絡搭建方式,都同樣遵循上面一到七的步驟,基本上一個人熟練的情況下,每一個神經網絡的搭建都可以在 5 分鐘內完成,比起其他的快速搭建方式,keras 同時也是最爲完整的一個 API,每個上述列舉的方法內還有與之方法對應的細分方法可以調用,可以自行查找官方文檔瞭解。

 

1-1. Sequential Linear Model

keras 可以從 tensorflow 中被呼叫,也可以直接使用 keras 本身的模塊,本系列由於跟 tensorflow 相關,因此主要從 tf 中使用 keras,不過模塊中的函數名稱和代碼使用方式基本上是完全相同的。

首先呼叫出 sequential 方法本身,如下代碼:

import numpy as np
import tensorflow as tf
import tensorflow.keras as K

接着使用 Sequential 創建一個對象,基於這個對象開始逐層添加神經網絡結構至對象中,其中 Dense 方法表示全聯接的意思,Dense 裏面的數字項表示的是該全聯接層有幾個輸出神經元。

等搭建到了最後一層神經網絡結構時,如果是分類問題的話,則激勵函數調整成 softmax 相關的方式即可。

model = K.models.Sequential()
model.add(K.layers.Flatten())
model.add(K.layers.Dense(units=128, activation=tf.nn.relu))
model.add(K.layers.Dense(units=128, activation=tf.nn.relu))
model.add(K.layers.Dense(units=10, activation=tf.nn.softmax))

建構的方式還有另一種代碼寫法,可以參考 官網的示範,不過為了不讓自己的記憶混淆,建議從一而終。

完成神經網絡的構建之後,接下來把整個框架使用 compile 打包起來,在參數部分設定需要使用的梯度下降函數和損失函數的使用算法。如果對於梯度下降算法有更細節調整的需要,可以進一步引入下面模塊,使用對象的方式設定好之後再傳入 .compile 方法中。

opt = K.optimizers.Adam(lr=1e-3)
model.compile(optimizer=opt,      # option no.1
              # optimizer='adam'  # option no.2
              loss='categorical_crossentropy',
              metrics=['accuracy'])

最後輸入我們期望訓練的數據開始訓練模型,並試圖讓損失函數降到最低。輸入數據標籤如果是分類問題,那就必須是 one hot 形式,否則會報錯。在參數像中調整好 epochs 的次數後就可以開始訓練。

 

1-1-1. Train MNIST Dataset

首先使用上面搭建好的神經網絡模型運行 MNIST 數據集,以 "圖像" 與 "one hot" 形式作爲輸入尤爲重要:

model.fit(M.format_images(mnist.img_train), 
          cc.one_hot(mnist_lab_train, class_num=10), 
          epochs=5)
Epoch 1/5
60000/60000 [==============================] - 5s 86us/step - loss: 0.2346 - acc: 0.9306
Epoch 2/5
60000/60000 [==============================] - 5s 79us/step - loss: 0.0981 - acc: 0.9696
Epoch 3/5
60000/60000 [==============================] - 5s 78us/step - loss: 0.0683 - acc: 0.9778
Epoch 4/5
60000/60000 [==============================] - 5s 79us/step - loss: 0.0514 - acc: 0.9833
Epoch 5/5
60000/60000 [==============================] - 5s 79us/step - loss: 0.0424 - acc: 0.9862

完成訓練後接下來使用驗證集測試訓練模型的結果,同樣的輸入參數需要使用圖像數據格式(不能是拉直狀態),並且標籤使用 one hot 格式。

mnist_loss, mnist_acc = model.evaluate(M.format_images(mnist.img_test), 
                                       cc.one_hot(mnist.lab_test))
print('The loss value: {}'.format(mnist_loss))
print('The accuracy: {}'.format(mnist_acc))
10000/10000 [==============================] - 0s 32us/step
The loss value: 0.08600640584569191
The accuracy: 0.9754

1-1-2. Train CIFAR10 Dataset

接下來是完全一摸一樣的操作,重複一遍套用在 CIFAR10 數據集上,唯一的差別是數據本身多了一個顏色通道,同樣多的圖片張數卻要多出三倍的運算量。

完整的代碼如下:

model.fit(cc.format_images(img_train),
          cc.one_hot(cifar_lab_train, class_num=10),
          epochs=5, batch_size=128)
Epoch 1/5
50000/50000 [==============================] - 8s 170us/step - loss: 1.8626 - acc: 0.3288
Epoch 2/5
50000/50000 [==============================] - 8s 156us/step - loss: 1.6912 - acc: 0.3922
Epoch 3/5
50000/50000 [==============================] - 8s 159us/step - loss: 1.6262 - acc: 0.4178
Epoch 4/5
50000/50000 [==============================] - 8s 159us/step - loss: 1.5786 - acc: 0.4355
Epoch 5/5
50000/50000 [==============================] - 8s 160us/step - loss: 1.5457 - acc: 0.4477

接着同樣步驟使用驗證集的數據檢測訓練完成的模型的準確率,切記同樣需要使用非拉直狀態的圖像數據和 one hot 形式的標籤數據作爲參數輸入。

cifar_img_test = cc.format_images(cc.load_binary_data(
    'test_batch', 'data', file_dir=path_cifar) / 255.0)
cifar_lab_test = cc.one_hot(cc.load_binary_data(
    'test_batch', 'labels', file_dir=path_cifar).astype(np.int))

cifar_loss, cifar_acc = model.evaluate(cifar_img_test, cifar_lab_test)
print('The loss value: {}'.format(cifar_loss))
print('The accuracy: {}'.format(cifar_acc))
10000/10000 [==============================] - 1s 57us/step
The loss value: 1.5932202987670898
The accuracy: 0.4278

 

1-2. Sequential CNN Model

線性模型構建的方式使用了全聯接層的方法,而論及卷積神經網絡則需要使用到卷積核掃描之,建構神經網絡的方法從核心概念來看是類似的,不過多了一個卷積層構建的函數調用,首先同樣導入需要用到的模塊:

import numpy as np
import tensorflow as tf
import tensorflow.keras as K

接着同樣使用模塊的功能開始創建神經網絡,如果一開始設定神經層的格式需要修改,可以參考下面方法,分作兩種輸入數據的格式。

1-2-1. MNIST input

mnist_img_size = 28

cnn_model = K.models.Sequential()

# To define the format of input data. Dimension scale and size.
cnn_model.add(K.layers.InputLayer(input_shape=(mnist_img_size**2,)))
cnn_model.add(K.layers.Reshape((mnist_img_size, mnist_img_size, 1)))

1-2-2. CIFAR10 input

cifar_img_size = 32

cnn_model = K.models.Sequential()

# To define the format of input data. Dimension scale and size.
cnn_model.add(K.layers.InputLayer(input_shape=(cifar_img_size, cifar_img_size, 3)))

上面兩種輸入模式根據執行需求自行選擇一個執行。


接着開始 CNN 卷積神經網絡的搭建過程,都是使用 .layers 模塊裏面的方法,爲了達到加深印象的目的,每一次呼叫指令的時候都還是把其來源輸入一遍,如下代碼:

# 1st convolutional layer with ReLU-activation and max-pooling.
cnn_model.add(K.layers.Conv2D(kernel_size=3, strides=1, filters=16, 
                              padding='same', activation='relu', name='layer_conv1'))
cnn_model.add(K.layers.MaxPooling2D(pool_size=2, strides=2))
cnn_model.add(K.layers.BatchNormalization())

# 2nd convolutional layer with ReLU-activation and max-pooling.
cnn_model.add(K.layers.Conv2D(kernel_size=3, strides=1, filters=36, 
                              padding='same', activation='relu', name='layer_conv2'))
cnn_model.add(K.layers.MaxPooling2D(pool_size=2, strides=2))
cnn_model.add(K.layers.BatchNormalization())

# Flatten the 4D tensor into 2D tensor for next fully connected step
cnn_model.add(K.layers.Flatten())

# 1st FC layer with 128 output units
cnn_model.add(K.layers.Dense(units=128, activation='relu'))
cnn_model.add(K.layers.BatchNormalization())

# 2nd FC layer connecting to classification answers
cnn_model.add(K.layers.Dense(units=10, activation='softmax'))

1-2-1. Train MNIST Dataset

框架構建好後,接着開始訓練模型,方法與上面線性模型相同,不過輸入數據的時候需要特別注意自己先前在模型搭建的時候設定的數據規格,如果有任何一點不一樣的話將報錯。

opt = K.optimizers.Adam(lr=1e-3)
cnn_model.compile(optimizer=opt,
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])

cnn_model.fit(x=mnist.img_train, 
              y=cc.one_hot(mnist.lab_train),
              epochs=2, batch_size=128)
Epoch 1/2
60000/60000 [==============================] - 43s 724us/step - loss: 0.1180 - acc: 0.9643
Epoch 2/2
60000/60000 [==============================] - 43s 715us/step - loss: 0.0366 - acc: 0.9887

如同在線性模型訓練完後所使用驗證集準確率測試操作,也使用 evaluate 函數檢測準模型準確率。

mnist_loss, mnist_acc = cnn_model.evaluate(mnist.img_test, 
                                           cc.one_hot(mnist.lab_test))
print('The loss value: {}'.format(mnist_loss))
print('The accuracy: {}'.format(mnist_acc))
10000/10000 [==============================] - 3s 297us/step
The loss value: 0.04114889272502623
The accuracy: 0.9879

1-2-2. Train CIFAR10 Dataset

同樣步驟訓練 CIFAR10 數據集,代碼如下:

opt = K.optimizers.Adam(lr=1e-3)
cnn_model.compile(optimizer=opt,
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])

cnn_model.fit(x=cifar_img_train, y=cc.one_hot(cifar_lab_train),
              epochs=3, batch_size=128)
Epoch 1/3
50000/50000 [==============================] - 59s 1ms/step - loss: 1.2917 - acc: 0.5494
Epoch 2/3
50000/50000 [==============================] - 57s 1ms/step - loss: 0.9213 - acc: 0.6799
Epoch 3/3
50000/50000 [==============================] - 52s 1ms/step - loss: 0.7637 - acc: 0.7344

如同在線性模型訓練完後所使用驗證集準確率測試操作,也使用 evaluate 函數檢測準模型準確率。

cifar_img_test = cc.format_images(cc.load_binary_data(
    'test_batch', 'data', file_dir=path_cifar) / 255.0)
cifar_lab_test = cc.one_hot(cc.load_binary_data(
    'test_batch', 'labels', file_dir=path_cifar).astype(np.int))

cifar_loss, cifar_acc = cnn_model.evaluate(cifar_img_test, cifar_lab_test)
print('The loss value: {}'.format(cifar_loss))
print('The accuracy: {}'.format(cifar_acc))
10000/10000 [==============================] - 4s 410us/step
The loss value: 0.994779656124115
The accuracy: 0.6507

下一章將繼續講述如何使用第二種 Functional 的方法搭建神經網絡。

e

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