16

我希望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.arraybinproto文件转换为可以作为infogain_loss_param { source }模型提供的文件?

  2. 假设我想H作为损失层的第三个输入(底部)提供(而不是作为模型参数)。我怎样才能做到这一点?
    我是否定义了一个“顶部”的新数据层H?如果是这样,这层的数据不是每次训练迭代都会增加,就像训练数据增加一样吗?如何定义多个不相关的输入“数据”层,以及 caffe 如何知道从训练/测试“数据”层批量读取,而从H“数据”层它知道在所有训练过程中只读取一次?

4

3 回答 3

10

1. 有InfogainLoss层的使用教程/例子吗?
一个很好的例子可以在这里找到:使用InfogainLoss来解决类不平衡问题。


2. 该层的输入,类别概率,应该是Softmax层的输出吗?从历史上看,根据Yair 的答案
,答案曾经是YES。旧的实现需要是层或任何其他层的输出,以确保输入值在 [0..1] 范围内。 "InfogainLoss""Softmax"

OP注意到在顶层使用会"InfogainLoss"导致"Softmax"数值不稳定。他的 pull request将这两层合并为一个(很像"SoftmaxWithLoss"层),于 2017 年 4 月 14 日被接受并合并到官方 Caffe 存储库中。这里给出了这个组合层的数学。

升级后的层“外观和感觉”与旧层完全一样,除了不再需要显式地通过"Softmax"层传递输入。


3. 如何将 numpy.array 转换为 binproto 文件

在蟒蛇

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 的帖子

目前没有办法让数据层以不同的速率加载输入。每次前向传递所有数据层都会前进。然而,恒定的 H 输入可以通过制作一个只有 H 的输入 lmdb / leveldb / hdf5 文件来完成,因为数据层将循环并继续加载相同的 H。这显然浪费了磁盘 IO。

于 2014-12-25T09:27:10.477 回答
2

该层正在总结

-log(p_i)

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

在此处输入图像描述

我不认为它们必须总和为 1,但是将它们通过 Softmax 层将实现这两​​个属性。

于 2015-05-04T18:44:06.337 回答
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"
  }
}
于 2018-08-01T20:07:50.010 回答