Caffe學習系列(23):如何將別人訓練好的model用到自己的數據上


caffe團隊用imagenet圖片進行訓練,迭代30多萬次,訓練出來一個model。這個model將圖片分為1000類,應該是目前為止最好的圖片分類model了。

假設我現在有一些自己的圖片想進行分類,但樣本量太小,可能只有幾百張,而一般深度學習都要求樣本量在1萬以上,因此訓練出來的model精度太低,根本用不上,那怎么辦呢?

那就用caffe團隊提供給我們的model吧。

因為訓練好的model里面存放的就是一些參數,因此我們實際上就是把別人預先訓練好的參數,拿來作為我們的初始化參數,而不需要再去隨機初始化了。圖片的整個訓練過程,說白了就是將初始化參數不斷更新到最優的參數的一個過程,既然這個過程別人已經幫我們做了,而且比我們做得更好,那為什么不用他們的成果呢?

使用別人訓練好的參數,必須有一個前提,那就是必須和別人用同一個network,因為參數是根據network而來的。當然,最后一層,我們是可以修改的,因為我們的數據可能並沒有1000類,而只有幾類。我們把最后一層的輸出類別改一下,然后把層的名稱改一下就可以了。最后用別人的參數、修改后的network和我們自己的數據,再進行訓練,使得參數適應我們的數據,這樣一個過程,通常稱之為微調(fine tuning).

既然前兩篇文章我們已經講過使用digits來進行訓練和可視化,這樣一個神器怎么能不使用呢?因此本文以此工具為例,講解整個微調訓練過程。

一、下載model參數

可以直接在瀏覽器里輸入地址下載,也可以運行腳本文件下載。下載地址為:http://dl.caffe.berkeleyvision.org/bvlc_reference_caffenet.caffemodel

文件名稱為:bvlc_reference_caffenet.caffemodel,文件大小為230M左右,為了代碼的統一,將這個caffemodel文件下載到caffe根目錄下的 models/bvlc_reference_caffenet/ 文件夾下面。也可以運行腳本文件進行下載:

# sudo ./scripts/download_model_binary.py models/bvlc_reference_caffenet

 二、准備數據

如果有自己的數據最好,如果沒有,可以下載我的練習數據:http://pan.baidu.com/s/1MotUe

這些數據共有500張圖片,分為大巴車、恐龍、大象、鮮花和馬五個類,每個類100張。編號分別以3,4,5,6,7開頭,各為一類。我從其中每類選出20張作為測試,其余80張作為訓練。因此最終訓練圖片400張(放在train文件夾內,每個類一個子文件夾),測試圖片100張(放在test文件夾內,每個類一個子文件夾)。

將圖片下載下來后解壓,放在一個文件夾內。比如我在當前用戶根目錄下創建了一個data文件夾,專門用來存放數據,因此我的訓練圖片路徑為:/home/xxx/data/re/train

打開瀏覽器,運行digits,如果沒有這個工具的,推薦安裝,真的是學習caffe的神器。安裝及使用可參見我的前兩篇文章:Caffe學習系列(21):caffe圖形化操作工具digits的安裝與運行

新建一個classification dataset,設置如下圖:

下面圖片格式選為jpg, 為dataset取一個名字,就開始轉換吧。結果如圖:

三、設置model

回到digits根目錄,新建一個classification model, 選中你的dataset, 開始設置最重要的network.

 

caffenet的網絡配置文件,放在 caffe/models/bvlc_reference_caffenet/ 這個文件夾里面,名字叫train_val.prototxt。打開這個文件,將里面的內容復制到上圖的Custom Network文本框里,然后進行修改,主要修改這幾個地方:

1、修改train階段的data層為:

layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mirror: true
    crop_size: 227
  }
}

即把均值文件(mean_file)、數據源文件(source)、批次大小(batch_size)和數據源格式(backend)這四項都刪除了。因為這四項系統會根據dataset和頁面左邊“solver options"的設置自動生成。

2、修改test階段的data層:

layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    mirror: false
    crop_size: 227
  }
}

和上面一樣,也是刪除那些項。

3、修改最后一個全連接層(fc8):

layer {
  name: "fc8-re"               #原來為"fc8"
  type: "InnerProduct"
  bottom: "fc7"
  top: "fc8"
  param {
    lr_mult: 1.0
    decay_mult: 1.0
  }
  param {
    lr_mult: 2.0
    decay_mult: 0.0
  }
  inner_product_param {
    num_output: 5        #原來為"1000"
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0.0
    }
  }
}

看注釋的地方,就只有兩個地方修改,其它不變。

設置好后,就可以開始微調了(fine tuning).

訓練結果就是一個新的model,可以用來單張圖片和多張圖片測試。具體測試方法前一篇文章已講過,在此就不重復了。

在此,將別人訓練好的model用到我們自己的圖片分類上,整個微調過程就是這樣了。如果你不用digits,而直接用命令操作,那就更簡單,只需要修改一個train_val.prototxt的配置文件就可以了,其它都是一樣的操作。

 

2016.12.6更新

這篇文章是將近一年前寫的,digits版本已經升級,所以有些地方設置有點變化,導致很多網友出現錯誤。最多的錯誤提示如下:

ERROR: Layer 'accuracy' references bottom 'label' at the TEST stage however this blob is not included at that stage. Please consider using an include directive to limit the scope of this layer.

我當時用的版本是digits 3.0, 現在大家用的是digits 4.0, 因此會出現這個錯誤。修改如下:

最后四層的設置:

layer {
  name: "re-fc8"
  type: "InnerProduct"
  bottom: "fc7"
  top: "fc8"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "fc8"
  bottom: "label"
  top: "accuracy"
  include {
     stage:"val"
  }
}
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "fc8"
  bottom: "label"
  top: "loss"
  exclude{
      stage:"deploy"
      }
}
layer {
  name: "prob"
  type: "Softmax"
  bottom: "fc8"
  top: "prob"
  include{
      stage:"deploy"
      }
}

  

原來網絡結構中的全連接層fc8, 需要改一下名字,如我的改成"re-fc8". 因為我們做的是微調。微調的意思就是先在別的數據集上進行訓練,把訓練好的權值,作為我們現在數據集的權值初始化,就不再需要隨機初始化了。現在的數據和訓練時的數據不一致,因此有些層數的設置就會有點區別。比如這個例子中,用來訓練模型的數據集是imagenet,分為1000類,而我們的數據集就只有5類,因此在fc8這層上的num_output就會有區別,因此在這一層上就不能用人家的權值了,就需要把這層的名字改得和原來的網絡結構不一樣。

在digits 4.0版本中,最后的全連接層不再需要num_output這個參數了,因此大家需要把這行刪除掉。digits會自動根據你的類別數把這個參數補充上。

也許原來的配置文件中沒有Softmax層,現在需要加上這一層,因為digits會根據這里的設置自動生成train_test.prototxt和deploy.prototxt兩個文件。其它需要修改的地方,就是最后三層的include和exclude了。

最后還有一個問題就是顯存的問題。實話講我的這個訓練數據選得不太好,很吃顯存,有些GPU不好的同學,運行起來很吃力。因此大家非要用這個數據的話,建議把batch_size調低些。我用的是nvidia k20, 4G顯存,batch_size設置為16—32之間,運行得不錯,1分鍾左右運行完。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM