Tensorflow_08B_Keras 的 Function 模型與訓練結果的儲存方法

Brief 概述

從上一章節的範例中我們成功使用 Keras 搭建全聯接神經網絡和卷積神經網絡,並分別使用此二網絡對最基礎的兩個數據集 MNIST 與 CIFAR10 做分類,旨在讓大家瞭解到使用 Keras 搭建神經網絡的簡潔性和人性化的一面。

Keras 從本來獨立發展的第三方模塊,到後來被 Tensorflow 認可後在隨後的 tf 升級版本中被納入 tf 的高級 API 行列中,確實證明了其設計理念的合理性和必要性,讓建構神經網絡的知識門檻降低,更多人將能夠通過此 API 入手親自搭建神經網絡。

繼續上節的介紹,完整了解了 Sequential 的搭建方式之後,接下來將要使用第二種搭建方式 Functional 方法,他們的功能一模一樣,爲什麼要學兩種的理由將在模型的儲存中跟大家說明。

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

 

2. Functional Model

跟 Sequential 模式比起來,Functional 模式在建構神經網絡上的意思也是相近的,不過差別在於它的構建方式如同函數呼叫一般的使用,首先引入需要用到的模塊:

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

mnist_img_size = 28
cifar_img_size = 32

2-1. Model Construction

每層用來構建神經網絡的函數,在 Keras 中在還沒有被指向一個對象之前,都可以作爲一個新的函數本身,讓其後面加上一對 () 傳入參數至其中,直接開始新一輪的計算,代碼如下:

### When taking MNIST as input, define the shape of (28, 28, 1)
inputs = K.layers.Input(shape=(mnist_img_size, mnist_img_size, 1))

### When taking CIFAR as input, define the shape of (32, 32, 3)
# inputs = K.layers.Input(shape=(cifar_img_size, cifar_img_size, 3))

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

# Construct the structure using Functionnal Model from now
net = inputs

net = K.layers.Conv2D(kernel_size=5, strides=1, filters=16, padding='same',
                      activation='relu', name='layer1')(net)
net = K.layers.MaxPooling2D(pool_size=2, strides=2)(net)
net = K.layers.BatchNormalization()(net)

net = K.layers.Conv2D(kernel_size=5, strides=1, filters=36, padding='same',
                      activation='relu', name='layer2')(net)
net = K.layers.MaxPooling2D(pool_size=2, strides=2)(net)
net = K.layers.BatchNormalization()(net)

# Fully connected part
net = K.layers.Flatten()(net)
net = K.layers.Dense(units=128, activation='relu')(net)
net = K.layers.Dense(units=10, activation='softmax')(net)

outputs = net

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

# Compile the structure into a Model
func_model = K.models.Model(inputs=inputs, outputs=outputs)
func_model.compile(optimizer='rmsprop',
                   loss='categorical_crossentropy',
                   metrics=['accuracy'])

2-2. Train Model

與 Sequential 的操作流程一般,根據需要使用的函數模型來執行代碼,其他的標註起來不啓動。

### Train the model using MNIST:
func_model.fit(x=mnist_img_train.reshape([-1, 28, 28, 1]),
               y=cc.one_hot(mnist.lab_train),
               epochs=2, batch_size=128)

### Train the model using CIFAR10:
# func_model.fit(x=cifar_img_train, 
#                y=cc.one_hot(cifar_lab_train),
#                epochs=3, batch_size=128)
Epoch 1/2
60000/60000 [==============================] - 83s 1ms/step - loss: 0.1151 - acc: 0.9657
Epoch 2/2
60000/60000 [==============================] - 79s 1ms/step - loss: 0.0371 - acc: 0.9891

2-3. Evaluate Model

訓練完的模型,使用下面的方法開啓測試集,測試結果。

### Evaluate Model using MNIST:
mnist_loss, mnist_acc = func_model.evaluate(mnist.img_test.reshape([-1, 28, 28, 1]), 
                                            cc.one_hot(mnist.lab_test))
print('The loss value: {}'.format(mnist_loss))
print('The accuracy: {}'.format(mnist_acc))

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

### Evaluate Model using CIFAR10:
# 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 = func_model.evaluate(cifar_img_test, cifar_lab_test)
# print('The loss value: {}'.format(cifar_loss))
# print('The accuracy: {}'.format(cifar_acc))
10000/10000 [==============================] - 6s 634us/step
The loss value: 0.03831068623477895
The accuracy: 0.9879

 

Save and Restore Training Results

儲存的記錄點是我們在做事情的時候非常重要的輔助工具,訓練模型的過程當然也需要這項功能。然而如果回顧前面使用 Tensorflow 儲存成 checkpoint 與重新呼叫儲存參數的方式,非得有幾次函數調用的過程才能夠完成存檔,設計的邏輯並不怎麼人性化,是一個比較繁瑣的過程。

而 Keras 的儲存方式被設計得非常人性化,容易理解之外也容易操作,然而一個深度學習框架有兩個部分組成,分別是運算結構與被運算的參數,因此也衍生出兩種主要的思路用來儲存訓練結果: 

  1. 整體儲存整體載入
  2. 分開儲存分開載入

Crutial Note:

ValueError: You are trying to load a weight file containing N layers into a model with M layers. 是一個版本更新的問題,普遍出現在 Keras 2.X 的版本中,如果使用了此係列版本的人想避開這個問題的話,換成 Functional Model 來搭建自己的神經網絡框架之後則能夠解決問題。

有些 Keras 版本里面,只有 Functional Model 可以順利把儲存好的模型和訓練參數重新呼叫回模型內,因此 Functional Model 在儲存這點上是比 Sequential 設計來的完備的。

 

1. Save and Load The Model as One Piece 整體儲存與載入

儲存與載入的過程一共各一行代碼即完成所有的工作,儲存方式如下:

func_model.save('save.h5')

# In order to save the RAM space, we can delete the useless object
del func_model

重新載入回整個框架與參數的方式如下:

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

執行完畢後, new_model 對象即附有完整的神經網絡框架功能,並執行預測等計算。

 

2. Save and Load The Model Separately 分開儲存與載入

在 Keras 中,框架的保存使用 json 形式完成,數據的保存使用 save_weights() 函數實現,保存方式如下代碼:

func_model.save_weights('save_weights.h5')

model_json = func_model.to_json()
# print(model_json)

with open('model.json', 'w') as file:
    file.write(model_json)

重新喚回模型之後,就可以使用 load_weights() 函數把參數完整叫回來,繼續上次訓練結果開始預估新的數據。

with open('model.json', 'r') as file:
    json_string = file.read()
    
# print(json_string)
new_model = K.models.model_from_json(json_string)
new_model.load_weights('save_weights.h5')

接着還有一段續集,將主要描述如何使用 Keras 開啓可視化好幫手 "Tensorboard",與如何使用數據增強,適當且簡單的改變圖片的性質。

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