繁体   English   中英

自定义损失 function 权重在 Keras

[英]Custom loss function with weights in Keras

我是神经网络的新手。 我想在 TensorFlow 中做一个自定义损失 function,但我需要得到一个权重向量,所以我这样做了:

def my_loss(weights):
  def custom_loss(y, y_pred):
    return weights*(y - y_pred)
  return custom_loss
model.compile(optimizer='adam', loss=my_loss(weights), metrics=['accuracy'])
model.fit(x_train, y_train, batch_size=None,  validation_data=(x_test, y_test), epochs=100)

当我启动它时,我收到此错误:

InvalidArgumentError:  Incompatible shapes: [50000,10] vs. [32,10]

形状是:

print(weights.shape)
print(y_train.shape)
(50000, 10)
(50000, 10)

所以我认为这是批次的问题,我没有TensorFlow的强大背景,所以我尝试使用全局变量以天真的方式解决

batch_index = 0

然后在自定义回调中将其更新到“on_batch_begin”钩子中。 但它不起作用,这是一个可怕的解决方案。 那么,我怎样才能得到具有相应 y 的权重的确切部分? 我有办法在自定义损失中获取当前批次索引吗? 预先感谢您的帮助

Keras 允许您从全局 scope 中获取任何张量。 实际上, y_truey_pred甚至可能不使用, 就像这里一样

您的 model 可以有多个输入(您可以在推理时将此输入设为虚拟,或将权重加载到 model 中,使用单个输入)。 请注意,您仍然需要它进行验证。

import keras
from keras.layers import *
from keras import backend as K

import numpy as np

inputs_x = Input(shape=(10,))
inputs_w = Input(shape=(10,))

y = Dense(10,kernel_initializer='glorot_uniform' )(inputs_x)

model = keras.Model(inputs=[inputs_x, inputs_w], outputs=[y])

def my_loss(y_true, y_pred):
    return K.abs((y_true-y_pred)*inputs_w)

def my_metrics(y_true, y_pred):
    # just to output something
    return K.mean(inputs_w)



model.compile(optimizer='adam', loss=[my_loss], metrics=[my_metrics])

data = np.random.normal(size=(50000, 10))
labels = np.random.normal(size=(50000, 10))
weights = np.random.normal(size=(50000, 10))


model.fit([data, weights], labels, batch_size=256, validation_data=([data[:100], weights[:100]], labels[:100]), epochs=100)

要在没有权重的情况下进行验证,您需要编译另一个版本的 model,具有不同的不使用权重的损失。

UPD:还要注意,如果 Keras 返回数组而不是标量,它将总结您损失的所有元素


UPD:似乎 Tor tensorflow 2.1.0 事情变得更加复杂。 go 的方向是@marco-cerliani 指出的方向(标签、重量和数据被输入到 model 并通过.add_loss()添加自定义损失张量),但是他的解决方案对我不起作用盒子。 首先是 model 不想使用 None loss,拒绝同时接受输入和输出。 因此,我引入了额外的虚拟损失 function。 当数据集大小不能被批量大小整除时,就会出现第二个问题。 在 keras 和 tf 1.x 中,最后一批问题通常由steps_per_epochvalidation_steps参数解决,但这里如果在第一批 Epoch 2 上开始失败。所以我需要制作简单的自定义数据生成器。

import tensorflow.keras as keras
from tensorflow.keras.layers import *
from tensorflow.keras import backend as K

import numpy as np

inputs_x = Input(shape=(10,))
inputs_w = Input(shape=(10,))
inputs_l = Input(shape=(10,))


y = Dense(10,kernel_initializer='glorot_uniform' )(inputs_x)

model = keras.Model(inputs=[inputs_x, inputs_w, inputs_l], outputs=[y])

def my_loss(y_true, y_pred):
    return K.abs((y_true-y_pred)*inputs_w)

def my_metrics():
    # just to output something
    return K.mean(inputs_w)

def dummy_loss(y_true, y_pred):
    return 0.


loss = my_loss(y, inputs_l)
metric = my_metrics()

model.add_loss(loss)
model.add_metric(metric, name='my_metric', aggregation='mean')


model.compile(optimizer='adam', loss=dummy_loss)

data = np.random.normal(size=(50000, 10))
labels = np.random.normal(size=(50000, 10))
weights = np.random.normal(size=(50000, 10))

dummy = np.zeros(shape=(50000, 10)) # or in can be labels, no matter now


# looks like it does not like when len(data) % batch_size != 0
# If I set steps_per_epoch, it fails on the second epoch.

# So, I proceded with data generator

class DataGenerator(keras.utils.Sequence):
    'Generates data for Keras'
    def __init__(self, x, w, y, y2, batch_size, shuffle=True):
        'Initialization'
        self.x = x
        self.w = w
        self.y = y
        self.y2 = y2
        self.indices = list(range(len(self.x)))
        self.shuffle = shuffle
        self.batch_size = batch_size
        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        return len(self.indices) // self.batch_size

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch

        ids = self.indices[index*self.batch_size:(index+1)*self.batch_size]

        # the last None to remove weird warning
        # https://stackoverflow.com/questions/59317919
        return [self.x[ids], self.w[ids], self.y[ids]], self.y2[ids], [None]

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        if self.shuffle == True:
            np.random.shuffle(self.indices)

batch_size = 256

train_generator = DataGenerator(data,weights,labels, dummy, batch_size=batch_size, shuffle=True)

val_generator = DataGenerator(data[:2*batch_size],weights[:2*batch_size],labels[:2*batch_size], dummy[:2*batch_size], batch_size=batch_size, shuffle=True)

model.fit(x=train_generator, validation_data=val_generator,epochs=100)

这是将额外的 arguments 传递给自定义损失 function 的解决方法,在您的情况下是权重数组。 诀窍在于使用虚假输入,这些输入有助于以正确的方式构建和使用损失。 不要忘记 keras 处理固定批次尺寸

我在回归问题中提供了一个虚拟示例

def mse(y_true, y_pred, weights):
    error = y_true-y_pred
    return K.mean(K.square(error) + K.sqrt(weights))

X = np.random.uniform(0,1, (1000,10))
y = np.random.uniform(0,1, 1000)
w = np.random.uniform(0,1, 1000)

inp = Input((10,))
true = Input((1,))
weights = Input((1,))
x = Dense(32, activation='relu')(inp)
out = Dense(1)(x)

m = Model([inp,true,weights], out)
m.add_loss( mse( true, out, weights ) )
m.compile(loss=None, optimizer='adam')
m.fit(x=[X, y, w], y=None, epochs=3)

## final fitted model to compute predictions (remove W if not needed)
final_m = Model(inp, out)

像@Michael Moretti 一样,我对这一切也是新手(深度学习、Python、TensorFlow、Keras,...)。 这个问题是在 19 个月前提出的,在“TF 年”中事情进展很快。

Apparently at some point, you could just write a Python function with arguments (y_true, y_pred) and pass it to your call to model.compile() and all was well. 现在这似乎在一些简单的情况下有效,但不是一般情况下。 在试图理解为什么它对我不起作用时,我发现了这个 SO 问题和其他相关问题。 @M.Innat 对这个问题的回答让我走上了正轨。 但事实上,他相关的最终示例CustomMSE是从Keras Guide 中的 Custom Losses 部分抄录而来的。 This example shows both how to write a custom loss fully compatible with TensorFlow version: 2.7.0 , as well as how to pass additional parameters to it via the constructor of a class based on keras.losses.Loss in the call to model.compile() :

class CustomMSE(keras.losses.Loss):
    def __init__(self, regularization_factor=0.1, name="custom_mse"):
        super().__init__(name=name)
        self.regularization_factor = regularization_factor

    def call(self, y_true, y_pred):
        mse = tf.math.reduce_mean(tf.square(y_true - y_pred))
        reg = tf.math.reduce_mean(tf.square(0.5 - y_pred))
        return mse + reg * self.regularization_factor

model.compile(optimizer=keras.optimizers.Adam(), loss=CustomMSE())

为获得最佳结果,请确保自定义损失 function(即自定义损失类的call()方法)中的所有计算都使用 TensorFlow 运算符完成,并且所有输入和 Z78E6221F6393D146D146D 数据都表示为 Ftensors.CE81DB39。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM