对Caffemodel的解析,更直接的说是对protobuf的解析。对Protobuf来说最重要的有三个文件,***.proto,***.pb.h,和***.pb.cc。基本的操作流程是首先写***.proto文件,然后编译出***.pb.h和***.pb.cc两个文件,我们就可以对Protobuf进行读写和修改了。
今天这里,我只想总结一下我在修改Caffemodel时遇到的一些坑,以及解决方案。
第一个也是困扰我最久的一个问题:
现象:读取层名时没有问题,但是读取层类型时会崩溃,而且这种崩溃时好时坏。
原因:在解读Caffemodel时使用了libcaffe.lib库,可能会造成解析混乱。
解决:我当时参考了这篇文章https://www.cnblogs.com/zhouyang209117/p/7218719.html,在文章的最后有如下两行代码:
编译可执行文件
g++ addressbook.pb.cc read_data.cpp -o read.out-lprotobuf g++ addressbook.pb.cc write_data.cpp -o write.out-lprotobuf
看到这两行代码时,让我幡然醒悟,Caffemodel就是一个Protobuf文件,我们无需再依赖libcaffe.lib去解析,我之所以犯错是因为没有理解***.pb.cc文件的作用,我们需要在自己的工程里添加这个文件,使其和我们的main.cpp一起编译。搞定!,不再崩溃了。
第二个问题:怎样去修改Caffemodel里的参数?
以下面代码为例
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
static const int kNameFieldNumber = 1;
inline const ::std::string& name() const;
inline void set_name(const ::std::string& value);
inline void set_name(const char* value);
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
inline void set_allocated_name(::std::string* name);
大家在第一次,修改参数很有可能发现,我明明修改了但是为什么没有写进去呢?是因为大家没有注意到函数前后,关键字const的限制,很多函数只允许我们读,不允许我们写。如果你想写请记住两条准则1、使用指针;2、使用带”mutable_“前缀的函数。在这里只能说谷歌大神的代码太规范了。
第三个问题:原本以为Caffemodel文件不能原地修改,后来发现,修改后的参数是可以直接写回原文件的。单请记住一点,每次写完一定要执行关闭文件的操作,否则无法生效。
最后给贴出一段代码:
#include <iostream>
#include <string>
#include <fstream>
#include <istream>
#include "caffe/proto/caffe.pb.h"
using namespace std;
int main(){
GOOGLE_PROTOBUF_VERIFY_VERSION;
caffe::NetParameter netparam;
string model = "test.caffemodel";
//ifstream caffemodel;
//caffemodel.open(model, ifstream::in | ifstream::binary);
ifstream caffemodel(model, ifstream::in | ifstream::binary);
if (&caffemodel == NULL){
cout << "The ptr of caffemodel is NULL" << endl;
return 0;
}
if (!caffemodel.is_open()){
cout << "Can not open model" << endl;
return 0;
}
bool flag=netparam.ParseFromIstream(&caffemodel);
//bool flag = ReadProtoFromBinaryFile(model, netparam);
int layer_size = netparam.layer_size();
cout << "layer_size = " << layer_size << endl;
caffe::LayerParameter* layerparam=NULL;
for (int i = 0; i < layer_size; i++){
layerparam = netparam.mutable_layer(i);
/*const string& layername = layerparam->name();
cout << "layername: " << layername << endl;*/
const string& layertype = layerparam->type();
//cout << "layertype: " << layertype << endl;
if (layertype == "hua"){
const string& layername = layerparam->name();
cout << "layername: " << layername << endl;
const string& topname = layerparam->top(0);
cout << " " << topname << endl;
cout << " " << layerparam->type() << endl;
//layerparam->Clear();
//layerparam->clear_type();
//layerparam->set_type("hua");
// convparam = layerparam->mutable_convolution_param();
// if (convparam->has_weight_filler()){
// weight_f = convparam->mutable_weight_filler();
// if (weight_f->has_type()){
// cout << weight_f->type() << endl;;
// }
// }
// weight_blob = layerparam->mutable_blobs(0);
// cout << "N: " << weight_blob->num() << endl;
// cout << "C: " << weight_blob->channels() << endl;
// cout << "H: " << weight_blob->height() << endl;
// cout << "W: " << weight_blob->width() << endl;
// if (weight_blob->has_shape()){
// BlobShape blobshape = weight_blob->shape();
// cout << "N: " << blobshape.dim(0) << endl;
// cout << "C: " << blobshape.dim(1) << endl;
// cout << "H: " << blobshape.dim(2) << endl;
// cout << "W: " << blobshape.dim(3) << endl;
// }
// BlobShape blobshape = weight_blob->shape();
// for (int i = 0; i < (blobshape.dim(0)*blobshape.dim(1)*blobshape.dim(2)*blobshape.dim(3)); i++){
// cout << "yuanshi:" << weight_blob->data(i) << endl;
// weight_blob->set_data(i, 9999.0);
// cout << "xiugai:" << weight_blob->data(i) << endl;
// if (i == 10){
// break;
// }
// }
}
}
//fstream outcaffemodel("test.caffemodel",ios_base::out|ios_base::trunc|ios_base::binary);
//netparam.SerializeToOstream(&outcaffemodel);
caffemodel.close();
//outcaffemodel.close();
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
// optional string name = 1;
inline bool has_name() const;
inline void clear_name();
static const int kNameFieldNumber = 1;
inline const ::std::string& name() const;
inline void set_name(const ::std::string& value);
inline void set_name(const char* value);
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
inline void set_allocated_name(::std::string* name);
#include <iostream>
#include <string>
#include <fstream>
#include <istream>
#include "caffe/proto/caffe.pb.h"
using namespace std;
int main(){
GOOGLE_PROTOBUF_VERIFY_VERSION;
caffe::NetParameter netparam;
string model = "test.caffemodel";
//ifstream caffemodel;
//caffemodel.open(model, ifstream::in | ifstream::binary);
ifstream caffemodel(model, ifstream::in | ifstream::binary);
if (&caffemodel == NULL){
cout << "The ptr of caffemodel is NULL" << endl;
return 0;
}
if (!caffemodel.is_open()){
cout << "Can not open model" << endl;
return 0;
}
bool flag=netparam.ParseFromIstream(&caffemodel);
//bool flag = ReadProtoFromBinaryFile(model, netparam);
int layer_size = netparam.layer_size();
cout << "layer_size = " << layer_size << endl;
caffe::LayerParameter* layerparam=NULL;
for (int i = 0; i < layer_size; i++){
layerparam = netparam.mutable_layer(i);
/*const string& layername = layerparam->name();
cout << "layername: " << layername << endl;*/
const string& layertype = layerparam->type();
//cout << "layertype: " << layertype << endl;
if (layertype == "hua"){
const string& layername = layerparam->name();
cout << "layername: " << layername << endl;
const string& topname = layerparam->top(0);
cout << " " << topname << endl;
cout << " " << layerparam->type() << endl;
//layerparam->Clear();
//layerparam->clear_type();
//layerparam->set_type("hua");
// convparam = layerparam->mutable_convolution_param();
// if (convparam->has_weight_filler()){
// weight_f = convparam->mutable_weight_filler();
// if (weight_f->has_type()){
// cout << weight_f->type() << endl;;
// }
// }
// weight_blob = layerparam->mutable_blobs(0);
// cout << "N: " << weight_blob->num() << endl;
// cout << "C: " << weight_blob->channels() << endl;
// cout << "H: " << weight_blob->height() << endl;
// cout << "W: " << weight_blob->width() << endl;
// if (weight_blob->has_shape()){
// BlobShape blobshape = weight_blob->shape();
// cout << "N: " << blobshape.dim(0) << endl;
// cout << "C: " << blobshape.dim(1) << endl;
// cout << "H: " << blobshape.dim(2) << endl;
// cout << "W: " << blobshape.dim(3) << endl;
// }
// BlobShape blobshape = weight_blob->shape();
// for (int i = 0; i < (blobshape.dim(0)*blobshape.dim(1)*blobshape.dim(2)*blobshape.dim(3)); i++){
// cout << "yuanshi:" << weight_blob->data(i) << endl;
// weight_blob->set_data(i, 9999.0);
// cout << "xiugai:" << weight_blob->data(i) << endl;
// if (i == 10){
// break;
// }
// }
}
}
//fstream outcaffemodel("test.caffemodel",ios_base::out|ios_base::trunc|ios_base::binary);
//netparam.SerializeToOstream(&outcaffemodel);
caffemodel.close();
//outcaffemodel.close();
google::protobuf::ShutdownProtobufLibrary();
return 0;
}