【问题标题】:Keras Loss Function with Additional Dynamic Parameter带有附加动态参数的 Keras 损失函数
【发布时间】:2018-10-11 22:40:14
【问题描述】:

我正在为 deep-q 网络实现优先体验回放,规范的一部分是将梯度乘以所谓的重要性采样 (IS) 权重。梯度修改在以下论文的第 3.4 节中讨论:https://arxiv.org/pdf/1511.05952.pdf 我正在努力创建一个自定义损失函数,该函数除了y_truey_pred 之外还接受一系列 IS 权重。

这是我的模型的简化版本:

import numpy as np
import tensorflow as tf

# Input is RAM, each byte in the range of [0, 255].
in_obs = tf.keras.layers.Input(shape=(4,))

# Normalize the observation to the range of [0, 1].
norm = tf.keras.layers.Lambda(lambda x: x / 255.0)(in_obs)

# Hidden layers.
dense1 = tf.keras.layers.Dense(128, activation="relu")(norm)
dense2 = tf.keras.layers.Dense(128, activation="relu")(dense1)
dense3 = tf.keras.layers.Dense(128, activation="relu")(dense2)
dense4 = tf.keras.layers.Dense(128, activation="relu")(dense3)

# Output prediction, which is an action to take.
out_pred = tf.keras.layers.Dense(2, activation="linear")(dense4)

opt     = tf.keras.optimizers.Adam(lr=5e-5)
network = tf.keras.models.Model(inputs=in_obs, outputs=out_pred)
network.compile(optimizer=opt, loss=huber_loss_mean_weighted)

这是我的自定义损失函数,它只是 Huber 损失乘以 IS 权重的实现:

'''
 ' Huber loss: https://en.wikipedia.org/wiki/Huber_loss
'''
def huber_loss(y_true, y_pred):
  error = y_true - y_pred
  cond  = tf.keras.backend.abs(error) < 1.0

  squared_loss = 0.5 * tf.keras.backend.square(error)
  linear_loss  = tf.keras.backend.abs(error) - 0.5

  return tf.where(cond, squared_loss, linear_loss)

'''
 ' Importance Sampling weighted huber loss.
'''
def huber_loss_mean_weighted(y_true, y_pred, is_weights):
  error = huber_loss(y_true, y_pred)

  return tf.keras.backend.mean(error * is_weights)

重要的是is_weights 是动态的,即每次调用fit() 时都不同。因此,我不能简单地关闭is_weights,如下所述:Make a custom loss function in keras

我在网上找到了这段代码,它似乎使用Lambda 层来计算损失:https://github.com/keras-team/keras/blob/master/examples/image_ocr.py#L475 看起来很有希望,但我很难理解它/使其适应我的特定问题。任何帮助表示赞赏。

【问题讨论】:

  • 可以将is_weights 视为网络的输入变量吗?如果是这样,您可以通过model.add_loss( huber_loss_mean_weightd( y_true, y_pred, is_weight) )
  • @user36624 当然,is_weights 可以被视为输入变量。使用add_loss 似乎是一个干净的解决方案,但我不知道如何使用它。例如,在您的代码 sn-p 中,y_truey_pred 来自哪里? y_true 是否对应于我的代码中的 out_pred?在我add_loss 之后,我使用什么作为loss 编译参数?

标签: tensorflow keras


【解决方案1】:

好的。这是一个例子。

from keras.layers import Input, Dense, Conv2D, MaxPool2D, Flatten
from keras.models import Model
from keras.losses import categorical_crossentropy

def sample_loss( y_true, y_pred, is_weight ) :
    return is_weight * categorical_crossentropy( y_true, y_pred ) 

x = Input(shape=(32,32,3), name='image_in')
y_true = Input( shape=(10,), name='y_true' )
is_weight = Input(shape=(1,), name='is_weight')
f = Conv2D(16,(3,3),padding='same')(x)
f = MaxPool2D((2,2),padding='same')(f)
f = Conv2D(32,(3,3),padding='same')(f)
f = MaxPool2D((2,2),padding='same')(f)
f = Conv2D(64,(3,3),padding='same')(f)
f = MaxPool2D((2,2),padding='same')(f)
f = Flatten()(f)
y_pred = Dense(10, activation='softmax', name='y_pred' )(f)
model = Model( inputs=[x, y_true, is_weight], outputs=y_pred, name='train_only' )
model.add_loss( sample_loss( y_true, y_pred, is_weight ) )
model.compile( loss=None, optimizer='sgd' )
print model.summary()

注意,由于您已通过add_loss() 添加损失,因此您不必通过compile( loss=xxx ) 进行添加。

关于训练模型,除了将 y_true 移动到输入端外,没有什么特别之处。见下文

import numpy as np 
a = np.random.randn(8,32,32,3)
a_true = np.random.randn(8,10)
a_is_weight = np.random.randint(0,2,size=(8,1))
model.fit( [a, a_true, a_is_weight] )

最后,您可以制作一个测试模型(共享model 中的所有权重)以便于使用,即

test_model = Model( inputs=x, outputs=y_pred, name='test_only' )
a_pred = test_model.predict( a )

【讨论】:

  • 太棒了!我非常感谢您花时间创建一个示例。我已经为此苦苦挣扎了一段时间,这个解决方案比我在问题中引用的 OCR 示例要干净得多。谢谢。
  • 通过生成器函数获取火车和测试输入时,此方法是否有效?
  • 是的。我想是的。
  • @pitfall,这对于多个损失函数是否相同。
猜你喜欢
  • 2021-07-28
  • 2018-08-26
  • 2019-12-06
  • 2018-10-10
  • 2018-10-21
  • 2020-10-05
  • 2021-04-26
  • 1970-01-01
  • 2019-04-11
相关资源
最近更新 更多