caffe上手:如何导出caffemodel参数

来源:互联网 发布:linux man命令怎么用 编辑:程序博客网 时间:2024/05/01 22:34

最近在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 caffeif __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 caffeif __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.)


2 0
原创粉丝点击