gpt4 book ai didi

python - 在 Keras/Tensorflow 自定义损失函数中使用额外的 *trainable* 变量

转载 作者:行者123 更新时间:2023-12-04 14:11:10 26 4
gpt4 key购买 nike

我知道如何使用附加输入在 Keras 中编写自定义损失函数,而不是标准 y_true , y_pred对,见下文。我的问题是输入带有可训练变量(其中一些)的损失函数,该变量是损失梯度的一部分,因此应该更新。
我的解决方法是:

  • 输入网络一个虚拟输入 N X V大小在哪里N是观察次数和 V附加变量的数量
  • 添加 Dense()dummy_output以便 Keras 跟踪我的 V “权重”
  • 使用这一层的V我的真实输出层的自定义损失函数中的权重
  • 为此 dummy_output 使用虚拟损失函数(仅返回 0.0 和/或权重 0.0)层所以我的V “权重”仅通过我的自定义损失函数更新

  • 我的问题是:有没有更自然的 Keras/TF-like 方式来做到这一点?因为它感觉如此做作,更不用说容易出现错误。
    我的解决方法示例:
    (是的,我知道这是一个非常愚蠢的自定义损失函数,实际上事情要复杂得多)
    import numpy as np
    from sklearn.model_selection import train_test_split
    import matplotlib.pyplot as plt
    from tensorflow.keras.layers import Dense
    from tensorflow.keras.callbacks import EarlyStopping
    import tensorflow.keras.backend as K
    from tensorflow.keras.layers import Input
    from tensorflow.keras import Model

    n_col = 10
    n_row = 1000
    X = np.random.normal(size=(n_row, n_col))
    beta = np.arange(10)
    y = X @ beta

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    # my custom loss function accepting my dummy layer with 2 variables
    def custom_loss_builder(dummy_layer):
    def custom_loss(y_true, y_pred):
    var1 = dummy_layer.trainable_weights[0][0]
    var2 = dummy_layer.trainable_weights[0][1]
    return var1 * K.mean(K.square(y_true-y_pred)) + var2 ** 2 # so var2 should get to zero, var1 should get to minus infinity?
    return custom_loss

    # my dummy loss function
    def dummy_loss(y_true, y_pred):
    return 0.0

    # my dummy input, N X V, where V is 2 for 2 vars
    dummy_x_train = np.random.normal(size=(X_train.shape[0], 2))

    # model
    inputs = Input(shape=(X_train.shape[1],))
    dummy_input = Input(shape=(dummy_x_train.shape[1],))
    hidden1 = Dense(10)(inputs) # here only 1 hidden layer in the "real" network, assume whatever network is built here
    output = Dense(1)(hidden1)
    dummy_output = Dense(1, use_bias=False)(dummy_input)
    model = Model(inputs=[inputs, dummy_input], outputs=[output, dummy_output])

    # compilation, notice zero loss for the dummy_output layer
    model.compile(
    loss=[custom_loss_builder(model.layers[-1]), dummy_loss],
    loss_weights=[1.0, 0.0], optimizer= 'adam')

    # run, notice y_train repeating for dummy_output layer, it will not be used, could have created dummy_y_train as well
    history = model.fit([X_train, dummy_x_train], [y_train, y_train],
    batch_size=32, epochs=100, validation_split=0.1, verbose=0,
    callbacks=[EarlyStopping(monitor='val_loss', patience=5)])
    无论 var1 的起始值如何,似乎都可以正常工作和 var2 ( dummy_output 层的初始化)他们渴望减去 inf0分别:
    (此图来自迭代运行模型并保存这两个权重,如下所示)
    var1_list = []
    var2_list = []
    for i in range(100):
    if i % 10 == 0:
    print('step %d' % i)
    model.fit([X_train, dummy_x_train], [y_train, y_train],
    batch_size=32, epochs=1, validation_split=0.1, verbose=0)
    var1, var2 = model.layers[-1].get_weights()[0]
    var1_list.append(var1.item())
    var2_list.append(var2.item())

    plt.plot(var1_list, label='var1')
    plt.plot(var2_list, 'r', label='var2')
    plt.legend()
    plt.show()
    enter image description here

    最佳答案

    在这里回答我自己的问题,经过几天的努力,我让它在没有虚拟输入的情况下工作,我认为这更好,应该是“规范”的方式,直到 Keras/TF 简化流程。 Keras/TF 文档就是这样做的 here .
    使用带有外部可训练变量的损失函数的关键是使用自定义损失/输出 图层 其中有 self.add_loss(...)在其 call()实现,像这样:

    class MyLoss(Layer):
    def __init__(self, var1, var2):
    super(MyLoss, self).__init__()
    self.var1 = K.variable(var1) # or tf.Variable(var1) etc.
    self.var2 = K.variable(var2)

    def get_vars(self):
    return self.var1, self.var2

    def custom_loss(self, y_true, y_pred):
    return self.var1 * K.mean(K.square(y_true-y_pred)) + self.var2 ** 2

    def call(self, y_true, y_pred):
    self.add_loss(self.custom_loss(y_true, y_pred))
    return y_pred
    现在注意 MyLoss层需要 两个输入,实际 y_true和预测 y直到那时:
    inputs = Input(shape=(X_train.shape[1],))
    y_input = Input(shape=(1,))
    hidden1 = Dense(10)(inputs)
    output = Dense(1)(hidden1)
    my_loss = MyLoss(0.5, 0.5)(y_input, output) # here can also initialize those var1, var2
    model = Model(inputs=[inputs, y_input], outputs=my_loss)

    model.compile(optimizer= 'adam')
    最后,正如 TF 文档所提到的,在这种情况下,您不必指定 lossyfit()功能:
    history = model.fit([X_train, y_train], None,
    batch_size=32, epochs=100, validation_split=0.1, verbose=0,
    callbacks=[EarlyStopping(monitor='val_loss', patience=5)])
    再次注意 y_train进入 fit()作为输入之一。
    现在它的工作原理:
    var1_list = []
    var2_list = []
    for i in range(100):
    if i % 10 == 0:
    print('step %d' % i)
    model.fit([X_train, y_train], None,
    batch_size=32, epochs=1, validation_split=0.1, verbose=0)
    var1, var2 = model.layers[-1].get_vars()
    var1_list.append(var1.numpy())
    var2_list.append(var2.numpy())

    plt.plot(var1_list, label='var1')
    plt.plot(var2_list, 'r', label='var2')
    plt.legend()
    plt.show()
    enter image description here
    (我还应该提到 var1var2 的这种特定模式高度依赖于它们的初始值,如果 var1 的初始值高于 1 它实际上不会减少直到减去 inf )

    关于python - 在 Keras/Tensorflow 自定义损失函数中使用额外的 *trainable* 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64223840/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com