實際工作中,目標檢測 yolov3 或者 yolov4 模型移植到 AI 晶片中,經常需要將其先轉換為 caffe1.x 模型,大家可能或多或少也有這方面的需求。例如華為海思 NNIE 只支援caffe1.x 模型,所以 yolov3/yolov4 模型要想在海思晶片上部署,轉換為 caffe1.x 模型是必須的。
今天,專門給大家寫一下將 yolov3/yolov4 模型轉為 caffe 模型的詳細步驟。
0. 系統環境
- Ubuntu 16.04
- cuda 9.x
1. 部署 caffe 環境
常規的方法是下載 caffe 的原始碼,進行編譯安裝。但是,這種方法比較複雜,不太容易成功。更簡單的方法是直接下載 caffe1.x 的docker 映象。這種方法需要你提前在 Ubuntu 裡安裝了 nvidia-docker。
開啟 docker hub 網站:
https://registry.hub.docker.com/
搜尋 caffe,看到這個映象:
點選進去,看到該映象的下拉命令:
sudo docker pull bvlc/caffe
就可以看到已下載的 caffe 映象了。
為映象建立容器:
docker run --runtime=nvidia --name caffe -i -t bvlc/caffe /bin/bash
這裡我們給該容器起的名字是 caffe,大家可以自由設定,根據 sudo docker ps -a
這條命令來檢視各個容器。
這樣,我們就進入了 caffe1.x 的 docker 容器之內了。
該容器已部署好了 caffe1.x,caffe1.x 路徑為:
2. caffe 原始碼修改
因為官方 caffe1.x 框架不支援 yolo3/yolov4 的 upsample 層,所以需要手動增加 upsample 層,對 caffe 原始碼進行修改。
克隆 GitHub 上的轉換工具專案:
git clone https://github.com/ChenYingpeng/darknet2caffe.git
- 將 darknet2caffe/caffe_layers/mish_layer 下的 mish_layer.hpp 檔案和 darknet2caffe/tree/master/caffe_layers/upsample_layer 下的 upsample_layer.hpp 複製到容器的路徑:/opt/caffe/include/caffe/layers 下。
-
將 darknet2caffe/caffe_layers/mish_layer 下的 mish_layer.cpp、mish_layer.cu 檔案和 darknet2caffe/tree/master/caffe_layers/upsample_layer 下的 upsample_layer.cpp、upsample_layer.cu 複製到容器的路徑:/opt/caffe/src/caffe/layers/ 下。
-
將 darknet2caffe/caffe_layers/pooling_layer 下的 pooling_layer.cpp 複製到容器的路徑:/opt/caffe/src/caffe/layers/ 下。
然後,開啟容器內的 caffe 檔案:/opt/caffe/src/caffe/proto/caffe.proto。按照如下說明修改相應欄位的程式。
// LayerParameter next available layer-specific ID: 147 (last added: recurrent_param)
message LayerParameter {
optional TileParameter tile_param = 138;
optional VideoDataParameter video_data_param = 207;
optional WindowDataParameter window_data_param = 129;
++optional UpsampleParameter upsample_param = 149; //added by chen for Yolov3, make sure this id 149 not the same as before.
++optional MishParameter mish_param = 150; //added by chen for yolov4,make sure this id 150 not the same as before.
}
// added by chen for YoloV3
++message UpsampleParameter{
++ optional int32 scale = 1 [default = 1];
++}
// Message that stores parameters used by MishLayer
++message MishParameter {
++ enum Engine {
++ DEFAULT = 0;
++ CAFFE = 1;
++ CUDNN = 2;
++ }
++ optional Engine engine = 2 [default = DEFAULT];
++}
其中,++ 表示該行是增加的內容。
3. caffe 重新編譯
修改完 caffe 的一些原始碼之後,需要對 caffe 重新編譯。
進入 /opt/caffe/build 目錄,輸入以下命令:
make clean
make all -j8
make pycaffe -j8
caffe 重新編譯之後,就可以對 yolov3/yolov4 模型進行 caffe 轉換了。
4. 模型轉換
準備好我們已有的 yolov3 模型的配置檔案和權重檔案,例如:yolov3.cfg 和 yolov3.weights。在 darknet2caffe 目錄下,輸入以下命令:
python darknet2caffe.py ./yolov3.cfg ./yolov3.weights ./yolov3.prototxt ./yolov3.caffemodel
如果輸出類似下面的語句,則證明轉換成功!
I0522 10:19:19.015708 25251 net.cpp:228] layer1-act does not need backward computation.
I0522 10:19:19.015712 25251 net.cpp:228] layer1-scale does not need backward computation.
I0522 10:19:19.015714 25251 net.cpp:228] layer1-bn does not need backward computation.
I0522 10:19:19.015718 25251 net.cpp:228] layer1-conv does not need backward computation.
I0522 10:19:19.015722 25251 net.cpp:228] input does not need backward computation.
I0522 10:19:19.015725 25251 net.cpp:270] This network produces output layer139-conv
I0522 10:19:19.015731 25251 net.cpp:270] This network produces output layer150-conv
I0522 10:19:19.015736 25251 net.cpp:270] This network produces output layer161-conv
I0522 10:19:19.015911 25251 net.cpp:283] Network initialization done.
unknow layer type yolo
unknow layer type yolo
save prototxt to ./yolov3.prototxt
save caffemodel to ./yolov3.caffemodel
其中,yolov3.prototxt 和 yolov3.caffemodel 為轉換後的 caffe 模型。
至此,yolov3/yolov4 轉換為 caffe 模型完成!