在优化深度网络时,首先要根据损失函数计算 loss,但它对计算梯度是没有用的, 因为 loss 对最后一层的误差敏感项 $\delta$ 可以根据input表示出来, 之后所有参数的梯度更新只需要根据前一层的 $\delta$ 计算. 所以它的存在是用来指导训练的, 即显示地告诉你模型的泛化能力是如何变化的,最否已经达到了最优。
在 Caffe 中, 所有的结构运算已经抽象成了 layer , 怎么计算 loss 呢? 如果一个 layer 是 loss 层, 则其 top 即为 loss.
指定 loss 属性
实际上 Layer 的 Forward 接口是返回值的 (loss), 但需要一个标记位指定这一层是否有 loss 权重, 从而决定是否需要计算 loss.
如下 loss_layer.cpp
, 如果一个 layer 属于 LossLayer 则指定 loss_weight
template <typename Dtype>
void LossLayer<Dtype>::LayerSetUp(
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
// LossLayers have a non-zero (1) loss by default.
if (this->layer_param_.loss_weight_size() == 0) {
this->layer_param_.add_loss_weight(Dtype(1));
}
}
在 Layer 层计算 loss
在 Layer 中根据是否有 loss_weight 设置每个 top 的 loss 的标识位 及 loss weight 到 top 的 diff.
loss weight 只是影响 loss 的表现形式, 导致在 Backforward 的时候也要用到. =.=
代码出自 Layer.hpp
:
inline void SetLossWeights(const vector<Blob<Dtype>*>& top) {
const int num_loss_weights = layer_param_.loss_weight_size();
if (num_loss_weights) {
CHECK_EQ(top.size(), num_loss_weights) << "loss_weight must be "
"unspecified or specified once per top blob.";
for (int top_id = 0; top_id < top.size(); ++top_id) {
const Dtype loss_weight = layer_param_.loss_weight(top_id);
if (loss_weight == Dtype(0)) { continue; }
this->set_loss(top_id, loss_weight);
const int count = top[top_id]->count();
Dtype* loss_multiplier = top[top_id]->mutable_cpu_diff();
caffe_set(count, loss_weight, loss_multiplier);
}
}
}
然后在 Forward 的时候, 根据 layer 各个 top 的loss 标记位计算 loss 即可.
template <typename Dtype>
inline Dtype Layer<Dtype>::Forward(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
// Lock during forward to ensure sequential forward
Lock();
Dtype loss = 0;
Reshape(bottom, top);
switch (Caffe::mode()) {
case Caffe::CPU:
Forward_cpu(bottom, top);
for (int top_id = 0; top_id < top.size(); ++top_id) {
if (!this->loss(top_id)) { continue; }
const int count = top[top_id]->count();
const Dtype* data = top[top_id]->cpu_data();
const Dtype* loss_weights = top[top_id]->cpu_diff();
loss += caffe_cpu_dot(count, data, loss_weights);
}
break;
...
Unlock();
return loss;
}
Net 中的 loss
Net 最后输出的 loss, 是所有可以计算 loss 的 layer的 loss 之和.
template <typename Dtype>
Dtype Net<Dtype>::ForwardFromTo(int start, int end) {
CHECK_GE(start, 0);
CHECK_LT(end, layers_.size());
Dtype loss = 0;
for (int i = start; i <= end; ++i) {
// LOG(ERROR) << "Forwarding " << layer_names_[i];
Dtype layer_loss = layers_[i]->Forward(bottom_vecs_[i], top_vecs_[i]);
loss += layer_loss;
if (debug_info_) { ForwardDebugInfo(i); }
}
return loss;
}
问题: 是否可以建立多损失函数的模型?