给定前馈步骤中张量的索引版本,pytorch 如何执行反向微分?

Posted

技术标签:

【中文标题】给定前馈步骤中张量的索引版本,pytorch 如何执行反向微分?【英文标题】:How does pytorch perform the reverse-differentiation given an indexed version of a tensor in the feedforward step? 【发布时间】:2021-09-26 05:37:42 【问题描述】:

部分代码改编自 Deep learning with Pytorch 一书

脚本:线性回归(尝试在给定 t_u 的情况下预测 t_c)

t_c = torch.tensor([0.5, 14.0, 15.0, 28.0, 11.0, 8.0,
                    3.0, -4.0, 6.0, 13.0, 21.0])
t_u = torch.tensor([35.7, 55.9, 58.2, 81.9, 56.3, 48.9,
                    33.9, 21.8, 48.4, 60.4, 68.4])

def model(t_u, w, b):
    return w * t_u + b

def loss_fn(t_p, t_c):
    squared_diffs = (t_p - t_c)**2
    return squared_diffs.mean()

params = torch.tensor([1.0, 0.0], requires_grad=True)

loss = loss_fn(model(t_u, params[0], params[1]), t_c)
loss.backward()

print(params.grad)

在这里,我将 params 的第 0 和第 1 个索引作为输入传递给 model 函数,该函数执行标量到向量的乘法和加法。

我的问题是,PyTorch 究竟在做什么来计算 params 张量的梯度? “前馈”步骤使用params 张量的两个子张量,而不是我所熟悉的用于偏差和权重的单独张量。

我的猜测是:params[0]params[1] 都是对 params 中元素的引用,并且它们都有自己独特的渐变存储在 params.grad 的某处。所以.backward() 调用将params[0]params[1] 视为新的单独张量(好像我们暂时有两个单独的张量-weightbias)并更新它们的梯度(params[0].gradparams[1].grad) ,因此更新params.grad,因为它们是对它的引用。

【问题讨论】:

【参考方案1】:

这里的主要思想是索引操作返回张量的新视图。如果您不使用就地操作(+=、-= 等),则“视图”并不重要,您可以将其视为另一个张量。

在这种情况下,索引操作与加法或矩阵乘法等其他操作没有什么不同——输入(原始张量)、输出(选择的张量)和梯度(如果选择,则为 1,否则为零*)。然后像往常一样进行反向传播。

* 更具体地说,如果从输入条目中选择输出条目,则输入条目相对于输出条目的梯度为 1;否则为 0。

编辑: 也许这样看更容易:

a = d_params[0]
c = W*a+b
--------------------------
dc/d_params 
= dc/d_params[0], d_params[1], d_params[2], ...
--------------------------
dc/d_params[0]
= dc/da * da/d_params[0]
= dc/da * 1
= W
--------------------------
dc/d_params[1], dc/d_params[2], ... = 0

【讨论】:

嗯,我不确定我是否完全理解。你的意思是 d_params/d_params[0] = 1?对于这个例子,如果我们有单独的权重和偏置张量,我们将有 dC/dW 和 dC/dB。现在有了可微分索引操作,我将如何表达 dC/d_params 的链式规则表达式?

以上是关于给定前馈步骤中张量的索引版本,pytorch 如何执行反向微分?的主要内容,如果未能解决你的问题,请参考以下文章

pytorch-(torch.take())根据索引返回指定索引上的数据集合

如何在pytorch中展平张量?

如何在 PyTorch 中获取张量的值?

PyTorch 张量是如何实现的?

PyTorch: 张量的拼接切分索引

pytorch中gather函数的理解。