当给定梯度下降中的迭代更新规则时,如何获得损失公式?

人工智能 机器学习 强化学习 梯度下降 目标函数
2021-10-27 18:20:27

来自强化学习书第 13.3 节

在此处输入图像描述

使用pytorch,我需要计算一个损失,然后在内部计算梯度。

如何从以关于梯度的迭代更新形式表示的方程中获得损失?

在这种情况下:

θθ+αγtGθlnπ(At|St,θ)

会有什么损失?

一般来说,如果更新规则是

θθ+αCθg(x|θ)

对于一些通用(可导出)函数g由θ参数化?

2个回答

您可以在以下 URL 的 PyTorch 中找到 REINFORCE 算法(如您的问题中所定义)的实现:https ://github.com/JamesChuanggg/pytorch-REINFORCE/ 。首先,我想指出,策略可以表示或实现为神经网络,其中输入是状态(您当前所处的状态),输出是“您可以从中采取的行动的概率分布”作为输入接收到的状态”。

在 Python 模块https://github.com/JamesChuanggg/pytorch-REINFORCE/blob/master/reinforce_discrete.py中,策略被定义为具有 2 个线性层的神经网络,其中第一个线性层之后是 ReLU 激活函数,而第二个后面是 soft-max。在同一个 Python 模块中,作者还定义了另一个名为 的类REINFORCE,该类创建一个Policy对象(在__init__方法中)并将其定义为该类的属性。该类REINFORCE还定义了两个方法select_actionupdate_parameters. 这两个方法是从模块中调用的,其中实现了算法main.py的主循环。REINFORCE在同一个主循环中,作者声明了 lists entropieslog_probs并且rewards. 请注意,这些列表在每一集都会重新初始化。从该方法返回一个“log_prob”和一个“熵” select_action,而在执行一个环境步骤后从环境返回一个“奖励”。该环境由 OpenAI 的 Gym 库提供。列表entropies,log_probs然后rewards用于更新参数,即它们由update_parameters类中定义的方法使用REINFORCE

现在让我们更好地了解这些方法select_actionupdate_parameters实际做了什么。

select_action首先调用forward类的方法,该方法Policy返回 NN 前向传递的输出(即 soft-max 层的输出),因此它返回选择每个可用动作的概率(从作为输入给出的状态) )。然后它选择与第一个动作关联的概率(我猜,它选择与具有最高概率的动作关联的概率),用prob(在源代码中)表示。本质上,到目前为止我所描述的关于这种select_action方法的是计算π(AtSt,θ)(如您问题的伪代码所示)。之后,select_action作者也用同样的方法计算了我刚才提到的那个概率的对数(即与概率最高的动作相关的一个,即 的对数prob),记为log_prob在相同的方法中,计算熵(如本答案中所定义)。实际上,作者仅使用一种分布(而不是两种)来计算熵:更具体地说,熵的计算方式如下entropy = -(probs*probs.log()).sum(). 事实上,熵损失函数通常需要真实标签(正如我在上面链接到的答案中所解释的那样),但是在这种情况下,我们没有真实标签(假设我们正在执行 RL 而不是监督学习)。尽管如此,在这种情况下,我无法真正告诉你为什么熵是这样计算的。最后,方法select_action然后返回action[0], log_prob, entropy

首先,我想指出该方法update_parameters仅在每集结束时调用(在main.py模块中)。在同样的方法中,一个被调用的变量loss首先被初始化为零。在该方法中,我们然后迭代当前情节的奖励列表。在该update_parameters方法的循环内,计算返回R值。R也乘以γ. 在每个时间步,损失计算如下

loss = loss - (log_probs[i]*(Variable(R).expand_as(log_probs[i])).cuda()).sum() - (0.0001*entropies[i].cuda()).sum()

loss是通过减去前一个来计算loss

(log_probs[i]*(Variable(R).expand_as(log_probs[i])).cuda()).sum() - (0.0001*entropies[i].cuda()).sum()

其中log_probs是方法中计算的对数概率select_actionlog_probs是部分logπ(AtSt,θ)你的伪代码的更新规则。log_probs然后乘以 return R然后我们将这个乘法的结果与向量的所有元素相加。然后我们用熵乘以 0.0001 减去刚刚获得的结果。我真的不能告诉你为什么作者决定以这种方式实现损失。我需要多考虑一下。

以下文章也可能有用:https ://pytorch.org/docs/stable/distributions.html 。

插话是因为我有同样的问题,偶然发现了你的帖子。您的问题的一般版本似乎仍未得到解答。

一般来说,一个格式良好的梯度更新规则是训练网络所需要的。我们正在考虑转换为“损失函数”,因为这是 pytorch 通过其 autograd 框架为训练网络提供的结构中的典型流程。

但是 pytorch 损失函数实际上只是我们要计算梯度的嵌套操作列表中的最后一个。所以如果你已经知道你的梯度更新规则,把它写成 pytorch“损失函数”的最简单方法是作为梯度更新规则相对于网络输出的积分——然后 pytorch 将计算你的梯度更新规则你自动。

因此,在您的示例中,损失函数将是:

αtGlnπ(At|St,θt)

正如@Brale 和其他人已经指出的那样。有减号是因为 pytorch 优化器通常会执行最小化,但您的梯度更新规则旨在最大化。

希望这个解释对仍在学习 pytorch 的其他人有所帮助!另外,我强烈建议任何刚开始使用 pytorch 的人在此处阅读他们最新的 autograd教程