pytorch常见错误_0240826

pytorch 常见错误

  1. RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.

如下程序会抱上述错误

x=torch.randn(3,requires_grad=True)
x += 1  # 原位操作 报错:RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.

报错:你在一个变量上进行操作,但是该变量是不可以修改的。这个变量是tensor。x是梯度是开启的,此时x不应该进行原位操作,但是x进行了原位操作。

原因:pytorch的自动求导机制的本质是使用链式求导法则,将求导的过程分解成一个一个的基本操作算子。其具体是通过自动构建计算图,来求解导数。

如下函数 \(y=f(x)\) , pytorch 的计算过程是这样

x = x0                # x取值x0
x.requires_grad=True  # 目标函数是否关于x求梯度
y=f(x)                # 前向过程
y.backward()          # 反向求导
x.grad                # 输出x在x0处的导数

py计算的是目标函数关于自变量在某一个确定点的导数值。此时已经构建了一张图,你将x进行了改变,此时计算图要重新构建。pytorch不允许这种操作。

假设 \(y=x*x\), 现在对x进行了操作x=x+1, 那么再对y求x的导数的时候,y关于x的映射关系是哪个?是\(y=x*x\), 还是 \(y = (x+1) * (x+1)\)​。pytorch决定不了,总要有一个选择。

解决方案:

  1. 使用tensor的data属性:tensor有一个基本属性data,它是tensor上存储的变量的数值,你可以修改这个数值,但是不修改其他属性。选择的是\(y=x*x的路子\)

    x=torch.tensor([1.0,1.0],requires_grad=True)
    x.data += 1  
    y=torch.dot(x,x)*0.5
    y.backward()
    x.grad        #tensor([2., 2.], requires_grad=True)
    x.grad == x   #tensor([True, True, True])
    
  2. 使用with torch.no_grad() 此时梯度属性被禁用了

    x=torch.tensor([1.0,1.0],requires_grad=True)
    with torch.no_grad():  # 在上下文管理器中进行
      x += 1
    y=torch.dot(x,x) * 0.5 
    y.backward()
    x.grad     #tensor([2., 2.], requires_grad=True)
    x.grad == x   #tensor([True, True, True])
    

2.tensor.grad.zero_() 梯度清零的使用场景

  • 构建tensor x。其梯度属性打开
  • 函数y=f(x) 对y关于\(x\) 在某一点求梯度x.grad
  • 使用\(x\) 构建函数\(g=g(x)\), 如果x不进行梯度清零,那么对g关于x求导,其结果为x.grad = g关于x的导数+y关于x的导数

在深度学习里面,神经网络的参数是在动态变化中,所以其对应的映射关系也是在动态变化中。所以一次反向求导之后,进行第二次反向求导,那么需要将导数清零。

x=torch.tensor([1.0,1.0],requires_grad=True)
y=torch.dot(x,x) * 0.5 
g=2*x
y.backward()
g.sum().backward()
x.grad    # tensor([3., 3.])  = tensor([1., 1.]) + 2

3.pytorch当loss是nan的时候,其是无法输出的,具体案例如下:

x=torch.tensor([0,1,1,1,1],requires_grad=True,dtype=torch.float)
y=x/x
y.sum().backward()
x.grad      # 产生了除0操作,y为NAN,此时x为NAN

4.python的生成器机制yield

通过yield关键字定义生成器。使得函数能够记住上一次执行的状态,并在下一次调用的时候,从该状态继续执行。生成器有如下特性:

  • 惰性求值:等到使用的时候再计算
  • 节省内存:由于生成器在任何时刻只处理一个值,因此它不需要在内存中存储整个数据集,这在处理大量数据时尤其有用。
  • 状态保持:生成器函数可以记住其上一次执行的状态,这意味着它可以从中断的地方继续执行。

定义生成器:

  1. 使用yield关键字

    def f(n):
      for i in range(n):
        yield i    # 使用yield定义生成器
    
  2. 生成器表达式

    y = (x * x for x in range(5))
    

如何使用生成器?

  1. 使用for循环: (该方式使用比较频繁,比如pytorch的dataloader函数)

    for i in f(3):
      x = i
      print(i)
    
  2. 使用next函数

    next(y)
    
    

使用场景

  • 大文件处理,节省内存

5.python 易错点

python 函数的特点

def f(n):
  print('x:',x)

x=10
f(1)  # 输出10
x=20
f(2)  # 输出20

注意:函数中定义了x,会优先寻找局部变量;如果没有局部变量,寻找外部距离调用函数最近的变量;如果没有外部变量,也没有全局变量,报错

6.pytorch报错TypeError: cannot assign 'torch.FloatTensor' as parameter 'weight' (torch.nn.Parameter or None expected)

net = nn.Sequential(nn.Linear(in_features=3, out_features=1,bias=True))
net[0].weight = torch.randn(3)  #[ERROR]
net[0].weight.data = torch.randn(3) # [OK]

7.pytorch报错,RuntimeError: mat2 must be a matrix, got 1-D tensor

net = nn.Sequential(nn.Linear(in_features=4, out_features=1,bias=True))
net[0].weight.data = torch.randn(4)  
x=torch.randn(10,4)
net(x)  # 报错,因为此时net[0].weight.data是一个向量mat2 must be a matrix, got 1-D tensor
net[0].weight.data = torch.randn(1,4) # 注意data的维度 是1*4 还是4*1
net(x)  # 输出正确结果
  1. pytorch 错误:RuntimeError: Trying to backward through the graph a second time
    解释: 函数关于自变量x在x0处的导数,你求了两次。 会出现上述的错误。
    求导是分为两个步骤:
    a. 前向过程,构建计算图
    b. 反向求导。通过链式法则,反向计算导数
    所以问题的关键在于 重新进行构建计算图
    解决方案:
    1. 梯度清零 不行。跟梯度清空无关
    2. 重新进行前向过程
    x = torch.randn(2,requires_grad=True)
    y = torch.dot(x,x)
    y.backward()
    x.grad
    y.backward()  # 错误:RuntimeError: Trying to backward through the graph a second time
    
    y.backward()
    x.grad
    x.grad == 4 * x # 输出 tensor([True, True]) 
    
posted @ 2024-08-27 23:00  金字塔下的蜗牛  阅读(92)  评论(0编辑  收藏  举报