caffe 通过工厂模式----先父类构造然后子类构造的原则,进行solver.cpp的构造函数初始化;
Solver<Dtype>::Solver(const SolverParameter& param)
: net_(), callbacks_(), requested_early_exit_(false) {
Init(param);
}
在构造函数中,进行网络初始化;
template <typename Dtype>
void Solver<Dtype>::Init(const SolverParameter& param) {
CHECK(Caffe::root_solver() || root_solver_)
<< "root_solver_ needs to be set for all non-root solvers";
LOG_IF(INFO, Caffe::root_solver()) << "Initializing solver from parameters: "
<< std::endl << param.DebugString();
param_ = param;
CHECK_GE(param_.average_loss(), 1) << "average_loss should be non-negative.";
CheckSnapshotWritePermissions();
if (Caffe::root_solver() && param_.random_seed() >= 0) {
Caffe::set_random_seed(param_.random_seed());
}
// Scaffolding code
InitTrainNet();
if (Caffe::root_solver()) {
InitTestNets();
LOG(INFO) << "Solver scaffolding done.";
}
iter_ = 0;
current_step_ = 0;
}
在void Solver<Dtype>::Init(const SolverParameter& param)函数中首先打印了lenet_solver.prototxt信息(主要通过protobuf自带的函数param.DebugString()),输出了调试信息
test_iter: 100
test_interval: 500
base_lr: 0.01
display: 100
max_iter: 10000
lr_policy: "inv"
gamma: 0.0001
power: 0.75
momentum: 0.9
weight_decay: 0.0005
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet"
solver_mode: GPU
device_id: 0
net: "examples/mnist/lenet_train_test.prototxt"
train_state {
level: 0
stage: ""
}
其实protobuf 中的调试信息函数应该为:param.ShortDebugString(); 但是该函数将结果进行换行,手册查询的;
test_iter: 100 test_interval: 500 base_lr: 0.01 display: 100 max_iter: 10000 lr_policy: "inv" gamma: 0.0001 power: 0.75 momentum: 0.9 weight_decay: 0.0005 snapshot: 5000 snapshot_prefix: "examples/mnist/lenet" solver_mode: GPU device_id: 0 net: "examples/mnist/lenet_train_test.prototxt" train_state { level: 0 stage: "" }
调试信息完成之后,然后进行网络展开解析
// Scaffolding code
InitTrainNet();
在函数void Solver<Dtype>::InitTrainNet() 中,首先对网络构建之前,进行一些参数初始化;
NetState net_state;
net_state.set_phase(TRAIN);
net_state.MergeFrom(net_param.state());
net_state.MergeFrom(param_.train_state());
net_param.mutable_state()->CopyFrom(net_state);
然后在new了一个网络对象,通过net.cpp文件进行net构造函数的初始化,这个过程就是对Net路径的网络进行解析即:
net_.reset(new Net<Dtype>(net_param));
net: "examples/mnist/lenet_train_test.prototxt"
在net.cpp文件中,执行了net的构造函数,进行初始化;
void Net<Dtype>::Init(const NetParameter& in_param)
通过gdb调试可以查看网络的名字(name: "LeNet"),层次(11)等;
phase_ = in_param.state().phase();
然后进行整个网络层次的规则检查,主要看存在的include/exclude是否满足条件;可以参考博客:https://yangwenbo.com/articles/caffe-net-config-all-in-one.html?utm_source=tuicool&utm_medium=referral
FilterNet(in_param, &filtered_param);
然后进行网络层次搭建,作者是把整个网络架构存放在map中;例如以mnist为例~~
name: "LeNet"
layer {
name: "mnist"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
}
data_param {
source: "examples/mnist/mnist_train_lmdb"
batch_size: 64
backend: LMDB
}
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
然后代码进行解析
void InsertSplits(const NetParameter& param, NetParameter* param_split) {
// Initialize by copying from the input NetParameter.
param_split->CopyFrom(param);
param_split->clear_layer();
map<string, pair<int, int> > blob_name_to_last_top_idx;
/*
第一层的mnist 中的top-name 及其位置定义转存blob-name
data 0 0
label 0 0
*/
map<pair<int, int>, pair<int, int> > bottom_idx_to_source_top_idx;
/*
第二层的conv1 中的 bottom-name 及其位置定义 转存在blob-name
此处为 data 位置为[1,0]
而连接为 mnist top-name (data)转存的blob 的位置 连接上 conv1 bottom-name (data)
[1,0] = 0 1
*/
map<pair<int, int>, int> top_idx_to_bottom_count;
map<pair<int, int>, float> top_idx_to_loss_weight;
map<pair<int, int>, int> top_idx_to_bottom_split_idx;
map<int, string> layer_idx_to_layer_name;
/*
存储的每一个层次的名字
0 layer_name mnist
1 layer_name conv1
. ................
*/
for (int i = 0; i < param.layer_size(); ++i) {
const LayerParameter& layer_param = param.layer(i);
layer_idx_to_layer_name[i] = layer_param.name();
cout<<"layer_idx_to_layer_name="<<layer_param.name()<<endl;
cout<<"layer_param.bottom_size="<<layer_param.bottom_size()<<endl;
for (int j = 0; j < layer_param.bottom_size(); ++j) {
const string& blob_name = layer_param.bottom(j);
cout<<"blob_name="<<blob_name<<endl;
if (blob_name_to_last_top_idx.find(blob_name) ==
blob_name_to_last_top_idx.end()) {
LOG(FATAL) << "Unknown bottom blob '" << blob_name << "' (layer '"
<< layer_param.name() << "', bottom index " << j << ")";
}
const pair<int, int>& bottom_idx = make_pair(i, j);
const pair<int, int>& top_idx = blob_name_to_last_top_idx[blob_name];
bottom_idx_to_source_top_idx[bottom_idx] = top_idx;
++top_idx_to_bottom_count[top_idx];
}
for (int j = 0; j < layer_param.top_size(); ++j) {
const string& blob_name = layer_param.top(j);
cout<<"blob_name="<<blob_name<<endl;
/*
blob_name 为caffe 存储的数据结构 记录了数据名称(top bottom )的坐标
0 0
0 1
*/
blob_name_to_last_top_idx[blob_name] = make_pair(i, j);
}
.......................
完待续。。。。