摘要:Caffe 模型的學習被分爲兩個部分:由 Solver 進行優化、更新參數,由 Net 計算出 loss 和 gradient。只要定義好了模型,這些計算就可以立即進行:Caffe 已經準備好了 forward 和 backward 的實現方法。

自動化實現過程,UI框架的自動化往往不能滿足所有場景的需求,比如:動態效果圖片內容一致性檢查;在全民AI的浪潮中,基於Caffe框架的AI圖像識別結合QT4A自動化測試嘗試,在企鵝電競彈幕識別,以及表情業務自動化中動態圖像識別有了落地,填補了自動化對動態圖片內容精準檢測的不足。

Caffe是一個清晰而高效的深度學習框架,也是一個被廣泛使用的開源深度學習框架,在Tensorflow出現之前一直是深度學習領域Github star最多的項目。

Caffe的主要優勢爲:容易上手,網絡結構都是以配置文件形式定義,不需要用代碼設計網絡。訓練速度快,組件模塊化,可以方便的拓展到新的模型和學習任務上。但是Caffe最開始設計時的目標只針對於圖像,沒有考慮文本、語音或者時間序列的數據,因此Caffe對卷積神經網絡的支持非常好,但是對於時間序列RNN,LSTM等支持的不是特別充分。

一、自動化檢測結合AI圖像識別效果圖

效果:caffe訓練的模型,企鵝電競APP中對當前整個手機屏幕中的某一個特徵彈幕識別率可達95%以上,其中表情的動態內容識別可達到100%。

企鵝電競彈幕識別:   

表情識別:

二、AI識別結合自動化整體方案

整體的流程:在Caffer框架環境下,我們對訓練好的模型生成服務,結合QT4A自動化框架,在用例中調用AI識別接口,回調給自動化檢查結果,整個過程簡單可分兩部分:模型訓練和自動化識別調用檢查

1、設計特徵

嘗試方案一:在企鵝電競彈幕中,最初擔心對整個屏幕任意區域去識別特徵,識別率不高,所以嘗試是對彈幕顯示的固定位置作爲採樣訓練,也就是對整個屏幕中縮小範圍到固定的區域識別特徵,這樣的識別效果準確率可達95%,但對訓練圖片採樣比較耗時,工作量有所增加,該方案也不靈活。

嘗試方案二:我們嘗試對整個手機屏幕中去識別某個特徵,這樣對採樣圖片沒有任何要求,只要圖片中有所需特徵,清晰就可以作爲訓練素材,無需二次介入加工處理,意想不到,通過多次的模型訓練調整,整體的識別率其實並不低,也在95%以上;

2、準備訓練集和測試集

Caffer的模型訓練需要預先準備好訓練集合測試集,同類型的數據最好要1000張以上,並且覆蓋儘可能多場景,增加泛化能力,目錄結構對應文件夾名爲0/1/2/3,其中文件夾0表示無特徵圖片,非0按順序對應每個文件夾對應一個特徵,比如1/2/3分別對應666/單身狗/坑三個特徵表情的多個特徵素材;

 

備註小技巧:準備素材可使用視頻分幀或者自動化腳本截圖方式。

採用ffmpeg視頻分幀,如下命令:

利用python腳本截圖:

3、生成訓練集及測試集

調用genTrainset.py腳本,對採集的訓練和測試素材重新生成:

4、處理數據

將圖片轉換爲Caffe識別的LMDB或LEVELDB,他們是Google開發的一種Key-Value存儲管理器。

5、選擇模型

模型選擇上,caffe工程的models文件夾中有這些網絡模型,查看models文件夾,常用的網絡模型比較多,比如Lenet、AlexNet、ZFNet、VGGNet、GoogleNet、ResNet根據實驗對比,如果純圖像識別,用GoogleNet已經遠可滿足使用:

deploy.prototxt爲部署網絡結構:

裏面定義各種網絡層,如:LRN層、cancat層、全鏈接層、全鏈接輸出層、損失層等等,一般無需修改次配置,具體每一層的含義:

solver.prototxt中定義了訓練所用到的參數:

具體每個參數的意義如下:

train_val.prototxt定義網絡結構

裏面定義包含字段:網絡名稱、定義一個層、層的名稱、層的數據類型、層的輸出、每次讀取圖片數目、圖片裁剪尺寸、圖片舉止RGB、層的參數等等,具體每層意義詳見本章節三

6、訓練模型

調用caffe train -solver solver.prototxt 開始訓練參數。添加-snapshot iter_100.caffemodel接着訓練,訓練過程需要持續觀察收斂loss的值,一般越小越成熟,但也不能過度,防止訓練出來的模型過擬合。

模型訓練經驗:

GoogleNet本身是比較大的網絡,我們可以根據自己的需求裁剪網絡。

GoogleNet中的LRN層影響不大可以去掉,或者刪除一些卷積層,降低網絡的層數。

當我們的數據量比較小的時候,訓練完整的網絡參數比較容易過擬合。這時我們可以通過只訓練網絡的某幾層來解決這個問題。

首先修改train_val.prototxt中的全連接層的名稱,即loss1/classifier,loss2/classifier,loss3/classifier這三層的名稱,以及他們的輸出分類個數,默認是1000,需要改成我們自己的種類總數。這樣我們再加載訓練好的model時,這三層的參數纔會重新初始化。然後將所有其他層的lr_mult該爲0,這樣其他層的參數不會改變,使用預先訓練好的參數。

下載bvlc_googlenet.caffemodel,這是谷歌在ImageNet上訓練出來的參數。

然後調用caffe train -solver solver.prototxt -weights bvlc_googlenet.caffemodel即可訓練。

當收斂loss值達不到要求時,可以調整train_val.prototxt文件中的test_iter和test_interval的值以及average_loss的值來訓練。

7、測試模型

訓練好的模型,還需驗證模型的識別率,這裏需要用到測試集素材(有特性,但跟訓練素材不是同一份),如下圖,我們對錶情訓練的模型,用測試圖片集的188圖片驗證整體識別率爲100%,同時,可取非特徵圖片驗證(文件夾0的圖片)不可識別。

8、部署模型

訓練好的模型,可作爲服務部署,供自動化調用:

9、自動化調用

提供post方法供自動化用例傳遞識別校驗圖片:

三、Caffe入門介紹

易上手

模型與相應優化都是以文本形式而非代碼形式給出。Caffe 給出了模型的定義、最優化設置以及預訓練的權重,方便立即上手。

速度快

能夠運行最棒的模型與海量的數據。Caffe 與 cuDNN 結合使用,測試 AlexNet 模型,在K40 上處理每張圖片只需要1.17ms。

模塊化

方便擴展到新的任務和設置上。可以使用 Caffe 提供的各層類型來定義自己的模型。

開放性

公開的代碼、可參考的模型和可再現性。

Caffe的安裝:

Caffe 需要預先安裝比較多的依賴項,CUDA,snappy,leveldb,gflags,glog,szip,lmdb,OpenCV,hdf5,BLAS,boost等等

Caffe官網:http://caffe.berkeleyvision.org/

Caffe Github : https://github.com/BVLC/caffe

Caffe 安裝教程:

http://caffe.berkeleyvision.org/installation.html

http://blog.csdn.net/yhaolpz/article/details/71375762

Caffe 安裝分爲CPU和GPU版本,GPU版本需要顯卡支持以及安裝CUDA。

Caffe依賴 ProtoBuffer Boost GFLAGS GLOG BLAS HDF5 OpenCV LMDB LEVELDB Snappy

Layer

Layer 是 Caffe 模型的本質內容和執行計算的基本單元。Layer 可以進行很多運算,如: convolve(卷積)、pool(池化)、inner product(內積),rectified-linear 和 sigmoid 等非線性運算,元素級的數據變換,normalize(歸一化)、load data(數據加載)、softmax 和 hinge 等losses(損失計算)。可在 Caffe 官方文檔的 layer catalogue 中查看所有操作,其囊括了絕大部分目前最前沿的深度學習任務所需要的層類型。

一個 layer 通過 bottom(底部)連接層接收數據,通過 top(頂部)連接層輸出數據。每一個 layer 都定義了 3 種重要的運算:setup (初始化設置),forward (前向傳播),backward (反向傳播)。

·         Setup: 在模型初始化時重置 layers 及其相互之間的連接 ;

·         Forward: 從 bottom 層中接收數據,進行計算後將輸出送入到 top 層中;

·         Backward: 給定相對於 top 層輸出的梯度,計算其相對於輸入的梯度,並傳遞到 bottom 層。一個有參數的 layer 需要計算相對於各個參數的梯度值並存儲在內部。

特別地,Forward 和 Backward 函數分別有 CPU 和 GPU 兩種實現方式。如果沒有實現 GPU 版本,那麼 layer 將轉向作爲備用選項的CPU 方式。儘管這樣會增加額外的數據傳送成本(輸入數據由 GPU 上覆制到 CPU,之後輸出數據從 CPU 又複製回到 GPU),但是對於做一些快速實驗這樣操作還是很方便的。

總的來說,layer 承擔了網絡的兩個核心操作:forward pass (前向傳播) —— 接收輸入並計算輸出;backward pass (反向傳播) —— 接收關於輸出的梯度,計算相對於參數和輸入的梯度並反向傳播給在它前面的層。由此組成了每個 layer 的前向和反向通道。

由於 Caffe 網絡的組合性和其代碼的模塊化,自定義 layer 是很容易的。只要定義好 layer 的 setup (初始化設置)、forward (前向通道)和backward (反向通道),就可將 layer 納入到網絡中。

Net

通過合成和自動微分,網絡同時定義了一個函數和其對應的梯度。通過合成各層的輸出來計算這個函數,來執行給定的任務,並通過合成各層的後向傳播過程來計算來自損失函數的梯度,從而學習任務。Caffe 模型是端到端的機器學習引擎。

準確的說,Net 是由一系列層組成的有向無環 (DAG) 計算圖,Caffe 保留了計算圖中所有的中間值以確保前向和反向迭代的準確性。一個典型的 Net 開始於 data layer ——從磁盤中加載數據,終止於 loss layer —— 計算如分類和重構這些任務的目標函數。

Net 由一系列層和它們之間的相互連接構成,用的是一種文本建模語言。一個簡單的邏輯迴歸分類器的定義如下:

Net::Init()進行模型的初始化。初始化主要實現兩個操作:創建 blobs 和 layers 以搭建整個網絡 DAG 圖,以及調用 layers 的SetUp()函數。初始化時也會做另一些記錄,例如確認整個網絡結構的正確與否等。另外,初始化期間,Net 會打印其初始化日誌到INFO 信息中。

Caffe 中網絡的構建與設備無關,可回憶下我們之前的解釋,blobs 和 layers 在模型定義時是隱藏了實現細節的。網絡構建完之後,通過設置 Caffe::mode() 函數中的 Caffe::set_mode(), 即可實現在 CPU 或 GPU 上的運行。採用 CPU 或 GPU 計算得到的結果相同,CPU 與 GPU 無縫切換並且獨立於模型定義。對於研究和調用來說,將模型定義和實現分離開來是最好不過了。

Model

模型是利用文本 protocol buffer (prototxt) 語言定義的,學習好的模型會被序列化地存儲在二進制 protocol buffer (binaryproto).caffemodel 文件中。

模型格式用 protobuf 語言定義在 caffe.proto 文件中。大部分源文件中都帶有解釋。

Caffe 使用 Google Protocol Buffer 有以下優勢:按序排列時二進制字符串尺寸最小,高效序列化,易讀的文本格式與二進制版本兼容,可用多種語言實現高效的接口,尤其是 C++ 和Python。這些優勢造就了 Caffe 模型的靈活性與擴展性。

Forward

forward 過程爲給定的待推斷的輸入計算輸出。在forward 過程中,Caffe 組合每一層的計算以得到整個模型的計算“函數”。本過程自底向上進行。數據 x 通過一個內積層得到 g(x),然後通過 softmax 層得到 h(g(x)),通過 softmax loss 得到 fw(x)。

Backward

backward 過程根據損失來計算梯度從而進行學習。在backward 過程中,Caffe 通過自動求導並反向組合每一層的梯度來計算整個網絡的梯度。這就是反傳過程的本質。本過程自頂向下進行。

Forward 和 Backward的實現

只要定義好了模型,這些計算就可以立即進行:Caffe 已經準備好了 forward 和 backward 的實現方法。

·         Net::Forward() 和 Net::Backward() 方法實現網絡的 forward 和 backward,而 Layer::Forward() 和Layer::Backward() 計算每一層的 forward 和 backward;

·         每一層都有 forward_{cpu, gpu}() 和 backward_{cpu, gpu} 方法來適應不同的計算模式。由於條件限制或者爲了使用便利,一個層可能僅實現了 CPU 或者 GPU 模式。

Loss

與大多數的機器學習模型一樣,在 Caffe 中,學習是由一個損失函數驅動的(通常也被稱爲誤差、代價或者目標函數)。一個損失函數通過將參數集(即當前的網絡權值)映射到一個可以標識這些參數 “不良程度” 的標量值來學習目標。因此,學習的目的是找到一個網絡權重的集合,使得損失函數最小。

在 Caffe 中,損失是通過網絡的前向計算得到的。每一層由一系列的輸入 blobs (bottom),然後產生一系列的輸出 blobs (top)。這些層的某些輸出可以用來作爲損失函數。典型的一對多分類任務的損失函數是 softMaxWithLoss 函數,使用以下的網絡定義,例如:

在 softMaxWithLoss 函數中,top blob 是一個標量數值,該數值是整個 batch 的損失平均值(由預測值 pred 和真實值 label 計算得到)。

Loss weights

對於含有多個損失層的網絡 (例如,一個網絡使用一個 softMaxWithLoss 輸入分類並使用 EuclideanLoss 層進行重構),損失權值可以被用來指定它們之間的相對重要性。

按照慣例,有着 Loss 後綴的 Caffe 層對損失函數有貢獻,其他層被假定僅僅用於中間計算。然而,通過在層定義中添加一個loss_weight:<float> 字段到由該層的 top blob,任何層都可以作爲一個 loss。對於帶後綴 Loss 的層來說,其對於該層的第一個top blob 含有一個隱式的 loss_weight:1;其他層對應於所有 top blob 有一個隱式的 loss_weight:0。因此,上面的softMaxWithLoss 層等價於:

然而,任何可以 backward 的層,可允許給予一個非 0 的 loss_weight,例如,如果需要,對網絡的某些中間層所產生的激活進行正則化。對於具有相關非 0 損失的非單輸出,損失函數可以通過對所有 blob 求和來進行簡單的計算。

那麼,在 Caffe 中最終的損失函數可以通過對整個網絡中所有的權值損失進行求和計算獲得,正如以下的僞代碼:

Solver

Solver 通過協調 Net 的前向推斷計算和反向梯度計算 (forward inference and backward gradients),來對參數進行更新,從而達到減小loss 的目的。Caffe 模型的學習被分爲兩個部分:由 Solver 進行優化、更新參數,由 Net 計算出 loss 和 gradient。

Caffe 支持的 Solver 包括有:

·         Stochastic Gradient Descent (type: "SGD"),隨機梯度下降

·         AdaDelta (type: "AdaDelta")

·         Adaptive Gradient (type: "AdaGrad"),自適應梯度

·         Adam (type: "Adam")

·         Nesterov’s Accelerated Gradient (type: "Nesterov") and

·         RMSprop (type: "RMSProp")

各項 Solver 的具體說明可以參見這裏。

Layer分類

爲了創建一個 caffe 模型,我們需要在一個 protocol buffer(prototxt) 文件中定義模型的結 構。在 caffe 中,層和相應的參數都定義在caffe.proto 文件裏。

視覺層 Vision Layers

頭文件:

./include/caffe/vision_layers.hpp

視覺層的輸入與輸出均爲圖像。一個典型的圖像通常爲單通道的灰度圖或三通道的 RBG 彩色圖。但本文所指圖像是一個廣義的概念,明顯特性來自於空間結構:高和寬通常均大於 1 而通道數不限,類似結構的數據均可理解爲圖像。這種結構可以幫助 caffe 的層決定如何處理輸入數據,具體來說,大多數視覺層通常是在輸入數據的某塊區域執行特定操作來產生對應的輸出。相反的,其它類型的層通常會忽略空間結構而把輸入圖像看作是一個維度爲 chw 的 “單個大向量”。

損失層 Loss Layers

Loss 設置了一個損失函數用來比較網絡的輸出和目標值,通過最小化損失來驅動網絡的訓練。網絡的損失通過前向操作計算,網絡參數相對於損失函數的梯度則通過反向操作計算。

激活層 Activation / Neuron Layers

一般來說,激活層執行逐個元素的操作,輸入一個底層 blob,輸出一個尺寸相同的 頂層 blob。 在以下列出的這些層中,我們將忽略輸入和輸出 blob 的尺寸,因爲它們是相同的。

數據層 DataLayers

數據能過數據層進入 caffe 網絡:數據層處於網絡的最底層,數據可以從高效率的數據庫中讀取 (如LevelDB 或 LMDB),可以直接從內存中讀取,若對讀寫效率要求不高也可以從硬盤上的 HDFT 文件或者普通的圖片文件讀取。常見的數據預處理操作 (減均值,尺度變換,隨機裁剪或者鏡像) 可以通過設定參數 TransformationParameter 來實現。

普通層 Common Layers

普通層主要負責做一些諸如:內積/全連接、分裂(Splitting)、平攤 (Flattening)、變形 (Reshape)、連結(Concatenation)、切片 (Slicing)、計算均值等操作。

Caffe的接口

Caffe 有命令行、Python 和 MATLAB 三種接口,來實現日常使用、研究代碼的交互以及實現快速原型。Caffe 以 C++ 庫爲核心,其在開發中使用模塊化接口,而不是每次都調用其定義的編譯。cmdcaffe,pycaffe 與 matcaffe 接口都可供用戶使用。

命令行

命令行接口 cmdcaffe 是 caffe 中用來訓練模型,計算得分以及方法判斷的工具。

訓練模型

caffe train 命令可以從零開始學習模型,也可以從已保存的快照繼續學習,或將已經訓練好的模型應用在新的數據與任務上進行微調即fine-tuning 學習:

·         所有的訓練都需要添加 -solver solver.prototxt 參數完成 solver 的配置

·         繼續訓練需要添加 -snapshot model_iter_1000.solverstate 參數來加載 solver 快照

·         fine-tuning 需要添加 -weights model.caffemodel 參數完成模 型初始化

例如,可以運行如下代碼:

對於 fine-tuning 的完整例子,可以參考 examples/finetuningonflickr_style,但是隻調用訓練命令如下:

測試

caffe test 命令通過在 test phase 中運行模型得到分數,並且用這分數表示網絡輸出的最終結果。網絡結構必須被適當定義,生成accuracy 或 loss 作爲其結果。測試過程中,終端會顯示每個 batch 的得分,最後輸出全部 batch 得分的平均值。

後期我們會根據每個維度陸續寫相關的測試文章,如果你有興趣,請關注我們哦。

長按指紋識別圖中的二維碼,獲取更多測試乾貨分享!

 將我們公衆號置頂   不會漏掉我們的原創乾貨哦!

相關文章