Keras weighted_metrics 在计算中不包括样本权重[关闭]

Posted

技术标签:

【中文标题】Keras weighted_metrics 在计算中不包括样本权重[关闭]【英文标题】:Keras weighted_metrics does not include sample weights in calculation [closed] 【发布时间】:2021-12-17 13:46:04 【问题描述】:

我正在训练一个 CNN 模型,其输入和输出均是形状为 (400,22) 的 2D 张量。我使用 categorical_crossentropy 作为损失和度量。但是损失/指标值非常不同。

我的模型有点像这样:

1.使用样本权重,并在model.compile 中使用metrics= 传递指标。

# Imports
import tensorflow as tf
from tensorflow.keras.layers import *
from tensorflow.keras.optimizers import *
from tensorflow.keras.regularizers import *
from tensorflow.keras import *
import numpy as np

# Build the model
X_input = Input(shape=(400,22))
X = Conv1D(filters=32, kernel_size=2, activation='elu', 
           kernel_regularizer=L2(1e-4), bias_regularizer=L2(1e-4), 
           padding='same')(X_input)
X = Dropout(0.2)(X)
X = Conv1D(filters=32, kernel_size=2, activation='elu', 
           kernel_regularizer=L2(1e-4), bias_regularizer=L2(1e-4), 
           padding='same')(X)
X = Dropout(0.2)(X)
y = Conv1D(filters=22, kernel_size=1, activation='softmax', 
           kernel_regularizer=L2(1e-4), bias_regularizer=L2(1e-4), 
           padding='same')(X)
model = Model(X_input, y, name='mymodel')


# Compile and train the model (with metrics=[])
model.compile(optimizer=Adam(1e-3),
              loss=tf.keras.losses.categorical_crossentropy,
               metrics=[tf.keras.losses.categorical_crossentropy])
Xtrain = np.random.rand(20,400,22)
ytrain = np.random.rand(20,400,22)
np.random.seed(0)
sample_weight = np.random.choice([0.01, 0.1, 1], size=20)
history = model.fit(x=Xtrain, y=ytrain, sample_weight=sample_weight, epochs=4)
Epoch 1/4
1/1 [==============================] - 0s 824us/step - loss: 10.2952 - categorical_crossentropy: 34.9296
Epoch 2/4
1/1 [==============================] - 0s 785us/step - loss: 10.2538 - categorical_crossentropy: 34.7858
Epoch 3/4
1/1 [==============================] - 0s 772us/step - loss: 10.2181 - categorical_crossentropy: 34.6719
Epoch 4/4
1/1 [==============================] - 0s 766us/step - loss: 10.1903 - categorical_crossentropy: 34.5797

从结果可以看出,Keras 没有在度量计算中使用样本权重,因此它大于损失。如果我们将样本权重更改为 1,我们会得到以下结果:

2。样本权重 = 个,在 `model.compile. 中使用 metrics= 传递指标。

# Compile and train the model
model.compile(optimizer=Adam(1e-3),
              loss=tf.keras.losses.categorical_crossentropy,
               metrics=[tf.keras.losses.categorical_crossentropy])
Xtrain = np.random.rand(20,400,22)
ytrain = np.random.rand(20,400,22)
np.random.seed(0)
sample_weight = np.ones((20,))
history = model.fit(x=Xtrain, y=ytrain, sample_weight=sample_weight, epochs=4)
Epoch 1/4
1/1 [==============================] - 0s 789us/step - loss: 35.2659 - categorical_crossentropy: 35.2573
Epoch 2/4
1/1 [==============================] - 0s 792us/step - loss: 35.0647 - categorical_crossentropy: 35.0562
Epoch 3/4
1/1 [==============================] - 0s 778us/step - loss: 34.9301 - categorical_crossentropy: 34.9216
Epoch 4/4
1/1 [==============================] - 0s 736us/step - loss: 34.8076 - categorical_crossentropy: 34.7991

现在指标和损失与样本权重非常接近。我知道,由于 dropout、正则化的影响,以及在每个 epoch 结束时计算度量的事实,损失比指标略大,而损失是训练中批次的平均值。

如何获取包含样本权重的指标?

3。更新:使用样本权重,并通过 weighted_metrics=model.compile 中传递指标。

有人建议我在model.compile 中使用weighted_metrics=[...] 而不是metrics=[...]。但是,Keras 仍然没有将样本权重纳入指标的评估中。

# Compile and train the model
model.compile(optimizer=Adam(1e-3),
              loss=tf.keras.losses.categorical_crossentropy,
               weighted_metrics=[tf.keras.losses.categorical_crossentropy])
Xtrain = np.random.rand(20,400,22)
ytrain = np.random.rand(20,400,22)
np.random.seed(0)
sample_weight = np.random.choice([0.01, 0.1, 1], size=20)
history = model.fit(x=Xtrain, y=ytrain, sample_weight=sample_weight, epochs=4)
Epoch 1/4
1/1 [==============================] - 0s 764us/step - loss: 10.2581 - categorical_crossentropy: 34.9224
Epoch 2/4
1/1 [==============================] - 0s 739us/step - loss: 10.2251 - categorical_crossentropy: 34.8100
Epoch 3/4
1/1 [==============================] - 0s 755us/step - loss: 10.1854 - categorical_crossentropy: 34.6747
Epoch 4/4
1/1 [==============================] - 0s 746us/step - loss: 10.1631 - categorical_crossentropy: 34.5990

如何确保在指标中评估样本权重?

【问题讨论】:

ytrain 的形状是什么?你为Conv1D 层使用了什么 kernel_size? ytrain 和 Xtrain 的形状相同,(400,22)。我使用的内核大小为 2。 我在model.fit 函数中有它。您希望在哪里更新? sample_weight 是如何定义的? 它被计算为样本所属的 bin 大小的倒数。首先将整个数据分成 10 个 bin,对每个 bin 的频率进行评估,并为 bin 中的每个样本分配max_bin_size / bin_size 作为其样本权重。 【参考方案1】:

Keras 不会在指标评估中自动包含样本权重。这就是损失和指标之间存在巨大差异的原因。

如果您希望在评估指标时包含样本权重,请将其传递为 weighted_metrics 而不是指标。

model.compile(optimizer=Adam(1e-3), 
              loss=tf.keras.losses.categorical_crossentropy,
              weighted_metrics=[tf.keras.losses.categorical_crossentropy]))

【讨论】:

你用你的例子检查过这个吗?它也没有给出接近或相似的结果。 但是,结果的差异可以通过 dropout 和正则化来解释,它们应用于损失而不是度量。因此,正如预期的那样,损失略大于指标。 您是否尝试过移除 dropout 和正则化器?可能不会,因为删除它后仍然没有给出关闭的结果。如果您找到接近的结果(这是您最初的问题),请添加可重现的代码示例。 即使去掉了dropout和regularizers,仍然有batch的效果。损失计算为训练时期中所有批次的平均值,而度量在时期结束时计算。这种损失和指标计算方式的差异意味着它们将相等。重要的是它们相距不远。 我认为它仍然不起作用,至少对于随机的sample_weight 不起作用,它仍然给出了一个很好的区别,这永远无法用你描述的事实来解释。如果它解决了您的问题,请删除可重现的代码示例以供将来参考。【参考方案2】:

首先,分类交叉熵通常不用作度量。其次,您正在执行某种类型的 seq2seq 任务,我希望您以这种意图设计模型。

最后,在您的设置中,使用 sample_weight 仅适用于损失,它对指标或验证没有影响。您的代码中还有其他小错误。这是固定的工作代码:

ref: TF 2.3.0 training keras model using tf dataset with sample weights does not apply to metrics (为什么sample_weight 只对丢失有效)

import tensorflow as tf
from tensorflow.keras.layers import *
from tensorflow.keras.optimizers import *
from tensorflow.keras import *
import numpy as np

X_input = Input(shape=(400,22))
X = Conv1D(filters=32, kernel_size=2, activation='elu', kernel_regularizer=L2(1e-4), bias_regularizer=L2(1e-4), padding='same')(X_input)
X = Dropout(0.2)(X)
X = Conv1D(filters=32, kernel_size=2, activation='elu', kernel_regularizer=L2(1e-4), bias_regularizer=L2(1e-4), padding='same')(X)
X = Dropout(0.2)(X)
y = Conv1D(filters=22, kernel_size=1, activation='softmax', kernel_regularizer=L2(1e-4), bias_regularizer=L2(1e-4), padding='same')(X)

model = Model(X_input, y, name='mymodel')
model.compile(optimizer=Adam(1e-3), loss=tf.keras.losses.categorical_crossentropy,
metrics=[tf.keras.losses.categorical_crossentropy])

Xtrain = np.random.rand(10,400,22)
ytrain = np.random.rand(10,400,22)

history = model.fit(Xtrain, ytrain, sample_weight=np.ones(10), epochs=10)
Epoch 1/10
1/1 [==============================] - 1s 719ms/step - loss: 35.4521 - categorical_crossentropy: 35.4437
Epoch 2/10
1/1 [==============================] - 0s 20ms/step - loss: 35.5138 - categorical_crossentropy: 35.5054
Epoch 3/10
1/1 [==============================] - 0s 19ms/step - loss: 35.5984 - categorical_crossentropy: 35.5900
Epoch 4/10
1/1 [==============================] - 0s 19ms/step - loss: 35.6617 - categorical_crossentropy: 35.6533
Epoch 5/10
1/1 [==============================] - 0s 19ms/step - loss: 35.7807 - categorical_crossentropy: 35.7723
Epoch 6/10
1/1 [==============================] - 0s 19ms/step - loss: 35.9045 - categorical_crossentropy: 35.8961
Epoch 7/10
1/1 [==============================] - 0s 18ms/step - loss: 36.0590 - categorical_crossentropy: 36.0505
Epoch 8/10
1/1 [==============================] - 0s 19ms/step - loss: 36.2040 - categorical_crossentropy: 36.1956
Epoch 9/10
1/1 [==============================] - 0s 18ms/step - loss: 36.4169 - categorical_crossentropy: 36.4084
Epoch 10/10
1/1 [==============================] - 0s 32ms/step - loss: 36.6622 - categorical_crossentropy: 36.6538

在这里,如果您对每个样本不使用 sample_weight 或 1,您将获得接近/相似的分类交叉熵。

根据文档使用weighted_metrics

【讨论】:

这很有趣!根据此链接 (keras.io/api/metrics),“与损失函数非常相似,任何具有签名 metric_fn(y_true, y_pred) 的可调用函数返回一组损失(输入批次中的样本之一)都可以传递给 compile( ) 作为指标。请注意,任何此类指标都会自动支持样本加权。” 我认为样本权重将自动包含在指标评估中。如何确保在指标中使用样本权重? 我发现我需要将指标列表作为weighted_metrics 传递,而不是model.compile 函数中的“metrics”。 阅读参考答案。

以上是关于Keras weighted_metrics 在计算中不包括样本权重[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Keras学习记录之模型编译-训练-评估-预测

keras中model.compile()基本用法

顺序模型api

keras 自定义 metrics

为啥keras安装以后导入失败?

keras如何快速入门