携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,上一篇文章中,我们介绍了介绍autograd的方法,包括梯度与机器学习中的最优解,Variable is Tensor,如何计算梯度。
今日我们来介绍autograd中的几个重要概念、torch.nn库、Visdom、tensorboardX、torchvision。
-
2.1 autograd中的几个重要概念
-
2.1.1 叶子张量(leaf)
X就是叶子张量,在这个图里,也是叶子节点,只有是叶子节点才有梯度值
-
grad VS grad_fn
- grad: 该Tensor的梯度值,每次在计算backward时都需要将前一时刻的梯度归零,否则梯度值会一致累加
- grad_fn: 叶子节点通常为None,只有结果节点的grad_fn才有效,用于指示梯度函数是哪种类型。
-
backward函数
- torch.autograd.backward(tensors,grd_tensors=None,retain_graph=None,create_graph=False)
- tensor: 用于计算梯度的tensor,torch.autograd.backward(z) == z.backward()
- grad_tensors:在计算矩阵的梯度时会用到。它其实也是一个tensor,shape一般需要和前面的tensor保持一致。
- retain_graph: 通常在调用一次backward后,pytorch会自动把计算图销毁,所以要想对某个变量重读调用backward,则需要将该参数设置为True
- create_graph:如果时True,那么就创建一个专门的graph of the derivative,这可以方便计算高阶微分
- torch.autograd.backward(tensors,grd_tensors=None,retain_graph=None,create_graph=False)
-
torch.autograd.grad()函数
- def grad(outputs, inputs, grad_outputs=None,retain_graph=None,create_graph=False, only_inputs=True, allow_unused=False)
- 计算和返回output关于input的梯度的和。
- outputs:函数的因变量,即需要求导的那个函数
- inputs:函数的自变量,可以定义多个tensor
- grad_outputs、retain_graph、create_graph:同backward
- only_inputs:只计算input的梯度
- allow_unused(bool,可选):如果为False,当计算输出出错时,(因此他们的梯度永远是0)指明不使用的inputs
- def grad(outputs, inputs, grad_outputs=None,retain_graph=None,create_graph=False, only_inputs=True, allow_unused=False)
- autograd例子
x = torch.ones(2, 2, requires_grad=True)
y = x + 2
z = y * y * 3
z.backward(torch.ones(2, 2))
print(x.grad)
print(y.grad)
print(x.grad_fn)
print(y.grad_fn)
print(z.grad_fn)
运行结果:
tensor([[18., 18.],
[18., 18.]])
None
None
<AddBackward0 object at 0x0000012F8E2302E0>
<MulBackward0 object at 0x0000012F8E191EE0>
除了z.backward还可以调用autograd下的backward来完成对梯度的计算
torch.autograd.backward(z,
grad_tensors=nn,
retain_graph=True)
如果z是一个值的话,比如
y = x + 2
z = y * y * 3
z = torch.sum(z)
在调用backward的时候是可以去掉调用的参数的,可以直接使用z.backward()
如果z是矩阵的话,这么调用会报错,必须要传入grad_tensors,
在调用autograd.backward的时候参数是grad_tensors,但是在调用z.backward的时候参数叫gradient
z.backward(gradient=nn)
torch.autograd.backward(z,
grad_tensors=nn,
retain_graph=True)
这时一定会报错的,第二次计算的时候计算图已经被销毁掉了
定义retain_graph为True就不会报错了
z.backward(gradient=nn, retain_graph=True)
torch.autograd.backward(z,
grad_tensors=nn,
retain_graph=True)
还可以采用grad的方法来计算梯度
torch.autograd.grad(z, [x, y, z],
grad_outputs=nn)
-
2.1.2 function
-
torch.autograd.Function
- 每一个原始的自动求导运算实际上是两个在Tensor上运行的函数
- forward函数计算从输入Tensors获得的输出Tensors
- backward函数接受输出Tensors对于某个标量值的梯度,并且计算输入Tensors相当于该相同标量值的梯度
- 有些函数没有导数,我们就可以自己去定义forward和backward,进而完成对这种运算的求解梯度的过程
- 最后,利用apply方法执行相应的运算
- 定义在Function类的父类_FunctionBase中定义的一个方法
- 每一个原始的自动求导运算实际上是两个在Tensor上运行的函数
代码示例:
对于这个class继承Function函数,在这个类中重写forward和backward来完成line的自定义函数的前向推理和反向传播
class line(torch.autograd.Function):
@staticmethod
def forward(ctx, w, x, b):
#y = w*x +b
ctx.save_for_backward(w, x, b)
return w * x + b
@staticmethod
def backward(ctx, grad_out):
w, x, b = ctx.saved_tensors
grad_w = grad_out * x
grad_x = grad_out * w
grad_b = grad_out
return grad_w, grad_x, grad_b
w = torch.rand(2, 2, requires_grad=True)
x = torch.rand(2, 2, requires_grad=True)
b = torch.rand(2, 2, requires_grad=True)
out = line.apply(w, x, b)
out.backward(torch.ones(2, 2))
print(w, x, b)
print(w.grad, x.grad, b.grad)
运行结果:
tensor([[0.3726, 0.2833],
[0.9369, 0.4898]], requires_grad=True) tensor([[0.0617, 0.5303],
[0.1750, 0.3860]], requires_grad=True) tensor([[0.4216, 0.8336],
[0.7906, 0.3395]], requires_grad=True)
tensor([[0.0617, 0.5303],
[0.1750, 0.3860]]) tensor([[0.3726, 0.2833],
[0.9369, 0.4898]]) tensor([[1., 1.],
[1., 1.]])
-
3.1 torch.nn库
-
torch.nn是专门为神经网络设计的模块化接口
-
nn构建于autograd之上,可以用来定义和运行神经网络。
-
在nn库中封装了非常多的基础的模块,这些模块都是构建于autograd之上,也就是说在这些模块中,自动完成了前向运算和反向传播。
-
nn.Parameter
- 定义可训练参数
- self.my_param = nn.Parameter(torch.randn(1))
- self.register_parameter
- nn.ParameterList & nn.ParameeterDict
模型包括结构和参数两个部分。
-
nn.Sequential
- nn.Sequential是通过一个序列的方式来完成对一个网络结构的定义,通过将几个卷积层串联起来,将它作为序列罗列到nn.Sequential这个方法中,就能定义一个model。
- 也可以采用OrderedDict采用字典的结构给定义的卷积一个key,我们可以通过key来定向的访问想要访问的相关的卷积层
-
nn.ModuleList
- 在ModuleList中首先继承nn.Module,然后定义一个init的初始化的函数,在init函数中通过nn.ModuleList来搭建我们的模型,接下来完成forward的前向推理
-
nn.ModuleDict
- 和nn.ModuleList类似,只是传入的方式是字典的方式来进行搭建,前向计算的方式就是对推理层完成相应的运算
-
nn.Module
- 它是一个抽象概念,既可以表示神经网络中的某个层(layer),也可以表示一个包含很多层的神经网络
- model.parameters() 获取可训练的参数
- model.buffers() 获取不可获取的参数
- model.state_dict() 访问当前网络结构中的参数
- model.modules() 定义当前模型包含了哪些模块
- forward(), to() 前向推理,数据从GPU搬到cpu或者从cpu搬到gpu
-
Parameters VS buffers
- 一种反向传播需要被optimizer更新的,称之为parameter
- self.register_parameter(“param”, param)
- self.param = nn.Parameter(torch.randn(1))
- 一种反向传播不需要被optimizer更新的,称之为buffers
- self.register_buffer(‘my_buffer’, torch.randn(1))
- 一种反向传播需要被optimizer更新的,称之为parameter
-
state_dict() & load_state_dict
- 对模型的保存
- torch.save(obj=model.state_dict(),f=”models/net.pth”)
- 对模型的加载
- model.load_state_dict(torch.load(“model/net.pth”))
- 对模型的保存
-
4.1 Visdom介绍
-
Facebook专门为Pytorch开发的一款可视化工具,开源于2017年3越,提供了大多数的科学原酸可视化API
- github.com/facebookres…
- 支持数值(折线图,直方图等)、图像、文本以及视频等(通过可视化可以直观看到数据的变化)
- 支持Pytorch、Torch、和numpy
- 用户可以通过编程的方式组织可视化空间或者通过用户接口为数据打造仪表板,检查实验结果和调试代码
- env:环境 & pane:窗格
Visdom的使用:
-
安装
- pip install visdom
-
启动服务
- python -m visdom.server
-
5.1 tensorboardX介绍
-
scalar,image,figure,histogram,audio,text,graph,onnx_graph,embedding,pr_curve and videosummaries等不同的可视化展示方式
-
安装
- pip install tensorboardX
代码展示:
from tensorboardX import SummaryWriter
writer = SummaryWriter("log")
for i in range(100):
writer.add_scalar("a", i, global_step=i)
writer.add_scalar("b", i ** 2, global_step=i)
writer.close()
使用tensorboard可视化:tensorboard –logdir ./
-
6.1 torchvision介绍
-
torchvision是独立于pytorch的关于图像操作的一些方便的工具库
-
torchvision主要包括以下几个包
- vision.datasets: 几个常用视觉数据集,可以下载和加载
- vision.models: 已经训练好的模型,例如:AlexNet,VGG,ResNet
- vision.transforms: 常用的图像操作,例如,随机切割,旋转,数据类型转换,图像到tensor,numpy到tensor,tensor到图像
- vision.utils、vision.io、vision.ops