我想为 TF 模型实现自定义优化算法。 我已阅读以下来源
但是还有很多问题。
在使用自定义优化器 API 时,似乎不可能在应用梯度步骤之前多次评估损失函数(针对不同的权重设置)。例如,在线性搜索类型的算法中,这是必要的。
我尝试手动完成所有步骤。
假设我已经像这样设置了我的模型和我的优化问题
from tensorflow.keras import layers
from tensorflow.keras import losses
from tensorflow.keras import models
model = models.Sequential()
model.add(layers.Dense(15, input_dim=10))
model.add(layers.Dense(20))
model.add(layers.Dense(1))
x_train, y_train = get_train_data()
loss = losses.MeanSquaredError()
def val_and_grads(weights):
model.set_weights(weights)
with tf.GradientTape() as tape:
val = loss(y_train, model(x_train))
grads = tape.gradient(val, model.trainable_variables)
return val, grads
initial_weights = model.get_weights()
optimal_weigths = my_fancy_optimization_algorithm(val_and_grads, initial_weights)
然而,我的函数 val_and_grads
需要 list
的权重,并从 list
的角度返回 my_fancy_optimization_algorithm
的梯度,这似乎不自然。
我可以像这样扭曲 val_and_grads
以“堆叠”返回的梯度并“拆分”传递的权重
def wrapped_val_and_grad(weights):
grads = val_and_grads(split_weights(weights))
return stack_grads(grads)
然而,这似乎非常低效。
无论如何,我不喜欢这种方法,因为我似乎会失去很多周围的 tensorflow 基础设施(在学习期间打印当前的损失函数值和指标,张量板的东西,......)。
>train_step
def CustomModel(keras.Model):
def train_step(self, data):
x_train, y_train = data
def val_and_grads(weights):
self.set_weights(weights)
with tf.GradientTape() as tape:
val = loss(y_train, self(x_train))
grads = tape.gradient(val, self.trainable_variables)
return val, grads
trainable_vars = self.trainable_variables
old_weights = self.get_weights()
update = my_fancy_update_finding_algorithm(val_and_grads, self.get_weights()) # this can do multiple evaluations of the model
self.set_weights(old_weights) # restore the weights
self.optimizer.apply_gradients(zip(update, trainable_vars))
在这里,我需要一个随附的自定义优化器,它除了通过添加 update
(new_weigths = current_weights + update) 更新当前权重外,什么都不做。
我仍然不确定这是否是最好的方法。
如果有人可以对上面的片段和想法发表评论,请指导我找到我应该考虑的任何其他资源,或者提供新的方法和其他反馈,我会非常高兴。
谢谢大家。
弗兰兹
编辑:
遗憾的是,到目前为止我没有得到任何回应。也许我的问题不够具体。作为第一个较小的问题:
鉴于第一个列表中的 model
和 val_and_grads
。我如何有效地计算整个梯度的范数?到目前为止我所做的是
import numpy as np
_, grads = val_and_grad(model.get_weights())
norm_grads = np.linalg.norm(np.concatenate([grad.numpy().flatten() for grad in grad]))
这肯定不是“正确”的方式。