class Layer {
public:
/**
* You should not implement your own constructor. Any set up code should go
* to SetUp(), where the dimensions of the bottom blobs are provided to the
* layer.
*/
explicit Layer(const LayerParameter& param)
: layer_param_(param) {
// Set phase and copy blobs (if there are any).
phase_ = param.phase();
// If the prototxt file has been set up blobs parameter,blobs parameters is used to initialize,
// otherwise, the LayerSetUp() is used to initialized.Here, blobs_ is used to save weight and bias
if (layer_param_.blobs_size() > 0) {
blobs_.resize(layer_param_.blobs_size());
for (int i = 0; i < layer_param_.blobs_size(); ++i) {
blobs_[i].reset(new Blob<Dtype>());
// read the blobs value in the prototxt file ,and to initialize the blobs_,
// which is saved weight and bias
<span style="color:#ff0000;"> blobs_[i]->FromProto(layer_param_.blobs(i));// 这句话改怎么理解,从哪里来</span>
}
}
}
: layer_param_(param) {
// Set phase and copy blobs (if there are any).
phase_ = param.phase();
if (layer_param_.blobs_size() > 0) {
blobs_.resize(layer_param_.blobs_size());
for (int i = 0; i < layer_param_.blobs_size(); ++i) {
blobs_[i].reset(new Blob<Dtype>());
blobs_[i]->FromProto(layer_param_.blobs(i));
}
}
}
repeated float diff = 6 [packed = true]; repeated表示可以重复设置。 根据设置大小
即,如果配置文件,哪一层不去配置这个,那么基类初始化构造函数则不去设置 blobs(i)。而是在具体类的实现中设置
LOG(INFO) << "Skipping parameter initialization";
} else { // 如果配置文件没有配置。 即基类构造没有初始化。所有这里需要初始化。
if (bias_term_) {
this->blobs_.resize(2);
} else {
this->blobs_.resize(1);
}
LOG(INFO) << "Skipping parameter initialization";
} else {
if (bias_term_) {
this->blobs_.resize(2);
} else {
this->blobs_.resize(1);
}
---------------------------------------------------------------------------------------------------------------------------------------------
下面是个人理解,不对地方还请您指点
(1) void Blob<Dtype>::FromProto(const BlobProto& proto, bool reshape) {
........
Dtype* data_vec = mutable_cpu_data();
for (int i = 0; i < count_; ++i) {
data_vec[i] = proto.data(i);
}
if (proto.diff_size() > 0) {
Dtype* diff_vec = mutable_cpu_diff();
for (int i = 0; i < count_; ++i) {
diff_vec[i] = proto.diff(i);
}
}
.......
}
函数中,proto.data(i)和proto.diff(i);是通过BlobProto& proto 参数传入的。
(2) 传参函数在net.cpp的Forward()函数中
string Net<Dtype>::Forward(const string& input_blob_protos, Dtype* loss) {
BlobProtoVector blob_proto_vec;
if (net_input_blobs_.size()) {
blob_proto_vec.ParseFromString(input_blob_protos);
CHECK_EQ(blob_proto_vec.blobs_size(), net_input_blobs_.size())
<< "Incorrect input size.";
for (int i = 0; i < blob_proto_vec.blobs_size(); ++i) {
net_input_blobs_[i]->FromProto(blob_proto_vec.blobs(i));
}
}
(3) 通过solver.cpp 中
void Solver<Dtype>::Test(const int test_net_id) {
CHECK_NOTNULL(test_nets_[test_net_id].get())->
ShareTrainedLayersWith(net_.get());
vector<Dtype> test_score;
vector<int> test_score_output_id;
vector<Blob<Dtype>*> bottom_vec;
const shared_ptr<Net<Dtype> >& test_net = test_nets_[test_net_id];
Dtype loss = 0;
for (int i = 0; i < param_.test_iter(test_net_id); ++i) {
Dtype iter_loss;
const vector<Blob<Dtype>*>& result =
test_net->Forward(bottom_vec, &iter_loss);
}
..........
}
所以 每一层的data和diff 是从下一层 的blobs 传入,进行设置data和diff。现在对net类和solver类 还有些不明白, 可能理解不好。
不对地方还请您指点。
每一层的data和diff 是从下一层 的blobs 传入
-------------------------------------------
explicit Layer(const LayerParameter& param)
: layer_param_(param) {
// Set phase and copy blobs (if there are any).
phase_ = param.phase();
if (layer_param_.blobs_size() > 0) {
blobs_.resize(layer_param_.blobs_size());
for (int i = 0; i < layer_param_.blobs_size(); ++i) {
blobs_[i].reset(new Blob<Dtype>());
blobs_[i]->FromProto(layer_param_.blobs(i));
}
}
}
这个函数里面,blobs_[i]表示的是可学习参数,其实就是weight和bias.
由下面一句可知,blobs_[i]是从layer_param_.blobs(i)传入的:
blobs_[i]->FromProto(layer_param_.blobs(i));
我的问题是:layer_param_.blobs(i)中的data和diff是哪儿来的?
每一层的input的data和
----------------------------------------------------------------------------------------------------------------blobs_[i]->FromProto(layer_param_.blobs(i)); 分析
一、BlobShape 在proto中定义:四个属性(num,channels,height,width)为optional类型,是可供选择的, 这个需要自己在配置文件中设置,
二、 而 data和diff数据,定义为 repeated float data = 5 [packed = true];repeated类型。因为每一层都需要这两个数据。所以定义为repeated 类型, 即在配置每一层之后,网络就自动设置data和diff数据。
至于如何网络如何读取的,从proto定义可以看出,
即,比如data层, 输入过程 : SolverParameter <----NetParameter <--LayerParameter(BlobProto 和DataParameter)
所以创建data层的时候,不需要设置data和diff, 但是num,channels,height,width这几个是optional 类型,需要设置。
message SolverParameter {
optional NetParameter net_param = 25;
}
message NetParameter {
repeated LayerParameter layer = 100; // ID 100 so layers are printed last.
}
message LayerParameter {
repeated BlobProto blobs = 7;
optional DataParameter data_param = 107;
}
三、从代码角度看
从代码里同样可以看出
代码中的数据流, 比如:layer(如具体类:datalayer)----> net.cpp ----->solver.cpp ,建立整个网络。
(1)solver.cpp
if (param_.has_net_param()) {
LOG(INFO) << "Creating training net specified in net_param.";
net_param.CopyFrom(param_.net_param());
}
(2)net.cpp init()函数中
for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) {
// Inherit phase from net if unset.
.....
layers_.push_back(LayerRegistry<Dtype>::CreateLayer(layer_param)); //获取每层param,
layer_names_.push_back(layer_param.name());
...
}
(3) 在 layer.hpp 中调用 blob.cpp FromProto()函数读取(FromProto函数分析 在上个邮件)
void Blob<Dtype>::FromProto(const BlobProto& proto, bool reshape) {
........
Dtype* data_vec = mutable_cpu_data();
for (int i = 0; i < count_; ++i) {
data_vec[i] = proto.data(i);
}
if (proto.diff_size() > 0) {
Dtype* diff_vec = mutable_cpu_diff();
for (int i = 0; i < count_; ++i) {
diff_vec[i] = proto.diff(i);
}
}
.......
}
总之,从上边分析可以得到: 为什么参数data和diff不需要设置, 还有参数如何读入网络过程。