caffe上手:如何导出caffemodel参数

Caffe模型参数转换
本文介绍如何使用Python和Matlab脚本从Caffe模型中提取并转换参数,以便于理解和调整。包括Python脚本load_caffemodel.py和Matlab脚本parse_param.m的具体实现。

最近在github上看到一个导出mnist的model参数的Matlab和Python的脚本,比较简单,以后可能用得到,记录一下。

load_caffemodel.py: 使用python脚本加载lenet的参数。

conv*.mat: 在blob数据中相同结构定义的层的参数。

parse_param.m: Matlab脚本,将加载到的每层参数保存出来的mat文件整合成一个parsed_param.mat文件。

parsed_param.mat: Matlab保存生成的mat文件。

如果github打不开的话,我这里把这几个脚本的代码贴出来。

================================================================================

load_caffemodel.py

[cpp]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. import numpy as np  
  2. import scipy.io as sio  
  3. import caffe  
  4.   
  5. def load():  
  6.     # Load the net  
  7.     caffe.set_mode_cpu()  
  8.     # You may need to train this caffemodel first  
  9.     # There should be script to help you do the training  
  10.     net = caffe.Net(root + 'lenet.prototxt', root + 'lenet_iter_10000.caffemodel',\  
  11.         caffe.TEST)  
  12.     conv1_w = net.params['conv1'][0].data  
  13.     conv1_b = net.params['conv1'][1].data  
  14.     conv2_w = net.params['conv2'][0].data  
  15.     conv2_b = net.params['conv2'][1].data  
  16.     ip1_w = net.params['ip1'][0].data  
  17.     ip1_b = net.params['ip1'][1].data  
  18.     ip2_w = net.params['ip2'][0].data  
  19.     ip2_b = net.params['ip2'][1].data  
  20.     sio.savemat('conv1_w', {'conv1_w':conv1_w})  
  21.     sio.savemat('conv1_b', {'conv1_b':conv1_b})  
  22.     sio.savemat('conv2_w', {'conv2_w':conv2_w})  
  23.     sio.savemat('conv2_b', {'conv2_b':conv2_b})  
  24.     sio.savemat('ip1_w', {'ip1_w':ip1_w})  
  25.     sio.savemat('ip1_b', {'ip1_b':ip1_b})  
  26.     sio.savemat('ip2_w', {'ip2_w':ip2_w})  
  27.     sio.savemat('ip2_b', {'ip2_b':ip2_b})  
  28.   
  29. if __name__ == "__main__":  
  30.     # You will need to change this path  
  31.     root = '/caffe/examples/mnist/'  
  32.     load()  
  33.     print 'Caffemodel loaded and written to .mat files successfully!'  

parse_param.m

[cpp]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. clear;close all;clc  
  2. %% Parse the ConvNet parameters loaded from caffe into better fit version  
  3. % Author: Yuliang Zou  
  4. % Date: 06/14/2016  
  5.   
  6. %% Load parameters  
  7. load('conv1_w.mat');  
  8. load('conv1_b.mat');  
  9. load('conv2_w.mat');  
  10. load('conv2_b.mat');  
  11. load('ip1_w.mat');  
  12. load('ip1_b.mat');  
  13. load('ip2_w.mat');  
  14. load('ip2_b.mat');  
  15.   
  16. %% Parse parameters into better fit version  
  17. % conv1 has 20 filters with 5 * 5 size   
  18. W1 = zeros(5,5,20);  
  19. for i = 1:20  
  20.     W1(:,:,i) = conv1_w(i,1,:,:);  
  21. end  
  22. b1 = double(conv1_b');  
  23. % conv2 has 50 filters with 5 * 5 size   
  24. W2 = zeros(5,5,20,50);  
  25. for k = 1:20  
  26.     for i = 1:50  
  27.         W2(:,:,k,i) = conv2_w(i,k,:,:);  
  28.     end  
  29. end  
  30. b2 = double(conv2_b');  
  31. % fc layers  
  32. ip1W = double(ip1_w);  
  33. ip1b = double(ip1_b');  
  34. ip2W = double(ip2_w);  
  35. ip2b = double(ip2_b');  
  36.   
  37. save('parsed_param.mat','W1','W2','b1','b2','ip1W','ip1b','ip2W','ip2b');  

========================================分割线===================================

基于caffe 的卷积神经网络模型训练后得到的权值是通过Google Protobuf来存储的后缀名为.caffemodel的二进制文件,这类文件一般很难直接打开进行权值的读取和修改。有的时候我们希望直观的看到网络中每个神经元的权值,或者希望更改网络的部分结构来得到新的结构进行finetune。在这样的情况下我们就需要对caffemodel文件进行操作。好在caffe的Python接口提供了针对caffemodel文件的修改方法,用户可以从caffemodel文件中读取参数,并对参数进行修改以得到新的caffemodel文件。 
1、读取caffemodel里的权值 
  首先caffe要先进行pycaffe 的编译并安装好pycaffe的依赖环境。然后用下述python文件可以查看caffemodel文件中各个层的参数,以查看lenet-5权值为例。

import caffe

if __name__ == "__main__":
    #文件的存放路径
    root = '/home/xhq11/caffe-master/examples/mnist/'
    caffe.set_mode_cpu
    net = caffe.Net(root+'lenet.prototxt',\
    root+'lenet_iter_10000.caffemodel',caffe.TEST')
    #第一个卷基层的权值
    conv1_w = net.params['conv1'][0].data
    #第一个卷基层的偏置值
    conv1_b = net.params['conv1'][1].data
    #可以打印相应的参数和参数的维度等信息
    print conv1_w,conv1_b
    print conv1_w.size,conv1_b.size
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

需要注意的是,这样的方法只能读取有训练参数层的权值,对于下采样、激活层等无训练参数的层,无法得到其层内权值(因为层内根本没有权值)。

2、修改caffemodel内的权值并保存为新的caffemodel 
  有的时候我们需要修改原caffemodel来得到新的caffemodel文件用于finetune等工作,可通过下述python文件实现,以修改lenet-5权值为例。

import caffe

if __name__ == "__main__":
    #文件的存放路径
    root = '/home/xhq11/caffe-master/examples/mnist/'
    caffe.set_mode_cpu
    net = caffe.Net(root+'lenet.prototxt',\
    root+'lenet_iter_10000.caffemodel',caffe.TEST')
    #在这部分做任何你希望的对权值的修改
    net.save('/path of your new caffemodel/newname.caffemodel')
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

  但是这种方法的弊端也很明显,这种方法只能在原有的结构上进行权值的修改,而不能对原有结构进行修改,比如,删除原有结构中的某一层或增加新的层,或更改原有层的维度等。 
  在caffe 的官方文档中提供了一种修改caffemodel文件的方法,具体参考http://nbviewer.jupyter.org/github/BVLC/caffe/blob/master/examples/net_surgery.ipynb(需翻墙)。这里面的案例是讲caffenet的后三个全连接层(fc6/fc7/fc8)改成全卷基层(fc6-conv/fc7-conv/fc8-conv)以形成新的网络权值文件bvlc_caffenet_full_conv.caffemodel。值得注意的是,这里面的案例也仅仅是将原来后三个全连接层的权值“摊平”(文中的写法为flat)并赋给卷积层,由于全连接层和卷基层的参数个数是相同的,因此这个案例本质上也属于权值的进一步修改。文中最后有这么一段话: 
Note that this model isn’t totally appropriate for sliding-window detection since it was trained for whole-image classification. Nevertheless it can work just fine. Sliding-window training and finetuning can be done by defining a sliding-window ground truth and loss such that a loss map is made for every location and solving as usual. (This is an exercise for the reader.)


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值