Caffe深度學習入門(5)—— caffenet 微調網絡 訓練自己的數據並測試訓練的模型

微調網絡,通常我們有一個初始化的模型參數文件,這裏是不同於training from scratch,scrachtch指的是我們訓練一個新的網絡,在訓練過程中,這些參數都被隨機初始化,而fine-tuning,是我們可以在ImageNet上1000類分類訓練好的參數的基礎上,根據我們的分類識別任務進行特定的微調

這裏我以一個車的識別爲例,假設我們有1種車需要識別,我的任務對象是車,現在有ImageNet的模型參數文件,在這裏使用的網絡模型是CaffeNet,是一個小型的網絡,其實別的網絡如GoogleNet也是一樣的原理。那麼這個任務的變化可以表示爲:

任務:分類 類別數目:1000(ImageNet上1000類的分類任務)------> 1(自己的特定數據集的分類任務車)

那麼在網絡的微調中,我們的整個流程分爲以下幾步:

1. 依然是準備好我們的訓練數據和測試數據
2. 計算數據集的均值文件,因爲集中特定領域的圖像均值文件會跟ImageNet上比較General的數據的均值不太一樣
3. 修改網絡最後一層的輸出類別,並且需要加快最後一層的參數學習速率
4. 調整Solver的配置參數,通常學習速率和步長,迭代次數都要適當減少
5. 啓動訓練,並且需要加載pretrained模型的參數

1.準備數據集
這一點就不用說了,準備兩個txt文件,放成list的形式,可以參考caffe下的example,圖像路徑之後一個空格之後跟着類別的ID,如下,這裏記住ID必須從0開始,要連續,否則會出錯,loss不下降,按照要求寫就OK。
這個是訓練的圖像label,測試的也同理

1. 創建lmdb文件,使用caffe下的convert_imageset 工具,具體命令如下:
./build/tools/convert_imageset /media/***/801328a5-39c6-4e08-b070-19fc662a5236/resnet/caffe/data/cartest/  data/cartest/carlist.txt data/cartest/train_car_lmdb -resize_width=227 -resize_height=227 -check_size -shuffle true

其中第一個參數是基地址路徑用來拼接的,第二個是label的文件,第三個是生成的數據庫文件支持leveldb或者lmdb,接着是resize的大小,最後是否隨機圖片順序

計算均值,使用caffe下的convert_imageset 工具,具體命令

./build/tools/compute_image_mean /media/***/801328a5-39c6-4e08-b070-19fc662a5236/resnet/caffe/data/cartest/train_car_lmdb/ data/carmean.binaryproto

第一個參數是基地址路徑用來拼接的,第二個是lmdb文件,第三個是生成的均值文件carmean.binaryproto

3.調整網絡層參數
參照Caffe上的例程,我用的是CaffeNet,首先在輸入層data層,修改我們的source 和 meanfile, 根據之前生成的lmdb 和mean.binaryproto修改即可。

最後輸出層是fc8,

1.首先修改名字,這樣預訓練模型賦值的時候這裏就會因爲名字不匹配從而重新訓練,也就達成了我們適應新任務的目的。
2.調整學習速率,因爲最後一層是重新學習,因此需要有更快的學習速率相比較其他層,因此我們將,weight和bias的學習速率加快10倍。

修改./models/bvlc_reference_caffenet/train_cal_resnet_lily.prototxt中 train和test對應的相關路徑

mean_file: "/media/***/801328a5-39c6-4e08-b070-19fc662a5236/resnet/caffe/data/cartest/carmean.binaryproto
source: "/media/***/801328a5-39c6-4e08-b070-19fc662a5236/resnet/caffe/data/cartest/train_car_lmdb"

修改./models/bvlc_reference_caffenet/solver_resnet_lily.prototxt

net: "models/bvlc_reference_caffenet/train_val_resnet_lily.prototxt"
test_iter: 100
test_interval: 1000
base_lr: 0.001
lr_policy: "step"
gamma: 0.1
stepsize: 20000
display: 20
max_iter: 50000
momentum: 0.9
weight_decay: 0.0005
snapshot: 10000
snapshot_prefix: "models/bvlc_reference_caffenet/caffenet_resnet_model_lily"
solver_mode: GPU

原來是fc8,記得把跟fc8連接的名字都要修改掉,修改修改./models/bvlc_reference_caffenet/train_val_resnet_lily.prototxt 後如下

layer {
  name: "fc8_comp_model"
  type: "InnerProduct"
  bottom: "fc7"
  top: "fc8_comp_model"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 1000
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "fc8_comp_model"
  bottom: "label"
  top: "accuracy"
  include {
    phase: TEST
  }
}
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "fc8_comp_model"
  bottom: "label"
  top: "loss"
}

主要的調整有:test_iter從1000改爲了100,因爲數據量減少了,base_lr從0.01變成了0.001,這個很重要,微調時的基本學習速率不能太大,學習策略沒有改變,步長從原來的100000變成了20000,最大的迭代次數也從450000變成了50000,動量和權重衰減項都沒有修改,依然是GPU模型,網絡模型文件和快照的路徑根據自己修改

train_val_resnet_lily.prototxt完整文件爲:

name: "CaffeNet"
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mirror: true
    crop_size: 227
    mean_file: "/media/***/801328a5-39c6-4e08-b070-19fc662a5236/resnet/caffe/data/cartest/carmean.binaryproto"
  }
# mean pixel / channel-wise mean instead of mean image
#  transform_param {
#    crop_size: 227
#    mean_value: 104
#    mean_value: 117
#    mean_value: 123
#    mirror: true
#  }
  data_param {
    source: "/media/***/801328a5-39c6-4e08-b070-19fc662a5236/resnet/caffe/data/cartest/train_car_lmdb"
    batch_size: 256
    backend: LMDB
  }
}
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    mirror: false
    crop_size: 227
    mean_file: "/media/***/801328a5-39c6-4e08-b070-19fc662a5236/resnet/caffe/data/cartest/carmean.binaryproto"
  }
# mean pixel / channel-wise mean instead of mean image
#  transform_param {
#    crop_size: 227
#    mean_value: 104
#    mean_value: 117
#    mean_value: 123
#    mirror: false
#  }
  data_param {
    source: "/media/***/801328a5-39c6-4e08-b070-19fc662a5236/resnet/caffe/data/cartest/train_car_lmdb"
    batch_size: 50
    backend: LMDB
  }
}
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 96
    kernel_size: 11
    stride: 4
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "conv1"
  top: "conv1"
}
layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_size: 3
    stride: 2
  }
}
layer {
  name: "norm1"
  type: "LRN"
  bottom: "pool1"
  top: "norm1"
  lrn_param {
    local_size: 5
    alpha: 0.0001
    beta: 0.75
  }
}
layer {
  name: "conv2"
  type: "Convolution"
  bottom: "norm1"
  top: "conv2"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 256
    pad: 2
    kernel_size: 5
    group: 2
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 1
    }
  }
}
layer {
  name: "relu2"
  type: "ReLU"
  bottom: "conv2"
  top: "conv2"
}
layer {
  name: "pool2"
  type: "Pooling"
  bottom: "conv2"
  top: "pool2"
  pooling_param {
    pool: MAX
    kernel_size: 3
    stride: 2
  }
}
layer {
  name: "norm2"
  type: "LRN"
  bottom: "pool2"
  top: "norm2"
  lrn_param {
    local_size: 5
    alpha: 0.0001
    beta: 0.75
  }
}
layer {
  name: "conv3"
  type: "Convolution"
  bottom: "norm2"
  top: "conv3"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 384
    pad: 1
    kernel_size: 3
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "relu3"
  type: "ReLU"
  bottom: "conv3"
  top: "conv3"
}
layer {
  name: "conv4"
  type: "Convolution"
  bottom: "conv3"
  top: "conv4"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 384
    pad: 1
    kernel_size: 3
    group: 2
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 1
    }
  }
}
layer {
  name: "relu4"
  type: "ReLU"
  bottom: "conv4"
  top: "conv4"
}
layer {
  name: "conv5"
  type: "Convolution"
  bottom: "conv4"
  top: "conv5"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 256
    pad: 1
    kernel_size: 3
    group: 2
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 1
    }
  }
}
layer {
  name: "relu5"
  type: "ReLU"
  bottom: "conv5"
  top: "conv5"
}
layer {
  name: "pool5"
  type: "Pooling"
  bottom: "conv5"
  top: "pool5"
  pooling_param {
    pool: MAX
    kernel_size: 3
    stride: 2
  }
}
layer {
  name: "fc6"
  type: "InnerProduct"
  bottom: "pool5"
  top: "fc6"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 4096
    weight_filler {
      type: "gaussian"
      std: 0.005
    }
    bias_filler {
      type: "constant"
      value: 1
    }
  }
}
layer {
  name: "relu6"
  type: "ReLU"
  bottom: "fc6"
  top: "fc6"
}
layer {
  name: "drop6"
  type: "Dropout"
  bottom: "fc6"
  top: "fc6"
  dropout_param {
    dropout_ratio: 0.5
  }
}
layer {
  name: "fc7"
  type: "InnerProduct"
  bottom: "fc6"
  top: "fc7"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 4096
    weight_filler {
      type: "gaussian"
      std: 0.005
    }
    bias_filler {
      type: "constant"
      value: 1
    }
  }
}
layer {
  name: "relu7"
  type: "ReLU"
  bottom: "fc7"
  top: "fc7"
}
layer {
  name: "drop7"
  type: "Dropout"
  bottom: "fc7"
  top: "fc7"
  dropout_param {
    dropout_ratio: 0.5
  }
}
layer {
  name: "fc8_comp_model"
  type: "InnerProduct"
  bottom: "fc7"
  top: "fc8_comp_model"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 1000
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "fc8_comp_model"
  bottom: "label"
  top: "accuracy"
  include {
    phase: TEST
  }
}
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "fc8_comp_model"
  bottom: "label"
  top: "loss"
}


訓練的指令如下:
./build/tools/caffe train --solver ./models/bvlc_reference_caffenet/solver_resnet_lily.prototxt --weights ./models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel --gpu 0

測試指令:

python ./python/classify02.py --model_def ./models/bvlc_reference_caffenet/train_val_test_resnet_lily.prototxt --pretrained_model ./models/bvlc_reference_caffenet/caffenet_resnet_model_lily_iter_50000.caffemodel --labels_file ./data/cartest/cartest.txt --center_only ./data/cartest/JPEGImages/crk201706301341.jpg foo

注意這裏的train_val_test_resnet_lily.prototxt文件與訓練時的文件train_val_resnet_lily.prototxt文件是不一樣的。

train_val_resnet_lily.prototxt文件爲:

name: "train_resnet_lily"

layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param { shape: { dim: 1 dim: 3 dim: 227 dim: 227 } }
}

layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 96
    kernel_size: 11
    stride: 4
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "conv1"
  top: "conv1"
}
layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_size: 3
    stride: 2
  }
}
layer {
  name: "norm1"
  type: "LRN"
  bottom: "pool1"
  top: "norm1"
  lrn_param {
    local_size: 5
    alpha: 0.0001
    beta: 0.75
  }
}
layer {
  name: "conv2"
  type: "Convolution"
  bottom: "norm1"
  top: "conv2"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 256
    pad: 2
    kernel_size: 5
    group: 2
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 1
    }
  }
}
layer {
  name: "relu2"
  type: "ReLU"
  bottom: "conv2"
  top: "conv2"
}
layer {
  name: "pool2"
  type: "Pooling"
  bottom: "conv2"
  top: "pool2"
  pooling_param {
    pool: MAX
    kernel_size: 3
    stride: 2
  }
}
layer {
  name: "norm2"
  type: "LRN"
  bottom: "pool2"
  top: "norm2"
  lrn_param {
    local_size: 5
    alpha: 0.0001
    beta: 0.75
  }
}
layer {
  name: "conv3"
  type: "Convolution"
  bottom: "norm2"
  top: "conv3"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 384
    pad: 1
    kernel_size: 3
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "relu3"
  type: "ReLU"
  bottom: "conv3"
  top: "conv3"
}
layer {
  name: "conv4"
  type: "Convolution"
  bottom: "conv3"
  top: "conv4"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 384
    pad: 1
    kernel_size: 3
    group: 2
    }
}
layer {
  name: "relu4"
  type: "ReLU"
  bottom: "conv4"
  top: "conv4"
}
layer {
  name: "conv5"
  type: "Convolution"
  bottom: "conv4"
  top: "conv5"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 256
    pad: 1
    kernel_size: 3
    group: 2
    
  }
}
layer {
  name: "relu5"
  type: "ReLU"
  bottom: "conv5"
  top: "conv5"
}
layer {
  name: "pool5"
  type: "Pooling"
  bottom: "conv5"
  top: "pool5"
  pooling_param {
    pool: MAX
    kernel_size: 3
    stride: 2
  }
}
layer {
  name: "fc6"
  type: "InnerProduct"
  bottom: "pool5"
  top: "fc6"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 4096
    weight_filler {
      type: "gaussian"
      std: 0.005
    }
    bias_filler {
      type: "constant"
      value: 1
    }
  }
}
layer {
  name: "relu6"
  type: "ReLU"
  bottom: "fc6"
  top: "fc6"
}
layer {
  name: "drop6"
  type: "Dropout"
  bottom: "fc6"
  top: "fc6"
  dropout_param {
    dropout_ratio: 0.5
  }
}
layer {
  name: "fc7"
  type: "InnerProduct"
  bottom: "fc6"
  top: "fc7"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 4096
  
    }
}
layer {
  name: "relu7"
  type: "ReLU"
  bottom: "fc7"
  top: "fc7"
}
layer {
  name: "drop7"
  type: "Dropout"
  bottom: "fc7"
  top: "fc7"
  dropout_param {
    dropout_ratio: 0.5
  }
}
layer {
  name: "fc8_comp_model"
  type: "InnerProduct"
  bottom: "fc7"
  top: "fc8_comp_model"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 1000
    
  }
}
layer {
  name: "prob"
  type: "Softmax"
  bottom: "fc8_comp_model"
  top: "prob"
}

報錯及解決方案

在最後一步測試的時候運行報錯

報錯:

File "python/classify.py", line 138, in <module>
    main(sys.argv)
  File "python/classify.py", line 110, in main
    channel_swap=channel_swap)
  File "/media/futurus/801328a5-39c6-4e08-b070-19fc662a5236/resnet/caffe/python/caffe/classifier.py", line 29, in __init__
    in_ = self.inputs[0]
IndexError: list index out of range

參考解決方案;
加入:

net: "train_resnet_lily"
input: "data"
input_shape {
  dim: 10
  dim: 3
  dim: 224
  dim: 224
}

加入之後 又報了其他錯誤:

[libprotobuf ERROR google/protobuf/text_format.cc:274] Error parsing text-format caffe.NetParameter: 1:4: Message type "caffe.NetParameter" has no field named "net".
F0125 11:48:14.708683 42586 upgrade_proto.cpp:88] Check failed: ReadProtoFromTextFile(param_file, param) Failed to parse NetParameter file: ./models/bvlc_reference_caffenet/train_val_test_resnet_lily.prototxt
*** Check failure stack trace: ***
Aborted (core dumped)

根據網友的博客修改加入爲

net: "train_resnet_lily"
input: "data"
input_dim: 10
input_dim: 3
input_dim: 224
input_dim: 224

測試還不不行,還是報錯。

最終解決方案如下,運行通過。加入

name: "train_resnet_lily"
layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param { shape: { dim: 1 dim: 3 dim: 227 dim: 227 } }
}

Reference:

https://www.cnblogs.com/louyihang-loves-baiyan/p/5038758.html
http://blog.csdn.net/sunshine_in_moon/article/details/49472901

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章