本文以线性模型为例,讲解线性模型的求解的pytorch梯度实现方法.

要注意几个问题:在PyTorch 0.4.0版本之后,Variable类已经被禁用了,所有的torch.Tensor与torch.autograd.Variable的功能可以通过torch.Tensor方法实现.

在pytorch里面,默认只能是标量对标量,或者标量对向量/矩阵求导!

要想使x支持求导,必须让x为浮点类型.

在目前的深度学习框架(PyTorch,Tensorflow,MXnet)中,自动求导功能是最核心也是最基础的功能.构建与训练深度学习的基本流程是:根据网络结构逐步搭建计算图,然后求得损失函数,之后根据计算图来计算导数,最后利用梯度下降方法更新参数.

首先根据一个例子,

,当

时,它的导数为12,这样通过一个代码来实现.

import torch

import torch.autograd

x = torch.tensor([2.0], requires_grad=True)

print("x = ",x)

print("x.requires_grad = ", x.requires_grad)

y = x ** 3

print("y = ",y)

print("y.requires_grad = ", y.grad_fn)

y.backward() #反向传播,求解导数

print("x.grad = ", x.grad)

输出结果为:

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

x.requires_grad = True

y = tensor([8.], grad_fn=)

y.requires_grad =

x.grad = tensor([12.])

这里要注意:需要反向传播的数值要为浮点型,不可以为整数.

1.torch.Tensor

PyTorch中数据以张量(n维数组)的形式流动torch.Tensor可以用来创建张量.当Tensor的属性中requires_grad=True时,则系统会开始跟踪针对此Tensor的所有操作.其中每个操作都会有此操作想对于输入的梯度,则整个操作完成的输出张量相对于输入张量的梯度就是中间过程中所有张量的链式法则.例如,

为输入张量,

,

,则:

其中

为叶节点,

为根节点,

并不会被收集.

每个张量都有一个grad_fn属性用于保存张量的操作,如果这个张量为用户自己创建的,则grad_fn为None.

从图中可以看出,一个Tensor中:data中保存着所存有的数据

grad中保存这梯度

requires_grad表示是否开始追踪所有的操作历史

想计算导数时,调用Tensor.backward()

在调用backward()时,只有当requires_grad和is_leaf同时为真时,才会计算节点的梯度值.

2.Pytorch到底在计算什么?(雅克比矩阵和向量)

autograd类的原理其实就是一个雅克比矩阵向量积计算引擎.

设函数

为从n维度映射到m维度的一个函数,它的输入为向量

,输出向量

为:

则雅可比矩阵是一个m*n的矩阵:

由于矩阵描述了向量空间中的运动-变换,而雅可比矩阵看作是将点

转化到点

.

设一个pytorch张量为

,通过函数f(X)得到一个向量

:

.这个过程相当于

的过程.然后设向量

通过函数映射到一个标量

.这时求解

相对与

的梯度

很容易,

的公式如下:

根据导数的链式法则,张量

相对于标量

的梯度为:

向量

到标量

类似于MSE函数将minibatch平均为一个平均loss上.

不为标量时,可以通过输入一个外部的梯度来获得其梯度.

3.例程

这一部分会详细说明一些细节性的问题,在最后会有线性模型的例程.

在上边说过叶子节点(is_leaf),如果有多个叶子节点,这些节点的is_leaf都是False,则整体才是不可求导的,例程如下:

import torch

import torch.autograd

x = torch.tensor(3.0, requires_grad=True)

y = torch.tensor(4.0, requires_grad=False)

z = torch.pow(x,2) + torch.pow(y,3)

print(x.requires_grad)

print(y.requires_grad)

print(z.requires_grad)

z.backward()

print(x.grad)

print(y.grad)

上边例程中,关闭了y的梯度追踪,但是x的梯度追踪还开着,所以z是可以求导(print(z.requires_grad)为True).

当x也关闭了梯度追踪,那么z也无法求导(print(z.requires_grad)为False).

当计算梯度之后,y是不可求导的,这时候y.grad为None.

可以通过x.requires_grad_(True/False)修改叶子节点的可导与不可导.

Tensor.backward()方法

.backward()默认计算对计算图叶子节点的导数,中间过程的导数是不计算的.例程如下:

x = torch.tensor(3.0, requires_grad=True)

y = 2*x

z = y**2

f = z+2

f.backward()

print(x.grad)

print(y.grad)

print(z.grad)

结果如下:

tensor(24.)

None

None

上边的例子大多都是标量对标量的求导例程.

标量对向量求导:

下面来说明一个线性模型的雏形版本,输入为向量,输出为标量.设一个输入为

,权重向量为

,则

.

偏导数为:

例程:

x = torch.tensor([1.0,2.0,3.0], requires_grad=True)

w = torch.tensor([4.0,5.0,6.0], requires_grad=True)

b = 10

y = torch.dot(x,w)+b

y.backward()

print(x.grad)

标量对矩阵求导:

设输入为一个矩阵(2*3)

第一次操作:

第二次操作,Y上每个元素平方:

第三次操作,Z上所有元素平均值:

偏导数为:

import torch

import torch.autograd

x = torch.tensor([[1.0,2.0,3.0],[4.0,5.0,6.0]], requires_grad=True)

y = x+1

z = y**2

f = torch.mean(z)

f.backward()

print(x.grad)

向量/矩阵对向量/矩阵求导

backward()默认输出为标量,这是因为我们在深度学习中最后的loss为一个标量,这是常用的方式.

当输出为向量或矩阵时,需要通过地一个参数gradient来实现.gradient参数的维度与最终的输出要保持一致,gradient中每个元素表示为对应的最终输出中相同位置元素所对应的权重.

例程:

import torch

import torch.autograd

x = torch.tensor([[1.0,2.0,3.0],[4.0,5.0,6.0]], requires_grad=True)

y = x**2 + x

gradient1 = torch.tensor([[1.,1.,1.],[1.,1.,1.]])

gradient2 = torch.tensor([[1.,0.1,0.01],[1.,1.,1.]])

y.backward(gradient1)

print(x.grad)

x.grad.zero_()

y = x**2 + x

y.backward(gradient2)

print(x.grad)

输出为:

tensor([[ 3., 5., 7.],

[ 9., 11., 13.]])

tensor([[ 3.0000, 0.5000, 0.0700],

[ 9.0000, 11.0000, 13.0000]])

线性模型的求解过程

import numpy as np

import torch.autograd

import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

#生成实验数据

def gendata():

gen_x = torch.randn(1000,2)

gen_w = torch.FloatTensor([5, 10]).view(2,1)

gen_b = 2.0

y_true = torch.mm(gen_x, gen_w) + gen_b

noise = torch.zeros(1000,1).normal_(std=0.01)

y_lable = y_true + noise

return gen_x,y_true,y_lable

#测试生成数据的有效性

def plot2d(x_in):

fig1 = plt.figure(1)

x_in = x_in.numpy()

plt.scatter(x_in[:,0], x_in[:,1])

plt.show()

#测试生成数据的有效性

def plot3d(x_in, y_in):

fig2 = plt.figure(2)

x_in = x_in.numpy()

y_in = y_in.numpy()

fig = plt.figure(2)

ax = fig.add_subplot(111, projection='3d')

ax.scatter(x_in[:,0], x_in[:,1], y_in)

plt.show()

def weight_init(layer_size):

weight = torch.randn(layer_size,1 , requires_grad = True)

bias = torch.randn(1,1, requires_grad = True)

return weight, bias

def loss_mse(y_l, y_pred):

return (y_l - y_pred) ** 2/2

x, y_t, y_l = gendata()

print(y_l.size())

# print(x.size())

# plot2d(x)

# plot3d(x,y_t)

weight, bias = weight_init(2)

print("w :", weight)

print("b :", bias)

learning_rate = 0.03

mini_batch = 1000

for i in range(500):

print(i)

y_pred = torch.matmul(x, weight) + bias

loss = loss_mse(y_l, y_pred)

loss.sum().backward()

weight.data = weight.data - learning_rate/mini_batch*weight.grad.data

bias.data = bias.data - learning_rate/mini_batch*bias.grad.data

weight.grad.zero_()## 必要清零

bias.grad.zero_()## 必要清零

print("w up:", weight)

print("b up:", bias)

with torch.no_grad():

y_pred = torch.matmul(x, weight) + bias

train_loss = loss_mse(y_l, y_pred)

print("epoch", i, train_loss.mean().item())

在这段代码中要注意,如果将

weight.data = weight.data - learning_rate/mini_batch*weight.grad.data

更换为

weight = weight - learning_rate/mini_batch*weight.grad.data

会报错,因为weight表示了一个新的对象,他的名字还是weight,变为了中间节点,默认情况下是无法获取其梯度的,可以采用weight.retain_grad()来处理.

参考:

pytorch如何计算导数_Pytorch的自动求导机制与使用方法(一)相关推荐

  1. Pytorch教程入门系列4----Autograd自动求导机制

    系列文章目录 文章目录 系列文章目录 前言 一.Autograd是什么? 二.Autograd的使用方法 1.在tensor中指定 2.重要属性 三.Autograd的进阶知识 1.动态计算图 2.梯 ...

  2. 【PyTorch基础教程2】自动求导机制(学不会来打我啊)

    文章目录 第一部分:深度学习和机器学习 一.机器学习任务 二.ML和DL区别 (1)数据加载 (2)模型实现 (3)训练过程 第二部分:Pytorch部分 一.学习资源 二.自动求导机制 2.1 to ...

  3. Pytorch学习(一)—— 自动求导机制

    现在对 CNN 有了一定的了解,同时在 GitHub 上找了几个 examples 来学习,对网络的搭建有了笼统地认识,但是发现有好多基础 pytorch 的知识需要补习,所以慢慢从官网 API 进行 ...

  4. 深度学习修炼(三)——自动求导机制

    文章目录 致谢 3 自动求导机制 3.1 传播机制与计算图 3.1.1 前向传播 3.1.2 反向传播 3.2 自动求导 3.3 再来做一次 3.4 线性回归 3.4.1 回归 3.4.2 线性回归的 ...

  5. PyTorch的计算图和自动求导机制

    文章目录 PyTorch的计算图和自动求导机制 自动求导机制简介 自动求导机制实例 梯度函数的使用 计算图构建的启用和禁用 总结 PyTorch的计算图和自动求导机制 自动求导机制简介 PyTorch ...

  6. PyTorch 笔记Ⅱ——PyTorch 自动求导机制

    文章目录 Autograd: 自动求导机制 张量(Tensor) 梯度 使用PyTorch计算梯度数值 Autograd 简单的自动求导 复杂的自动求导 Autograd 过程解析 扩展Autogra ...

  7. Pytorch Autograd (自动求导机制)

    Introduce Pytorch Autograd库 (自动求导机制) 是训练神经网络时,反向误差传播(BP)算法的核心. 本文通过logistic回归模型来介绍Pytorch的自动求导机制.首先, ...

  8. 【PyTorch学习(三)】Aurograd自动求导机制总结

    ​Aurograd自动求导机制总结 PyTorch中,所有神经网络的核心是 autograd 包.autograd 包为tensor上的所有操作提供了自动求导机制.它是一个在运行时定义(define- ...

  9. pytorch自动求导机制

    Torch.autograd 在训练神经网络时,我们最常用的算法就是反向传播(BP). 参数的更新依靠的就是loss function针对给定参数的梯度.为了计算梯度,pytorch提供了内置的求导机 ...

最新文章

  1. 全球首款碳纳米管通用计算芯片问世!RISC-V架构,5倍于摩尔定律,Nature连发三文推荐...
  2. 阅读源码技术与艺术五
  3. 互联网1分钟 | 1009
  4. 阐述Linux操作系统之rpm五种基本操作
  5. java 枚举类型enum
  6. 杭电acm 2177 取(2堆)石子游戏(威佐夫博弈)
  7. 95-190-032-源码-window-CountWindow
  8. DynamicsCompressorNode
  9. 观点 | 2017,区块链与加密货币“追逐者”玩命的一年
  10. validators配置要点及No result defined for action报错解决方案
  11. 转:计算机视觉专业词汇(中英文对照)
  12. 新零售到家O2O 和到店O2O的区别?
  13. 南邮NOJ2029节奏大师
  14. vue input组件设置失焦与聚焦
  15. 如何为word增加页码,且第一页不显示页码?
  16. redis cluster 集群 HA 原理和实操(史上最全、面试必备)
  17. IBM SPSS Modeler使用技巧 ----参数及全局变量的使用
  18. 从唐骏携手金和看协同OA企业的个性及实力
  19. 使用ScriptX.cab控件
  20. 10万级半导体无尘车间尘埃粒子检测器

热门文章

  1. Rainbond v5.1.2发布,微服务架构应用便捷管理和交付
  2. 改进博客园Markdown显示功能(加代码行号、显示代码所用编程语言)
  3. 如何将视频下载并且转码拼接
  4. 我对CopyOnWrite的思考
  5. solr安装笔记与定时器任务
  6. android dpi
  7. Sqlserver数据库的恢复
  8. Druid如何自动根据URL自动识别DriverClass的
  9. Linq使用Group By 1
  10. C# 手动/自动保存图片