简体   繁体   English

在 Keras 中使用 add_loss 回调

[英]Callback with add_loss in Keras

I am trying to implement a VAE style network in Keras.我正在尝试在 Keras 中实现 VAE 风格的网络。 I compute my negative log-likelihood and KL divergence and add them to my model with model.add_loss(NLL) and model.add_loss(KL) , respectively.我计算了我的负对数似然和 KL 散度,并分别使用model.add_loss(NLL)model.add_loss(KL)将它们添加到我的模型中。

I would like to scale my KL term as training progresses ("KL-annealing").我想随着训练的进行(“KL 退火”)扩展我的 KL 术语。 I attempted to do this with custom callback ( detailed here ), but the KL loss term does not get updated - the model.add_loss(KL) term is constant over time, despite the KL weight getting updated (see Figure).我尝试使用自定义回调(此处详细说明)来执行此操作,但 KL 损失项未更新 - 尽管 KL 权重已更新,但model.add_loss(KL)项随时间保持不变(见图)。

Loss over training epochs How can I make the model.add_loss(KL) term depend on KL_weight ?训练时期的损失如何使model.add_loss(KL)项取决于KL_weight

Code to demonstrate the idea:代码来演示这个想法:

...
<NLL calculations>
...

# Add the first loss to the model, the NLL:
model.add_loss(NLL)

from keras.callbacks import Callback

klstart = 40
# number of epochs over which KL scaling is increased from 0 to 1
kl_annealtime = 20

weight = tf.keras.backend.variable(0.0) #intialiase KL weight term
class AnnealingCallback(Callback):
    def __init__(self, weight):
        self.weight = weight
    def on_epoch_end (self, epoch, logs={}):
        if epoch > klstart :
            new_weight = min(tf.keras.backend.get_value(self.weight) + (1./ kl_annealtime), 1.)
            tf.keras.backend.set_value(self.weight, new_weight)
        print ("Current KL Weight is " + str(tf.keras.backend.get_value(self.weight)))

# Now the KL divergence:
<KL weight calculations>
KL = weight*tf.reduce_mean(tfp.distributions.kl_divergence(p, q))
model.add_loss(KL)

# Now compile the model with a specified optimiser
opt = tf.keras.optimizers.Adam(lr=0.001,clipnorm=0.1)
model.compile(optimizer=opt)

# Monitor how the NLL and KL divergence differ over time
model.add_metric(KL, name='kl_loss', aggregation='mean')
model.add_metric(NLL, name='mse_loss', aggregation='mean')

ops.reset_default_graph()
history=model.fit(Y_portioned, # Input or "Y_true"
                    verbose=1,
                    callbacks=[earlystopping_callback,callback_reduce_lr,AnnealingCallback(weight)],
                    epochs=650,
                    batch_size=8
                    ) # <- Increase batch size for speed up

Versions: TensorFlow 2.1.0, Keras 2.2.4版本:TensorFlow 2.1.0、Keras 2.2.4

Many thanks in advance提前谢谢了

So I was exactly looking for this implementation in Keras when I came across your post.所以当我看到你的帖子时,我正是在 Keras 中寻找这个实现。 After a while I seem to have found only two mistakes:过了一会儿,我似乎只发现了两个错误:

  1. You declared a tf variable out of the class context so it was not recognized.您在类上下文之外声明了一个 tf 变量,因此无法识别它。
  2. for the first reason you didn't properly instantiate the weight.第一个原因是您没有正确实例化权重。

the corrected version would look like this:更正后的版本如下所示:

#start = klstart
#time = kl_annealtime

class AnnealingCallback(keras.callbacks.Callback):
    def __init__(self, weight=tf.keras.backend.variable(0.0), start=20, time=40):
        self.weight = weight
        self.start = start
        self.time = time    
    def on_epoch_end (self, epoch, logs={}):
        if epoch > self.start :
            new_weight = min(tf.keras.backend.get_value(self.weight) + (1./self.time), 1.)
            tf.keras.backend.set_value(self.weight, new_weight)
        print("Current KL Weight is " + str(tf.keras.backend.get_value(self.weight)))

Now you can instantiate the weight:现在您可以实例化权重:

AC = AnnealingCallback()
w = AC.weight

which pre-multpiplies your KL-divergence.它预先乘以您的 KL 散度。

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

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