TL;DR
我曾经做过类似的任务,根据我的经验,训练离散标签和回归单个连续值之间几乎没有区别(在输出准确性方面)。
有几种方法可以解决这个问题:
1。回归单个输出
由于您只需要预测单个标量值,因此您应该训练您的网络来做到这一点:
layer {
bottom: "pool5"
top: "fc1"
name: "fc1"
type: "InnerProduct"
inner_product_param {
num_output: 1 # predict single output
}
}
您需要确保预测值在 [0..99] 范围内:
layer {
bottom: "fc1"
top: "pred01" # map to [0..1] range
type: "Sigmoid"
name: "pred01"
}
layer {
bottom: "pred01"
top: "pred_age"
type: "Scale"
name: "pred_age"
param { lr_mult: 0 } # do not learn this scale - it is fixed
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",因为它更健壮。
2。回归离散预测的期望
您可以在 caffe 中实现您的预测公式。为此,您需要一个 fixed 值 [0..99] 向量。有很多方法可以做到这一点,没有一个是非常直接的。这是使用net-surgery的一种方式:
首先,定义网络
layer {
bottom: "prob"
top: "pred_age"
name: "pred_age"
type: "Convolution"
param { lr_mult: 0 } # fixed layer.
convolution_param {
num_output: 1
bias_term: false
}
}
layer {
bottom: "pred_age"
bottom: "true_age"
top: "loss"
type: "EuclideanLoss" # same comment about type of loss as before
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') # get layer index
net.layers[li].blobs[0].data[...] = np.arange(100, dtype=np.float32) # set the kernel
net.save('/path/to/init_weights.caffemodel') # save the weights
现在您可以训练您的网络了,但是确保您将从'/path/to/init_weights.caffemodel' 中保存的权重开始训练。