【tensorflow2caffe】一、caffemodel存储解析

     在博客开始前,首先郑重感谢博主jiongnima的博客对我的帮助,我按照博主的方法顺利的把bcnn模型的tensorflow版转为caffe版,关于bcnn模型,它是个细粒度分类模型,我将在后续的博客中详细介绍。

首先隆重呈上博主的链接:

https://blog.csdn.net/jiongnima/article/details/72904526

    转模型系列博文的操作主要基于博主的实验探索,中间也穿插着我自己的一些想法以及重新编排,在强烈膜拜原创的基础上,将转模型过程进行了亲自的实践并成功复现,因此暂时(不要脸)的将该系列博文归为原创。

    下面进入正题部分。

    转模型的初衷无非是处于现有条件的某些设备对某一框架的支持比另一个更好,因此需要将后者训练所得的模型转成前者的形式。要转模型首先应该明确我们需要转成的模型,到底需要哪些东西。对于tensorflow转caffe来说,我们最终的目的是得到deploy.prototxt和caffemodel,以便用接口来调用模型(调用接口请见:https://blog.csdn.net/zl3090/article/details/88082728),因此我们需要知道deploy.prototxt和caffemodel分别存了点啥。

    对于deploy.prototxt,是个类似于caffe训练时所用的train.prototxt的文档,记录了模型结构,二者的具体区别详见:https://blog.csdn.net/zl3090/article/details/88082799,很多新手(包括楼主最初操作的时候)都是不禁询问,deploy去哪里找或者怎么生成呢?经过楼主的实践操作,可以对这一问题作出回答,deploy是需要自己写的(当然有些标准模型在下载prototxt时会自带deploy,那样就不用自己写了),是在你训练所用train.prototxt基础上改变输入形式,最主要的变化是在文件的开头不再添加lmdb存储的路径,而是变为写入数据输入的shape,格式遵循caffe的nchw输入形式,示例如下:

name:"VGG16"
layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param { 
       dim: 1 
       dim: 3 
       dim: 224
       dim: 224 
   }
}

以及输出层增加softmax,示例如下:

#layer {
#  name: "accuracy"
#  type: "Accuracy"
# bottom: "fc7"
#  bottom: "label"
#  top: "accuracy"
#}
layer {
  name: "prob"
  type: "Softmax"
  bottom: "fc7"
 # bottom: "label"
  top: "prob"
}
...
...
...

    接下来说caffemodel,首先剧透,它实际上等于prototxt和weight以及bias参数的合并,也就是说它详细记录了模型的结构和训练所得的权重参数,具体扒源码的思考过程请参见文章最开头博主的文章,此处直接简单粗暴开始写如何解析出caffemodel.

    caffe源码中读写prototxt及caffemodel文件的函数是io.cpp,其中把caffemodel读入prototxt的代码段如下:

bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
  int fd = open(filename, O_RDONLY);
  CHECK_NE(fd, -1) << "File not found: " << filename;
  ZeroCopyInputStream* raw_input = new FileInputStream(fd);
  CodedInputStream* coded_input = new CodedInputStream(raw_input);
  coded_input->SetTotalBytesLimit(kProtoReadBytesLimit, 536870912);
 
  bool success = proto->ParseFromCodedStream(coded_input);
 
  delete coded_input;
  delete raw_input;
  close(fd);
  return success;
}

    读者朋友们可以看到,这个函数里面就使用了open函数,和一些底层的google::protobuf的数据流。在这里其实就是先把二进制文件(caffemodel)转化成文件流,再放入prototxt里面。

    那么,将prototxt中的文档读出,写入txt才是我们想看到的形式,而caffe中已经定义了proto转txt的接口,代码如下:

void WriteProtoToTextFile(const Message& proto, const char* filename) {
  int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  FileOutputStream* output = new FileOutputStream(fd);
  CHECK(google::protobuf::TextFormat::Print(proto, output));
  delete output;
  close(fd);
}

    所以,我们现在的问题转化为如何调用这俩函数,实现我们由caffemodel转txt的目的,以lenet作为例子,所需调用代码如下:

#include <caffe/caffe.hpp>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include <algorithm>
#include <iosfwd>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <iostream>
#include "caffe/common.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"
 
using namespace caffe;
using namespace std;
using google::protobuf::io::FileInputStream;
using google::protobuf::io::FileOutputStream;
using google::protobuf::io::ZeroCopyInputStream;
using google::protobuf::io::CodedInputStream;
using google::protobuf::io::ZeroCopyOutputStream;
using google::protobuf::io::CodedOutputStream;
using google::protobuf::Message;
 
int main()
{
	NetParameter proto;
	ReadProtoFromBinaryFile("/home/cvlab/files/caffe-master/data/mnist/lenet_iter_10000.caffemodel", &proto);
	WriteProtoToTextFile(proto, "/home/cvlab/files/caffe-master/data/mnist/test.txt");
	return 0;
}

所需的CMakeLists文件如下:

cmake_minimum_required (VERSION 2.8)
 
project (pt_test)
 
add_executable(pt_test pt.cpp)
 
include_directories ( /home/cvlab/files/caffe-master/include
    /usr/local/include
    /usr/local/cuda/include
    /usr/include )
 
target_link_libraries(pt_test
    /home/cvlab/files/caffe-master/build/lib/libcaffe.so
    /usr/lib/x86_64-linux-gnu/libglog.so
    /usr/lib/x86_64-linux-gnu/libboost_system.so
    )

编译步骤如下:

  (1) cmake .

  (2) make

  (3) ./pt_test

运行效果如图:

如果make过程报错,大多情况是缺少了一些依赖库,可以根据所报内容,对CMakeLists进行修改,少啥就向target_lik_libraries里放啥。

然后打开txt文件可以见到:

    至此,我们就可以清晰看到caffemodel里存了啥,印证了上文剧透中所说的话,它实际上等于prototxt和weight以及bias参数的合并,也就是说它详细记录了模型的结构和训练所得的权重参数。为了解决后续参数提出来不知道该放哪的问题,此处提前剧透,weight和bias在对应层的layer最后顺序排放即可。

    现在我们知道caffemodel放了啥,也就知道自己缺少啥,缺少有二,一是自己写的deploy,二是tf中训练所得的参数,如何提取参数请见下一篇博文。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值