如何在TensorFlow自定义训练循环中考虑L1和L2正则化?

3
当使用model.fit_on_batch方法和自定义训练循环时,我意识到在自定义训练循环代码中,损失和梯度没有考虑任何l1-l2正则化器,因此optimizer.apply_gradients方法不考虑正则化器。下面是展示这一点的代码,但这个想法非常简单。所以我的问题是是否有一种方法以优化器详细信息不可知的方式使用所有这些优化器来考虑正则化器。在Keras中如何实现?另外,model.fit_on_batch返回一个值,而不是文档字符串中所述的损失。我想知道这个返回值是什么。

代码

为了看到这个效果,首先创建一些数据

x=tf.constant([[1]])
y=tf.constant([[1]])

并创建一个函数来制作可复制的模型。
def make_model(l1=.01,l2=.01):
    tf.random.set_seed(42)
    np.random.seed(42)
    model=tf.keras.models.Sequential([
        tf.keras.layers.Dense(2,'softmax',
                              use_bias=False,
                              kernel_regularizer=tf.keras.regularizers.l1_l2(l1=l1,l2=l2),
                              input_shape=(1,))
    ])
    return model

现在运行Keras的train_on_batch函数。
model=make_model()
loss_object=tf.keras.losses.SparseCategoricalCrossentropy()
optimizer=tf.keras.optimizers.RMSprop()
model.compile(loss=loss_object,optimizer=optimizer)
model.train_on_batch(x,y)

并将输出与上面链接中解释的自定义训练循环以及此处进行比较。

model=make_model()
loss_object=tf.keras.losses.SparseCategoricalCrossentropy()
optimizer=tf.keras.optimizers.RMSprop()

@tf.function
def train_step(x,y):

    with tf.GradientTape() as tape:
        predictions  = model(x)
        loss = loss_object(y, predictions)

    gradients = tape.gradient(loss, model.trainable_variables)    
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))
    return loss

train_step(x,y).numpy()

除非l1==0且l2==0,否则您会发现这两个结果是不同的。
2个回答

6

实际上,我在Aurelien Geron的书中找到了答案:enter image description here

事实上,在我实现以下代码后,我发现这在tensorflow自定义训练指南中有所涉及(我不知道为什么它没有出现在问题提到的教程中,因为这是一个重要的点)。那里提供的解决方案比这里提到的更通用,但我仍然保留这个方案,因为它可以更清楚地说明正在发生的事情。

因此,修改自定义训练循环就像简单地进行以下操作:

def add_model_regularizer_loss(model):
    loss=0
    for l in model.layers:
        if hasattr(l,'layers') and l.layers: # the layer itself is a model
            loss+=add_model_loss(l)
        if hasattr(l,'kernel_regularizer') and l.kernel_regularizer:
            loss+=l.kernel_regularizer(l.kernel)
        if hasattr(l,'bias_regularizer') and l.bias_regularizer:
            loss+=l.bias_regularizer(l.bias)
    return loss

def train_step(x,y):

    with tf.GradientTape() as tape:
        predictions  = model(x)
        loss = loss_object(y, predictions)
        loss += add_model_regularizer_loss(model)

    gradients = tape.gradient(loss, model.trainable_variables)    
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))
    return loss

回答我问题的第二部分,就是Keras模型fit方法返回的损失值。

2

根据TF官网上的推荐做法,应该使用model.losses。例如:

def train_step(x,y):

    with tf.GradientTape() as tape:
        predictions  = model(x)
        loss = loss_object(y, predictions)
        loss += tf.add_n(model.losses)   # <--- SEE HERE

    gradients = tape.gradient(loss, model.trainable_variables)    
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))
    return loss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接