Pytorch简介
Pytorch安装
登录Pytorch官网,选择需要的配置和包管理方法,是否使用GPU,复制最下面一行代码,输入终端(windows: Terminal or cmd)安装Pytorch。
Conda环境下的Pytorch新版本安装完毕后自带GPU配置,因此不用再配置CUDA。
如果一切正常,torch.cuda.is_available()
应当为True
张量计算
Pytorch的运算单元称为张量(tensor)。我们可以将张量理解成一个多维数据,一阶张量即为一阶数组,我们也可以称之为向量(vector),二维张量即为二维数组,通常称之为矩阵(matrix),三维张量即为三维数组;n阶张量为n维数组。
一般的RGB图片就是一个三维张量,有三个通道的二维矩阵组合。
定义张量
首先我们需要导入Pytorch的包
import torch
接下来,我们定义一个尺寸为(5,3)的二阶张量,我们希望每个元素的数值是随机赋予的[0, 1]区间的一个实数。
x = torch.rand(5,3)
x
>>> tensor([[0.3297, 0.7021, 0.1119],
[0.6668, 0.6904, 0.1953],
[0.6683, 0.4260, 0.2950],
[0.0899, 0.4099, 0.0882],
[0.4675, 0.8369, 0.1926]])
同样的,我们可以使用torch.ones(5, 3)来生成一个全是1的张量,torch.zeros(2, 5, 3)来生成一个尺寸为(2, 5, 3)的三维张量,而他的内容全为0。
y = torch.ones(5, 3)
y
>>> tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
z = torch.zeros(2,5,3)
z
>>> tensor([[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]]])
访问张量
访问张量的方法就和访问数组元素一样,可以使用下标方法来访问张量内容
z[0]
这代表访问z张量的第一个元素,因为z是一个三维张量,因此访问的是第一维的第一个元素,那么就是(5,3)大小的一个二维张量
>>> tensor([[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
如果想访问x张量的第2行第3列数组,那么我们可以使用x[1,2],比起传统的下标方法x[1][2],这种方法稍微会便捷一点。
最后,我们还可以使用切片(slicing)来访问张量,就和python数组的方法一样,如果希望访问x中第三列全部元素,我们可以使用x[:,2],这是比起Python数组方便的地方,:可以代表一个维度的所有数值。其实可以发现,tensor和numpy的定义和访问基本没什么区别。
张量的运算
Pytorch中张量也可以像Numpy的多维数组一样完成各种运算,例如张量可以相加
z=x+y
z
>>> tensor([[1.3297, 1.7021, 1.1119],
[1.6668, 1.6904, 1.1953],
[1.6683, 1.4260, 1.2950],
[1.0899, 1.4099, 1.0882],
[1.4675, 1.8369, 1.1926]])
当然,要保证x和y尺寸一样才可以相加
我们可以使用tensor.mm来进行矩阵乘法
q=x.mm(y.t())
这段代码意思就是矩阵x 矩阵乘 矩阵y的转置,因为矩阵乘法必须满足左边矩阵的列等于右边矩阵的行,(5,3) @ (3, 5) = (5,5),最后我们会得到一个5行5列的矩阵
>>> tensor([[1.1993, 1.1993, 1.1993, 1.1993, 1.1993],
[2.0680, 2.0680, 2.0680, 2.0680, 2.0680],
[1.6001, 1.6001, 1.6001, 1.6001, 1.6001],
[0.8946, 0.8946, 0.8946, 0.8946, 0.8946],
[1.9811, 1.9811, 1.9811, 1.9811, 1.9811]])
张量与Numpy数组之间的转换
我们可以通过tensor.numpy()将tensor转换为Numpy数组,例如x.numpy()
也可以将numpy转换为张量,这需要使用torch.from_numpy()方法。
GPU上的张量计算
我们可以使用tensor.cuda()来将一个tensor转移到GPU上,例如以下代码
if torch.cuda.is_available():
x=x.cuda()
y=y.cuda()
print(x+y)
动态计算图
人工神经网络之所以在诸多机器学习算法中脱颖而出,就是因为它可以利用反向传播算法来更新内在的计算单元,从而更加精准地解决问题。反向传播算法能够精确地计算出网络中每一个单元对于网络表现的贡献(即所谓的梯度信息),利用这种技术大大提高了神经网络的训练效率,从而避免了大量无效学习。
在深度学习框架出现之前,针对不同的神经网络架构,需要编写不同的反向传播算法,这就增加了难度和工作量。现在大多数深度学习框架采用了计算图(computational graph)技术,于是我们就有了通用的解决方案,不需要为每一种架构的网络定制不同的反向传播算法,只需要关注如何实现神经网络的前馈运算即可。当前馈运算步骤完成之后,深度学习框架就会自动搭建一个计算图,通过这个图,就可以让反向传播算法自动进行。因此,计算图技术的出现大幅提升了构建神经计算系统的效率。这就是我们必须采用深度学习框架的原因。
计算图解决这一问题的基本思想是将正向的计算过程步骤都记录下来。只要这些运算步骤是可微分(differentialable,即可以进行求导运算)的,那么我们就可以沿着计算图的路径对任意变量进行求导,进而自动计算每个变量的梯度。因此,动态计算图是数值运算和符号运算(体现为微分求导)的一种综合,它是整套深度学习技术和框架中最重要的核心。
简而言之就是,Pytorch可以根据你写的前向传播的结构,自动给你把反向传播的公式算好了,你只需要调用backward就行了,非常的方便。
# 变量需要设置requires_grad为True,代表需要求梯度
x = torch.ones(2, 2, requires_grad=True)
y = x + 2
z = y * y
t = torch.mean(z)
于是我们得到了一个数学公式
t
(
x
)
=
m
(
x
+
2
)
2
t(x)=m(x+2)^2
t(x)=m(x+2)2
我们只需要调用t.backward()
就可以计算t对x的导数,输出x.grad
t.backward()
x.grad
>>> tensor([[1.5000, 1.5000],
[1.5000, 1.5000]])
无论神经网络多复杂,函数依赖关系多么复杂,我们只需要通过backward()函数就可以自动完成梯度的计算。
注意 只有叶节点才能计算grad信息,非叶节点不能计算。这是因为非叶节点大多是计算中间变量,只为了方便人类阅读,而不会影响计算,因此也不需要计算梯度信息。