InfogainLoss层

问题描述 投票:16回答:3

我想在我的模型中使用InfogainLoss类型的损失层。但我很难正确定义它。

  1. 是否有关于INFOGAIN_LOSS图层使用的教程/示例?
  2. 这个层的输入,类概率,应该是SOFTMAX层的输出,还是足以输入完全连接层的“顶部”?

INFOGAIN_LOSS需要三个输入:类概率,标签和矩阵H。矩阵H可以作为层参数infogain_loss_param { source: "fiename" }提供。 假设我有一个python脚本,用H计算numpy.array作为形状(L,L)dtype='f4'(其中L是我模型中的标签数量)。

  1. 如何将我的numpy.array转换为binproto文件,可以作为infogain_loss_param { source }提供给模型?
  2. 假设我希望将H作为损失层的第三个输入(底部)提供(而不是作为模型参数)。我怎样才能做到这一点? 我是否定义了一个“顶部”是H的新数据层?如果是这样,那么每次训练迭代都不会增加该层的数据,就像训练数据增加一样?如何定义多个不相关的输入“数据”图层,以及caffe如何知道批量读取训练/测试“数据”图层,而从H“数据”图层知道只读取一次所有培训处理?
numpy neural-network protocol-buffers deep-learning caffe
3个回答
10
投票

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层的一部分

引用Evan Shelhamer's post

目前无法使数据层以不同的速率加载输入。每个前向传递所有数据层都将前进。但是,常量H输入可以通过使输入lmdb / leveldb / hdf5文件仅为H来完成,因为数据层将循环并继续加载相同的H.这显然浪费了磁盘IO。


2
投票

该层正在总结

-log(p_i)

所以p_i需要在(0,1)中作为损失函数才有意义(否则更高的置信度得分会产生更高的损失)。请参阅下面的曲线,了解log(p)的值。

我不认为他们必须总结为1,但是通过Softmax层传递它们将实现两个属性。


1
投票

由于我不得不搜索许多网站来拼写完整的代码,我想我分享了我的实现:

用于计算每个类权重的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"
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.