TensorFlow官方文檔卷積神經網絡

卷積神經網絡

注意: 本教程適用於對Tensorflow有豐富經驗的用戶,並假定用戶有機器學習相關領域的專業知識和經驗。

艾伯特(http://www.aibbt.com/)國內第一家人工智能門戶

概述

對CIFAR-10 數據集的分類是機器學習中一個公開的基準測試問題,其任務是對一組大小爲32x32的RGB圖像進行分類,這些圖像涵蓋了10個類別:

飛機, 汽車, 鳥, 貓, 鹿, 狗, 青蛙, 馬, 船以及卡車。TensorFlow 官方文檔中文版

想了解更多信息請參考CIFAR-10 page,以及Alex Krizhevsky寫的技術報告

目標

本教程的目標是建立一個用於識別圖像的相對較小的卷積神經網絡,在這一過程中,本教程會:

着重於建立一個規範的網絡組織結構,訓練並進行評估;

爲建立更大規模更加複雜的模型提供一個範例

選擇CIFAR-10是因爲它的複雜程度足以用來檢驗TensorFlow中的大部分功能,並可將其擴展爲更大的模型。與此同時由於模型較小所以訓練速度很快,比較適合用來測試新的想法,檢驗新的技術。

本教程的重點

CIFAR-10 教程演示了在TensorFlow上構建更大更復雜模型的幾個種重要內容:

相關核心數學對象,如卷積、修正線性激活、最大池化以及局部響應歸一化;

  • 訓練過程中一些網絡行爲的可視化,這些行爲包括輸入圖像、損失情況、網絡行爲的分佈情況以及梯度;
  • 算法學習參數的移動平均值的計算函數,以及在評估階段使用這些平均值提高預測性能;
  • 實現了一種機制,使得學習率隨着時間的推移而遞減;
  • 爲輸入數據設計預存取隊列,將磁盤延遲和高開銷的圖像預處理操作與模型分離開來處理;
  • 我們也提供了模型的多GPU版本,用以表明:
  • 可以配置模型後使其在多個GPU上並行的訓練
  • 可以在多個GPU之間共享和更新變量值
  • 我們希望本教程給大家開了個頭,使得在Tensorflow上可以爲視覺相關工作建立更大型的CNN模型
  • 模型架構
  • 本教程中的模型是一個多層架構,由卷積層和非線性層(nonlinearities)交替多次排列後構成。這些層最終通過全連通層對接到softmax分類器上。這一模型除了最頂部的幾層外,基本跟Alex Krizhevsky提出的模型一致。
  • 在一個GPU上經過幾個小時的訓練後,該模型最高可以達到86%的精度。細節請查看下面的描述以及代碼。模型中包含了1,068,298個學習參數,對一副圖像進行分類大概需要19.5M個乘加操作。
  • 代碼組織
  • 本教程的代碼位於tensorflow/models/image/cifar10/.
文件作用
cifar10_input.py讀取本地CIFAR-10的二進制文件格式的內容。
cifar10.py建立CIFAR-10的模型。
cifar10_train.py在CPU或GPU上訓練CIFAR-10的模型。
cifar10_multi_gpu_train.py在多GPU上訓練CIFAR-10的模型。
cifar10_eval.py評估CIFAR-10模型的預測性能。

CIFAR-10 模型

CIFAR-10 網絡模型部分的代碼位於 cifar10.py. 完整的訓練圖中包含約765個操作。但是我們發現通過下面的模塊來構造訓練圖可以最大限度的提高代碼複用率:

模型輸入: 包括inputs() 、 distorted_inputs()等一些操作,分別用於讀取CIFAR的圖像並進行預處理,做爲後續評估和訓練的輸入;


  1. 模型預測:
     包括inference()等一些操作,用於進行統計計算,比如在提供的圖像進行分類; adds operations that perform inference, i.e. classification, on supplied images.
  2. 模型訓練: 包括loss() and train()等一些操作,用於計算損失、計算梯度、進行變量更新以及呈現最終結果。

模型輸入

輸入模型是通過 inputs() 和distorted_inputs()函數建立起來的,這2個函數會從CIFAR-10二進制文件中讀取圖片文件,由於每個圖片的存儲字節數是固定的,因此可以使用tf.FixedLengthRecordReader函數。更多的關於Reader類的功能可以查看Reading Data。

圖片文件的處理流程如下:

  • 圖片會被統一裁剪到24x24像素大小,裁剪中央區域用於評估或隨機裁剪用於訓練;
  • 圖片會進行近似的白化處理,使得模型對圖片的動態範圍變化不敏感。

對於訓練,我們另外採取了一系列隨機變換的方法來人爲的增加數據集的大小:

  • 對圖像進行隨機的左右翻轉;
  • 隨機變換圖像的亮度;
  • 隨機變換圖像的對比度;

可以在Images頁的列表中查看所有可用的變換,對於每個原始圖我們還附帶了一個image_summary,以便於在TensorBoard中查看。這對於檢查輸入圖像是否正確十分有用。

TensorFlow 官方文檔中文版

從磁盤上加載圖像並進行變換需要花費不少的處理時間。爲了避免這些操作減慢訓練過程,我們在16個獨立的線程中並行進行這些操作,這16個線程被連續的安排在一個TensorFlow隊列中。

模型預測

模型的預測流程由inference()構造,該函數會添加必要的操作步驟用於計算預測值的 logits,其對應的模型組織方式如下所示:

Layer 名稱描述
conv1實現卷積 以及 rectified linear activation.
pool1max pooling.
norm1局部響應歸一化.
conv2卷積 and rectified linear activation.
norm2局部響應歸一化.
pool2max pooling.
local3基於修正線性激活的全連接層.
local4基於修正線性激活的全連接層.
softmax_linear進行線性變換以輸出 logits.

這裏有一個由TensorBoard繪製的圖形,用於描述模型建立過程中經過的步驟:TensorFlow 官方文檔中文版

練習inference的輸出是未歸一化的logits,嘗試使用tf.softmax()修改網絡架構後返回歸一化的預測值。

inputs() 和 inference() 函數提供了評估模型時所需的所有構件,現在我們把講解的重點從構建一個模型轉向訓練一個模型。

練習: inference() 中的模型跟cuda-convnet中描述的CIFAR-10模型有些許不同,其差異主要在於其頂層不是全連接層而是局部連接層,可以嘗試修改網絡架構來準確的複製全連接模型。

模型訓練

訓練一個可進行N維分類的網絡的常用方法是使用多項式邏輯迴歸,又被叫做softmax 迴歸。Softmax 迴歸在網絡的輸出層上附加了一個softmax nonlinearity,並且計算歸一化的預測值和label的1-hot encoding的交叉熵。在正則化過程中,我們會對所有學習變量應用權重衰減損失。模型的目標函數是求交叉熵損失和所有權重衰減項的和,loss()函數的返回值就是這個值。

在TensorBoard中使用scalar_summary來查看該值的變化情況:TensorFlow 官方文檔中文版

我們使用標準的梯度下降算法來訓練模型(也可以在Training中看看其他方法),其學習率隨時間以指數形式衰減。

TensorFlow 官方文檔中文版

train() 函數會添加一些操作使得目標函數最小化,這些操作包括計算梯度、更新學習變量(詳細信息請查看GradientDescentOptimizer)。train() 函數最終會返回一個用以對一批圖像執行所有計算的操作步驟,以便訓練並更新模型。

開始執行並訓練模型

我們已經把模型建立好了,現在通過執行腳本cifar10_train.py來啓動訓練過程。

python cifar10_train.py注意: 當第一次在CIFAR-10教程上啓動任何任務時,會自動下載CIFAR-10數據集,該數據集大約有160M大小,因此第一次運行時泡杯咖啡小棲一會吧。

你應該可以看到如下類似的輸出:

Filling queue with 20000 CIFAR images before starting to train. This will take a few minutes.
2015-11-04 11:45:45.927302: step 0, loss = 4.68 (2.0 examples/sec; 64.221 sec/batch)
2015-11-04 11:45:49.133065: step 10, loss = 4.66 (533.8 examples/sec; 0.240 sec/batch)
2015-11-04 11:45:51.397710: step 20, loss = 4.64 (597.4 examples/sec; 0.214 sec/batch)
2015-11-04 11:45:54.446850: step 30, loss = 4.62 (391.0 examples/sec; 0.327 sec/batch)
2015-11-04 11:45:57.152676: step 40, loss = 4.61 (430.2 examples/sec; 0.298 sec/batch)
2015-11-04 11:46:00.437717: step 50, loss = 4.59 (406.4 examples/sec; 0.315 sec/batch)
...

腳本會在每10步訓練過程後打印出總損失值,以及最後一批數據的處理速度。下面是幾點註釋:

第一批數據會非常的慢(大概要幾分鐘時間),因爲預處理線程要把20,000個待處理的CIFAR圖像填充到重排隊列中;

  • 打印出來的損失值是最近一批數據的損失值的均值。請記住損失值是交叉熵和權重衰減項的和;
  • 上面打印結果中關於一批數據的處理速度是在Tesla K40C上統計出來的,如果你運行在CPU上,性能會比此要低;
  • 練習: 當實驗時,第一階段的訓練時間有時會非常的長,長到足以讓人生厭。可以嘗試減少初始化時初始填充到隊列中圖片數量來改變這種情況。在cifar10.py搜索NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN並修改之。
  • cifar10_train.py 會週期性的在檢查點文件中保存模型中的所有參數,但是不會對模型進行評估。cifar10_eval.py會使用該檢查點文件來測試預測性能(詳見下面的描述:評估模型)。
  • 如果按照上面的步驟做下來,你應該已經開始訓練一個CIFAR-10模型了。恭喜你!
  • cifar10_train.py輸出的終端信息中提供了關於模型如何訓練的一些信息,但是我們可能希望瞭解更多關於模型訓練時的信息,比如:

  • 損失是真的在減小還是看到的只是噪聲數據?
  • 爲模型提供的圖片是否合適?
  • 梯度、激活、權重的值是否合理?
  • 當前的學習率是多少?
  • TensorBoard提供了該功能,可以通過cifar10_train.py中的SummaryWriter週期性的獲取並顯示這些數據。
  • 比如我們可以在訓練過程中查看local3的激活情況,以及其特徵維度的稀疏情況:
  • TensorFlow 官方文檔中文版TensorFlow 官方文檔中文版
  • 相比於總損失,在訓練過程中的單項損失尤其值得人們的注意。但是由於訓練中使用的數據批量比較小,損失值中夾雜了相當多的噪聲。在實踐過程中,我們也發現相比於原始值,損失值的移動平均值顯得更爲有意義。請參閱腳本ExponentialMovingAverage瞭解如何實現。
  • 評估模型
  • 現在可以在另一部分數據集上來評估訓練模型的性能。腳本文件cifar10_eval.py對模型進行了評估,利用 inference()函數重構模型,並使用了在評估數據集所有10,000張CIFAR-10圖片進行測試。最終計算出的精度爲1:N,N=預測值中置信度最高的一項與圖片真實label匹配的頻次。(It calculates the precision at 1: how often the top prediction matches the true label of the image)。
  • 爲了監控模型在訓練過程中的改進情況,評估用的腳本文件會週期性的在最新的檢查點文件上運行,這些檢查點文件是由cifar10_train.py產生。
  • python cifar10_eval.py
  • 注意:不要在同一塊GPU上同時運行訓練程序和評估程序,因爲可能會導致內存耗盡。儘可能的在其它單獨的GPU上運行評估程序,或者在同一塊GPU上運行評估程序時先掛起訓練程序。
  • 你可能會看到如下所示輸出:
  • 2015-11-06 08:30:44.391206: precision @ 1 = 0.860
  • ...
  • 評估腳本只是週期性的返回precision@1 (The script merely returns the precision @ 1 periodically)--在該例中返回的準確率是86%。cifar10_eval.py 同時也返回其它一些可以在TensorBoard中進行可視化的簡要信息。可以通過這些簡要信息在評估過程中進一步的瞭解模型。
  • 訓練腳本會爲所有學習變量計算其移動均值,評估腳本則直接將所有學習到的模型參數替換成對應的移動均值。這一替代方式可以在評估過程中提升模型的性能。http://www.aibbt.com/a/16370.html
  • 練習: 通過precision @ 1測試發現,使用均值參數可以將預測性能提高約3%,在cifar10_eval.py中嘗試修改爲不採用均值參數的方式,並確認由此帶來的預測性能下降。
  • 在多個GPU板卡上訓練模型
  • 現代的工作站可能包含多個GPU進行科學計算。TensorFlow可以利用這一環境在多個GPU卡上運行訓練程序。
  • 在並行、分佈式的環境中進行訓練,需要對訓練程序進行協調。對於接下來的描述,術語模型拷貝model replica)特指在一個數據子集中訓練出來的模型的一份拷貝。
  • 如果天真的對模型參數的採用異步方式更新將會導致次優的訓練性能,這是因爲我們可能會基於一箇舊的模型參數的拷貝去訓練一個模型。但與此相反採用完全同步更新的方式,其速度將會變得和最慢的模型一樣慢(Conversely, employing fully synchronous updates will be as slow as the slowest model replica.)。
  • 在具有多個GPU的工作站中,每個GPU的速度基本接近,並且都含有足夠的內存來運行整個CIFAR-10模型。因此我們選擇以下方式來設計我們的訓練系統:
  • 在每個GPU上放置單獨的模型副本;
  • 等所有GPU處理完一批數據後再同步更新模型的參數;
  • 下圖示意了該模型的結構::
  • TensorFlow 官方文檔中文版
  • 可以看到,每一個GPU會用一批獨立的數據計算梯度和估計值。這種設置可以非常有效的將一大批數據分割到各個GPU上。
  • 這一機制要求所有GPU能夠共享模型參數。但是衆所周知在GPU之間傳輸數據非常的慢,因此我們決定在CPU上存儲和更新所有模型的參數(對應圖中綠色矩形的位置)。這樣一來,GPU在處理一批新的數據之前會更新一遍的參數。
  • 圖中所有的GPU是同步運行的。所有GPU中的梯度會累積並求平均值(綠色方框部分)。模型參數會利用所有模型副本梯度的均值來更新。
  • 在多個設備中設置變量和操作
  • 在多個設備中設置變量和操作時需要做一些特殊的抽象。
  • 我們首先需要把在單個模型拷貝中計算估計值和梯度的行爲抽象到一個函數中。在代碼中,我們稱這個抽象對象爲“tower”。對於每一個“tower”我們都需要設置它的兩個屬性:

  • 在一個tower中爲所有操作設定一個唯一的名稱。tf.name_scope()通過添加一個範圍前綴來提供該唯一名稱。比如,第一個tower中的所有操作都會附帶一個前綴tower_0,示例:tower_0/conv1/Conv2D
  • 在一個tower中運行操作的優先硬件設備。 tf.device() 提供該信息。比如,在第一個tower中的所有操作都位於 device('/gpu:0')範圍中,暗含的意思是這些操作應該運行在第一塊GPU上;
  • 爲了在多個GPU上共享變量,所有的變量都綁定在CPU上,並通過tf.get_variable()訪問。可以查看Sharing Variables以瞭解如何共享變量。
  • 啓動並在多個GPU上訓練模型
  • 如果你的機器上安裝有多塊GPU,你可以通過使用cifar10_multi_gpu_train.py腳本來加速模型訓練。該腳本是訓練腳本的一個變種,使用多個GPU實現模型並行訓練。
  • python cifar10_multi_gpu_train.py --num_gpus=2
  • 訓練腳本的輸出如下所示:
  • Filling queue with 20000 CIFAR images before starting to train. This will take a few minutes.
2015-11-04 11:45:45.927302: step 0, loss = 4.68 (2.0 examples/sec; 64.221 sec/batch)
2015-11-04 11:45:49.133065: step 10, loss = 4.66 (533.8 examples/sec; 0.240 sec/batch)
2015-11-04 11:45:51.397710: step 20, loss = 4.64 (597.4 examples/sec; 0.214 sec/batch)
2015-11-04 11:45:54.446850: step 30, loss = 4.62 (391.0 examples/sec; 0.327 sec/batch)
2015-11-04 11:45:57.152676: step 40, loss = 4.61 (430.2 examples/sec; 0.298 sec/batch)
2015-11-04 11:46:00.437717: step 50, loss = 4.59 (406.4 examples/sec; 0.315 sec/batch)
...
需要注意的是默認的GPU使用數是1,此外,如果你的機器上只有一個GPU,那麼所有的計算都只會在一個GPU上運行,即便你可能設置的是N個。 練習: cifar10_train.py中的批處理大小默認配置是128。嘗試在2個GPU上運行cifar10_multi_gpu_train.py腳本,並且設定批處理大小爲64,然後比較2種方式的訓練速度。 下一步 恭喜你! 你已經完成了CIFAR-10教程。 如果你對開發和訓練自己的圖像分類系統感興趣,我們推薦你新建一個基於該教程的分支,並修改其中的內容以建立解決您問題的圖像分類系統。 練習: 下載Street View House Numbers (SVHN) 數據集。新建一個CIFAR-10教程的分支,並將輸入數據替換成SVHN。嘗試改變網絡結構以提高預測性能。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章