我想在我的模型中使用InfogainLoss
类型的损失层。但我很难正确定义它。
INFOGAIN_LOSS
图层使用的教程/示例?SOFTMAX
层的输出,还是足以输入完全连接层的“顶部”?INFOGAIN_LOSS
需要三个输入:类概率,标签和矩阵H
。矩阵H
可以作为层参数infogain_loss_param { source: "fiename" }
提供。
假设我有一个python脚本,用H
计算numpy.array
作为形状(L,L)
的dtype='f4'
(其中L
是我模型中的标签数量)。
numpy.array
转换为binproto
文件,可以作为infogain_loss_param { source }
提供给模型?H
作为损失层的第三个输入(底部)提供(而不是作为模型参数)。我怎样才能做到这一点?
我是否定义了一个“顶部”是H
的新数据层?如果是这样,那么每次训练迭代都不会增加该层的数据,就像训练数据增加一样?如何定义多个不相关的输入“数据”图层,以及caffe如何知道批量读取训练/测试“数据”图层,而从H
“数据”图层知道只读取一次所有培训处理?1.是否有关于InfogainLoss层使用的教程/示例?: 一个很好的例子可以找到here:使用InfogainLoss来解决类不平衡问题。
2.此层的输入(类概率)是否应为Softmax层的输出?
从历史上看,根据Yair's answer,答案过去是肯定的。 "InfogainLoss"
的旧实现需要是"Softmax"
层或任何其他层的输出,以确保输入值在[0..1]范围内。
OP注意到在"InfogainLoss"
层顶部使用"Softmax"
会导致数值不稳定。 His pull request,将这两个层组合成一个(很像"SoftmaxWithLoss"
层),被接受并于2017年4月14日合并到官方Caffe存储库中。这个组合层的数学给出了here。
升级后的“外观和感觉”层与旧版层完全相同,除了不再需要通过"Softmax"
层明确传递输入的事实。
3.如何将numpy.array转换为binproto文件:
在python中
H = np.eye( L, dtype = 'f4' )
import caffe
blob = caffe.io.array_to_blobproto( H.reshape( (1,1,L,L) ) )
with open( 'infogainH.binaryproto', 'wb' ) as f :
f.write( blob.SerializeToString() )
现在,您可以使用INFOGAIN_LOSS
作为参数将H
图层添加到模型原型文本中:
layer {
bottom: "topOfPrevLayer"
bottom: "label"
top: "infoGainLoss"
name: "infoGainLoss"
type: "InfogainLoss"
infogain_loss_param {
source: "infogainH.binaryproto"
}
}
4.如何加载H
作为DATA层的一部分
目前无法使数据层以不同的速率加载输入。每个前向传递所有数据层都将前进。但是,常量H输入可以通过使输入lmdb / leveldb / hdf5文件仅为H来完成,因为数据层将循环并继续加载相同的H.这显然浪费了磁盘IO。
该层正在总结
-log(p_i)
所以p_i需要在(0,1)中作为损失函数才有意义(否则更高的置信度得分会产生更高的损失)。请参阅下面的曲线,了解log(p)的值。
我不认为他们必须总结为1,但是通过Softmax层传递它们将实现两个属性。
由于我不得不搜索许多网站来拼写完整的代码,我想我分享了我的实现:
用于计算每个类权重的H矩阵的Python层:
import numpy as np
import caffe
class ComputeH(caffe.Layer):
def __init__(self, p_object, *args, **kwargs):
super(ComputeH, self).__init__(p_object, *args, **kwargs)
self.n_classes = -1
def setup(self, bottom, top):
if len(bottom) != 1:
raise Exception("Need (only) one input to compute H matrix.")
params = eval(self.param_str)
if 'n_classes' in params:
self.n_classes = int(params['n_classes'])
else:
raise Exception('The number of classes (n_classes) must be specified.')
def reshape(self, bottom, top):
top[0].reshape(1, 1, self.n_classes, self.n_classes)
def forward(self, bottom, top):
classes, cls_num = np.unique(bottom[0].data, return_counts=True)
if np.size(classes) != self.n_classes or self.n_classes == -1:
raise Exception("Invalid number of classes")
cls_num = cls_num.astype(float)
cls_num = cls_num.max() / cls_num
weights = cls_num / np.sum(cls_num)
top[0].data[...] = np.diag(weights)
def backward(self, top, propagate_down, bottom):
pass
以及train_val.prototxt中的相关部分:
layer {
name: "computeH"
bottom: "label"
top: "H"
type: "Python"
python_param {
module: "digits_python_layers"
layer: "ComputeH"
param_str: '{"n_classes": 7}'
}
exclude { stage: "deploy" }
}
layer {
name: "loss"
type: "InfogainLoss"
bottom: "score"
bottom: "label"
bottom: "H"
top: "loss"
infogain_loss_param {
axis: 1 # compute loss and probability along axis
}
loss_param {
normalization: 0
}
exclude {
stage: "deploy"
}
}