Tensorflow儲存神經網路引數有妙招:Saver和Restore

華為雲開發者社群 發表於 2021-09-13
神經網路
摘要:這篇文章將講解TensorFlow如何儲存變數和神經網路引數,通過Saver儲存神經網路,再通過Restore呼叫訓練好的神經網路。

本文分享自華為雲社群《[Python人工智慧] 十一.Tensorflow如何儲存神經網路引數 丨【百變AI秀】》,作者: eastmount。

一.儲存變數

通過tf.Variable()定義權重和偏置變數,然後呼叫tf.train.Saver()儲存變數,將資料儲存至本地“my_net/save_net.ckpt”檔案中。

# -*- coding: utf-8 -*-
"""
Created on Thu Jan  2 20:04:57 2020
@author: xiuzhang Eastmount CSDN
"""
import tensorflow as tf
import numpy as np

#---------------------------------------儲存檔案---------------------------------------
W = tf.Variable([[1,2,3], [3,4,5]], dtype=tf.float32, name='weights') #2行3列的資料
b = tf.Variable([[1,2,3]], dtype=tf.float32, name='biases')

# 初始化
init = tf.initialize_all_variables()

# 定義saver 儲存各種變數
saver = tf.train.Saver()

# 使用Session執行初始化
with tf.Session() as sess:
    sess.run(init)
    # 儲存 官方儲存格式為ckpt
    save_path = saver.save(sess, "my_net/save_net.ckpt")
    print("Save to path:", save_path)

“Save to path: my_net/save_net.ckpt”儲存成功如下圖所示:

Tensorflow儲存神經網路引數有妙招:Saver和Restore

開啟內容如下圖所示:

Tensorflow儲存神經網路引數有妙招:Saver和Restore

接著定義標記變數train,通過Restore操作使用我們儲存好的變數。注意,在Restore時需要定義相同的dtype和shape,不需要再定義init。最後直接通過 saver.restore(sess, “my_net/save_net.ckpt”) 提取儲存的變數並輸出即可。

# -*- coding: utf-8 -*-
"""
Created on Thu Jan  2 20:04:57 2020
@author: xiuzhang Eastmount CSDN
"""
import tensorflow as tf
import numpy as np

# 標記變數
train = False

#---------------------------------------儲存檔案---------------------------------------
# Save
if train==True:
    # 定義變數
    W = tf.Variable([[1,2,3], [3,4,5]], dtype=tf.float32, name='weights') #2行3列的資料
    b = tf.Variable([[1,2,3]], dtype=tf.float32, name='biases')

    # 初始化
    init = tf.global_variables_initializer()
 
    # 定義saver 儲存各種變數
    saver = tf.train.Saver()
 
    # 使用Session執行初始化
    with tf.Session() as sess:
        sess.run(init)
        # 儲存 官方儲存格式為ckpt
        save_path = saver.save(sess, "my_net/save_net.ckpt")
        print("Save to path:", save_path)
#---------------------------------------Restore變數-------------------------------------
# Restore
if train==False:
    # 記住在Restore時定義相同的dtype和shape
    # redefine the same shape and same type for your variables
    W = tf.Variable(np.arange(6).reshape((2,3)), dtype=tf.float32, name='weights') #空變數
    b = tf.Variable(np.arange(3).reshape((1,3)), dtype=tf.float32, name='biases') #空變數
 
    # Restore不需要定義init
    saver = tf.train.Saver()
    with tf.Session() as sess:
        # 提取儲存的變數
        saver.restore(sess, "my_net/save_net.ckpt")
        # 尋找相同名字和標識的變數並儲存在W和b中
        print("weights", sess.run(W))
        print("biases", sess.run(b))

執行程式碼,如果報錯“NotFoundError: Restoring from checkpoint failed. This is most likely due to a Variable name or other graph key that is missing from the checkpoint. Please ensure that you have not altered the graph expected based on the checkpoint. ”,則需要重置Spyder即可。

Tensorflow儲存神經網路引數有妙招:Saver和Restore

最後輸出之前所儲存的變數,weights為 [[1,2,3], [3,4,5]],偏置為 [[1,2,3]]。

Tensorflow儲存神經網路引數有妙招:Saver和Restore

二.儲存神經網路

那麼,TensorFlow如何儲存我們的神經網路框架呢?我們需要把整個網路訓練好再進行儲存,其方法和上面類似,完整程式碼如下:

"""
Created on Sun Dec 29 19:21:08 2019
@author: xiuzhang Eastmount CSDN
"""
import os
import glob
import cv2
import numpy as np
import tensorflow as tf

# 定義圖片路徑
path = 'photo/'

#---------------------------------第一步 讀取影像-----------------------------------
def read_img(path):
    cate = [path + x for x in os.listdir(path) if os.path.isdir(path + x)]
    imgs = []
    labels = []
    fpath = []
    for idx, folder in enumerate(cate):
        # 遍歷整個目錄判斷每個檔案是不是符合
        for im in glob.glob(folder + '/*.jpg'):
            #print('reading the images:%s' % (im))
            img = cv2.imread(im)             #呼叫opencv庫讀取畫素點
            img = cv2.resize(img, (32, 32))  #影像畫素大小一致
            imgs.append(img)                 #影像資料
            labels.append(idx)               #影像類標
            fpath.append(path+im)            #影像路徑名
            #print(path+im, idx)
 
    return np.asarray(fpath, np.string_), np.asarray(imgs, np.float32), np.asarray(labels, np.int32)

# 讀取影像
fpaths, data, label = read_img(path)
print(data.shape)  # (1000, 256, 256, 3)
# 計算有多少類圖片
num_classes = len(set(label))
print(num_classes)

# 生成等差數列隨機調整影像順序
num_example = data.shape[0]
arr = np.arange(num_example)
np.random.shuffle(arr)
data = data[arr]
label = label[arr]
fpaths = fpaths[arr]

# 拆分訓練集和測試集 80%訓練集 20%測試集
ratio = 0.8
s = np.int(num_example * ratio)
x_train = data[:s]
y_train = label[:s]
fpaths_train = fpaths[:s] 
x_val = data[s:]
y_val = label[s:]
fpaths_test = fpaths[s:] 
print(len(x_train),len(y_train),len(x_val),len(y_val)) #800 800 200 200
print(y_val)
#---------------------------------第二步 建立神經網路-----------------------------------
# 定義Placeholder
xs = tf.placeholder(tf.float32, [None, 32, 32, 3])  #每張圖片32*32*3個點
ys = tf.placeholder(tf.int32, [None])               #每個樣本有1個輸出
# 存放DropOut引數的容器 
drop = tf.placeholder(tf.float32)                   #訓練時為0.25 測試時為0

# 定義卷積層 conv0
conv0 = tf.layers.conv2d(xs, 20, 5, activation=tf.nn.relu)    #20個卷積核 卷積核大小為5 Relu啟用
# 定義max-pooling層 pool0
pool0 = tf.layers.max_pooling2d(conv0, [2, 2], [2, 2])        #pooling視窗為2x2 步長為2x2
print("Layer0:\n", conv0, pool0)
 
# 定義卷積層 conv1
conv1 = tf.layers.conv2d(pool0, 40, 4, activation=tf.nn.relu) #40個卷積核 卷積核大小為4 Relu啟用
# 定義max-pooling層 pool1
pool1 = tf.layers.max_pooling2d(conv1, [2, 2], [2, 2])        #pooling視窗為2x2 步長為2x2
print("Layer1:\n", conv1, pool1)

# 將3維特徵轉換為1維向量
flatten = tf.layers.flatten(pool1)

# 全連線層 轉換為長度為400的特徵向量
fc = tf.layers.dense(flatten, 400, activation=tf.nn.relu)
print("Layer2:\n", fc)

# 加上DropOut防止過擬合
dropout_fc = tf.layers.dropout(fc, drop)

# 未啟用的輸出層
logits = tf.layers.dense(dropout_fc, num_classes)
print("Output:\n", logits)

# 定義輸出結果
predicted_labels = tf.arg_max(logits, 1)
#---------------------------------第三步 定義損失函式和優化器---------------------------------

# 利用交叉熵定義損失
losses = tf.nn.softmax_cross_entropy_with_logits(
        labels = tf.one_hot(ys, num_classes),       #將input轉化為one-hot型別資料輸出
        logits = logits)

# 平均損失
mean_loss = tf.reduce_mean(losses)

# 定義優化器 學習效率設定為0.0001
optimizer = tf.train.AdamOptimizer(learning_rate=1e-4).minimize(losses)
#------------------------------------第四步 模型訓練和預測-----------------------------------
# 用於儲存和載入模型
saver = tf.train.Saver()
# 訓練或預測
train = False
# 模型檔案路徑
model_path = "model/image_model"

with tf.Session() as sess:
    if train:
        print("訓練模式")
        # 訓練初始化引數
        sess.run(tf.global_variables_initializer())
        # 定義輸入和Label以填充容器 訓練時dropout為0.25
        train_feed_dict = {
                xs: x_train,
                ys: y_train,
                drop: 0.25
        }
        # 訓練學習1000次
        for step in range(1000):
            _, mean_loss_val = sess.run([optimizer, mean_loss], feed_dict=train_feed_dict)
            if step % 50 == 0:  #每隔50次輸出一次結果
                print("step = {}\t mean loss = {}".format(step, mean_loss_val))
        # 儲存模型
        saver.save(sess, model_path)
        print("訓練結束,儲存模型到{}".format(model_path))
    else:
        print("測試模式")
        # 測試載入引數
        saver.restore(sess, model_path)
        print("從{}載入模型".format(model_path))
        # label和名稱的對照關係
        label_name_dict = {
            0: "人類",
            1: "沙灘",
            2: "建築",
            3: "公交",
            4: "恐龍",
            5: "大象",
            6: "花朵",
            7: "野馬",
            8: "雪山",
            9: "美食"
        }
        # 定義輸入和Label以填充容器 測試時dropout為0
        test_feed_dict = {
            xs: x_val,
            ys: y_val,
            drop: 0
        }
 
        # 真實label與模型預測label
        predicted_labels_val = sess.run(predicted_labels, feed_dict=test_feed_dict)
        for fpath, real_label, predicted_label in zip(fpaths_test, y_val, predicted_labels_val):
            # 將label id轉換為label名
            real_label_name = label_name_dict[real_label]
            predicted_label_name = label_name_dict[predicted_label]
            print("{}\t{} => {}".format(fpath, real_label_name, predicted_label_name))
        # 評價結果
        print("正確預測個數:", sum(y_val==predicted_labels_val))
        print("準確度為:", 1.0*sum(y_val==predicted_labels_val) / len(y_val))

核心步驟為:

saver = tf.train.Saver()
model_path = "model/image_model"
with tf.Session() as sess:
    if train:
        #儲存神經網路
        sess.run(tf.global_variables_initializer())
        for step in range(1000):
            _, mean_loss_val = sess.run([optimizer, mean_loss], feed_dict=train_feed_dict)
            if step % 50 == 0:
                print("step = {}\t mean loss = {}".format(step, mean_loss_val))
        saver.save(sess, model_path)
    else:
        #載入神經網路
        saver.restore(sess, model_path)
        predicted_labels_val = sess.run(predicted_labels, feed_dict=test_feed_dict)
        for fpath, real_label, predicted_label in zip(fpaths_test, y_val, predicted_labels_val):
            real_label_name = label_name_dict[real_label]
            predicted_label_name = label_name_dict[predicted_label]
            print("{}\t{} => {}".format(fpath, real_label_name, predicted_label_name))    

預測輸出結果如下圖所示,最終預測正確181張圖片,準確度為0.905。相比之前機器學習KNN的0.500有非常高的提升。

Tensorflow儲存神經網路引數有妙招:Saver和Restore

測試模式

INFO:tensorflow:Restoring parameters from model/image_model
從model/image_model載入模型
b'photo/photo/3\\335.jpg'       公交 => 公交
b'photo/photo/1\\129.jpg'       沙灘 => 沙灘
b'photo/photo/7\\740.jpg'       野馬 => 野馬
b'photo/photo/5\\564.jpg'       大象 => 大象
...
b'photo/photo/9\\974.jpg'       美食 => 美食
b'photo/photo/2\\220.jpg'       建築 => 公交
b'photo/photo/9\\912.jpg'       美食 => 美食
b'photo/photo/4\\459.jpg'       恐龍 => 恐龍
b'photo/photo/5\\525.jpg'       大象 => 大象
b'photo/photo/0\\44.jpg'        人類 => 人類

正確預測個數: 181
準確度為: 0.905

 

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章