【一】caffe依赖开源库

【C++】google gflags详解
【C++】google glog详解
【C++】Google Protocol Buffer(protobuf)详解(一)
【C++】Google Protocol Buffer(protobuf)详解(二)
【C++】google gtest 详解

【二】基本模块分析

1、 Blob

Blob的维度:图像数量N x 通道数K x 图像高度H x 图像宽度W;
坐标为:(n, k, h, w),指定偏移的计算:((n*K+k)*H+h)*W+w;

主要成员变量:

protected:shared_ptr<SyncedMemory> data_;  // 存储网络中传递的普通参数valuesshared_ptr<SyncedMemory> diff_;  // 存储相对于自身的梯度误差gradientsshared_ptr<SyncedMemory> shape_data_; //vector<int> shape_; //维度表示,如:shape(0)=num; shape(1)=channels; shape(2)=height; shape(3)=widthint count_;int capacity_;

主要成员函数:
1) void Reshape(const vector& shape); //更改blob的大小,必要时分配新内存。
可以调用此函数来创建内存的初始分配,并在Layer:: rename或Layer::Forward期间调整顶部blob的大小。
当更改blob的大小时,只有在没有足够的内存时才会重新分配内存,并且永远不会释放多余的内存。
注意,重新构造输入blob并立即调用Net::Backward是一个错误;要将新的输入形状传播到更高的层,需要调用Net::Forward或Net::Reshape。

2) int shape(int index); //返回第index维度的大小(如果索引为负,则从末尾返回负index维度的大小)

3) int count(int start_axis, int end_axis) //计算切片的体积,一系列维度之间的尺寸乘积
4) int count(int start_axis) //计算从一个特定的维度到最后一个维度的切片的体积。

5) int offset(const int n, const int c = 0, const int h = 0, const int w = 0) //换算出第n个、第c通道、第h行、第w列的偏移量
6) int offset(const vector& indices) //将indices换算成偏移量(可以超出四维)
7) void CopyFrom(const Blob& source, bool copy_diff = false, bool reshape = false) //复制source Blob(最终调用memcpy)
参数说明:copy_diff=true,复制差值;reshape=true,改变本Blob成和source Blob相同的维度(形状),否则在本Blob和source Blob不同时,将会报错
8) Dtype data_at(const int n, const int c, const int h, const int w) //返回数据data指定位置的值
9) Dtype diff_at(const int n, const int c, const int h, const int w) //返回差分diff指定位置的值
10) Dtype data_at(const vector& index) //同上
11) Dtype diff_at(const vector& index) //同上
12) const shared_ptr& data() //返回数据指针
13) const shared_ptr& diff() //返回差分指针
14) void FromProto(const BlobProto& proto, bool reshape = true); //从proto中恢复Blob
15) void ToProto(BlobProto* proto, bool write_diff = false) const; //将Blob转换成proto
16) Dtype asum_data() const; //计算数据data绝对值(L1范数)的和。
17) Dtype asum_diff() const; //计算差diff的绝对值(L1范数)的和。
18) Dtype sumsq_data() const; //计算数据data的平方和(L2范数的平方)。
19) Dtype sumsq_diff() const; //计算差diff的平方和(L2范数的平方)。
20) void scale_data(Dtype scale_factor); //将blob数据data 缩放一个常数因子。
21) void scale_diff(Dtype scale_factor); //将blob差分diff 缩放一个常数因子。
22) void ShareData(const Blob& other); //将本Blob中的data_和shared_ptr指针指向other中的,在layer层中转发它们的副本时,很有用。
当shared_ptr在使用“=”操作符重置时调用析构函数时,它会释放保存这个Blob的data_的SyncedMemory。
23) void ShareDiff(const Blob& other); //参见上
24) bool ShapeEquals(const BlobProto& other); //判断维度是否相同
25)const Dtype* cpu_data() const;
26)void set_cpu_data(Dtype* data);

2、 Layer

主要成员变量:

protected:LayerParameter layer_param_;       //存储层参数protobufPhase phase_;                        //阶段:训练 或者 测试vector<shared_ptr<Blob<Dtype> > > blobs_; //将可学习参数存储为一组blob的向量vector<bool> param_propagate_down_;       //该向量用于指示是否计算每个参数blob的diff。vector<Dtype> loss_;               //表示目标函数中每个顶部blob的权值是否为非零的向量

主要成员函数:
1) Layer(const LayerParameter& param) //不要自己实现构造函数,应该通过SetUp()函数来设置

2) void SetUp(const vector<Blob>& bottom, const vector<Blob>& top) //实现公共层设置功能。
bottom:预先输入的blobs;
top:分配但未成形的输出块,将通过整形来成形;
调用LayerSetUp为各个层类型执行特殊的层设置,然后进行重新塑形以设置顶部块和内部缓冲区的大小。为任何非零损耗权值设置损耗权乘法器blob。
此方法不可重写。

3) virtual void LayerSetUp(const vector<Blob>& bottom, const vector<Blob>& top) {} //执行特定于层的设置:您的层应该实现此功能以及重新塑造。
bottom:预压缩的输入块,其数据字段存储该层的输入数据
top:分配但未成形的输出块
此方法应一次性执行特定于层的设置。这包括从layer_param_读取和处理相关参数。
设置顶部blobs和内部缓冲区的形状应在 Reshape 中完成,该操作将在向前传播之前调用,以调整顶部blob的大小。

4) virtual void Reshape(const vector<Blob>& bottom, const vector<Blob>& top) = 0; //调整顶部blobs和内部缓冲器的形状(维度),以适应底部blobs的形状(维度)。
bottom:根据输入形状(维度)要求的输入blobs
top:根据需求的顶部blobs
这种方法应该根据底部(输入)blobs块的形状根据需要重新塑造顶部块,以及重新塑造任何内部缓冲区和进行任何其他必要的调整,以便该层可以容纳底部块。

5) Dtype Forward(const vector<Blob>& bottom, const vector<Blob>& top); //给定底部的blobs,计算顶部的blobs和损失。
bottom:输入块,其数据字段存储该层的输入数据
top:预压缩的输出块,其数据data字段将存储该层的输出
return:这一层的总损失。
Forward函数调用与设备相关的函数(Forward_cpu或Forward_gpu)来计算给定底部blob的顶部blob值。
如果该层有任何非零的loss_weights,那么Forward函数将计算并返回损耗。
自己实现的层应该实现Forward_cpu和Forward_gpu(可选)。

6) void Backward(const vector<Blob>& top, const vector& propagate_down, const vector<Blob>& bottom);
给定顶部的blob梯度误差,计算底部的blob梯度误差。
top:输出blobs,其diff字段存储相对于自身的梯度误差
propagate_down:与底部长度相等的向量,每个索引表示是否将梯度误差向下传播到对应索引处的底部blob
bottom:输入blobs,其diff字段存储向后传播Backward时相对于自身的梯度误差
Backward函数调用与设备相关的函数(Backward_cpu或Backward_gpu)来计算给定顶部blob差异的底部blob差异。
自己实现的层应该实现Backward_cpu和Backward_gpu(可选)。

7) vector<shared_ptr<Blob > >& blobs() {return blobs_;} //返回可学习参数blob的向量。
8) const LayerParameter& layer_param() const { return layer_param_; } //返回层参数
9) virtual void ToProto(LayerParameter* param, bool write_diff = false);//将层参数写入协议缓冲区protocol
10) Dtype loss(const int top_index) //返回给定索引处与顶部blob关联的标量损失。
11) void set_loss(const int top_index, const Dtype value) //设置给定索引处与顶部blob关联的损失。

12) virtual inline int ExactNumBottomBlobs() const { return -1; } //返回该层所需的底部blobs的确切数目,如果不需要确切数目,则返回-1. 如果需要,则应重写此方法以返回非负值。
13) virtual inline int MinBottomBlobs() const { return -1; } //返回底部blobs最小数量
14) virtual inline int MaxBottomBlobs() const { return -1; } //返回底部blobs最大数量
15) virtual inline int ExactNumTopBlobs() const { return -1; } //返回顶部blobs的确切数量
16) virtual inline int MinTopBlobs() const { return -1; } //返回顶部blobs最小数量
17) virtual inline int MaxTopBlobs() const { return -1; } //返回顶部blobs最大数量
18) virtual inline bool EqualNumBottomTopBlobs() const { return false; } //顶部blobs和底部blobs的数量是否相同
19) virtual inline bool AutoTopBlobs() const { return false; } //返回该层是否自动创建“匿名”顶块top blobs。
如果这个方法返回true, Net::Init将创建足够的“匿名”top blob来满足ExactNumTopBlobs()或MinTopBlobs()指定的需求。

20) virtual inline bool AllowForceBackward(const int bottom_index) const { return true; } //返回是否允许对给定的底部blob索引使用force_backwards。
如果If AllowForceBackward(i) == false, 我们将忽略force_back设置,仅当它需要梯度信息时才将其反向传播到blob i(当force_backer_= = false时就是这样做的)。
21) bool param_propagate_down(const int param_id)
//指定该层是否应该计算特定引索param_id处的梯度 w.r.t。* ;您可以安全地忽略假false值,并始终为所有参数计算梯度,但可能会造成计算的浪费。

22) void set_param_propagate_down(const int param_id, const bool value)
//设置该层是否应该计算param_id处梯度w.r.t。

3、 Net

主要成员变量:

protected:string name_;  //网络名Phase phase_;  //阶段:训练或者测试(TRAIN or TEST)vector<shared_ptr<Layer<Dtype> > > layers_;    //网络中的各个层vector<string> layer_names_;map<string, int> layer_names_index_;vector<bool> layer_need_backward_;vector<shared_ptr<Blob<Dtype> > > blobs_;    //在层之间存储中间结果的块。vector<string> blob_names_;map<string, int> blob_names_index_;vector<bool> blob_need_backward_;vector<vector<Blob<Dtype>*> > bottom_vecs_; //bottom_vecs存储包含每个层输入的向量。它们并不是这些团块的宿主,所以我们只存储指针。vector<vector<int> > bottom_id_vecs_;vector<vector<bool> > bottom_need_backward_;vector<vector<Blob<Dtype>*> > top_vecs_;   //top_vecs存储包含每个层输出的向量vector<vector<int> > top_id_vecs_;vector<Dtype> blob_loss_weights_; //每个网络blob的损失(或目标)函数中的权重向量,由blob_id索引vector<vector<int> > param_id_vecs_;vector<int> param_owners_;vector<string> param_display_names_;vector<pair<int, int> > param_layer_indices_;map<string, int> param_names_index_;vector<int> net_input_blob_indices_; //blob索引用于网络的输入和输出vector<int> net_output_blob_indices_;vector<Blob<Dtype>*> net_input_blobs_;vector<Blob<Dtype>*> net_output_blobs_;vector<shared_ptr<Blob<Dtype> > > params_;  //网络中的参数。vector<Blob<Dtype>*> learnable_params_;/*** The mapping from params_ -> learnable_params_: we have learnable_param_ids_.size() == params_.size(), and learnable_params_[learnable_param_ids_[i]] == params_[i].get() if and only if params_[i] is an "owner"; otherwise, params_[i] is a sharer and learnable_params_[learnable_param_ids_[i]] gives its owner.*/vector<int> learnable_param_ids_;vector<float> params_lr_;   //学习速率因子,和learnable_params_一起使用vector<bool> has_params_lr_;vector<float> params_weight_decay_;   //权重衰减因子,和learnable_params_一起使用vector<bool> has_params_decay_;size_t memory_used_; //这个网络使用的内存字节bool debug_info_;  //是否为网络计算和显示调试信息。// Callbacks回调函数vector<Callback*> before_forward_;vector<Callback*> after_forward_;vector<Callback*> before_backward_;vector<Callback*> after_backward_;

主要成员函数:
1) void Init(const NetParameter& param); //使用NetParameter初始化网络
2) const vector<Blob>& Forward(Dtype loss = NULL); 向前运行并返回结果。

3) Dtype ForwardFromTo(int start, int end);
4) Dtype ForwardFrom(int start);
5) Dtype ForwardTo(int end);
// 前向和后向的From和To变体按指定网络的(拓扑)顺序操作。
// 对于一般的DAG网络,请注意(1)从一个层到另一个层的计算可能需要在不相关的分支上进行额外的计算;(2)如果所有层不包含fan-in,则从中间开始的计算可能是不正确的。

6) void ClearParamDiffs(); //将所有网络参数的差异归零。应该在向后运行Backward之前运行。

7) void Backward(); //反向网络不需要输入和输出,因为它只计算梯度w.r。t参数,数据已在转发过程中提供。
void BackwardFromTo(int start, int end);
void BackwardFrom(int start);
void BackwardTo(int end);

8) void Reshape(); //从底部到顶部重新塑造所有图层。这对于将更改传播到层大小而不运行前向传递非常有用,例如计算输出特性大小。
9) void Update(); //根据计算的差异值更新网络权重。
10) void ShareWeights(); //与共享的blob共享所有者blob的权重数据。注意:这是由Net::Init调用的,因此通常不应手动调用。
11) void ShareTrainedLayersWith(const Net* other); //对于已初始化的网络,隐式复制(即(不使用额外内存)来自另一个网络的预训练层。

12)void CopyTrainedLayersFrom(const NetParameter& param); //对于已经初始化的网络,CopyTrainedLayersFrom()从另一个net参数实例复制已经训练好的层。
void CopyTrainedLayersFrom(const string& trained_filename);
void CopyTrainedLayersFromBinaryProto(const string& trained_filename);
void CopyTrainedLayersFromHDF5(const string& trained_filename);

13)void ToProto(NetParameter* param, bool write_diff = false) const; //将网络写入原型proto。
14)void ToHDF5(const string& filename, bool write_diff = false) const; //将网络写入HDF5文件。

15)返回成员变量的值
inline const string& name() const { return name_; } // 返回网络名称。
inline const vector& layer_names() const { return layer_names_; } // 返回层名称
inline const vector& blob_names() const { return blob_names_; } // 返回blob名称
inline const vector<shared_ptr<Blob > >& blobs() const { return blobs_; } //返回blobs
inline const vector<shared_ptr<Layer > >& layers() const { return layers_; } //返回层layers
inline Phase phase() const { return phase_; } //返回阶段:训练或测试TRAIN or TEST
inline const vector<shared_ptr<Blob > >& params() const { return params_; } //返回参数
inline const vector<Blob>& learnable_params() const { return learnable_params_; } //返回学习参数
inline const vector& params_lr() const { return params_lr_; } //返回学习速率因子
inline const vector& has_params_lr() const { return has_params_lr_; }
inline const vector& params_weight_decay() const { return params_weight_decay_; } //返回可学习参数衰减乘法器
inline const vector& has_params_decay() const { return has_params_decay_; }
const map<string, int>& param_names_index() const { return param_names_index_; }
inline const vector& param_owners() const { return param_owners_; }
inline const vector& param_display_names() const { return param_display_names_; }
inline int num_inputs() const { return net_input_blobs_.size(); } 输入和输出blob数
inline int num_outputs() const { return net_output_blobs_.size(); }
inline const vector<Blob
>& input_blobs() const { return net_input_blobs_; }
inline const vector<Blob*>& output_blobs() const { return net_output_blobs_; }
inline const vector& input_blob_indices() const { return net_input_blob_indices_; }
inline const vector& output_blob_indices() const { return net_output_blob_indices_; }

inline const vector<vector<Blob> >& bottom_vecs() const { return bottom_vecs_; } //返回每一层的底部向量(通常不需要这样做,除非您对每一层进行诸如渐变之类的检查)。
inline const vector<vector<Blob
> >& top_vecs() const { return top_vecs_; } //返回每一层的顶部向量——通常不需要这样做,除非您对每一层进行诸如渐变之类的检查。

16)inline const vector & top_ids(int i) //返回第i层的顶部块top blobs的id
inline const vector & bottom_ids(int i) //返回第i层底部块bottom blobs 的id

17)static void FilterNet(const NetParameter& param, NetParameter* param_filtered); //删除用户指定的层,除了当前阶段、级别和阶段
18)static bool StateMeetsRule(const NetState& state, const NetStateRule& rule, const string& layer_name); //返回NetState状态是否满足NetStateRule规则

4、 Solver

主要成员变量:

protected:SolverParameter param_;int iter_;int current_step_;shared_ptr<Net<Dtype> > net_;vector<shared_ptr<Net<Dtype> > > test_nets_;vector<Callback*> callbacks_;vector<Dtype> losses_;Dtype smoothed_loss_;ActionCallback action_request_function_; //由求解程序的客户端设置的一个函数,该函数提供它希望保存快照和/或提前退出的指示。bool requested_early_exit_;    //如果收到提前停止的请求,则为真。Timer iteration_timer_;    //定时信息,便于调整,如nbr的gpufloat iterations_last_;

主要成员函数:
1) 初始化
void Init(const SolverParameter& param);
void InitTrainNet();
void InitTestNets();

2)void SetActionFunction(ActionCallback func); //求解器的客户端可以选择性地调用这个函数,以便设置求解器用来查看应该采取什么操作的函数(例如快照或提前退出培训)。
SolverAction::Enum GetRequestedAction();

3)virtual void Solve(const char* resume_file = NULL); //求解器函数的主要入口。默认情况下,iter为零。输入一个非零的iter数字,为一个预先训练过的网络恢复训练。
inline void Solve(const string& resume_file) { Solve(resume_file.c_str()); }
void Step(int iters);

4)void Restore(const char* resume_file); //还原方法简单地将数据分派给RestoreSolverStateFrom___ (protected方法)。您应该实现这些方法来从适当的快照类型恢复状态。

5)void Snapshot(); //Solver::Snapshot函数实现了存储学习网络的基本快照实用程序。您应该实现SnapshotSolverState()函数,该函数生成一个SolverState协议缓冲区,该缓冲区需要与所学习的网络一起写入磁盘。

5、解码器solver注册和使用SolverRegistry SolverRegisterer
6、 层注册和使用 LayerRegisterer LayerRegistry
6.1 宏定义:
#define REGISTER_LAYER_CREATOR(type, creator)                                  \static LayerRegisterer<float> g_creator_f_##type(#type, creator<float>);     \static LayerRegisterer<double> g_creator_d_##type(#type, creator<double>)    \

#define REGISTER_LAYER_CLASS(type)                                             \template <typename Dtype>                                                    \shared_ptr<Layer<Dtype> > Creator_##type##Layer(const LayerParameter& param) \{                                                                            \return shared_ptr<Layer<Dtype> >(new type##Layer<Dtype>(param));           \}                                                                            \REGISTER_LAYER_CREATOR(type, Creator_##type##Layer)#define INSTANTIATE_CLASS(classname) \char gInstantiationGuard##classname; \template class classname<float>; \template class classname<double>
6.2 宏使用例子

以 DataLayer 为例
源码:

 INSTANTIATE_CLASS(DataLayer);REGISTER_LAYER_CLASS(Data);

展开:

 char gInstantiationGuardDataLayer; \template class DataLayer<float>; \template class DataLayer<double>template <typename Dtype>                                                   shared_ptr<Layer<Dtype> > Creator_DataLayer(const LayerParameter& param) {                                                                            return shared_ptr<Layer<Dtype> >(new DataLayer<Dtype>(param));           }     // 创建LayerRegisterer<float>静态实例g_creator_f_Data,构造函数的参数:"Data", Creator_DataLayer<float>static LayerRegisterer<float> g_creator_f_Data("Data", Creator_DataLayer<float>);  static LayerRegisterer<double> g_creator_d_Data("Data", Creator_DataLayer<double>)
6.3 LayerRegisterer 类,实现上面用的构造函数
   template <typename Dtype>class LayerRegisterer {public:LayerRegisterer(const string& type, shared_ptr<Layer<Dtype> > (*creator)(const LayerParameter&)) {LayerRegistry<Dtype>::AddCreator(type, creator);}};
6.4 LayerRegistry::AddCreator(type, creator);的实现
  static void AddCreator(const string& type, Creator creator) {CreatorRegistry& registry = Registry();CHECK_EQ(registry.count(type), 0) << "Layer type " << type << " already registered.";registry[type] = creator;}
6.5 静态函数 Registry() 实现单例模式,返回静态全局 g_registry_
  static CreatorRegistry& Registry() {static CreatorRegistry* g_registry_ = new CreatorRegistry();return *g_registry_;}
6.6 CreatorRegistry的定义
  typedef shared_ptr<Layer<Dtype> > (*Creator)(const LayerParameter&);typedef std::map<string, Creator> CreatorRegistry;
6.7 registry[type] = creator; 说明

registry 的类型是 CreatorRegistry --> typedef std::map<string, Creator> CreatorRegistry;
是一个std::map类型,而std::map类型对“[]”运算符重载了:创建键值对 type --> creator
至此成功注册了 DataLayer 类到 g_registry_ 中。

6.8 何时创建 DataLayer,在 LayerRegistry::CreateLayer 函数中
  static shared_ptr<Layer<Dtype> > CreateLayer(const LayerParameter& param) {if (Caffe::root_solver()) {LOG(INFO) << "Creating layer " << param.name();}const string& type = param.type();CreatorRegistry& registry = Registry();CHECK_EQ(registry.count(type), 1) << "Unknown layer type: " << type << " (known types: " << LayerTypeListString() << ")";return registry[type](param);}

根据 LayerParameter 中的 type 字段(这里是Data)找到,上面注册的 Creator_DataLayer 函数并执行,使用参数 param,创建 DataLayer

6.9 何时调用 LayerRegistry::CreateLayer

在 Net 的构造函数中调用 Init(const NetParameter& param) 时,循环调用了 LayerRegistry::CreateLayer layers_.push_back(LayerRegistry::CreateLayer(layer_param));
如果 layer_param 参数 type() = “Data”,则会创建 DataLayer 层

6.10 layer_param 从 param 中来,param从哪来的

train() 中 caffe::ReadSolverParamsFromTextFileOrDie(FLAGS_solver, &solver_param); 将*solver.prototxt 读取到求解器参数 caffe::SolverParameter solver_param 中,
然后调用 SolverRegistry::CreateSolver(solver_param),使用求解器参数 solver_param 创建求解器 Solver
在求解器 Solver 构造函数中调用 Init(param); --> InitTrainNet();
在 InitTrainNet() 中 将 SolverParameter::net
指定的 *train_test.prototxt 文件读取到网络参数 NetParameter net_param 中:ReadNetParamsFromTextFileOrDie(param.net(), &net_param);

然后使用网络参数 net_param 创建网络:net_.reset(new Net(net_param));

7、 读取 *_solver.prototxt 和 *_train_test.prototxt :
7.1 ReadSolverParamsFromTextFileOrDie
void ReadSolverParamsFromTextFileOrDie(const string& param_file, SolverParameter* param) {CHECK(ReadProtoFromTextFile(param_file, param)) << "Failed to parse SolverParameter file: " << param_file;UpgradeSolverAsNeeded(param_file, param);UpgradeSnapshotPrefixProperty(param_file, param);
}

其中 ReadProtoFromTextFile的源码如下

bool ReadProtoFromTextFile(const char* filename, Message* proto) {int fd = open(filename, O_RDONLY);CHECK_NE(fd, -1) << "File not found: " << filename;FileInputStream* input = new FileInputStream(fd);bool success = google::protobuf::TextFormat::Parse(input, proto);delete input;close(fd);return success;
}
7.2 ReadNetParamsFromTextFileOrDie
void ReadNetParamsFromTextFileOrDie(const string& param_file, NetParameter* param) {CHECK(ReadProtoFromTextFile(param_file, param)) << "Failed to parse NetParameter file: " << param_file;UpgradeNetAsNeeded(param_file, param);
}
8、 序列化 *.caffemodel

以 void Solver::Snapshot(); 中序列化为例

8.1 Snapshot 序列化
template <typename Dtype>
void Solver<Dtype>::Snapshot() { // 检查当前是否是root_solver(多GPU模式下,只有root_solver才运行这一部分的代码)CHECK(Caffe::root_solver());// 根据 solver.prototxt 文件中 snapshot_format 字段(默认值是 BINARYPROTO),将proto序列化为二进制格式或者HDF5格式string model_filename;switch (param_.snapshot_format()) {case caffe::SolverParameter_SnapshotFormat_BINARYPROTO:model_filename = SnapshotToBinaryProto();break;case caffe::SolverParameter_SnapshotFormat_HDF5:model_filename = SnapshotToHDF5();break;default:LOG(FATAL) << "Unsupported snapshot format.";}SnapshotSolverState(model_filename);
}
8.2 以序列化为二进制格式为例 SnapshotToBinaryProto
template <typename Dtype>
string Solver<Dtype>::SnapshotToBinaryProto() {string model_filename = SnapshotFilename(".caffemodel");    // 生成文件名LOG(INFO) << "Snapshotting to binary proto file " << model_filename;NetParameter net_param;net_->ToProto(&net_param, param_.snapshot_diff());  // 递归获取网络参数WriteProtoToBinaryFile(net_param, model_filename);   // 将网络参数序列化到二进制文件中return model_filename;
}void WriteProtoToBinaryFile(const Message& proto, const char* filename) {fstream output(filename, ios::out | ios::trunc | ios::binary);CHECK(proto.SerializeToOstream(&output));   // 原型bool Message::SerializeToOstream(ostream* output) const; // 将 Message 序列化到c++标准输出流中,必须设置所有必需字段。
}
8.3 序列化函数汇总
  bool SerializeToFileDescriptor(int file_descriptor) const;     // 将 Message 序列化到文件描述符中,必须设置所有必需字段。bool SerializePartialToFileDescriptor(int file_descriptor) const; // 同上,但是允许缺少必需的字段。bool SerializeToOstream(ostream* output) const;            // 将 Message 序列化到c++标准输出流中,必须设置所有必需字段。bool SerializePartialToOstream(ostream* output) const;   // 同上,但是允许缺少必需的字段。
9、 反序列化 *.caffemodel

以void Solver::Restore(const char* resume_file); 反序列化为例

9.1 Restore反序列化
template <typename Dtype>
void Solver<Dtype>::Restore(const char* state_file) {string state_filename(state_file);if (state_filename.size() >= 3 && state_filename.compare(state_filename.size() - 3, 3, ".h5") == 0) {RestoreSolverStateFromHDF5(state_filename);} else {RestoreSolverStateFromBinaryProto(state_filename);}
}
9.2 以反序列化二进制文件为例 RestoreSolverStateFromBinaryProto
emplate <typename Dtype>
void SGDSolver<Dtype>::RestoreSolverStateFromBinaryProto(const string& state_file) {SolverState state;ReadProtoFromBinaryFile(state_file, &state);this->iter_ = state.iter();if (state.has_learned_net()) {NetParameter net_param;ReadNetParamsFromBinaryFileOrDie(state.learned_net().c_str(), &net_param);this->net_->CopyTrainedLayersFrom(net_param);}this->current_step_ = state.current_step();CHECK_EQ(state.history_size(), history_.size()) << "Incorrect length of history blobs.";LOG(INFO) << "SGDSolver: restoring history";for (int i = 0; i < history_.size(); ++i) {history_[i]->FromProto(state.history(i));}
}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);    // 原型 bool ParseFromCodedStream(io::CodedInputStream* input);delete coded_input;delete raw_input;close(fd);return success;
}
9.3 其它反序列化函数
  bool ParsePartialFromCodedStream(io::CodedInputStream* input); // 同 ParseFromCodedStream ,但是接受缺少必需字段的消息。bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);       // 从 io::ZeroCopyInputStream 流中获取bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input); // 同上,但是接受缺少必需字段的消息。bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size); // 同上,指定 message 大小必须是 sizebool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, , int size); // 同上,但是接受缺少必需字段的消息。

【AI】caffe源码分析(一)相关推荐

  1. caffe源码分析--SyncedMemory 内存管理机制

    caffe源码分析–SyncedMemory 内存管理机制 ​ SyncedMemory 是caffe中用来管理内存分配和CPU.GPU数据及同步的类,只服务于Blob类.SyncedMemory 对 ...

  2. caffe源码分析-layer

    本文主要分析caffe layer层,主要内容如下: 从整体上说明下caffe的layer层的类别,以及作用 通过proto定义与类Layer简要说明下Layer的核心成员变量; Layer类的核心成 ...

  3. caffe源码分析:layer.hpp分析

    文件路径:caffe-master_github/include/caffe/ Backward函数: template <typename Dtype> inline void Laye ...

  4. caffe 源码分析:Euclidean loss layer

    最近做项目需要修改Euclidean loss函数,所以就先分析了一下Euclidean loss layer的代码 以gpu版本的为例: 一. 前向函数 template <typename ...

  5. caffe源码分析:softmax_layer.cpp softmax_loss_layer.cpp

    本文仅分析了softmax_layer.cpp 和 softmax_loss_layer.cpp两个文件中的forward函数,backward函数有待补充. 1.softmax_layer.cpp ...

  6. caffe源码分析:blob.hpp分析

    文件路径:caffe-master_github/include/caffe/ 如果想对blob有详细了解,参考Caffe官网教程:http://caffe.berkeleyvision.org/tu ...

  7. Caffe源码中common文件分析

    Caffe源码(caffe version:09868ac , date: 2015.08.15)中的一些重要头文件如caffe.hpp.blob.hpp等或者外部调用Caffe库使用时,一般都会in ...

  8. caffe.proto源码分析

    一什么是protocol buffer 二caffeproto中的几个重要数据类型 三caffeproto源码 分析caffe源码,看首先看caffe.proto,是明智的选择.好吧,我不是创造者,只 ...

  9. UnityStandardAsset工程、源码分析_5_赛车游戏[AI控制]_AI机制

    上一章地址: UnityStandardAsset工程.源码分析_4_赛车游戏[玩家控制]_摄像机控制 前几章我们已经将赛车游戏的绝大多数机制分析过了,而Unity还提供了不同的操控模式--AI控制. ...

最新文章

  1. 规则引擎 drools_为什么要用规则引擎?
  2. 进阶学习(3.13) Proxy Pattern 代理模式
  3. file类打印目录---树状结构,递归
  4. 20170824图论选讲部分习题
  5. 多线程 调用 axis 报错_java笔记录(三、多线程)
  6. IP: 169.254.0.0/16 地址用途
  7. Report_SRW在RDF中初始化的重要性(案例)
  8. 「leetcode」37. 解数独【回溯算法】详细图解!
  9. pythonturtle是标准库_Python常用标准库1-Turtle,Random,Time和Datetime
  10. Java加密总结:常见哈希算法总结、对称式加密与非对称式加密的对比
  11. 买个社区团购小程序多少钱呢?微信社区团购小程序怎么做
  12. 特征筛选:WOE值与IV值
  13. C语言实现一个矩阵乘法计算器
  14. K8S 探针 readinessProbe、livenessProbe和startupProbe
  15. java的高精度大数字运算的问题
  16. 大数据早报:阿里巴巴收购以色列创业公司 迅雷再次回应玩客云用户维权事件(12.1)
  17. 使用微信企业机器人发送信息
  18. 电容笔有什么用?适合iPad画画的电容笔推荐
  19. 淘宝抽奖html 页面,基于jQuery实现的双11天猫拆红包抽奖效果
  20. wps字体缺失,问题

热门文章

  1. wpf 多线程处理同步数据_一文带你理解多线程的实际意义和优势
  2. VS生成dll和lib库文件
  3. 【sgTopo】强哥古法炮制、纯手工打造简单拓扑图、流程图、思维导图组件(完善中ing)
  4. centos 6.8 x86_64下autoconf版本升级到2.69
  5. ATS日志格式中的Squid-和Netscape-格式的缓存结果码
  6. Unity粒子系统创建VFX游戏特效学习教程 Visual Effects in Unity Particle Systems [Beginner’s Guide]
  7. Go 语言实现字符串匹配算法 -- BF(Brute Force) 和 RK(Rabin Karp)
  8. r-rpm常用命令集
  9. 快速排序的实现与注意点
  10. 汇编试验十五:安装新的int 9中断例程