TensorFlow極簡教程:創建、保存和恢復機器學習模型

在每個例子中,我們用一條直線擬合一些數據。使用梯度下降(gradient descent)確定最適合數據的線的斜率和 y 截距的值。如果你不知道梯度下降,請查看維基百科

創建所需的變數後,數據和線之間的誤差是可以被定義(計算)的。定義的誤差被嵌入到優化器(optimizer)中。然後啟動 TensorFlow,並重複調用優化器。通過不斷迭代最小化誤差來達到數據與直線的最佳擬合。

按照順序閱讀下列腳本:

  • serial.py

  • tensor.py

  • bigdata.py

Serial.py

這個腳本的目的是說明 TensorFlow 模型的基本要點。這個腳本使你更容易理解模型是如何組合在一起的。我們使用 for 循環來定義數據與線之間的誤差。由於定義誤差的方式為循環,該腳本以序列化(串列)計算的方式運行。

Tensor.py

這個腳本比 serial.py 更進一步,雖然實際上這個腳本的代碼行更少。代碼的結構與之前相同,唯一不同的是這次使用張量(tensor)操作來定義誤差。使用張量可以並行(parallel)運行代碼。

每個數據點被看作是來自獨立同分布的樣本。因為每個數據點假定是獨立的,所以計算也是獨立的。當使用張量時,每個數據點都在分隔的計算內核上運行。我們有 8 個數據點,所以如果你有一個有八個內核的計算機,它的運行速度應該快八倍。

BigData.py

你現在距離專業水平僅有一個流行語之遙。我們現在不需要將一條線擬合到 8 個數據點,而是將一條線擬合到 800 萬個數據點。歡迎來到大數據時代。

代碼中有兩處主要的修改。第一點變化是簿記(bookkeeping),因為所有數據必須使用佔位符(placeholder)而不是實際數據來定義誤差。在代碼的後半部分,數據需要通過佔位符饋送(feed)入模型。第二點變化是,因為我們的數據量是巨大的,在給定的任意時間我們僅將一個樣本數據傳入模型。每次調用梯度下降操作時,新的數據樣本將被饋送到模型中。通過對數據集進行抽樣,TensorFlow 不需要一次處理整個數據集。這樣抽樣的效果出奇的好,並有理論支持這種方法:

Stochastic gradient descent

理論上需要滿足一些重要的條件,如步長(step size)必須隨每次迭代而縮短。不管是否滿足條件,這種方法至少是有效的。

結論

當你運行腳本時,你可能看到怎樣定義任何你想要的誤差。它可能是一組圖像和卷積神經網路(convolutional neural network)之間的誤差。它可能是古典音樂和循環神經網路(recurrent neural network)之間的誤差。它讓你的想像力瘋狂。一旦定義了誤差,你就可以使用 TensorFlow 進行嘗試並最小化誤差。

希望你從這個教程中得到啟發。

需求

  • Python3 (Welcome to Python.org)

  • TensorFlow (tensorflow.org/)

  • NumPy (NumPy - NumPy)

TensorFlow:保存/恢復和混合多重模型

在第一個模型成功建立並訓練之後,你或許需要了解如何保存與恢復這些模型。繼續之前,也可以閱讀這個 Tensorflow 小入門:

blog.metaflow.fr/tensor

你有必要了解這些信息,因為了解如何保存不同級別的代碼是非常重要的,這可以避免混亂無序。

如何實際保存和載入

  • 保存(saver)對象

可以使用 Saver 對象處理不同會話(session)中任何與文件系統有持續數據傳輸的交互。構造函數(constructor)允許你控制以下 3 個事物:

  • 目標(target):在分散式架構的情況下用於處理計算。可以指定要計算的 TF 伺服器或「目標」。

  • 圖(graph):你希望會話處理的圖。對於初學者來說,棘手的事情是:TF 中總存在一個默認的圖,其中所有操作的設置都是默認的,所以你的操作範圍總在一個「默認的圖」中。

  • 配置(config):你可以使用 ConfigProto 配置 TF。查看本文最後的鏈接資源以獲取更多詳細信息。

Saver 可以處理圖的元數據和變數數據的保存和載入(又稱恢復)。它需要知道的唯一的事情是:需要使用哪個圖和變數?

默認情況下,Saver 會處理默認的圖及其所有包含的變數,但是你可以創建儘可能多的 Saver 來控制你想要的任何圖或子圖的變數。這裡是一個例子:

import tensorflow as tf

import os

dir = os.path.dirname(os.path.realpath(__file__))

# First, you design your mathematical operations

# We are the default graph scope

# Lets design a variable

v1 = tf.Variable(1. , name="v1")

v2 = tf.Variable(2. , name="v2")

# Lets design an operation

a = tf.add(v1, v2)

# Lets create a Saver object

# By default, the Saver handles every Variables related to the default graph

all_saver = tf.train.Saver()

# But you can precise which vars you want to save under which name

v2_saver = tf.train.Saver({"v2": v2})

# By default the Session handles the default graph and all its included variables

with tf.Session() as sess:

# Init v and v2

sess.run(tf.global_variables_initializer())

# Now v1 holds the value 1.0 and v2 holds the value 2.0

# We can now save all those values

all_saver.save(sess, dir + /data-all.chkp)

# or saves only v2

v2_saver.save(sess, dir + /data-v2.chkp)

如果查看你的文件夾,它實際上每創建 3 個文件調用一次保存操作並創建一個檢查點(checkpoint)文件,我會在附錄中講述更多的細節。你可以簡單理解為權重被保存到 .chkp.data 文件中,你的圖和元數據被保存到 .chkp.meta 文件中。

  • 恢復操作和其它元數據

一個重要的信息是,Saver 將保存與你的圖相關聯的任何元數據。這意味著載入元檢查點還將恢復與圖相關聯的所有空變數、操作和集合(例如,它將恢復訓練優化器)。

當你恢復一個元檢查點時,實際上是將保存的圖載入到當前默認的圖中。現在你可以通過它來載入任何包含的內容,如張量、操作或集合。

import tensorflow as tf

# Lets load a previously saved meta graph in the default graph

# This function returns a Saver

saver = tf.train.import_meta_graph(results/model.ckpt-1000.meta)

# We can now access the default graph where all our metadata has been loaded

graph = tf.get_default_graph()

# Finally we can retrieve tensors, operations, collections, etc.

global_step_tensor = graph.get_tensor_by_name(loss/global_step:0)

train_op = graph.get_operation_by_name(loss/train_op)

hyperparameters = tf.get_collection(hyperparameters)

  • 恢復權重

請記住,實際的權重只存在於一個會話中。這意味著「恢復」操作必須能夠訪問會話以恢復圖內的權重。理解恢復操作的最好方法是將其簡單地當作一種初始化。

with tf.Session() as sess:

# To initialize values with saved data

saver.restore(sess, results/model.ckpt.data-1000-00000-of-00001)

print(sess.run(global_step_tensor)) # returns 1000

  • 在新圖中使用預訓練圖

現在你知道了如何保存和載入,你可能已經明白如何去操作。然而,這裡有一些技巧能夠幫助你走得更快。

  • 一個圖的輸出可以是另一個圖的輸入嗎?

是的,但有一個缺點:我還不知道使梯度流(gradient flow)在圖之間容易傳遞的一種方法,因為你將必須評估第一個圖,獲得結果,並將其饋送到下一個圖。

這樣一直下去是可以的,直到你需要重新訓練第一個圖。在這種情況下,你將需要將輸入梯度饋送到第一個圖的訓練步驟……

  • 我可以在一個圖中混合所有這些不同的圖嗎?

是的,但你需要對命名空間(namespace)倍加小心。好的一點是,這種方法簡化了一切:例如,你可以載入預訓練的 VGG-16,訪問圖中的任何節點,嵌入自己的操作和訓練整個圖!

如果你只想微調(fine-tune)節點,你可以在任意地方停止梯度來避免訓練整個圖。

import tensorflow as tf

# Load the VGG-16 model in the default graph

vgg_saver = tf.train.import_meta_graph(dir + gg/resultsgg-16.meta)

# Access the graph

vgg_graph = tf.get_default_graph()

# Retrieve VGG inputs

self.x_plh = vgg_graph.get_tensor_by_name(input:0)

# Choose which node you want to connect your own graph

output_conv =vgg_graph.get_tensor_by_name(conv1_2:0)

# output_conv =vgg_graph.get_tensor_by_name(conv2_2:0)

# output_conv =vgg_graph.get_tensor_by_name(conv3_3:0)

# output_conv =vgg_graph.get_tensor_by_name(conv4_3:0)

# output_conv =vgg_graph.get_tensor_by_name(conv5_3:0)

# Stop the gradient for fine-tuning

output_conv_sg = tf.stop_gradient(output_conv) # Its an identity function

# Build further operations

output_conv_shape = output_conv_sg.get_shape().as_list()

W1 = tf.get_variable(W1, shape=[1, 1, output_conv_shape[3], 32], initializer=tf.random_normal_initializer(stddev=1e-1))

b1 = tf.get_variable(b1, shape=[32], initializer=tf.constant_initializer(0.1))

z1 = tf.nn.conv2d(output_conv_sg, W1, strides=[1, 1, 1, 1], padding=SAME) + b1

a = tf.nn.relu(z1)

附錄:更多關於 TF 數據生態系統的內容

我們在這裡談論谷歌,他們主要使用內部構建的工具來處理他們的工作,所以數據保存的格式為 ProtoBuff 也是不奇怪的。

  • 協議緩衝區

協議緩衝區(Protocol Buffer/簡寫 Protobufs)是 TF 有效存儲和傳輸數據的常用方式。

我不在這裡詳細介紹它,但可以把它當成一個更快的 JSON 格式,當你在存儲/傳輸時需要節省空間/帶寬,你可以壓縮它。簡而言之,你可以使用 Protobufs 作為:

  • 一種未壓縮的、人性化的文本格式,擴展名為 .pbtxt

  • 一種壓縮的、機器友好的二進位格式,擴展名為 .pb 或根本沒有擴展名

這就像在開發設置中使用 JSON,並且在遷移到生產環境時為了提高效率而壓縮數據一樣。用 Protobufs 可以做更多的事情,如果你有興趣可以查看教程

整潔的小技巧:在張量流中處理 protobufs 的所有操作都有這個表示「協議緩衝區定義」的「_def」後綴。例如,要載入保存的圖的 protobufs,可以使用函數:tf.import_graph_def。要獲取當前圖作為 protobufs,可以使用:Graph.as_graph_def()。

  • 文件的架構

回到 TF,當保存你的數據時,你會得到 5 種不同類型的文件:

  • 「檢查點」文件

  • 「事件(event)」文件

  • 「文本 protobufs」文件

  • 一些「chkp」文件

  • 一些「元 chkp」文件

現在讓我們休息一下。當你想到,當你在做機器學習時可能會保存什麼?你可以保存模型的架構和與其關聯的學習到的權重。你可能希望在訓練或事件整個訓練架構時保存一些訓練特徵,如模型的損失(loss)和準確率(accuracy)。你可能希望保存超參數和其它操作,以便之後重新啟動訓練或重複實現結果。這正是 TensorFlow 的作用。

在這裡,檢查點文件的三種類型用於存儲模型及其權重有關的壓縮後數據。

  • 檢查點文件只是一個簿記文件,你可以結合使用高級輔助程序載入不同時間保存的 chkp 文件。

  • 元 chkp 文件包含模型的壓縮 Protobufs 圖以及所有與之關聯的元數據(集合、學習速率、操作等)。

  • chkp 文件保存數據(權重)本身(這一個通常是相當大的大小)。

  • 如果你想做一些調試,pbtxt 文件只是模型的非壓縮 Protobufs 圖。

  • 最後,事件文件在 TensorBoard 中存儲了所有你需要用來可視化模型和訓練時測量的所有數據。這與保存/恢復模型本身無關。

下面讓我們看一下結果文件夾的屏幕截圖:

一些隨機訓練的結果文件夾的屏幕截圖

  • 該模型已經在步驟 433,858,1000 被保存了 3 次。為什麼這些數字看起來像隨機?因為我設定每 S 秒保存一次模型,而不是每 T 次迭代後保存。

  • chkp 文件比元 chkp 文件更大,因為它包含我們模型的權重

  • pbtxt 文件比元 chkp 文件大一點:它被認為是非壓縮版本!

TF 自帶多個方便的幫助方法,如:

在時間和迭代中處理模型的不同檢查點。它如同一個救生員,以防你的機器在訓練結束前崩潰。

注意:TensorFlow 現在發展很快,這些文章目前是基於 1.0.0 版本編寫的。

--------文章來源:TensorFlow極簡教程:創建、保存和恢復機器學習模型

推薦閱讀:

用戶數據使用合規實務指南
大數據那些事(2):三駕馬車之永垂不朽的GFS
卷積?神經?網路?教你從讀懂詞語開始了解計算機視覺識別最火模型 | CNN入門手冊(上)
這大概是史上最全的「大數據」學習資源了!
有了大數據加智能,你願把荷包交給機器打理嗎?

TAG:大数据 | 机器学习 | TensorFlow |