不平衡数据的 TensorFlow 调整成本函数

数据挖掘 张量流 损失函数
2021-10-10 03:37:22

我有一个高度不平衡数据的分类问题。我已经读到过采样和欠采样以及更改代表性不足的分类输出的成本将导致更好的拟合。在此之前,tensorflow 会将每个输入分类为多数组(并获得超过 90% 的准确率,尽管那毫无意义)。

我注意到每组的倒数百分比的对数是我尝试过的最好的乘数。成本函数是否有更标准的操作?这是否正确实施?

from collections import Counter
counts = Counter(category_train)
weightsArray =[]
for i in range(n_classes):
    weightsArray.append(math.log(category_train.shape[0]/max(counts[i],1))+1)

class_weight = tf.constant(weightsArray)
weighted_logits = tf.mul(pred, class_weight)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(weighted_logits, y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
3个回答

这似乎是损失函数的一个很好的解决方案。我最近用类似的方法取得了成功,但我认为你想重新排序你在class_weight.

从逻辑上考虑,class_weight将是一个常数 wrt 输出,因此它将被携带并应用于梯度,就像应用于成本函数一样。不过有一个问题。

你拥有它的方式class_weight会影响预测值。但是您希望它影响渐变的比例。如果我没记错的话,我认为您想颠倒操作顺序:

# Take the cost like normal
error = tf.nn.softmax_cross_entropy_with_logits(pred, y)

# Scale the cost by the class weights
scaled_error = tf.mul(error, class_weight)

# Reduce
cost = tf.reduce_mean(scaled_error)

与简单地对代表性不足的班级进行过采样相比,我很想知道它的表现如何,这更典型。因此,如果您对此有所了解,请发布!:)

有趣的是,我最近在一个不同的问题域中成功地使用了一种非常相似的技术(这让我来到了这篇文章):

多任务学习,找到“忽略”某些样本的损失函数

结帐tf.nn.weighted_cross_entropy_with_logits()

计算加权交叉熵。

这与 sigmoid_cross_entropy_with_logits() 类似,除了 pos_weight 允许人们通过对正错误相对于负错误的成本进行上下加权来权衡召回率和精度。

这应该让你做你想做的事。

我有 2 种不同的实现:

  1. 使用带有 logits 的“常规”softmax: tf.nn.softmax_cross_entropy_with_logits

class_weight 是我在每批迭代中填写的占位符。

self.class_weight  = tf.placeholder(tf.float32, shape=self.batch_size,self._num_classes], name='class_weight')    
self._final_output = tf.matmul(self._states,self._weights["linear_layer"]) + self._biases["linear_layer"] 
self.scaled_logits = tf.multiply(self._final_output, self.class_weight)
self.softmax = tf.nn.softmax_cross_entropy_with_logits(logits=self.scaled_logits,labels= self._labels)
  1. tf.nn.softmax_cross_entropy_with_logits

我在哪里使用实现的 tensorflow 函数,但我需要计算批次的权重。文档对此有点困惑。有两种方法可以使用 tf.gather 或像这样:

self.scaled_class_weights=tf.reduce_sum(tf.multiply(self._labels,self.class_weight),1)
self.softmax = tf.losses.softmax_cross_entropy(logits=self._final_output,
                                                   onehot_labels=self._labels,weights=self.scaled_class_weights)

这里有一个很好的讨论

最后,由于我一直不想嫁给任何实现,所以我添加了一点 tf.case 并在训练时间传递了我想使用的策略。

self.sensitive_learning_strategy = tf.placeholder(tf.int32 , name='sensitive_learning_strategy')
self.softmax =tf.case([
            (tf.equal(self.sensitive_learning_strategy, 0), lambda: self.softmax_0),
            (tf.equal(self.sensitive_learning_strategy, 1), lambda: self.softmax_1),
            (tf.equal(self.sensitive_learning_strategy, 2), lambda: self.softmax_2)