tensorflow2caffe(1) : caffemodel解析,caffemodel里面到底记录了什么?
来源:互联网 发布:网络侵权管辖最新规定 编辑:程序博客网 时间:2024/05/16 07:58
在本文正式开始之前,笔者要先和各位读者朋友们道个歉。因为身为研一小白的笔者实在身不由己,除了各种任务之外,还要应付繁忙的课程,忙于各种考试像一只咸鱼。因此耽误了博文的撰写,对不起各位读者朋友,笔者在忙完6月进入研二之后一定再接再厉。下面开始干货~
本篇还是一个插播的博客,旨在向大家分享caffemodel里面记录的信息。在我们使用caffe框架训练网络时,最终总会生成一个caffemodel,我们大概知道里面记录了模型的参数。而作为初学者的笔者,总是不分青红皂白地就直接在模型的验证阶段就调用了。从来没有去看过caffemodel里面到底讲了什么,那么,本篇中笔者就解析一下caffemodel。
有读者朋友未免会问,笔者是出于什么目的想解析caffemodel的呢?这说来话长,是笔者最近做的项目需要将model拆开并进行改动,因此需要去解析caffemodel。那么笔者是怎么摸索的呢?各位读者朋友们是否还记得,笔者前两期的博客里面提及的caffe官方提供的classification.cpp文件,里面在执行Classifier类的构造函数的时候,有一个net_指针,并且执行了一个操作:
net_->CopyTrainedLayersFrom(trained_file);
这个CopyTrainedLayersFrom函数就是从caffemodel里面载入我们需要的参数了。然后笔者就从这个函数开始挖,进入net.cpp文件:
template <typename Dtype>void Net<Dtype>::CopyTrainedLayersFrom(const string trained_filename) { if (H5Fis_hdf5(trained_filename.c_str())) { CopyTrainedLayersFromHDF5(trained_filename); } else { CopyTrainedLayersFromBinaryProto(trained_filename); }}
在这里很明显执行了else下面的语句,从二进制文件中去读取了参数,然后,笔者又找到了CopyTrainedLayersFromBinaryProto函数,很巧就在CopyTrainedLayersFrom函数的下方:
template <typename Dtype>void Net<Dtype>::CopyTrainedLayersFromBinaryProto( const string trained_filename) { NetParameter param; ReadNetParamsFromBinaryFileOrDie(trained_filename, &parm); CopyTrainedLayersFrom(param);}
在里面首先执行了一个ReadNetParamsFromBinaryFileOrDie函数,把二进制文件中的参数读到parm里面,parm是一个NetParameter类型的,NetParameter继承了实际是一个Message,Message是proto类型的,详细的笔者后话解析。然后笔者去找了一下ReadNetParamsFromBinaryFileOrDie函数,这个函数在upgrade_proto.cpp里面:
void ReadNetParamsFromBinaryFileOrDie(const string& param_file, NetParameter* param) { CHECK(ReadProtoFromBinaryFile(param_file, param)) << "Failed to parse NetParameter file: " << param_file; UpgradeNetAsNeeded(param_file, param);}这个函数完成的功能是首先进行ReadProtoFromBinaryFile,然后执行了一个更新的操作。然后笔者就去找这个ReadProtoFromBinaryFile函数,这个函数在io.cpp里面:
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)转化成文件流,再放入proto里面。
那么,笔者大胆猜想,能读就能写。
其实io.cpp里面已经定义了这种接口:
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);}
也就是说:先用ReadProtoFromBinaryFile函数将二进制文件读入proto里面,再将proto文件读入txt文件就行了。
笔者迫不及待地拿lenet网络训练生成的caffemodel做了个测试:
#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;}
笔者训练了一个lenet训练生成的二进制文件,并将其写入了一个名为test.txt的文件中。
其对应的CMakeLists.txt文件为:
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 )编译执行:
然后我们打开test.txt文件可以见到:
一共43万多行,记录了lenet-5的网络参数。因为lenet-5使用了全连接层,因此参数规模是庞大的(全连接层的参数约占了总体参数规模的90%)。
同时也可以看到,读出的二进制文件中参数规格是按照caffe.proto中协定的格式来的。
到此,我们就能清晰地看到caffemodel中记载的数据和格式了。
欢迎阅读笔者后续博客,各位读者朋友的支持与鼓励是我最大的动力!
written by jiong
故上兵伐谋,其次伐交,其次伐兵,其下攻城;攻城之法为不得已。
- tensorflow2caffe(1) : caffemodel解析,caffemodel里面到底记录了什么?
- Caffe到底训练出了个什么东西:caffemodel解析
- Caffemodel解析
- Caffemodel解析
- Caffemodel解析
- Caffemodel解析
- Caffemodel解析代码
- tensorflow2caffe(4) : caffemodel的生成与tensorflow2caffe框架转换的总结
- 【深度学习:caffe】Caffemodel解析
- caffemodel protobuf
- Caffemodel数据结构解析与Protocol Buffer技术详解(C++实例)
- 使用caffemodel的方法
- caffemodel转matlab格式
- 如何导出caffemodel参数
- 利用caffemodel进行预测
- caffemodel进行批量测试
- python读取caffemodel文件
- pycaffe读取caffemodel参数
- c语言文件读写相关函数
- 图像分割
- 55--寻找倍数
- centos6.5的php5.3.3 通过yum升级到5.6
- 【zoj】System overload
- tensorflow2caffe(1) : caffemodel解析,caffemodel里面到底记录了什么?
- Linux 截图工具之 gnome-screenshot
- 简述操作系统
- MSSQL实用脚本
- 安卓之常用按钮ProgressBar滚动体
- 【zoj】约瑟夫环相关- system overload
- ubuntu16.04下安装tensorflow(二)
- 多重继承引发的二义性问题及解决方法分析
- Git使用