前言¶
有不少開發者在學習深度學習框架的時候會開源一些訓練好的模型,我們可以使用這些模型來運用到我們自己的項目中。如果使用的是同一個深度學習框架,那就很方便,可以直接使用,但是如果時不同深度學習框架,我們就要對模型轉換一下。下面我們就介紹如何把Caffe的模型轉換成PaddlePaddle的Fluid模型。
環境準備¶
- 在線安裝最新發布的PaddlePaddle,可以使用pip命令直接在線安裝PaddlePaddle。
pip install paddlepaddle
- 下在安裝最新的PaddlePaddle,可以在下面選擇適合自己PaddlePaddle的版本,這裏下載的是最新編譯得到的,然後使用pip命令安裝。
http://www.paddlepaddle.org/documentation/docs/zh/0.14.0/new_docs/beginners_guide/install/install_doc.html#id26
- 克隆PaddlePaddle下的models源碼。
git clone https://github.com/PaddlePaddle/models.git
轉換模型¶
- 進入到上一步克隆的
models的caffe2fluid目錄。
cd models/fluid/image_classification/caffe2fluid/
- 下載轉換時所需要的依賴的Python文件。
cd proto/ && wget https://raw.githubusercontent.com/ethereon/caffe-tensorflow/master/kaffe/caffe/caffepb.py
修改剛下載的文件名:
mv caffepb.py caffe_pb2.py
- 獲取需要轉換的Caffe模型,筆者是參考以下這個開源獲取的:
https://gist.github.com/ksimonyan/211839e770f7b538e2d8
首先是獲取VGG_ILSVRC_16_layers_deploy.prototxt網絡文件。
cd ../ && wget https://gist.githubusercontent.com/ksimonyan/211839e770f7b538e2d8/raw/ded9363bd93ec0c770134f4e387d8aaaaa2407ce/VGG_ILSVRC_16_layers_deploy.prototxt
其次是獲取VGG_ILSVRC_16_layers.caffemodel權重文件。
wget http://www.robots.ox.ac.uk/~vgg/software/very_deep/caffe/VGG_ILSVRC_16_layers.caffemodel
- 把Caffe模型轉換成Fluid版本的網絡結構文件和權重文件,其中
VGG16.py是PaddlePaddle定義網絡結構的Python文件,VGG16.npy是網絡的權重文件。
python convert.py VGG_ILSVRC_16_layers_deploy.prototxt \
--caffemodel VGG_ILSVRC_16_layers.caffemodel \
--data-output-path VGG16.npy \
--code-output-path VGG16.py
在執行過程中會生產以下信息:
register layer[Axpy]
register layer[Flatten]
register layer[ArgMax]
register layer[Reshape]
register layer[ROIPooling]
register layer[PriorBox]
register layer[Permute]
register layer[DetectionOutput]
register layer[Normalize]
register layer[Select]
register layer[Crop]
register layer[Reduction]
------------------------------------------------------------
WARNING: PyCaffe not found!
Falling back to a pure protocol buffer implementation.
* Conversions will be drastically slower.
------------------------------------------------------------
Type Name Param Output
----------------------------------------------------------------------------------------------
Data data -- (10, 3, 224, 224)
Convolution conv1_1 (64, 3, 3, 3) (10, 64, 224, 224)
Convolution conv1_1 (64,) (10, 64, 224, 224)
Convolution conv1_2 (64, 64, 3, 3) (10, 64, 224, 224)
Convolution conv1_2 (64,) (10, 64, 224, 224)
Pooling pool1 -- (10, 64, 112, 112)
Convolution conv2_1 (128, 64, 3, 3) (10, 128, 112, 112)
Convolution conv2_1 (128,) (10, 128, 112, 112)
Convolution conv2_2 (128, 128, 3, 3) (10, 128, 112, 112)
Convolution conv2_2 (128,) (10, 128, 112, 112)
Pooling pool2 -- (10, 128, 56, 56)
Convolution conv3_1 (256, 128, 3, 3) (10, 256, 56, 56)
Convolution conv3_1 (256,) (10, 256, 56, 56)
Convolution conv3_2 (256, 256, 3, 3) (10, 256, 56, 56)
Convolution conv3_2 (256,) (10, 256, 56, 56)
Convolution conv3_3 (256, 256, 3, 3) (10, 256, 56, 56)
Convolution conv3_3 (256,) (10, 256, 56, 56)
Pooling pool3 -- (10, 256, 28, 28)
Convolution conv4_1 (512, 256, 3, 3) (10, 512, 28, 28)
Convolution conv4_1 (512,) (10, 512, 28, 28)
Convolution conv4_2 (512, 512, 3, 3) (10, 512, 28, 28)
Convolution conv4_2 (512,) (10, 512, 28, 28)
Convolution conv4_3 (512, 512, 3, 3) (10, 512, 28, 28)
Convolution conv4_3 (512,) (10, 512, 28, 28)
Pooling pool4 -- (10, 512, 14, 14)
Convolution conv5_1 (512, 512, 3, 3) (10, 512, 14, 14)
Convolution conv5_1 (512,) (10, 512, 14, 14)
Convolution conv5_2 (512, 512, 3, 3) (10, 512, 14, 14)
Convolution conv5_2 (512,) (10, 512, 14, 14)
Convolution conv5_3 (512, 512, 3, 3) (10, 512, 14, 14)
Convolution conv5_3 (512,) (10, 512, 14, 14)
Pooling pool5 -- (10, 512, 7, 7)
InnerProduct fc6 (4096, 25088) (10, 4096)
InnerProduct fc6 (4096,) (10, 4096)
Dropout drop6 -- (10, 4096)
InnerProduct fc7 (4096, 4096) (10, 4096)
InnerProduct fc7 (4096,) (10, 4096)
Dropout drop7 -- (10, 4096)
InnerProduct fc8 (1000, 4096) (10, 1000)
InnerProduct fc8 (1000,) (10, 1000)
Softmax prob -- (10, 1000)
Converting data...
Saving data...
Saving source...
set env variable before using converted model if used custom_layers:
- 使用PaddlePaddle的網絡結構文件和權重文件生成預測模型文件。
python VGG16.py VGG16.npy ./fluid_models
- 執行上面的命令之後,就可以生成預測模型了,並存放在當前目錄的
fluid_models目錄下,一共有兩文件,分別是model和params,這個跟我們使用paddle.fluid.io.save_inference_model接口是一樣的,接口文檔在這裏。在下一步我們會使用這個模型文件來預測我們的圖片。
測試預測模型¶
獲得預測模型之後,我們可以使用它來在PaddlePaddle預測圖像,首先要編寫一個PaddlePaddle的預測程序:
# coding=utf-8
import os
import time
from PIL import Image
import numpy as np
import paddle.v2 as paddle
import paddle.fluid as fluid
def load_image(file):
im = Image.open(file)
im = im.resize((224, 224), Image.ANTIALIAS)
im = np.array(im).astype(np.float32)
# PIL打開圖片存儲順序爲H(高度),W(寬度),C(通道)。
# PaddlePaddle要求數據順序爲CHW,所以需要轉換順序。
im = im.transpose((2, 0, 1))
# CIFAR訓練圖片通道順序爲B(藍),G(綠),R(紅),
# 而PIL打開圖片默認通道順序爲RGB,因爲需要交換通道。
im = im[(2, 1, 0), :, :] # BGR
# 減去均值
mean = [123.68, 116.78, 103.94]
mean = np.array(mean, dtype=np.float32)
mean = mean[:, np.newaxis, np.newaxis]
im -= mean
return im
def infer_one(image_path, use_cuda, model_path, model_filename, params_filename):
# 是否使用GPU
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
# 生成調試器
exe = fluid.Executor(place)
inference_scope = fluid.core.Scope()
with fluid.scope_guard(inference_scope):
# 加載模型
[inference_program, feed_target_names, fetch_targets] = fluid.io.load_inference_model(model_path, exe, model_filename=model_filename, params_filename=params_filename)
# 獲取預測數據
test_datas = [load_image(image_path)]
test_data = np.array(test_datas)
# 開始預測
results = exe.run(inference_program,
feed={feed_target_names[0]: test_data},
fetch_list=fetch_targets)
results = np.argsort(-results[0])
result = results[0][0]
print("infer label is: %d" % result)
if __name__ == '__main__':
image_path = "0b77aba2-9557-11e8-a47a-c8ff285a4317.jpg"
use_cuda = False
model_path = "fluid_models/"
model_filename = "model"
params_filename = "params"
infer_one(image_path, use_cuda, model_path, model_filename, params_filename)
使用上面的程序就是使用轉換的模型來預測圖片了。要注意訓練模型時對圖片的處理。
參考資料¶
- https://github.com/PaddlePaddle/models/tree/develop/fluid/image_classification/caffe2fluid
- https://gist.github.com/ksimonyan/211839e770f7b538e2d8