Tensorflow_08C_Keras 的數據增強與 Tensorboard 使用方法

Brief 概述

前面兩章重點描述了使用 Keras 搭建模型的兩種方式,並且妥善的儲存模型到 .h5 文件中,等下一次使用的時候直接呼叫儲存文檔,就可以把整個模型,連同參數一起回傳到新的模型中繼續開始工作。

最後,既然 Keras 已經大致完好的被 Tensorflow 移植過來,那麼 tf 最厲害的可視化工具 Tensorboard 肯定也不能落於人後,接下來將使用非常簡單的方式,讓我們能夠隨後開啓 Tensorboard 觀察我們模型定義的長相,並加上一系列的數據預處理,讓模型訓練的更完善。

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,故值得一探究竟。

 

Load The Model as One Piece 整體模型的載入

new_model = K.models.load_model('save.h5')

Review the Trained Results

關於一個完整的神經網絡,可以查看的內容非常多,而 Keras 也很貼心的幫使用者整理方法,可以很輕鬆的讓我們看清每一層神經之間的參數量,同時使用函數呼叫指定層框架中的參數。

model.summary( )

首先是 summary 函數,調用它來查看我們在上面重新載入回來的模型架構,如下指令。

new_model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 28, 28, 1)         0         
_________________________________________________________________
layer1 (Conv2D)              (None, 28, 28, 16)        416       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 14, 14, 16)        0         
_________________________________________________________________
batch_normalization (BatchNo (None, 14, 14, 16)        64        
_________________________________________________________________
layer2 (Conv2D)              (None, 14, 14, 36)        14436     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 7, 7, 36)          0         
_________________________________________________________________
batch_normalization_1 (Batch (None, 7, 7, 36)          144       
_________________________________________________________________
flatten (Flatten)            (None, 1764)              0         
_________________________________________________________________
dense (Dense)                (None, 128)               225920    
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1290      
=================================================================
Total params: 242,270
Trainable params: 242,166
Non-trainable params: 104
_________________________________________________________________

每層之間的參數變化總量都在這個函數的幫助下一覽無遺。

 

Plot Wrong Predicted Images

接着我們可以使用重新載入的 model 框架中的 predict 函數預測輸入數字圖像的對應類別是什麼,如下代碼:

### Predict MNIST image
rand_img = mnist.img_test.reshape([-1, 28, 28, 1])[3:5004]
rand_lab = mnist.lab_test[3:5004]
lab_name = [i for i in range(10)]

### Predict CIFAR10 image
# rand_img = cifar_img_test[3:100]
# rand_lab = cc.load_binary_data('test_batch', 'labels', 
#                                file_dir=path_cifar).astype(np.int)[3:100]
# lab_name = get_class_name()

# ----------------------------------------------------------------------

pred_oh = new_model.predict(rand_img)

### Only when using MNIST dataset, turn this on
rand_img = rand_img.reshape([-1, 28, 28])

pred_lab = np.argmax(pred_oh, axis=1)
# print(pred_lab)
incorrect = (pred_lab != rand_lab)

cc.plot_images(rand_img[incorrect], rand_lab[incorrect], lab_name,
               size=[3, 4], pred_labels=pred_lab[incorrect])

 

 

Lookup Weights between Layers

  1. 首先使用 model.layers 方法呼叫所有的層,以列表 list 的方式回傳
  2. 指定好選擇的層之後,使用 get_weights() 函數同樣呼叫所有該層的參數集,以列表的方式回傳
  3. 指定好是哪一個參數集之後,即可得到一個以 numpy list 作爲數據格式的結果

上面的三點說來話長,執行的時候也就不過是下面的一段話,如下代碼:

new_model.layers[4].get_weights()[0].shape
(5, 5, 16, 36)

摳出指定層的指定節點之數字之後,需要進一步圖像話觀察或是特定區域分析權重大小的相關探討,都將變得非常簡單。


還有另一些方法可以呼叫沒層的參數:K.backendK.models.Model 如果上面第一個方法行不通了,下面兩個是可以嘗試的切入點。

 

Tensorboard in Keras

既然 Keras 是依託於 Tensorflow 來執行一切算法與參數的傳遞,那麼 Tensorboard 的使用肯定也是使用者馬上能夠聯想上的一個重要工具,此一工具也非常完好的在 Keras 中被保留和使用,使用方式更是如出一轍的簡單,一個函數 K.callbacks.TensorBoard() 調用即可完成所有的工作(點擊此進入源代碼),不過需要注意安插其他配套代碼的位置與時機,流程如下:

  1. Construct a model using Sequential or Model function
  2. Add more layers within a constructed model
  3. Compile the model
  4. 1st additional step: Apply K.callbacks.TensorBoard() function
  5. 2nd additional step: Fit (train) the model with new argument "callbacks=[K...TensorBoard]"
  6. ... Same procedure ...

詳細代碼將於下面的 Data Preprocessing 環節一同展現,執行完後即得到一個新的文件,使用者即可在終端使用此文件開啓文檔在 Tensorboard 中查看結果。

 

Data Preprocessing in Keras

說到數據的前期處理,Keras 同樣應該給出了它自己獨有且簡單方便的執行方法,其對應函數爲 K.preprocessing.image.ImageDataGenerator(),其執行順序如下流程:

  1. 前期預處理數據時,即使用此函數,並設定一系列參數
  2. 賦予設定好的函數一個對象,並使用對象的方法 .fit()
  3. 例行公事的架構神經網絡
  4. 最後要使用 model.fit() 訓練時,需改成 model.fit_generator()
  5. 正常執行模型評估

Step 1

此步驟也是耗時最久的一步,先跟 Keras 說明圖像數據要被處理成什麼樣子,再指定是哪些數據要被處理,但是注意一個很重要的一點是,第一步做完後,並沒有任何因爲預處理而佔用的緩存,如下代碼:

import numpy as np
import tensorflow as tf
import tensorflow.keras as K
import matplotlib.pyplot as plt

# First set up what are we going to deal with the images
img_augment = K.preprocessing.image.ImageDataGenerator(
    rotation_range=10, width_shift_range=0.2, height_shift_range=0.2,
    shear_range=0.15, zoom_range=0.1, channel_shift_range=0.3,
    horizontal_flip=True, vertical_flip=False)
# Second appoint the certain images into the preset procedure using .fit
img_augment.fit(cifar_img_train, augment=True)

Step 2

經過第一步驟告知好所有信息後,接下來就讓數據沿着這些信息參數 "流" 出來,經過 .flow 方法流出來的對象是一個需要被遍歷的函數,每次出來的量設定爲一個 batch,放到循環裏面遍歷之後出來的結果就直接是增強過後的數據本身。

# What we will get from the called function below is an "iterable object"
Iteration = img_augment.flow(cifar_img_train, 
                             cifar_lab_train, 
                             batch_size=12)
k = 1
for aug_img, aug_lab in Iteration:
    fig, axes = plt.subplots(3, 4)
    fig.subplots_adjust(hspace=0.6, wspace=0.6)
    for n, ax in enumerate(axes.flat):
        ax.imshow(aug_img[n])
        xlabel = get_class_name()[aug_lab[n]]
        ax.set_xlabel(xlabel)
        ax.set_xticks([])
        ax.set_yticks([])
    plt.show()
    print("---------- Separation {} ----------".format(k))
    k += 1

---------- Separation 1 ----------

---------- Separation 2 ----------

....

... This process will be iterated all the time~

....

從上面執行的結果我們可以看到,使用遍歷會以每次一個 batch 的速度持續執行,直到 fit 的目標圖像所有都被強化一遍之後纔算結束。

Step 3

接着是我們熟悉的模型構建方法,這裏結合了上面用 Keras 使用 Tensorboard 的代碼環節,並注意在 fit model 的時候使用的函數將不再是 .fit 而是 .fit_generator。這麼一來 model 才能夠接受數據增強所流出來的增強了的數據,而 .flow 後面除了增強的數據外,還接了一個標籤參數,注意使用的標籤是 one hot 形式,放在 .flow 中的標籤會被自動的對應增強的數據被迭代出來。

### Model construction using Sequential method
model = K.models.Sequential()
model.add(K.layers.InputLayer(input_shape=(32, 32, 3)))
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))

model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# ----------------------------------------------------------------------

### Tensorboard activated by Keras API
tb = K.callbacks.TensorBoard(log_dir='./keras.tb',
                             histogram_freq=0,
                             batch_size=128,
                             write_graph=True,
                             write_grads=True,
                             write_images=True)
#                              embeddings_freq=1,
#                              embeddings_layer_names=None,
#                              embeddings_metadata=None)
# Third feed the input images into the model set above letting it "flow"
model.fit_generator(img_augment.flow(cifar_img_train, 
                                     cc.one_hot(cifar_lab_train), 
                                     batch_size=128),
                    steps_per_epoch=len(cifar_lab_train)/128, epochs=10,
                    callbacks=[tb])
Epoch 1/10
391/390 [==============================] - 31s 80ms/step - loss: 1.8821 - acc: 0.3279
Epoch 2/10
391/390 [==============================] - 30s 77ms/step - loss: 1.8726 - acc: 0.3318
Epoch 3/10
391/390 [==============================] - 32s 83ms/step - loss: 1.8704 - acc: 0.3313
Epoch 4/10
391/390 [==============================] - 31s 79ms/step - loss: 1.8581 - acc: 0.3353
Epoch 5/10
391/390 [==============================] - 32s 81ms/step - loss: 1.8555 - acc: 0.3361
Epoch 6/10
391/390 [==============================] - 31s 80ms/step - loss: 1.8506 - acc: 0.3376
Epoch 7/10
391/390 [==============================] - 32s 82ms/step - loss: 1.8516 - acc: 0.3395
Epoch 8/10
391/390 [==============================] - 32s 81ms/step - loss: 1.8442 - acc: 0.3399
Epoch 9/10
391/390 [==============================] - 31s 80ms/step - loss: 1.8419 - acc: 0.3439
Epoch 10/10
391/390 [==============================] - 31s 79ms/step - loss: 1.8327 - acc: 0.3455

Step 4

最後一步例行公事檢測一下模型經過數據增強後的效果,能夠發現其一定程度的提升了分類的準確率,同時也增強了模型泛化的能力。

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 61us/step
The loss value: 1.6989541765213012
The accuracy: 0.4079

p.s. 如果準確率沒有顯著提升,表示數據增強的強度可能過大,或是訓練的 epoch 次數不夠多表示。

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