我已经了解了如何对单个分类进行类权重不平衡校正。但就我而言,我的输出层是:
model.add(Dense(4, activation='sigmoid'))
我的 target
是一个 DataFrame
,它有:
0 1 2 3
0 1 1 0 0
1 0 0 0 0
2 1 1 1 0
3 1 1 0 0
4 1 1 0 0
5 1 1 0 0
6 1 0 0 0
... .. .. .. ..
14989 1 1 1 1
14990 1 1 1 0
14991 1 1 1 1
14992 1 1 1 0
[14993 rows x 4 columns]
我的预测可以采用 5 个可能值之一的形式:
[[0, 0, 0, 0],
[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 1, 1, 1]]
但是,这些类肯定是不平衡的。我已经看到如何计算 class weights if I have 1 target output使用 softmax
,但这略有不同。
具体来说,
model.fit(..., class_weights=weights)
在这种情况下如何定义权重
?
最佳答案
可能的解决方案
IMO 你应该使用几乎标准的 categorical_crossentropy
并从网络输出 logits,它将在损失函数中映射到值 [0,1,2,3,4]
使用 argmax
操作(相同的过程将应用于 one-hot-encoded
标签,请参阅本答案的最后一部分以获取示例)。
使用加权交叉熵
,您可以根据您在评论中指出的预测值与正确值
不同地处理不正确性。
您所要做的就是取减去正确值和预测值的绝对值并将其乘以损失,请参见下面的示例:
让我们将每个编码映射到它的一元值(可以使用 argmax
完成,稍后会看到):
[0, 0, 0, 0] -> 0
[1, 0, 0, 0] -> 1
[1, 1, 0, 0] -> 2
[1, 1, 1, 0] -> 3
[1, 1, 1, 1] -> 4
然后让我们通过模型进行一些随机目标和预测以查看本质:
correct predicted with Softmax
0 0 4
1 4 3
2 3 3
3 1 4
4 3 1
5 1 0
现在,当您减去 correct
和 predicted
并取绝对值时,您基本上会得到这样的权重列:
weights
0 4
1 1
2 0
3 3
4 2
5 1
如您所见,当真实目标为 4
时,0
的预测权重将是 3
的预测权重的 4 倍4
目标,这就是您本质上想要的 IIUC。
作为Daniel Möller在他的回答中指出,我建议您也创建一个自定义损失函数,但要简单一些:
import tensorflow as tf
# Output logits from your network, not the values after softmax activation
def weighted_crossentropy(labels, logits):
return tf.losses.softmax_cross_entropy(
labels,
logits,
weights=tf.abs(tf.argmax(logits, axis=1) - tf.argmax(labels, axis=1)),
)
你也应该在你的 model.compile
中使用这个损失,我认为没有必要重申已经提出的观点。
该方案的缺点:
- 对于正确的预测,梯度将等于零,这意味着网络将更难加强连接(最大化/最小化朝向
+inf/-inf
的 logits) - 可以通过向每个加权损失添加随机噪声(附加正则化)来缓解上述问题。也可以作为正则化,可能会有所帮助。
- 更好的解决方案可能是排除预测值相等(或使其为 1)的加权情况,这样不会为网络优化添加随机化。
该方案的优点:
- 您可以轻松地为不平衡的数据集添加权重(例如,某些类出现的频率更高)
- 干净地映射到现有 API
- 概念上简单并保持在分类领域
- 您的模型无法预测不存在的分类值,例如对于你的多目标案例,它可以预测
[1, 0, 1, 0]
,上面的方法没有这样的。较低的自由度将有助于它训练和消除无意义(如果我对你的问题描述正确)预测的机会。
评论中聊天室提供的额外讨论
具有自定义损失的示例网络
这是一个带有上面定义的自定义损失函数的示例网络。
您的标签必须是 one-hot-encoded
才能正常工作。
import keras
import numpy as np
import tensorflow as tf
# You could actually make it a lambda function as well
def weighted_crossentropy(labels, logits):
return tf.losses.softmax_cross_entropy(
labels,
logits,
weights=tf.abs(tf.argmax(logits, axis=1) - tf.argmax(labels, axis=1)),
)
model = keras.models.Sequential(
[
keras.layers.Dense(32, input_shape=(10,)),
keras.layers.Activation("relu"),
keras.layers.Dense(10),
keras.layers.Activation("relu"),
keras.layers.Dense(5),
]
)
data = np.random.random((32, 10))
labels = keras.utils.to_categorical(np.random.randint(5, size=(32, 1)))
model.compile(optimizer="rmsprop", loss=weighted_crossentropy)
model.fit(data, labels, batch_size=32)
关于python - 如何使用 keras 计算具有 4 个神经元的输出的类权重?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55010794/