我想使用
Tensorflow
训练循环神经网络。我的模型为每个训练样本输出一个 1 x 100 向量。假设 y = [y_1, y_2, ..., y_100]
是我训练样本 x
的输出,预期输出是 y'= [y'_1, y'_2, ..., y'_100]
。
我希望编写一个自定义损失函数来计算该特定样本的损失,如下所示:
Loss = 1/sum(weights) * sqrt(w_1*(y_1-y'_1)^2 + ... + w_100*(y_100-y'_100)^2)
其中
weights = [w_1,...,w_100]
是给定的权重数组。
有人可以帮助我实现这样的自定义损失函数吗? (我在训练时也使用小批量)
我想强调,根据你的问题,你有两种可能性:
[1] 如果所有样本的权重相等:
您可以构建一个损失包装器。这是一个虚拟示例:
n_sample = 200
X = np.random.uniform(0,1, (n_sample,10))
y = np.random.uniform(0,1, (n_sample,100))
W = np.random.uniform(0,1, (100,)).astype('float32')
def custom_loss_wrapper(weights):
def loss(true, pred):
sum_weights = tf.reduce_sum(weights) * tf.cast(tf.shape(pred)[0], tf.float32)
resid = tf.sqrt(tf.reduce_sum(weights * tf.square(true - pred)))
return resid/sum_weights
return loss
inp = Input((10,))
x = Dense(256)(inp)
pred = Dense(100)(x)
model = Model(inp, pred)
model.compile('adam', loss=custom_loss_wrapper(W))
model.fit(X, y, epochs=3)
[2] 如果样本之间的权重不同:
您应该使用
add_loss
构建模型,以便动态考虑每个样本的权重。这是一个虚拟示例:
n_sample = 200
X = np.random.uniform(0,1, (n_sample,10))
y = np.random.uniform(0,1, (n_sample,100))
W = np.random.uniform(0,1, (n_sample,100))
def custom_loss(true, pred, weights):
sum_weights = tf.reduce_sum(weights)
resid = tf.sqrt(tf.reduce_sum(weights * tf.square(true - pred)))
return resid/sum_weights
inp = Input((10,))
true = Input((100,))
weights = Input((100,))
x = Dense(256)(inp)
pred = Dense(100)(x)
model = Model([inp,true,weights], pred)
model.add_loss(custom_loss(true, pred, weights))
model.compile('adam', loss=None)
model.fit([X,y,W], y=None, epochs=3)
使用
add_loss
时,您应该将损失涉及的所有张量作为输入层传递,并将它们传递到损失内部进行计算。
在推理时,您可以像往常一样计算预测,只需删除真实值和权重作为输入:
final_model = Model(model.input[0], model.output)
final_model.predict(X)
您可以通过以下方式实现自定义加权mse
import numpy as np
from tensorflow.keras import backend as K
def custom_mse(class_weights):
def weighted_mse(gt, pred):
# Formula:
# w_1*(y_1-y'_1)^2 + ... + w_100*(y_100-y'_100)^2 / sum(weights)
return K.sum(class_weights * K.square(gt - pred)) / K.sum(class_weights)
return weighted_mse
y_true = np.array([[0., 1., 1, 0.], [0., 0., 1., 1.]])
y_pred = np.array([[0., 1, 0., 1.], [1., 0., 1., 1.]])
weights = np.array([0.25, 0.50, 1., 0.75])
print(y_true.shape, y_pred.shape, weights.shape)
(2, 4) (2, 4) (4,)
loss = custom_mse(class_weights=weights)
loss(y_true, y_pred).numpy()
0.8
将其与模型编译一起使用。
model.compile(loss=custom_mse(weights))
这将使用提供的 weighted 矩阵计算 mse。然而,在你的问题中,你引用了
sqrt...
,我认为你的意思是root mse(rmse)。为此,您可以在 K.sqrt(K.sum(...)) / K.sum(...)
的自定义函数中使用 custom_mse
。
仅供参考,您可能还有兴趣在
class_weights
期间查看sample_weights
和Model. fit
。来自来源:
class_weight:可选字典将类索引(整数)映射到权重(浮点)值,用于对损失进行加权 功能(仅在训练期间)。这对于告诉模型很有用 “更多地关注”来自代表性不足的班级的样本。
sample_weight:训练样本的可选 Numpy 权重数组,用于对损失函数进行加权(仅在训练期间)。 您可以传递一个长度相同的平面(一维)Numpy 数组 输入样本(权重和样本之间的 1:1 映射),或者在 对于时态数据,您可以传递形状为(样本, 序列长度),对每个时间步应用不同的权重 每个样本。当 x 是数据集时,不支持此参数, 生成器或
实例,而是提供 Sample_weights 作为 x 的第三个元素。
keras.utils.Sequence
还有
loss_weights
中的Model.compile
,来自来源
loss_weights:指定标量系数(Python 浮点数)的可选列表或字典,用于对损失贡献进行加权 不同模型的输出。将通过以下方式最小化损失值 那么模型将是所有个体损失的加权和,加权 通过loss_weights系数。如果有一个列表,预计会有一个 1:1 映射到模型的输出。如果是字典,则预计会映射 将名称(字符串)输出为标量系数。
加权均方误差损失函数的类版本。
class WeightedMSE(object):
def __init__(self):
pass
def __call__(self, y_true, y_pred, weights):
sum_weights = tf.reduce_sum(weights)
resid = tf.reduce_sum(weights * tf.square(y_true - y_pred))
return resid / sum_weights