【问题标题】:How does a gradient backpropagates through random samples?如何通过随机样本进行梯度反向传播?
【发布时间】:2022-01-06 20:11:45
【问题描述】:

我正在学习策略梯度,但我很难理解梯度如何通过随机操作。来自hereIt is not possible to directly backpropagate through random samples. However, there are two main methods for creating surrogate functions that can be backpropagated through

他们有一个score function的例子:

probs = policy_network(state)
# Note that this is equivalent to what used to be called multinomial
m = Categorical(probs)
action = m.sample()
next_state, reward = env.step(action)
loss = -m.log_prob(action) * reward
loss.backward()

我试图创建一个示例:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.distributions import Normal
import matplotlib.pyplot as plt
from tqdm import tqdm

softplus = torch.nn.Softplus()

class Model_RL(nn.Module):
    def __init__(self):
        super(Model_RL, self).__init__()
        self.fc1 = nn.Linear(1, 20)
        self.fc2 = nn.Linear(20, 30)
        self.fc3 = nn.Linear(30, 2)

    def forward(self, x):
        x1 = self.fc1(x)
        x = torch.relu(x1)
        x2 = self.fc2(x)
        x = torch.relu(x2)
        x3 = softplus(self.fc3(x))
        return x3, x2, x1

# basic 

net_RL = Model_RL()

features = torch.tensor([1.0]) 
x = torch.tensor([1.0]) 
y = torch.tensor(3.0)

baseline = 0
baseline_lr = 0.1

epochs = 3

opt_RL = optim.Adam(net_RL.parameters(), lr=1e-3)
losses = []
xs = []
for _ in tqdm(range(epochs)):
    out_RL = net_RL(x)
    mu, std = out_RL[0]
    dist = Normal(mu, std)
    print(dist)
    a = dist.sample()
    log_p = dist.log_prob(a)
    
    out = features * a
    reward = -torch.square((y - out))
    baseline = (1-baseline_lr)*baseline + baseline_lr*reward
    
    loss = -(reward-baseline)*log_p

    opt_RL.zero_grad()
    loss.backward()
    opt_RL.step()
    losses.append(loss.item())

这似乎神奇地工作得很好,我不明白渐变是如何通过的,因为他们提到它不能通过随机操作(但后来不知何故)。

现在由于梯度无法通过我尝试替换的随机操作 mu, std = out_RL[0]mu, std = out_RL[0].detach() 导致错误: RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn。如果梯度不通过随机操作,我不明白为什么要在操作之前分离张量。

【问题讨论】:

标签: python pytorch reinforcement-learning backpropagation


【解决方案1】:

确实,采样不是一个可微操作本身。但是,有两种(广泛的)方法可以缓解这种情况 - [1] REINFORCE 方式和 [2] 重新参数化 方式。由于您的示例与 [1] 有关,因此我将回答 REINFORCE。

REINFORCE 所做的是完全摆脱了计算图中的采样操作。但是,采样操作仍然在图表之外。所以,你的陈述

..梯度如何通过随机操作..

不正确。它通过任何随机操作。让我们看看你的例子

mu, std = out_RL[0]
dist = Normal(mu, std)
a = dist.sample()
log_p = dist.log_prob(a)

a 的计算不涉及创建计算图。它在技术上相当于从数据集中插入一些离线数据(如在监督学习中)

mu, std = out_RL[0]
dist = Normal(mu, std)
# a = dist.sample()
a = torch.tensor([1.23, 4.01, -1.2, ...], device='cuda')
log_p = dist.log_prob(a)

由于我们事先没有离线数据,因此我们动态地创建它们.sample() 方法仅能做到这一点。

所以,图上没有随机操作。 log_p 确定性地取决于 mustd,就像任何标准计算图一样。如果你像这样切断连接

mu, std = out_RL[0].detach()

..当然会投诉。

另外,不要被这个操作弄糊涂了

dist = Normal(mu, std)
log_p = dist.log_prob(a)

因为它本身不包含任何随机性。这只是为Normal 分发编写乏味的log-likelihood formula 的捷径。

【讨论】:

  • 所以澄清一下,mustd 在延伸到 Normal(mu, std) 的计算图中。然后我们用.sample创建一些不在计算图中的数据,然后用dist.log_prob将其插入计算图中?
  • 当然。 @企鹅
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-24
  • 2020-01-07
  • 1970-01-01
  • 1970-01-01
  • 2019-04-16
  • 2018-05-23
相关资源
最近更新 更多