net.cpp部分源码

// 接着上一篇博客的介绍,此部分为Net类中前向反向计算函数,以及一些与HDF5文件或proto文件相互转换的函数。

template <typename Dtype>
Dtype Net<Dtype>::ForwardFromTo(int start, int end) { //执行第start层到第end层的前向计算过程
CHECK_GE(start, 0); //检查start >= 0, end < 总层数
CHECK_LT(end, layers_.size());
Dtype loss = 0; //存储每层前向计算的loss之和
for (int i = start; i <= end; ++i) {
for (int c = 0; c < before_forward_.size(); ++c) {
before_forward_[c]->run(i); //在调用前向计算之前调用的回调函数
}
Dtype layer_loss = layers_[i]->Forward(bottom_vecs_[i], top_vecs_[i]); //调用Layer类的前向计算函数,返回计算出的loss
loss += layer_loss; //累加
if (debug_info_) { ForwardDebugInfo(i); } //允许打印调试信息,则打印输出blob和参数blob的数据的均值信息
for (int c = 0; c < after_forward_.size(); ++c) {
after_forward_[c]->run(i); //同样,在调用前向计算之后调用的回调函数
}
}
return loss;
} template <typename Dtype>
Dtype Net<Dtype>::ForwardFrom(int start) { //执行第start层到末尾层的前向计算过程
return ForwardFromTo(start, layers_.size() - 1);
} template <typename Dtype>
Dtype Net<Dtype>::ForwardTo(int end) { //执行起始层到第end层的前向计算过程
return ForwardFromTo(0, end);
} template <typename Dtype>
const vector<Blob<Dtype>*>& Net<Dtype>::Forward(Dtype* loss) { //执行网络的所有层的前向计算过程
if (loss != NULL) {
*loss = ForwardFromTo(0, layers_.size() - 1); //返回的loss保存起来
} else {
ForwardFromTo(0, layers_.size() - 1);
}
return net_output_blobs_; //输出网络的输出blob数据
} template <typename Dtype>
const vector<Blob<Dtype>*>& Net<Dtype>::Forward(
const vector<Blob<Dtype>*> & bottom, Dtype* loss) { //旧版本函数,将bottom当作网络的输入,执行整个网络的前向计算过程
LOG_EVERY_N(WARNING, 1000) << "DEPRECATED: Forward(bottom, loss) "
<< "will be removed in a future version. Use Forward(loss).";
// Copy bottom to net bottoms
for (int i = 0; i < bottom.size(); ++i) {
net_input_blobs_[i]->CopyFrom(*bottom[i]); //bottom中的数据拷贝至网络的输入blob中
}
return Forward(loss); //前向计算
} template <typename Dtype>
void Net<Dtype>::BackwardFromTo(int start, int end) { //执行第start层到第end层的反向计算过程
CHECK_GE(end, 0);
CHECK_LT(start, layers_.size()); //检查输入参数,从后往前,start不超过末尾层,end不小于起始层
for (int i = start; i >= end; --i) {
for (int c = 0; c < before_backward_.size(); ++c) {
before_backward_[c]->run(i); //反向计算之前调用的回调函数
}
if (layer_need_backward_[i]) { //当前层是否需要反向计算
layers_[i]->Backward(top_vecs_[i], bottom_need_backward_[i], bottom_vecs_[i]); //反向计算
if (debug_info_) { BackwardDebugInfo(i); } //打印调试信息
}
for (int c = 0; c < after_backward_.size(); ++c) {
after_backward_[c]->run(i); //反向计算之后调用的回调函数
}
}
} template <typename Dtype>
void Net<Dtype>::ForwardDebugInfo(const int layer_id) { //打印第layer_id层的前向计算结果的调试信息
for (int top_id = 0; top_id < top_vecs_[layer_id].size(); ++top_id) {
const Blob<Dtype>& blob = *top_vecs_[layer_id][top_id]; //第layer_id层的第top_id个输出blob
const string& blob_name = blob_names_[top_id_vecs_[layer_id][top_id]]; //该blob对应的名称
const Dtype data_abs_val_mean = blob.asum_data() / blob.count(); //计算blob中data_的绝对值之和的均值
LOG_IF(INFO, Caffe::root_solver())
<< " [Forward] "
<< "Layer " << layer_names_[layer_id]
<< ", top blob " << blob_name
<< " data: " << data_abs_val_mean; //打印信息
}
for (int param_id = 0; param_id < layers_[layer_id]->blobs().size(); ++param_id) {
const Blob<Dtype>& blob = *layers_[layer_id]->blobs()[param_id]; //第layer_id层的第param_id个参数blob
const int net_param_id = param_id_vecs_[layer_id][param_id]; //该参数blob在params_中索引
const string& blob_name = param_display_names_[net_param_id]; //由索引得到参数blob的名称
const Dtype data_abs_val_mean = blob.asum_data() / blob.count(); //参数blob的data_的绝对值之和的均值
LOG_IF(INFO, Caffe::root_solver())
<< " [Forward] "
<< "Layer " << layer_names_[layer_id]
<< ", param blob " << blob_name
<< " data: " << data_abs_val_mean; //打印均值信息
}
} template <typename Dtype>
void Net<Dtype>::BackwardDebugInfo(const int layer_id) { //打印第layer_id层的反向计算结果的调试信息
const vector<Blob<Dtype>*>& bottom_vec = bottom_vecs_[layer_id];
for (int bottom_id = 0; bottom_id < bottom_vec.size(); ++bottom_id) { //第layer_id层的第bottom_id个输入blob
if (!bottom_need_backward_[layer_id][bottom_id]) { continue; } //不处理不需要反传的输入
const Blob<Dtype>& blob = *bottom_vec[bottom_id]; //输入blob数据
const string& blob_name = blob_names_[bottom_id_vecs_[layer_id][bottom_id]]; //输入blob名称
const Dtype diff_abs_val_mean = blob.asum_diff() / blob.count(); //输入blob的diff_的绝对值之和的均值
LOG_IF(INFO, Caffe::root_solver())
<< " [Backward] "
<< "Layer " << layer_names_[layer_id]
<< ", bottom blob " << blob_name
<< " diff: " << diff_abs_val_mean; //打印
}
for (int param_id = 0; param_id < layers_[layer_id]->blobs().size(); ++param_id) {
if (!layers_[layer_id]->param_propagate_down(param_id)) { continue; } //略过无需反传的
const Blob<Dtype>& blob = *layers_[layer_id]->blobs()[param_id]; //第layer_id层的第param_id个参数blob
const Dtype diff_abs_val_mean = blob.asum_diff() / blob.count(); //参数blob的diff_的绝对值之和的均值
LOG_IF(INFO, Caffe::root_solver())
<< " [Backward] "
<< "Layer " << layer_names_[layer_id]
<< ", param blob " << param_id
<< " diff: " << diff_abs_val_mean; //打印
}
} template <typename Dtype>
void Net<Dtype>::UpdateDebugInfo(const int param_id) { //打印net中第param_id个参数的一些信息
const Blob<Dtype>& blob = *params_[param_id]; //net中第param_id个参数blob
const int param_owner = param_owners_[param_id]; //net中第param_id个参数的来源的索引(源参数的索引)
const string& layer_name = layer_names_[param_layer_indices_[param_id].first]; //第param_id个参数所在层的名称
const string& param_display_name = param_display_names_[param_id]; //该参数的名称
const Dtype diff_abs_val_mean = blob.asum_diff() / blob.count(); //该参数的diff_的绝对值之和的均值
if (param_owner < 0) { //param_owner为-1表示该参数为源参数
const Dtype data_abs_val_mean = blob.asum_data() / blob.count(); //计算data_的绝对值之和的均值
LOG_IF(INFO, Caffe::root_solver())
<< " [Update] Layer " << layer_name
<< ", param " << param_display_name
<< " data: " << data_abs_val_mean
<< "; diff: " << diff_abs_val_mean; //打印
} else { //该参数为共享参数
const string& owner_layer_name =
layer_names_[param_layer_indices_[param_owner].first]; //该共享参数对应的源参数的名称
LOG_IF(INFO, Caffe::root_solver())
<< " [Update] Layer " << layer_name
<< ", param blob " << param_display_name
<< " (owned by layer " << owner_layer_name << ", " << "param "
<< param_display_names_[param_owners_[param_id]] << ")"
<< " diff: " << diff_abs_val_mean; //打印
}
} //将other网络的layer的参数blob数据共享给当前网络中的相同名称的layer(只修改指针指向的位置,并不会复制数据)
template <typename Dtype>
void Net<Dtype>::ShareTrainedLayersWith(const Net* other) {
int num_source_layers = other->layers().size(); //来源网络的layer的个数
for (int i = 0; i < num_source_layers; ++i) {
Layer<Dtype>* source_layer = other->layers()[i].get(); //来源网络的第i个layer的指针
const string& source_layer_name = other->layer_names()[i]; //来源网络第i个layer的名称
int target_layer_id = 0;
while (target_layer_id != layer_names_.size() &&
layer_names_[target_layer_id] != source_layer_name) { //在当前网络中寻找与来源网络第i个layer名称相同的layer
++target_layer_id;
}
if (target_layer_id == layer_names_.size()) { //未找到名称相同的,该layer的参数不进行共享
LOG(INFO) << "Ignoring source layer " << source_layer_name;
continue;
}
//当前网络中第target_layer_id个layer与other网络的第i个layer的名称相同,开始共享参数
DLOG(INFO) << "Copying source layer " << source_layer_name;
vector<shared_ptr<Blob<Dtype> > >& target_blobs = layers_[target_layer_id]->blobs(); //当前层的blob数据
CHECK_EQ(target_blobs.size(), source_layer->blobs().size())
<< "Incompatible number of blobs for layer " << source_layer_name; //检查两个layer的参数blob是否相等
for (int j = 0; j < target_blobs.size(); ++j) {
Blob<Dtype>* source_blob = source_layer->blobs()[j].get(); //other的第i层的第j个参数blob
CHECK(target_blobs[j]->shape() == source_blob->shape())
<< "Cannot share param " << j << " weights from layer '"
<< source_layer_name << "'; shape mismatch. Source param shape is "
<< source_blob->shape_string() << "; target param shape is "
<< target_blobs[j]->shape_string(); //检查两个参数blob的形状是否相同
target_blobs[j]->ShareData(*source_blob); //共享数据,将target_blobs[j]的data_的数据指针指向source_blob中的data_
}
}
} template <typename Dtype>
void Net<Dtype>::BackwardFrom(int start) { //执行第start层到起始层的反向计算过程
BackwardFromTo(start, 0);
} template <typename Dtype>
void Net<Dtype>::BackwardTo(int end) { //执行末尾层到第end层的反向计算过程
BackwardFromTo(layers_.size() - 1, end);
} template <typename Dtype>
void Net<Dtype>::Backward() { //执行网络的所有层的反向计算过程
BackwardFromTo(layers_.size() - 1, 0); //整个网络
if (debug_info_) { //打印调试信息
Dtype asum_data = 0, asum_diff = 0, sumsq_data = 0, sumsq_diff = 0;
for (int i = 0; i < learnable_params_.size(); ++i) { //net中的所有可学习参数
asum_data += learnable_params_[i]->asum_data(); //参数blob的data_的绝对值之和
asum_diff += learnable_params_[i]->asum_diff(); //参数blob的diff_的绝对值之和
sumsq_data += learnable_params_[i]->sumsq_data(); //参数blob的data_的平方和
sumsq_diff += learnable_params_[i]->sumsq_diff(); //参数blob的diff_的平方和
}
const Dtype l2norm_data = std::sqrt(sumsq_data); //开方
const Dtype l2norm_diff = std::sqrt(sumsq_diff);
LOG(ERROR) << " [Backward] All net params (data, diff): "
<< "L1 norm = (" << asum_data << ", " << asum_diff << "); "
<< "L2 norm = (" << l2norm_data << ", " << l2norm_diff << ")"; //打印
}
} template <typename Dtype>
void Net<Dtype>::Reshape() { //调整网络中所有层的输入输出数据和参数数据等的形状
for (int i = 0; i < layers_.size(); ++i) {
layers_[i]->Reshape(bottom_vecs_[i], top_vecs_[i]); //调用各层各自的reshape函数
}
} //从param中拷贝同名的layer的参数blob数据(与ShareTrainedLayersWith不同,该函数是复制数据而不是修改数据指针的位置)
template <typename Dtype>
void Net<Dtype>::CopyTrainedLayersFrom(const NetParameter& param) {
int num_source_layers = param.layer_size(); //来源网络参数中layer的个数
for (int i = 0; i < num_source_layers; ++i) {
const LayerParameter& source_layer = param.layer(i); //来源的第i个layer对应的LayerParameter
const string& source_layer_name = source_layer.name(); //来源网络的layer的名称
int target_layer_id = 0;
while (target_layer_id != layer_names_.size() &&
layer_names_[target_layer_id] != source_layer_name) { //同样,在当前net中寻找与之名称相同的layer
++target_layer_id;
}
if (target_layer_id == layer_names_.size()) { //未找到,跳过该层
LOG(INFO) << "Ignoring source layer " << source_layer_name;
continue;
}
//当前net中第target_layer_id个layer与param的第i个对应
DLOG(INFO) << "Copying source layer " << source_layer_name;
vector<shared_ptr<Blob<Dtype> > >& target_blobs =
layers_[target_layer_id]->blobs(); //当前net中第target_layer_id个layer的参数blob
CHECK_EQ(target_blobs.size(), source_layer.blobs_size())
<< "Incompatible number of blobs for layer " << source_layer_name; //检查参数个数是否相等
for (int j = 0; j < target_blobs.size(); ++j) {
if (!target_blobs[j]->ShapeEquals(source_layer.blobs(j))) { //检查参数blob与param中的BlobProto消息的数据形状是否一致
Blob<Dtype> source_blob;
const bool kReshape = true;
//不一致,则将source_layer的BlobProto消息的数据拷贝至source_blob中,然后报错
source_blob.FromProto(source_layer.blobs(j), kReshape);
LOG(FATAL) << "Cannot copy param " << j << " weights from layer '"
<< source_layer_name << "'; shape mismatch. Source param shape is "
<< source_blob.shape_string() << "; target param shape is "
<< target_blobs[j]->shape_string() << ". "
<< "To learn this layer's parameters from scratch rather than "
<< "copying from a saved net, rename the layer."; //报错
}
const bool kReshape = false;
//将source_layer中第j个BlobProto消息数据拷贝至target_blobs[j]中
target_blobs[j]->FromProto(source_layer.blobs(j), kReshape);
}
}
} template <typename Dtype>
void Net<Dtype>::CopyTrainedLayersFrom(const string& trained_filename) { //从文件trained_filename中拷贝网络参数
if (H5Fis_hdf5(trained_filename.c_str())) { //判断文件是否未hdf5格式
CopyTrainedLayersFromHDF5(trained_filename); //从hdf5类型的文件中拷贝网络参数
} else {
CopyTrainedLayersFromBinaryProto(trained_filename); //从二进制的proto文件中读取网络的参数
}
} template <typename Dtype>
void Net<Dtype>::CopyTrainedLayersFromBinaryProto(const string& trained_filename) { //从二进制的proto文件中读取网络的参数
NetParameter param;
ReadNetParamsFromBinaryFileOrDie(trained_filename, &param); //从trained_filename文件中读取,存入param中
CopyTrainedLayersFrom(param); //将参数拷贝至当前网络中
} template <typename Dtype>
void Net<Dtype>::CopyTrainedLayersFromHDF5(const string& trained_filename) { //从hdf5类型的文件中拷贝网络参数
#ifdef USE_HDF5
hid_t file_hid = H5Fopen(trained_filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); //打开hdf5类型的文件
CHECK_GE(file_hid, 0) << "Couldn't open " << trained_filename; //检查是否打开
hid_t data_hid = H5Gopen2(file_hid, "data", H5P_DEFAULT); //打开file_hid中的"data"数据集
CHECK_GE(data_hid, 0) << "Error reading weights from " << trained_filename; //检查是否打开
int num_layers = hdf5_get_num_links(data_hid); //获取data_hid中links(元素?)的个数,此处即为layer的个数
for (int i = 0; i < num_layers; ++i) {
string source_layer_name = hdf5_get_name_by_idx(data_hid, i); //data_hid中第i个link的名称
if (!layer_names_index_.count(source_layer_name)) { //在当前net中寻找同名的layer
LOG(INFO) << "Ignoring source layer " << source_layer_name; //未找到,跳过
continue;
}
int target_layer_id = layer_names_index_[source_layer_name]; //得到该layer在当前网络中的索引
DLOG(INFO) << "Copying source layer " << source_layer_name;
vector<shared_ptr<Blob<Dtype> > >& target_blobs = layers_[target_layer_id]->blobs(); //当前网络中该layer的参数blob
hid_t layer_hid = H5Gopen2(data_hid,
source_layer_name.c_str(), H5P_DEFAULT); //打开data_hid中名为source_layer_name的数据集
CHECK_GE(layer_hid, 0) << "Error reading weights from " << trained_filename; //检查是否打开
// Check that source layer doesn't have more params than target layer
int num_source_params = hdf5_get_num_links(layer_hid); //返回layer_hid中links的个数,即为参数的个数
CHECK_LE(num_source_params, target_blobs.size())
<< "Incompatible number of blobs for layer " << source_layer_name; //检查是否与参数blob的个数相等
for (int j = 0; j < target_blobs.size(); ++j) { //拷贝每个参数blob
ostringstream oss;
oss << j;
string dataset_name = oss.str();
int target_net_param_id = param_id_vecs_[target_layer_id][j]; //第target_layer_id层第j个参数在params_中的索引
if (!H5Lexists(layer_hid, dataset_name.c_str(), H5P_DEFAULT)) { //layer_hid中是否存在名为dataset_name的数据集
// Target param doesn't exist in source weights...
if (param_owners_[target_net_param_id] != -1) { //hdf5文件中不存在该参数,但是该参数为共享参数,所以不影响
// ...but it's weight-shared in target, so that's fine.
continue;
} else {
LOG(FATAL) << "Incompatible number of blobs for layer "
<< source_layer_name; //源参数,但是在hdf5文件中不存在,报错
}
}
hdf5_load_nd_dataset(layer_hid, dataset_name.c_str(), 0, kMaxBlobAxes,
target_blobs[j].get()); //读取dataset_name数据集,检查其形状和数据类型,并存入target_blobs[j]的cpu data中
}
H5Gclose(layer_hid); //关闭
}
H5Gclose(data_hid);
H5Fclose(file_hid);
#else
LOG(FATAL) << "CopyTrainedLayersFromHDF5 requires hdf5;"
<< " compile with USE_HDF5.";
#endif // USE_HDF5
} //将当前net的所有LayerParameter拷贝至NetParameter类型的变量中
template <typename Dtype>
void Net<Dtype>::ToProto(NetParameter* param, bool write_diff) const {
param->Clear(); //先清空所有数据
param->set_name(name_); //当前net的名称存入param中
// Add bottom and top
DLOG(INFO) << "Serializing " << layers_.size() << " layers";
for (int i = 0; i < layers_.size(); ++i) { //处理每一层
LayerParameter* layer_param = param->add_layer(); //在param中添加新的LayerParameter消息,返回其指针
layers_[i]->ToProto(layer_param, write_diff); //将当前net中的layer数据拷贝至layer_param消息中
}
} //将当前net的所有LayerParameter写入到hdf5类型的filename文件中
template <typename Dtype>
void Net<Dtype>::ToHDF5(const string& filename, bool write_diff) const {
// This code is taken from https://github.com/sh1r0/caffe-android-lib
#ifdef USE_HDF5
hid_t file_hid = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); //创建hdf5文件
CHECK_GE(file_hid, 0) << "Couldn't open " << filename << " to save weights.";
hid_t data_hid = H5Gcreate2(file_hid, "data", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); //创建"data"数据集
CHECK_GE(data_hid, 0) << "Error saving weights to " << filename << ".";
hid_t diff_hid = -1;
if (write_diff) {
diff_hid = H5Gcreate2(file_hid, "diff", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); //如果需要存梯度信息,则再创建"diff"数据集
CHECK_GE(diff_hid, 0) << "Error saving weights to " << filename << ".";
}
for (int layer_id = 0; layer_id < layers_.size(); ++layer_id) { //处理每一层
const LayerParameter& layer_param = layers_[layer_id]->layer_param(); //当前网络的第layer_id层的layer参数
string layer_name = layer_param.name(); //layer的名称
hid_t layer_data_hid = H5Gcreate2(data_hid, layer_name.c_str(),
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); //使用该名称在"data"中创建数据集
CHECK_GE(layer_data_hid, 0) << "Error saving weights to " << filename << ".";
hid_t layer_diff_hid = -1;
if (write_diff) {
layer_diff_hid = H5Gcreate2(diff_hid, layer_name.c_str(),
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); //需要写梯度,则再在"diff"中创建数据集
CHECK_GE(layer_diff_hid, 0) << "Error saving weights to " << filename << ".";
}
int num_params = layers_[layer_id]->blobs().size(); //该layer中参数blob的个数
for (int param_id = 0; param_id < num_params; ++param_id) {
ostringstream dataset_name;
dataset_name << param_id;
const int net_param_id = param_id_vecs_[layer_id][param_id]; //第layer_id层第param_id个参数在params_的索引
if (param_owners_[net_param_id] == -1) {
// Only save params that own themselves
//源参数,则在layer_data_hid中创建dataset_name数据集,并将参数blob的data_数据写入其中
hdf5_save_nd_dataset<Dtype>(layer_data_hid, dataset_name.str(), *params_[net_param_id]);
}
if (write_diff) {
// Write diffs regardless of weight-sharing
//在layer_diff_hid中创建dataset_name数据集,并将参数blob的diff_数据写入其中
hdf5_save_nd_dataset<Dtype>(layer_diff_hid, dataset_name.str(),
*params_[net_param_id], true);
}
}
H5Gclose(layer_data_hid); //关闭
if (write_diff) {
H5Gclose(layer_diff_hid);
}
}
H5Gclose(data_hid); //各种关闭
if (write_diff) {
H5Gclose(diff_hid);
}
H5Fclose(file_hid);
// This code is taken from https://github.com/sh1r0/caffe-android-lib
#else
LOG(FATAL) << "ToHDF5 requires hdf5; compile with USE_HDF5.";
#endif // USE_HDF5
} template <typename Dtype>
void Net<Dtype>::Update() { //网络更新,把网络中的所有可学习参数blob更新一次
for (int i = 0; i < learnable_params_.size(); ++i) {
learnable_params_[i]->Update(); //调用blob类的函数,data_ = Dtype(-1) * diff_ + data_
}
} template <typename Dtype>
void Net<Dtype>::ClearParamDiffs() { //梯度清空,清空网络中所有可学习参数blob的diff_数据
for (int i = 0; i < learnable_params_.size(); ++i) { //处理每个可学习参数
Blob<Dtype>* blob = learnable_params_[i];
switch (Caffe::mode()) { //当前caffe运行的模式
case Caffe::CPU:
caffe_set(blob->count(), static_cast<Dtype>(0), blob->mutable_cpu_diff()); //将blob中diff_在cpu上的数据全部置为0
break;
case Caffe::GPU:
#ifndef CPU_ONLY
caffe_gpu_set(blob->count(), static_cast<Dtype>(0), blob->mutable_gpu_diff()); //将diff_在gpu上的数据全部置为0
#else
NO_GPU;
#endif
break;
}
}
} template <typename Dtype>
void Net<Dtype>::ShareWeights() { //layer间的参数共享,将所有共享参数的data_和diff_数据指针指向对应的源参数的对应数据
for (int i = 0; i < params_.size(); ++i) { //网络中的所有参数
if (param_owners_[i] < 0) { continue; } //源参数才为-1,不处理
params_[i]->ShareData(*params_[param_owners_[i]]); //共享参数,则将源参数的data_和diff_指针传给当前参数
params_[i]->ShareDiff(*params_[param_owners_[i]]);
}
} template <typename Dtype>
bool Net<Dtype>::has_blob(const string& blob_name) const { //判断网络中是否存在名为blob_name的输出blob
return blob_names_index_.find(blob_name) != blob_names_index_.end();
} template <typename Dtype>
const shared_ptr<Blob<Dtype> > Net<Dtype>::blob_by_name( //返回名为blob_name的blob的数据指针
const string& blob_name) const {
shared_ptr<Blob<Dtype> > blob_ptr;
if (has_blob(blob_name)) { //网络中是否存在该名称的blob
blob_ptr = blobs_[blob_names_index_.find(blob_name)->second]; //由名称确定在blobs_中的位置,返回索引
} else {
blob_ptr.reset((Blob<Dtype>*)(NULL));
LOG(WARNING) << "Unknown blob name " << blob_name; //不存在,警告
}
return blob_ptr;
} template <typename Dtype>
bool Net<Dtype>::has_layer(const string& layer_name) const { //判断网络中是否存在名为layer_name的层
return layer_names_index_.find(layer_name) != layer_names_index_.end();
} template <typename Dtype>
const shared_ptr<Layer<Dtype> > Net<Dtype>::layer_by_name( //返回名为layer_name的layer的指针
const string& layer_name) const {
shared_ptr<Layer<Dtype> > layer_ptr;
if (has_layer(layer_name)) { //网络中是否存在该名称的layer
layer_ptr = layers_[layer_names_index_.find(layer_name)->second]; //找到在layers_中的位置,返回其指针
} else {
layer_ptr.reset((Layer<Dtype>*)(NULL));
LOG(WARNING) << "Unknown layer name " << layer_name; //未找到,警告
}
return layer_ptr;
}

小结

  1. Protocol库中定义了两种序列化数据的格式,一种为文本类型(textual类型),caffe中 ".prototxt" 文件均是此类型,用户可以用来定义网络参数(如train_val.prototxt中设置的是NetParameter类型数据)和求解器参数(如solver.prototxt中设置的是SolverParameter类型数据)。另一种为二进制类型(binary类型),caffe中的模型快照文件".caffemodel"和求解器快照文件".solverstate"均是此类型,一般用来存储数据量较大且无需用户修改的数据,如网络中的所有blob类型的可学习参数等。

参考

https://confluence.hdfgroup.org/display/HDF5

https://developers.google.com/protocol-buffers

(链接打不开的话则需要某科学上网工具)

Caffe的源码笔者是第一次阅读,一边阅读一边记录,对代码的理解和分析可能会存在错误或遗漏,希望各位读者批评指正,谢谢支持!

Caffe源码-Net类(下)的更多相关文章

  1. Caffe源码-SyncedMemory类

    SyncedMemory类简介 最近在阅读caffe源码,代码来自BVLC/caffe,基本是参照网络上比较推荐的 Blob-->Layer-->Net-->Solver 的顺序来分 ...

  2. Caffe源码-Solver类

    Solver类简介 Net类中实现了网络的前向/反向计算和参数更新,而Solver类中则是对此进行进一步封装,包含可用于逐次训练网络的Step()函数,和用于求解网络的优化解的Solve()函数,同时 ...

  3. Caffe源码-SGDSolver类

    SGDSolver类简介 Solver类用于网络参数的更新,而SGDSolver类实现了优化方法中的随机梯度下降法(stochastic gradient descent),此外还具备缩放.正则化梯度 ...

  4. Caffe源码-Net类(上)

    Net类简介 Net类主要处理各个Layer之间的输入输出数据和参数数据共享等的关系.由于Net类的代码较多,本次主要介绍网络初始化部分的代码.Net类在初始化的时候将各个Layer的输出blob都统 ...

  5. Caffe源码-Layer类

    Layer类简介 Layer是caffe中搭建网络的基本单元,caffe代码中包含大量Layer基类派生出来的各种各样的层,各自通过虚函数 Forward() 和 Backward() 实现自己的功能 ...

  6. Caffe源码-Blob类

    Blob类简介 Blob是caffe中的数据传递的一个基本类,网络各层的输入输出数据以及网络层中的可学习参数(learnable parameters,如卷积层的权重和偏置参数)都是Blob类型.Bl ...

  7. Caffe源码-几种优化算法

    SGD简介 caffe中的SGDSolver类中实现了带动量的梯度下降法,其原理如下,\(lr\)为学习率,\(m\)为动量参数. 计算新的动量:history_data = local_rate * ...

  8. vscode下调试caffe源码

    caffe目录: ├── build -> .build_release // make生成目录,生成各种可执行bin文件,直接调用入口: ├── cmake ├── CMakeLists.tx ...

  9. Caffe源码理解2:SyncedMemory CPU和GPU间的数据同步

    目录 写在前面 成员变量的含义及作用 构造与析构 内存同步管理 参考 博客:blog.shinelee.me | 博客园 | CSDN 写在前面 在Caffe源码理解1中介绍了Blob类,其中的数据成 ...

随机推荐

  1. Python 深入浅出支持向量机(SVM)算法

    相比于逻辑回归,在很多情况下,SVM算法能够对数据计算从而产生更好的精度.而传统的SVM只能适用于二分类操作,不过却可以通过核技巧(核函数),使得SVM可以应用于多分类的任务中. 本篇文章只是介绍SV ...

  2. NTP服务搭建详解一条龙

    说在前面:ntp和ntpdate区别 ①两个服务都是centos自带的(centos7中不自带ntp).ntp的安装包名是ntp,ntpdate的安装包是ntpdate.他们并非由一个安装包提供. ② ...

  3. scrapy结合selenium抓取武汉市环保局空气质量日报

    1.前言 目标网站:武汉市环境保护局(http://hbj.wuhan.gov.cn/viewAirDarlyForestWaterInfo.jspx).scrapy对接selenium模块抓取空气质 ...

  4. pymongo的基本操作和使用

    MongoDB简介 MongoDB是一个开源的文档类型数据库,它具有高性能,高可用,可自动收缩的特性.MongoDB能够避免传统的ORM映射从而有助于开发. 文档 在MongoDB中,一行纪录就是一个 ...

  5. 利用Spring AOP的通知类型以及创建通知

    写在最前端 1.SpringAOP中共有六种通知类型,只要我们自定义一个类实现对应的接口,它们全都是org.springframework.aop包中的. 2.AOP的连接点可以是方法调用.方法调用本 ...

  6. cesium定义线面

    面: var polygon = viewer.entities.add({ polygon : { hierarchy : { positions : null, holes : [{ positi ...

  7. Oracle procedure 在命令行里面执行出错

    One procedure do well in SQL developer but error during exceute it under sqlplus command line: Remem ...

  8. 《吊打面试官》系列-HashMap

    你知道的越多,你不知道的越多 点赞再看,养成习惯 本文 GitHub https://github.com/JavaFamily 上已经收录,有一线大厂面试点思维导图,也整理了很多我的文档,欢迎Sta ...

  9. Apache ServiceComb 开源两周年,聊聊其与微服务的前世今生

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  10. php上传下载文件

    之前做一个上传下载的项目,发现网上的和自己需求不是很一样,翻阅了下书籍和整理了下网上的一些代码.做了一个上传下载的demo,上传通过php本身的uploadfile函数,并返回以时间戳命名的文件名后, ...