我正在尝试使用caffe重现以下论文:
最后一层有100个输出,每个输出代表预测年龄的概率。最终预测的年龄通过以下方程计算:
因此,我想使用EUCLIDEAN_LOSS来计算标签和预测值之间的损失。
我展示了最后输出层和损失层的prototxt文件:
layer { bottom: "pool5" top: "fc100" name: "fc100" type: "InnerProduct" inner_product_param { num_output: 100 }}layer { bottom: "fc100" top: "prob" name: "prob" type: "Softmax"}layer { name: "loss" type: "SoftmaxWithLoss" bottom: "fc100" bottom: "label" top: "loss" loss_weight: 1}
目前,我正在尝试使用SoftmaxWithLoss。然而,这种损失更适合分类任务,而不是回归任务。在这种情况下,我该如何设计损失层呢?
提前感谢。
回答:
TL;DR
我曾经经历过类似的任务,从我的经验来看,训练离散标签和回归单一连续值在输出精度方面几乎没有差异。
你可以用几种方式来处理这个问题:
1. 回归单一输出
由于你只需要预测一个标量值,你应该训练你的网络来完成这个任务:
layer { bottom: "pool5" top: "fc1" name: "fc1" type: "InnerProduct" inner_product_param { num_output: 1 # 预测单一输出 }}
你需要确保预测值在[0..99]范围内:
layer { bottom: "fc1" top: "pred01" # 映射到[0..1]范围 type: "Sigmoid" name: "pred01"}layer { bottom: "pred01" top: "pred_age" type: "Scale" name: "pred_age" param { lr_mult: 0 } # 不学习这个缩放 - 它是固定的 scale_param { bias_term: false filler { type: "constant" value: 99 } }}
一旦你有了pred_age
中的预测值,你可以添加一个损失层
layer { bottom: "pred_age" bottom: "true_age" top: "loss" type: "EuclideanLoss" name: "loss"}
不过,我建议在这种情况下使用"SmoothL1"
,因为它更robust。
2. 回归离散预测的期望值
你可以在caffe中实现你的预测公式。为此,你需要一个固定的[0..99]值向量。有很多方法可以做到这一点,没有一种是非常直接的。这里是一种使用net-surgery的方法:
首先,定义网络
layer { bottom: "prob" top: "pred_age" name: "pred_age" type: "Convolution" param { lr_mult: 0 } # 固定层。 convolution_param { num_output: 1 bias_term: false }}layer { bottom: "pred_age" bottom: "true_age" top: "loss" type: "EuclideanLoss" # 关于损失类型的评论同前 name: "loss"}
你还不能使用这个网络,首先你需要将pred_age
层的内核设置为0..99。
在python中,加载新的
net = caffe.Net('path/to/train_val.prototxt', caffe.TRAIN)li = list(net._layer_names).index('pred_age') # 获取层索引net.layers[li].blobs[0].data[...] = np.arange(100, dtype=np.float32) # 设置内核net.save('/path/to/init_weights.caffemodel') # 保存权重
现在你可以训练你的网络,但务必确保你从'/path/to/init_weights.caffemodel'
中保存的权重开始训练。