Pytorch模型轉換Caffe模型踩坑指南,代碼使用的是Github上的工程,地址:https://github.com/longcw/pytorch2caffe
操作環境:ubuntu = 14.04 miniconda 3 caffe pytorch = 0.2.0 torchvision = 0.1.8 python = 2.7
環境配置:
第一步 : 在miniconda創建一個虛擬環境pytorch2caffe : conda create -n pytorch2caffe python=2.7
第二步 : 激活虛擬環境 source activate pytorch2caffe
第三步 : 在該虛擬環境下安裝對應版本的pytorch和torchvision : conda install pytorch=0.2.0 torchvision=0.1.8 安裝完成后conda list看一看有沒有安裝成功對應的版本
第四步 : 在該虛擬環境下編譯caffe,官網指南鏈接 : http://caffe.berkeleyvision.org/install_apt.html
第五步 : 編譯配置caffe的python接口pycaffe,操作指南鏈接 : https://www.cnblogs.com/lyyang/p/6573846.html
配置環境的時候因Github上沒有關於這個項目的環境介紹,所以我以前用的是習慣的python 3.6和pytorch 0.4.0 ,而這個項目是用python 2.7寫的,所以在創建虛擬環境的時候使用python 2.7的環境,要不然之后也會有很多問題,pytorch和torchvision版本很重要。
博主調代碼時老是遇到:KeyError: ‘ExpandBackward’這個錯誤,在改變pytorch和torchvision版本后這個問題解決了,這個Github的項目比較久了,並不支持新版本的Pytorch,這就是我在配置操作環境下幫大家踩得坑啦。
在轉換自己的模型之前,先調通項目中的demo,驗證配置環境已經配置成功。項目中的demo是轉換Google的inception-v3模型,我們根據終端里提示的模型地址將模型下載到本地,然后將模型載入進行轉換。轉換成功之后在項目的demo文件夾中生成model.prototxt與model.caffemodel兩個新文件。測試的話將demo中設置test_mod = True,給定同樣的隨機輸入數據,測試兩個模型得出的結果。
遇到的問題:
caffe支持的卷積和池化層操作都是2D的,我的這個模型所做的卷積和池化操作都是1D的,當時找這個問題也花了很久的時間,沒想到caffe只支持2D的操作。我將原來的input_size=(1, 1, 1024)修改成了(1, 1, 1, 1024),然后做相應的2D卷積和池化操作。
我還遇到過的一個Import問題是:Segmentation fault (core dumped)這個問題的原因我不是很清楚,我在查看是哪個inport出問題時發現import caffe在import torch之后是並不會報這個錯誤,但是import torch之后再import caffe就會報這個錯誤。
在調試代碼時遇到過這個問題:ValueError: could not broadcast input array from shape (3,128) into shape (3,512),這個問題和caffe的源碼有關,需要在caffe的proto文件中修改pooling層的參數optional bool ceil_mode = 13 [default = true],而因為caffe版本的原因,我的caffe並沒有這個參數,所以要往現在caffe的源碼pooling層中將ceil_mode相關參數和代碼添加進去,然后重新編譯caffe與pycaffe。
1、在pooling_layer.hpp中往PoolingLayer類中添加ceil_mode_這個參數: int height_, width_; int pooled_height_, pooled_width_; bool global_pooling_; bool ceil_mode_; //添加的類成員變量 Blob<Dtype> rand_idx_; Blob<int> max_idx_; 2、修改pooling_layer.cpp文件中相關參數,主要涉及到LayerSetUp函數和Reshape函數。 LayerSetUp函數修改如下: || (!pool_param.has_stride_h() && !pool_param.has_stride_w())) << "Stride is stride OR stride_h and stride_w are required."; global_pooling_ = pool_param.global_pooling(); ceil_mode_ = pool_param.ceil_mode(); //添加的代碼,主要作用是從參數文件中獲取ceil_mode_的參數數值。 Reshape函數修改如下: if (global_pooling_) { kernel_h_ = bottom[0]->height(); kernel_w_ = bottom[0]->width(); //刪除下面四行代碼-------------------------------- pooled_height_ = static_cast<int>(ceil(static_cast<float>( height_ + 2 * pad_h_ - kernel_h_) / stride_h_)) + 1; pooled_width_ = static_cast<int>(ceil(static_cast<float>( width_ + 2 * pad_w_ - kernel_w_) / stride_w_)) + 1; // Specify the structure by ceil or floor mode // 添加下面的代碼------------------------ if (ceil_mode_) { pooled_height_ = static_cast<int>(ceil(static_cast<float>( height_ + 2 * pad_h_ - kernel_h_) / stride_h_)) + 1; pooled_width_ = static_cast<int>(ceil(static_cast<float>( width_ + 2 * pad_w_ - kernel_w_) / stride_w_)) + 1; } else { pooled_height_ = static_cast<int>(floor(static_cast<float>( height_ + 2 * pad_h_ - kernel_h_) / stride_h_)) + 1; pooled_width_ = static_cast<int>(floor(static_cast<float>( width_ + 2 * pad_w_ - kernel_w_) / stride_w_)) + 1; } 3、修改caffe.proto文件中PoolingParameter的定義: // Specify floor/ceil mode optional bool ceil_mode = 13 [default = true]; 4、重新編譯caffe與pycaffe
原文:https://blog.csdn.net/weixin_38501242/article/details/82624071