在机器学习中,给定一个需要最小化的损失函数,我们通常会选择使用某种机器学习库来更新参数。例如,在TensorFlow中,我们通常会做以下事情,首先写下损失函数,
self.loss = F(\theta, \eta)self.optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) self.train_op = self.optimizer.minimize( self.loss, global_step=tf.contrib.framework.get_global_step())
然后使用 _, loss = sess.run([self.train_op, self.loss], feed_dict)
来更新参数以最小化损失函数。
在这种情况下,我们不需要关心 F(\theta, \eta) 相对于 \theta 和 \eta 的梯度的具体形式是什么。
我想知道如何使用损失函数相对于其参数的特定梯度形式来更新参数并最小化损失。也就是说,给定梯度的形式,如何使用机器学习库编写代码来进行更新。
更新1 @[隐藏人名] 提供了一个惊人的答案(见下文),帮助解决这个问题,该方法基于首先通过Adam计算一些 true_gradient
,然后将梯度修改为你想要的形式。然而,对我来说,我想知道是否有可能绕过这个步骤,直接将所需形式的梯度应用于损失函数。原因是我不知道计算出的 true_gradients
的形式,因此我无法对其进行添加。例如,我所需的梯度形式是 f(\theta)
,但如何从计算出的 true_gradients
转变为 f(\theta)
是未知的,因为我们不知道计算出的 true_gradients
的形式。
回答:
首先,值得注意的是,梯度只有一种正确的“形式”,并且它是由像TF这样的库通过自动微分自动计算的。如果你对这个梯度做任何事情,它就不再是你所考虑的损失函数的梯度。遵循它可能仍然会导致收敛(有许多定理表明,如果更新方向“足够相似”,它仍然会起作用),但值得理解的是,玩弄梯度通常会创造出不是任何函数的正确梯度的东西。如果一个人使用除梯度下降之外的任何优化器,这一点尤其重要——例如,在你的代码中你使用了Adam,如果你提供的不是正确的梯度,它可能会完全崩溃(因为它使用梯度来进行二阶估计,因此如果你搞乱了梯度,这些估计将完全错误,甚至可能导致发散/随机行为)。
然而,如果你简单地知道一个梯度(或者有充分的数学理由相信你所做的事情不会破坏优化),你可以直接在TF中应用它,利用.minimize内部调用两个函数的事实:compute_gradients 和 apply_gradients。
所以(在伪代码中)它将是类似于以下内容:
self.optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) true_gradients = self.optimizer.compute_gradients(self.loss)my_own_gradients = do_some_magical_stuff_with(true_gradients)self.train_op = self.optimizer.apply_gradients(my_own_gradients)
就是这样!