主要有以下部分:net, blob, layer, solver.
net.cpp:
net定义网络, 整个网络中含有很多layers,net构造函数中将所有layer按配置组装起来。net.cpp负责计算整个网络在训练中的forward, backward过程, 即计算forward/backward 时各layer的gradient。
layer:
在protobuffer
(.proto文件中定义message类型,.prototxt或.binaryproto文件中定义message的值)
中调用时包含属性name, type(data/conv/pool…), connection structure (input blobs
and output blobs),layer-specific
parameters(如conv层的kernel大小)。定义一个layer需要定义其setup, forward 和backward过程。
blob.cpp:
net中的数据和求导结果通过4维的blob传递,而实际上,它们只是一维的指针而已。一个layer有很多blobs。
对data,weight blob大小为Number * Channels * Height * Width, 如256*3*224*224;
对conv层,weight blob大小为 Output 节点数 * Input 节点数 * Height * Width,如AlexNet第一个conv层的blob大小为96 x 3 x 11 x 11;
对inner product 层, weight blob大小为 1 * 1 * Output节点数 * Input节点数; bias blob大小为1 * 1 * 1 * Output节点数( conv层和inner product层一样,也有weight和bias,所以在网络结构定义中我们会看到两个blobs_lr,第一个是weights的,第二个是bias的。类似地,weight_decay也有两个,一个是weight的,一个是bias的);
blob中,mutable_cpu/gpu_data() 和cpu/gpu_data()用来管理memory,cpu/gpu_diff()和 mutable_cpu/gpu_diff()用来计算求导结果。blob内存采用SyncedMemory管理,在一定程度上隐藏了cpu和gpu直接的数据拷贝,head_表示数据的状态。其中的mutable_cpu/gpu_data() 和cpu/gpu_data()的获得是同一个指针,但是mutable意味着数据将被更改,所以head_被修改。
slover.cpp:
结合loss,用gradient更新weights。主要函数:
Init(),
Solve(),
ComputeUpdateValue(),
Snapshot(), Restore(),//快照(拷贝)与恢复 网络state
Test();
在solver.cpp中有3中solver,即3个类:AdaGradSolver, SGDSolver和NesterovSolver可供选择。
关于loss,可以同时有多个loss,可以加regularization(L1/L2);
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.
在深度神经网络中为了减少参数,一些神经元的链接采用共享权值。params_记录了整个网络的参数,其中部分参数是共享的,即存在params_[i]和params_[j]这两个blob中的data和diff是一块内存。learnable_param_ids_[i]记录的是第i个参数的owner的id。在net的Init结束时,调用了ShareWeights函数,将共享的参数指向了同一块内存。
void Net<Dtype>::ShareWeights() { for (int i = 0; i < params_.size(); ++i) { if (param_owners_[i] < 0) { continue; } params_[i]->ShareData(*params_[param_owners_[i]]); params_[i]->ShareDiff(*params_[param_owners_[i]]); } }