Pytorch 学习 - 6.pytorch 张量数学-自动求取梯度

先掌握pytorch,学好pytorch,  才能学好人工智能

autograd

torch.autograd.backward

torch.autograd.backward 是 PyTorch 中用于自动计算张量(tensor)梯度的函数。在深度学习和神经网络训练中,梯度计算是反向传播算法的核心部分,它允许我们更新模型的权重以最小化损失函数。下面是对 torch.autograd.backward 函数的详细解释:

功能

torch.autograd.backward 函数用于计算图中所有需要梯度的叶子节点的梯度。这些叶子节点通常是模型的参数(如权重和偏置),它们被标记为 requires_grad=True。在调用此函数后,PyTorch 会自动计算这些叶子节点相对于某个标量(通常是损失函数值)的梯度。

使用方法

  1. 准备张量:首先,你需要确保你的模型参数(张量)设置了 requires_grad=True。这意味着 PyTorch 会跟踪对这些张量的所有操作,以便后续计算梯度。

  2. 前向传播:执行模型的前向传播,计算损失值。这个损失值应该是一个标量(单个数值),因为 torch.autograd.backward 默认只能对标量进行操作。如果损失值是一个向量或矩阵,你需要指定一个 gradient_arguments 参数来指明对每个元素求导的权重。

  3. 调用 backward:调用 torch.autograd.backward() 或张量自身的 .backward() 方法来计算梯度。对于标量损失,不需要额外的参数。

  4. 更新参数:使用优化器(如 SGD, Adam 等)根据计算出的梯度更新模型参数。

参数

  • tensor(可选):如果你不是对某个标量直接调用 torch.autograd.backward(),而是对一个非标量张量调用,你需要传递一个与这个张量形状相同的 gradient 参数,指明对每个元素的梯度贡献。
  • retain_graph(布尔值,默认为 False):如果设置为 True,则保留计算图,用于多次调用 backward。这在某些情况下很有用,比如当你需要在一个模型的不同部分多次计算梯度时。
  • create_graph(布尔值,默认为 False):如果设置为 True,则对梯度计算图进行记录,以便计算更高阶的梯度。
  • grad_tensors(可选):如果 tensor 不是标量,则需要传递一个与 tensor 形状相同的张量,表示对每个元素的梯度权重。

注意事项

  • 每次调用 backward 后,梯度会被累积到 .grad 属性中,而不是被覆盖。因此,如果你不想累积梯度,需要在每次调用 backward 前调用 .zero_() 方法清除梯度。
  • 默认情况下,backward 只能对标量进行操作。如果你需要对非标量进行操作,需要传递 grad_tensors 参数。
  • 在某些情况下,如循环神经网络中,可能需要使用 retain_graph=True 来保留计算图,但这会增加内存消耗。

通过理解 torch.autograd.backward 的工作原理,你可以更有效地进行深度学习模型的训练和优化。

Pytorch 学习 - 6.pytorch 张量数学-自动求取梯度_第1张图片

根据链式法则和乘法法则,我们可以这样计算:

b*1+a*1 = b+a = 2 + 3 = 5

import torch 


w = torch.tensor([1.],requires_grad=True) 
x = torch.tensor([2.],requires_grad=True) 

a = torch.add(x,w)
b = torch.add(w,1)
y0 = torch.mul(a,b)
y1 = torch.add(a,b)
loss = torch.cat([y0,y1],dim=0) #[y0,y1]

grad_tensors = torch.tensor([1.,2.])
loss.backward(gradient=grad_tensors)
print('output','\n', 'x :', x,'w :', w,'a :', a,'b :', b,'y0 :', y0,'y1 :', y1,'loss :', loss)
# 查看梯度
print('grad :', 'x :', x.grad,'w :', w.grad,'a :', a.grad,'b :', b.grad,'y0 :', y0.grad,'y1 :', y1.grad,'loss :', loss.grad)

output

x : tensor([2.], requires_grad=True)

w : tensor([1.], requires_grad=True)

a : tensor([3.], grad_fn=)

b : tensor([2.], grad_fn=)

y0 : tensor([6.], grad_fn=)

y1 : tensor([5.], grad_fn=)

loss : tensor([6., 5.], grad_fn=)

grad :

x : tensor([4.])

w : tensor([9.]) a : None b : None y0 : None y1 : None loss : None

当 grad_tensors = torch.tensor([1.,1.]) ,w.grad =  tensor([7.]) = 5+2

grad_tensors = torch.tensor([1.,3.]) ,w.grad =  tensor([11.]) = 5+2*3

torch.autograd.grad

功能概述

  1. 作用
    • 在 PyTorch 中,torch.autograd.grad用于计算梯度。它是自动求导机制的一部分,在深度学习中,计算梯度对于优化模型参数(如在神经网络中更新权重)是非常关键的操作。
  2. 与计算图的关系
    • PyTorch 通过构建计算图来记录张量之间的运算关系。当调用torch.autograd.grad时,它会根据这个计算图来计算所需张量相对于其他张量的导数。

函数参数

  1. 基本参数
    • outputs:这是需要求导的张量或者张量的元组。例如,在一个神经网络中,它可能是损失函数的值。
    • inputs:这是相对于哪些张量求导,是一个张量或者张量的元组。例如,在神经网络中,可能是模型的权重和偏置等参数。
    • grad_outputs(可选):如果outputs不是标量(即一个单独的数),那么需要提供grad_outputs,它表示outputs关于外部梯度的预乘因子。
    • retain_graph(可选):默认值为False。如果设置为True,则计算完梯度后不会释放计算图中的中间变量,这在需要多次反向传播(例如计算二阶导数)时是有用的。
    • create_graph(可选):默认值为False。如果设置为True,将会创建一个新的计算图,这样可以用于计算高阶导数。

示例

以下是一个简单的示例:

import torch

x = torch.tensor([2.0], requires_grad = True)
y = x ** 2
z = torch.square(x)
# 计算y关于x的导数
grad = torch.autograd.grad(y, x,create_graph=True)
print(grad)
grad2 = torch.autograd.grad(grad[0],x)
print(grad2)

(tensor([4.], grad_fn=),)
(tensor([2.]),)
 

在这个示例中:

  1. 首先创建了一个张量x,并设置requires_grad = True,表示这个张量在计算过程中需要跟踪其梯度。
  2. 然后计算y = x ** 2
  3. 最后使用torch.autograd.grad计算y关于x的导数,得到的结果是[4.],因为y = x^2的导数是2x,当x = 2时,导数为4
  4. create_graph(可选):默认值为False。如果设置为True,将会创建一个新的计算图,这样可以用于计算高阶导数。
  5. grad2 = torch.autograd.grad(grad[0],x) 是二阶求导 

grad.zero_()

在 PyTorch 中,grad.zero_()(注意方法名中有一个下划线)通常用于将模型参数的梯度清零。以下是详细介绍:

作用与重要性

在深度学习的训练过程中,每次进行反向传播计算梯度后,梯度会累加到参数的.grad属性中。如果不及时清零梯度,那么在后续的迭代中,新计算出的梯度会与之前未清零的梯度累加,这将导致梯度计算错误,进而影响模型的训练效果。因此,在每一轮训练迭代开始前,通常需要将模型参数的梯度清零。

使用方法及示例

import torch 


w = torch.tensor([1.], requires_grad=True) 
x = torch.tensor([2.], requires_grad=True) 



for i in range(4):
    a = torch.add(x,w)
    b = torch.add(w,1)
    y = torch.mul(a,b)
    y.backward()
    print(w.grad)

    # w.grad.zero_() # 清0
    

tensor([5.])
tensor([10.])
tensor([15.])
tensor([20.])
 

假设我们有一个简单的神经网络模型,如下所示:

import torch
import torch.nn as nn

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(10, 5)
        self.fc2 = nn.Linear(5, 2)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        return self.fc2(x)

model = Net()

在训练循环中,我们通常会这样使用grad.zero_()

optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(10):
    for inputs, labels in data_loader:
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = loss_function(outputs, labels)
        loss.backward()
        optimizer.step()

在这个训练循环中:

  1. optimizer.zero_grad()这一行代码会遍历模型的所有参数,并将它们的梯度清零。
  2. 接着,前向传播计算输出outputs,然后根据输出和标签计算损失loss
  3. loss.backward()进行反向传播,计算参数的梯度。
  4. 最后,optimizer.step()根据计算出的梯度更新模型参数。

三、注意事项

  1. 确保在正确的位置调用grad.zero_():一般是在每一轮迭代的开始,就在计算损失之前调用。如果忘记清零梯度,可能会导致训练结果不准确。
  2. 不同优化器的清零方法:虽然大多数情况下我们使用optimizer.zero_grad()来清零梯度,但也可以直接对模型参数进行清零操作,例如for param in model.parameters(): param.grad.zero_()。不过,使用优化器提供的方法更加简洁和通用,因为它可以处理不同类型的优化器。

你可能感兴趣的:(pytorch,学习,人工智能)