pytorch模型轉caffe模型


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


免責聲明!

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



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