使用pytorch,我需要计算一个损失,然后在内部计算梯度。
如何从以关于梯度的迭代更新形式表示的方程中获得损失?
在这种情况下:
会有什么损失?
一般来说,如果更新规则是
对于一些通用(可导出)函数由θ参数化?
使用pytorch,我需要计算一个损失,然后在内部计算梯度。
如何从以关于梯度的迭代更新形式表示的方程中获得损失?
在这种情况下:
会有什么损失?
一般来说,如果更新规则是
对于一些通用(可导出)函数由θ参数化?
您可以在以下 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_action
和update_parameters
. 这两个方法是从模块中调用的,其中实现了算法main.py
的主循环。REINFORCE
在同一个主循环中,作者声明了 lists entropies
,log_probs
并且rewards
. 请注意,这些列表在每一集都会重新初始化。从该方法返回一个“log_prob”和一个“熵” select_action
,而在执行一个环境步骤后从环境返回一个“奖励”。该环境由 OpenAI 的 Gym 库提供。列表entropies
,log_probs
然后rewards
用于更新参数,即它们由update_parameters
类中定义的方法使用REINFORCE
。
现在让我们更好地了解这些方法select_action
和update_parameters
实际做了什么。
select_action
首先调用forward
类的方法,该方法Policy
返回 NN 前向传递的输出(即 soft-max 层的输出),因此它返回选择每个可用动作的概率(从作为输入给出的状态) )。然后它选择与第一个动作关联的概率(我猜,它选择与具有最高概率的动作关联的概率),用prob
(在源代码中)表示。本质上,到目前为止我所描述的关于这种select_action
方法的是计算(如您问题的伪代码所示)。之后,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_action
。log_probs
是部分你的伪代码的更新规则。log_probs
然后乘以 return R
。然后我们将这个乘法的结果与向量的所有元素相加。然后我们用熵乘以 0.0001 减去刚刚获得的结果。我真的不能告诉你为什么作者决定以这种方式实现损失。我需要多考虑一下。
以下文章也可能有用:https ://pytorch.org/docs/stable/distributions.html 。
插话是因为我有同样的问题,偶然发现了你的帖子。您的问题的一般版本似乎仍未得到解答。
一般来说,一个格式良好的梯度更新规则是训练网络所需要的。我们正在考虑转换为“损失函数”,因为这是 pytorch 通过其 autograd 框架为训练网络提供的结构中的典型流程。
但是 pytorch 损失函数实际上只是我们要计算梯度的嵌套操作列表中的最后一个。所以如果你已经知道你的梯度更新规则,把它写成 pytorch“损失函数”的最简单方法是作为梯度更新规则相对于网络输出的积分——然后 pytorch 将计算你的梯度更新规则你自动。
因此,在您的示例中,损失函数将是:
正如@Brale 和其他人已经指出的那样。有减号是因为 pytorch 优化器通常会执行最小化,但您的梯度更新规则旨在最大化。
希望这个解释对仍在学习 pytorch 的其他人有所帮助!另外,我强烈建议任何刚开始使用 pytorch 的人在此处阅读他们最新的 autograd教程