pytorch的基础使用(二)

169 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

在神经网络中我们经常需要使用到求导的计算,因此本文主要对 pytorch求导进行简单讲解。

写在前面:本人刚上研究生,可能很多地方写的不周到,有些资料也是参考大佬的,希望读者如果发现问题,能给我提出宝贵的意见,谢谢大家。

1、导包

# 导入 包import torchimport numpy as np

2、创建数据

x = torch.ones((2,2), requires_grad=True)print(x)# out:tensor([[1., 1.],        [1., 1.]], requires_grad=True)

备注: 可能有人问,这个 requires_grad=True 是啥,为什么为 true, 其实读者可以理解为。设置了 requires_grad = True 之后,就可以进行对 x 求导了

3、创建模拟的函数

y = x + 2z = y * y * 3

这里其实就是创建了一个函数 z = 3(x+2)^2

4、求平均值

# 对 z 求平均值result = z.mean()print(result)# out:tensor(27., grad_fn=<MeanBackward0>)

分析 因为四个值都是 1 ,将1代入上面的函数中 得到 z = 27,因为四个数都是27,自然平均数也就是27了

5、求导

例子一:

这个例子就比较好理解了

# 创建一个 tensors.x = torch.tensor(2.) # 增加梯度 这里没增加梯度,后面就不可以求导y = torch.tensor(3., requires_grad=True) # 增加梯度z = torch.tensor(4., requires_grad=True) # 增加梯度# 假设 w = x * y + z# Compute derivativesy.backward()# Display gradientsprint('dw/dx:', x.grad)  #  = yprint('dw/dy:', y.grad)  #  = xprint('dw/dz:', z.grad)  #  = 1    因为b的系数为1# out dw/dx: Nonedw/dy: tensor(3.)dw/dz: tensor(1.)

为什么 dw/dx 为None 呢,因为前面没有设置 requires_grad,可以理解为不可求导。

例子二:

x = torch.ones((2,2), requires_grad=True)y = x +2z = y*y*3  # 相当于  3(x+2)^2  result = z.mean() # 求平均值 如果不先求平均值会报错,后面的例子会提到result.backward() # 求导printf(x.grad)  # 对 x 求导并将 x 值代入,也就是 x 方向的梯度# out:tensor([[4.5000, 4.5000],        [4.5000, 4.5000]])备注:result = 1/4 x([[ [Z1,Z2],[Z3,Z4]])= 1/4 x([[ [27,27],[27,27]])

本来 x 是一个二维的张量,也就是二维向量,如果没有进行 mean() 操作是无法求偏导的,我们看下 mean() 做了啥,看下图也就是得到一个平均数,那么上面的例子中 平均数就是 1.

mean函数

例子三:

假设函数F = a*ba = 10b = 20# 假设 ab 都是未知数,分别对ab 求偏导由∂F/∂a = b 得到 ∂F/∂a = 20由∂F/∂b = a 得到 ∂F/∂b = 10a = torch.tensor(10., requires_grad = True)b = torch.tensor(20., requires_grad = True)f = a*bf.backward()print(a.grad) # a 方向的梯度  关于梯度的介绍在后面有介绍print(b.grad) # b 方向的梯度 关于梯度的介绍在后面有介绍# out: tensor(20.)tensor(10.)

这个想必大家都能理解,就是一个普通求导而已

但是当 a、b是一个向量的时候就会出错

6、求导深入

先举一个例子

a = torch.tensor([10., 10.], requires_grad = True)b = torch.tensor([20., 20], requires_grad = True)f = a*bf.backward()print(a.grad)print(b.grad)# out: 【报错】grad can be implicitly created only for scalar outputs只能为标量输出隐式创建Grad,也就是说pytorch不支持张量对张量直接求导,什么是张量什么是标量呢其实张量就是向量、二维、三维、多维向量的统称。标量就是一个数,它不是向量,没有方向。

分析:为什么会报错

a = [ x1, x2]

f = a*b

∂f/∂a = ? 是不是就没法计算了

解决办法:

在求导的时候把需要的梯度参数传递过去,其实可以理解为求导时候的权重,上面a的权重其实是[1,1]我们在这里f.backward(gradient=torch.tensor([2.,1.]))那这样处理之后有什么结果呢a.grad   # out:tensor([40., 20.])b.grad  #  out:tensor([20., 10.])此时 a.grad  = [ 20*2, 20*1] = [40., 20.]同理 b.grad

再举一个例子

a = torch.tensor([10. ,10.], requires_grad = True)b = torch.tensor([20., 20], requires_grad = True)f = a*bg = 2*fg.backward(gradient=torch.tensor([1.,1.]))print(a.grad)print(b.grad)print(f.grad)# out:【报错】The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won't be populated during autograd.backward().If you indeed want the gradient for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor......

backward()仅在默认情况下只计算最底层的变量的梯度,也就是a、b

同时官方也提供了一个方法

f.retain_grad()

再调用 print(f.grad) 就不会报错了

补充知识:

下面这些补充知识,在网上都可以搜索到,我在这里帮大家补充下而已,也是摘抄的。

1、梯度

连续可微的多元函数

多元函数

,用矢量表示其在点

其中一点

的梯度为

,表示 f 在该点沿着梯度方向函数值增长最快,梯度的模表示增长的程度。

2、求导

求导是数学计算中的一个计算方法,它的定义就是,当自变量的增量趋于零时,因变量的增量与自变量的增量之商的极限。在一个函数存在导数时,称这个函数可导或者可微分。可导的函数一定连续。不连续的函数一定不可导。其实可以简单的理解为某个方向的斜率。

如果读者对这块知识不是很了解,建议可以查阅下相关资料,我这里三言两语也没法说清楚。图片资料也是网上摘录的,大家可以自行充电。

求导图片