首页 > 解决方案 > 了解 Keras 优化器的 get_updates(以及一般的张量评估)

问题描述

我正在尝试制作一个根据损失调整其学习率的优化器。在我开始这种方法之后,我意识到优化器是如何工作的,并且我应该制作一个学习率调度器。

无论如何,我很想知道为什么我目前的方法不起作用,因为我认为这将帮助我最终掌握符号张量和数组之间的区别。

特别是代码运行和损失正在减少,但是

  1. (已修复,由于缩进问题,学习率没有更新)
  2. print_tensor 调用似乎没有做任何事情,更新中插入的另一个 K.print_tensor(counter,'C') 也没有——这使得调试变得困难。目前,该算法似乎非常不稳定,并且很难在没有输出的情况下进行调试。
    • 现在只需使用回调来打印东西
  3. 我不确定在 switch 语句中返回 [0.0,0.0,0.0] 是处理 if X do Y(否则什么都不做)情况的首选方法。此外,无论条件如何,K.switch 似乎都会评估双方
    • 固定使用类似 K.update(a, K.switch(bool, a, 0))
  4. 输出没有什么意义,事情似乎没有按预期更新。
    • 返回列表的评估顺序是否不保证?如果是这样,我怎么能做到这一点。
import keras.backend as K
import numpy as np
from keras import callbacks, optimizers
from keras.models import Sequential
from keras.layers import Dense
from keras.legacy import interfaces


class AutoOptim(optimizers.Nadam):

  def __init__(self,**kwargs):
    super().__init__(**kwargs)
    with K.name_scope(self.__class__.__name__):
      self.counter = K.variable(0, name='counter',dtype='int32')
      self.lr_cand = K.variable(self.lr, name='lr_cand')
      self.lastloss= K.variable(1e9,   name='lastloss')
      self.dloss   = K.variable([1,0,0],   name='dloss')
      self.lr_update_facs = K.constant([1.0, 1.3, 1.0/1.3])

  @interfaces.legacy_get_updates_support
  def get_updates(self, loss, params):

    dloss_update = K.update( self.dloss[ (self.counter+2) % 3 ] , self.dloss[ (self.counter+2) % 3 ] + (self.lastloss - loss) )

    lastloss_save = K.update( self.lastloss, loss )

    update_lr  =  K.update(self.lr_cand, K.switch( self.counter % 18, self.lr_cand, self.lr_cand * K.gather(self.lr_update_facs, K.argmax(self.dloss) ) ) )
    reset_hist =  K.update(self.dloss,   K.switch( self.counter % 18, self.dloss, K.constant( [0.0,0.0,0.0]) ) )

    lr_upd = K.update(self.lr, self.lr_cand * K.gather( self.lr_update_facs, self.counter % 3 ) )
    super_updates = super().get_updates(loss,params)
    counter_update = K.update(self.counter,self.counter+1 )

    updates = [dloss_update, lastloss_save, update_lr, reset_hist, lr_upd, super_updates, counter_update]

    return updates

model = Sequential()
model.add(Dense(1, input_dim=2, activation='relu'))

opt = AutoOptim()
model.compile(loss='mae', optimizer=opt, metrics=['accuracy'])


class My_Callback(callbacks.Callback):
  def on_batch_end(self, batch, logs={}):
    print(K.eval(self.model.optimizer.counter)-1, K.eval(self.model.optimizer.lr), K.eval(self.model.optimizer.lastloss), K.eval(self.model.optimizer.dloss))


#%%
X=np.random.rand(500,2)
Y=(X[:,0]+X[:,1])/2

model.fit(X,Y,epochs=1, callbacks=[My_Callback()], batch_size=10, verbose=0)

我希望看到学习率在 3 个值(当前、略高、略低)之间循环,并每 18 个时期设置一个新的“当前”值。

我的行为相当不稳定,dloss 和 lr 没有按预期更新。

标签: tensorflowoptimizationkeras

解决方案


代码格式问题:

没有调用 get_updates 方法,因为缩进问题导致 get_updates() 成为 __init__() 的一部分。因此,Nadam 的 get_updates() 被调用。

一旦缩进问题得到解决,AutoOptim 的 get_updates() 就会被调用。

您可以在 get_updates() 方法中打印如下变量的值:

print(f'Learning rate: {K.get_session().run([self.lr,self.lr_cand])}')

推荐阅读