- 从 keras 文档中可以看出
类别权重:可选字典将类索引(整数)映射到权重(浮点)值,用于对损失函数进行加权(仅在训练期间)。这对于告诉模型“更多地关注”代表性不足的类别的样本很有用。
So class_weight
只影响训练期间的损失。我本人一直有兴趣了解在测试和训练期间如何处理类和样本权重。查看keras github repo以及metric和loss的代码,似乎loss或metric都没有受到它们的影响。打印的值很难在训练代码中跟踪,例如model.fit()
及其相应的tensorflow后端训练函数。所以我决定制作一个测试代码来测试可能的场景,请参阅下面的代码。结论是,两者class_weight
and sample_weight
只影响训练损失,对任何指标或验证损失没有影响。有点令人惊讶的是val_sample_weights
(你可以指定)似乎什么也没做(??)。
此类问题始终取决于您的问题、日期的偏差程度以及您尝试优化模型的方式。您是否针对准确性进行了优化,那么只要训练数据与模型在生产中时的偏差相同,只需训练即可获得最佳结果,而无需任何过采样/欠采样和/或类别权重。
另一方面,如果您有一个类比另一个类更重要(或更昂贵)的东西,那么您应该对数据进行加权。例如,在预防欺诈方面,欺诈通常比非欺诈的收入要昂贵得多。我建议您尝试未加权的类别、加权的类别和一些欠采样/过采样,并检查哪一个可以提供最佳的验证结果。使用最能比较不同模型的验证函数(或编写自己的函数)(例如,根据成本对真阳性、假阳性、真阴性和假阴性进行不同的加权)。
一个相对较新的损失函数在偏斜数据的 Kaggle 竞赛中取得了很好的成绩:Focal-loss
. Focal-loss
减少过采样/欠采样的需要。很遗憾Focal-loss
还不是 keras 中的内置函数,但可以手动编程。
是的,我认为你是对的。我通常使用sample_weight
有两个原因。 1、训练数据具有某种测量不确定性,如果已知的话,可以用来对准确数据进行加权,而不是对不准确测量进行加权。或者2,我们可以对新数据赋予比旧数据更大的权重,迫使模型更快地适应新行为,而不忽略有价值的旧数据。
比较有和没有的代码class_weights
and sample_weights
,同时保持模型和其他一切静止。
import tensorflow as tf
import numpy as np
data_size = 100
input_size=3
classes=3
x_train = np.random.rand(data_size ,input_size)
y_train= np.random.randint(0,classes,data_size )
#sample_weight_train = np.random.rand(data_size)
x_val = np.random.rand(data_size ,input_size)
y_val= np.random.randint(0,classes,data_size )
#sample_weight_val = np.random.rand(data_size )
inputs = tf.keras.layers.Input(shape=(input_size))
pred=tf.keras.layers.Dense(classes, activation='softmax')(inputs)
model = tf.keras.models.Model(inputs=inputs, outputs=pred)
loss = tf.keras.losses.sparse_categorical_crossentropy
metrics = tf.keras.metrics.sparse_categorical_accuracy
model.compile(loss=loss , metrics=[metrics], optimizer='adam')
# Make model static, so we can compare it between different scenarios
for layer in model.layers:
layer.trainable = False
# base model no weights (same result as without class_weights)
# model.fit(x=x_train,y=y_train, validation_data=(x_val,y_val))
class_weights={0:1.,1:1.,2:1.}
model.fit(x=x_train,y=y_train, class_weight=class_weights, validation_data=(x_val,y_val))
# which outputs:
> loss: 1.1882 - sparse_categorical_accuracy: 0.3300 - val_loss: 1.1965 - val_sparse_categorical_accuracy: 0.3100
#changing the class weights to zero, to check which loss and metric that is affected
class_weights={0:0,1:0,2:0}
model.fit(x=x_train,y=y_train, class_weight=class_weights, validation_data=(x_val,y_val))
# which outputs:
> loss: 0.0000e+00 - sparse_categorical_accuracy: 0.3300 - val_loss: 1.1945 - val_sparse_categorical_accuracy: 0.3100
#changing the sample_weights to zero, to check which loss and metric that is affected
sample_weight_train = np.zeros(100)
sample_weight_val = np.zeros(100)
model.fit(x=x_train,y=y_train,sample_weight=sample_weight_train, validation_data=(x_val,y_val,sample_weight_val))
# which outputs:
> loss: 0.0000e+00 - sparse_categorical_accuracy: 0.3300 - val_loss: 1.1931 - val_sparse_categorical_accuracy: 0.3100
使用权重和不使用权重之间存在一些小偏差(即使所有权重都是一),可能是由于对加权和未加权数据使用不同的后端函数进行拟合,或者是由于舍入误差?