- 从 keras 文档中说
class_weight:可选字典将类索引(整数)映射到权重(浮点)值,用于加权损失函数(仅在训练期间)。这对于告诉模型“更加关注”来自代表性不足的类的样本很有用。
所以class_weight 只会影响训练过程中的损失。我本人一直有兴趣了解在测试和培训期间如何处理类和样本权重。查看 keras github repo 和 metric 和 loss 的代码,似乎 loss 或 metric 都不受它们的影响。在model.fit() 等训练代码及其相应的 tensorflow 后端训练函数中很难跟踪打印的值。所以我决定做一个测试代码来测试可能的场景,见下面的代码。结论是class_weight 和sample_weight 都只影响训练损失,对任何指标或验证损失没有影响。 val_sample_weights(您可以指定)似乎什么都不做(??)。
此类问题始终取决于您的问题、日期的偏差程度以及您尝试优化模型的方式。您是否针对准确性进行了优化,那么只要训练数据与模型在生产中时一样倾斜,那么只需在没有任何过度/不足采样和/或类权重的情况下进行训练即可获得最佳结果。
另一方面,如果您有一个类比另一个类更重要(或更昂贵)的东西,那么您应该对数据进行加权。例如在欺诈预防中,欺诈通常比非欺诈的收入昂贵得多。我建议您尝试未加权类、加权类和一些欠/过采样,并检查哪个可以提供最佳验证结果。使用最能比较不同模型的验证函数(或自己编写)(例如,根据成本对真阳性、假阳性、真阴性和假阴性进行不同的加权)。
一个相对较新的损失函数是Focal-loss。 Focal-loss 减少过采样/欠采样的需要。不幸的是,Focal-loss 还不是 keras 中的内置函数,但可以手动编程。
是的,我认为你是正确的。我通常使用sample_weight 有两个原因。 1,训练数据具有某种测量不确定性,如果已知,可以使用比不准确测量更多的权重准确数据。或者 2,我们可以比旧数据更多地加权新数据,迫使模型更快地适应新行为,而不会忽略有价值的旧数据。
比较有和没有class_weights 和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
使用权重与不使用权重之间存在一些小的偏差(即使所有权重都为 1),这可能是由于对加权和未加权数据使用不同的后端函数进行拟合,还是由于舍入误差?