最近心血来潮开始进行学习pytorch框架,考虑到本人忘性大,于是决定顺手把学习的过程整理出来便于以后回头来查找。第一阶段的内容将全部搬运自Pytorch官方教程,会翻译教程的全部流程并记录下自己的理解。欢迎英语苦手的盆友们来参考!也欢迎刚入门的盆友一起交流指正!
这里也附上官方Tutorial的链接(传送门)。
工欲善其事必先利其器,开始Pytorch框架的学习之前要先准备好系统环境,详细的安装流程在官网上也都有,照着上面的指引一步步做下来就可以了。按照惯例还是贴一下官网的链接https://pytorch.org/get-started/locally/。
官网上Pytorch安装的方法多种多样,个人强烈推荐使用Anaconda来管理设备上的python环境,安装方便操作简洁。安装Anaconda的同时会自动配置好Jupyter Notebook的相关环境,Jupyter在代码调试与结果展示的过程中将会提供极大的便利。Anaconda的安装十分简单,只需要在下载完安装包,后面就可以通过傻瓜式的图形交互界面完成安装了,安装好的Anaconda内置了numpy、pandas、matplotlib等常见的机器学习相关库。当然!我们的主角torch库也包含其中了。一步到位的安装流程省去了繁琐的环境变量配置等工作,其便利性简直是在windows系统下的开发人员的一大福音!
关于IDE的使用就更是见仁见智了,这里推荐Pycharm,和Anaconda是互相兼容的。
完成了准备工作,接下来就让我们一起看看走进科学 Pytorch的第一课到底讲了什么。
Pytorch是Python下的一个用于科学计算的包,该包主要有一下两个用途:
Pytorch中的Tensors与Numpy中的ndarrays十分接近,但是其优势在于能够支持GPU的加速运算。(这里的GPU加速实际上就是CUDA了,Nvidia牛逼!)
那么我们现在来尝试创建一个张量,首先需要引入相关库。虽然一直都在说Pytorch,但不要忘了库的实际名称是torch。
from __future__ import print_function
import torch
现在创建一个大小为5x3的矩阵,这个刚被创建出来的矩阵是没有初始化过的。未初始化过的矩阵内部的数值是无法确定的,张量申请到的内存区域上的存放的值将会被显示为初始值,这些值对我们而言是毫无意义的,只是上一个程序使用后残留的数据而已。
x = torch.empty(5, 3)
print(x)
# Out:
# tensor([[ 2.1660e+35, 4.5808e-41, -2.4203e+15],
# [ 3.0655e-41, 0.0000e+00, 1.4013e-45],
# [ 0.0000e+00, 0.0000e+00, 0.0000e+00],
# [ 0.0000e+00, 0.0000e+00, 0.0000e+00],
# [ 0.0000e+00, 0.0000e+00, 0.0000e+00]])
接下来让我们创建一个数值随机的5x3矩阵,torch.rand(rows, cols)在创建矩阵的同时会对其完成初始化,将矩阵中每一个元素初始化为[0,1]之间的一个值。
x = torch.rand(5, 3)
print(x)
# Out:
# tensor([[0.4707, 0.7056, 0.8309],
# [0.3842, 0.7964, 0.8027],
# [0.1584, 0.0038, 0.0977],
# [0.3735, 0.5157, 0.2004],
# [0.3184, 0.5997, 0.1331]])
与Numpy类似的,我们也可以用torch.zeros()初始化值为0的矩阵,并通过传输dtype参数来指定数据类型(该参数对上面的几个方法同样有效)。
x = torch.zeros(5, 3, dtype=torch.long)
print(x)
# Out
# tensor([[0, 0, 0],
# [0, 0, 0],
# [0, 0, 0],
# [0, 0, 0],
# [0, 0, 0]])
直接将已有的数据转换为张量:
x = torch.tensor([5.5, 3])
print(x)
# Out:
# tensor([5.5000, 3.0000])
以现有张量为模板创建新的张量,新的张量会复用模板中的性质,例如:数据类型、设备类型等,当然也可以通过传递参数的方式对某些性质做针对性的修改。
x = x.new_ones(5, 3, dtype=torch.double) # new_* 方法需要矩阵大小作为输入参数
print(x)
x = torch.randn_like(x, dtype=torch.float) # 指定新张量的数据类型
print(x) # result has the same size
# Out
# tensor([[1., 1., 1.],
# [1., 1., 1.],
# [1., 1., 1.],
# [1., 1., 1.],
# [1., 1., 1.]], dtype=torch.float64)
# tensor([[-1.1635, -1.0563, -0.7356],
# [ 0.0370, -1.5329, 0.4804],
# [-0.9072, 0.0670, 0.1239],
# [ 0.4044, 3.2442, 0.3095],
# [ 1.0097, -0.2127, -0.1874]]) # dtype为torch.float32时不显示
通过.size()函数获取张量的大小,返回的结果类型为torch.Size,实际上就是一个tuple,支持素有tuple相关的操作。
print(x.size())
# Out:
# torch.Size([5, 3])
这里顺带提一下,刚才随机初始化张量时出现了两个不同的函数torch.rand()和torch.randn(),这两个函数的区别在于,rand()生成的是[0,1]区间内随机分布的数值,而randn()是根据均值为0且方差为1的正态分布进行随机数生成的。
张量的运算中有多种不同的语法对应同一种运算,这里我们以加法为例。Tensor的加法操作要求两个相加元素的大小是一致的。不过两个维度不同的矩阵也可以相加,例如矩阵A是一个三维矩阵,大小为3x5x5,矩阵B是一个二维矩阵大小为5x5,这时两个矩阵就可以相加,加法操作就是把B矩阵与A矩阵中的3个5x5的子矩阵相加。因此,不同维度的矩阵加法要求是高维矩阵的低维部分与低维矩阵的大小一致。
言归正传,回到张量加法的语法上:
y = torch.rand(5, 3) # 创建一个新的张量,加法要求两个张量的大小是一致的
# Syntax 1
print(x + y)
# Syntax 2
print(torch.add(x, y))
result = torch.empty(5, 3) # 以传递out参数的形式获取结果,结果会直接赋给result
torch.add(x, y, out=result)
print(result)
# Syntax 3
y.add_(x) # 不要漏了下划线!
print(y) # 一步到位,直接将结果赋给y,等价于y = y + x
注:所有带下划线“_”的操作都会修改实例的值。
其他操作:
'''张量的索引方式与Numpy中ndarray完全相同!'''
print(x[:, 1])
# Out:
# tensor([-1.0563, -1.5329, 0.0670, 3.2442, -0.2127])
'''使用torch.view来对张量进行resize/reshape'''
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # -1为缺省值,该维度的大小将取决于另一个维度的值
print(x.size(), y.size(), z.size())
# Out:
# torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
'''当张量中有且只有一个元素时,可以使用.item()将元素值提取出来'''
x = torch.randn(1)
print(x)
print(x.item())
# Out:
# tensor([-1.0658])
# -1.0657769441604614
Torch Tensor与NumPy array之间能够很方便的完成相互转换。转换后的tensor与array将会共享他们所在的内存区域,这就意味着修改其中一个变量的值也将会影响到另一个变量。
由于NumPy不支持GPU,所以所有存放在GPU上的Tensor都需要先转移到CPU上,然后才能做转换。
'''Tensor转换为array'''
a = torch.ones(5)
print(a)
b = a.numpy()
prnt(b)
# Out:
# tensor([1., 1., 1., 1., 1.])
# [1. 1. 1. 1. 1.]
a.add_(1) # 改变其中一个变量的值会影响到另一个变量
print(a)
print(b)
# Out:
# tensor([2., 2., 2., 2., 2.])
# [2. 2. 2. 2. 2.]
'''array转换为Tensor'''
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a) # 注意这里使用的是.from_numpy()!
np.add(a, 1, out=a)
print(a)
print(b)
# Out:
# [2. 2. 2. 2. 2.]
# tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
这里有两个需要注意的点:
我们不止一次的提到了GPU,那么如何将tensor转移到GPU上呢?要实现这个操作首先需要有支持CUDA加速的相关设备,翻译成人话就是一块Nvidia显卡(购买前记得在官网上找一下是否支持最新的CUDA版本)。目前Pytorch支持的CUDA版本为9.2和10.1,所以购买老显卡的时候需要慎重!
将tensor转移到GPU上的操作比起前期的准备工作就显得十分简单了,通过.to()函数即可完成。
# 仅在有设备支持CUDA的情况下进行数据的转移,否则会报错
if torch.cuda.is_available():
device = torch.device("cuda") # CUDA设备对象,一台机器上可能安装了多个显卡
y = torch.ones_like(x, device=device) # 直接在GPU上创建一个tensor
x = x.to(device) # 将CPU上的tensor转移至GPU上
z = x + y # 仅有存放在相同设备上的tensor才能进行运算
print(z)
print(z.to("cpu", torch.double)) # 通过.to()将tensor转移至CPU的同时修改数据格式
# Out:
# tensor([-0.0658], device='cuda:0')
# tensor([-0.0658], dtype=torch.float64)
好啦,入门部分到此结束!如果文中有任何错误以及不准确的地方就麻烦大家帮忙一起抓虫啦