- 张量
- 创建tensor
- 张量的操作
- 广播机制
- 自动求导
- autograd简介
- 保存的张量
- 并行计算简介
- 为什么需要CUDA
- 现在主流的并行方式——Data parallelism
张量是现代机器学习的基础,它的核心是一个数据容器,多数情况下,它包含数字,较少时候包含字符串。
存储在各种类型张量的公用数据集类型:
- 0维张量代表的是标量(数字)
- 1维张量代表的是向量
- 2维张量代表的是矩阵
- 3维张量代表的是时间序列数据、股价、文本数据、单张彩色图片(RGB)
- 4维张量代表的是图像
- 5维张量代表的是视频
比如:一个图像可以用三个字段表示:
(width, height, channel) = 3D
但是,在机器学习工作中,经常要处理不止一张图片,可能有10,000张照片,这意味着,需要用4D张量:
(batch_size, width, height, channel) = 4D
在PyTorch中,torch.Tensor是存储和变换数据的主要工具,提供GPU计算和自动求梯度等功能。
创建tensor介绍几种常见的创建tensor的方法:
Tensor(sizes) 基础构造函数
tensor(data) 将其他类型数据转为torch.tensor
ones(sizes) 全1
zeros(sizes) 全0
eye(sizes) 对角为1,其余为0
arange(s,e,step) 从s到e,步长为step
linspace(s,e,step) 从s到e,均匀分成step份
rand/randn(sizes) rand是[0,1)均匀分布,randn是服从N(0,1)的正态分布
normal(mean,std) 正态分布(均值是mean,标准差是std)
randperm(m) 随机排列
#for example #基于已经存在的tensor,创建一个tensor x = x.new_ones(4, 3, dtype=torch.double) x = torch.randn_like(x, dtype=torch.float) #结果会有一样的size,获取他的维度信息 #返回的torch.Size其实是一个tuple,支持所有tuple的操作。可以使用索引操作取得张量的长、宽等数据维度。张量的操作
几种常见的张量操作方法:
- 加法操作:
import torch y = torch.rand(4,3) print(x+y) # method 1 print(torch.add(x,y)) # method 2 y.add_(x) print(y) # method 3 原值修改
- 索引操作
索引出来的结果与原数据共享内存,修改一个,另一个也会跟着修改。如果不想修改,可以考虑使用copy()等方法。
import torch x = torch.rand(4,3) print(x[:,1]) #取第二列 y = x[0,:] y += 1 print(y) print(x[0,:])#源tensor也被改了
- 维度变换
张量的维度变换常见的方法有torch.view()和torch.reshape(),
x = torch.randn(4,4) y = x.view(16) z = x.view(-1, 8) #-1是指这一维的维数由其他维度决定 print(x.size(),y.size(),z.size()) #torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
注:torch.view()返回的新tensor与源tensor共享内存,也就是同一个tensor,更改其中一个则另一个也会改变。(view()仅仅是改变了对这个张量的观察角度)
因此,为了使创建的张量和原始张量不共享内存,我们需要使用第二种方法torch.reshape(), 同样可以改变张量的形状,但是此函数并不能保证返回的是其拷贝值,所以官方不推荐使用。推荐的方法是先用 clone() 创造一个张量副本然后再使用 torch.view()进行函数维度变换 。
注:使用 clone() 还有一个好处是会被记录在计算图中,即梯度回传到副本时也会传到源 Tensor 。
- 取值操作
使用.item()来获得value
print(type(x.item())) #广播机制
当对两个形状不同的 Tensor 按元素运算时,可能会触发广播(broadcasting)机制:先适当复制元素使这两个 Tensor 形状相同后再按元素运算。
自动求导PyTorch中,所有神经网络的核心是autograd包,为张量上的所有操作提供了自动求导机制。它是一个在运行时定义(define-by-run)的框架,这意味着反向传播是根据代码如何运行来决定的,并且每次迭代可以是不同的。
autograd简介Autograd是反向自动微分系统。autograd记录一个图表,记录在您执行操作时创建数据的所有操作,并提供一个有向无环图,其叶子是输入张量,根是输出张量。通过从根到叶跟踪此图,可以使用链式法则自动计算梯度。
在内部,autograd将此图表示为Function对象图(即表达式),可以apply()编辑它来计算评估图的结果。在计算前向传递时,autograd同时执行请求的计算并构建一个表示计算梯度的函数的图(.grad_fn每个属性都是torch.Tensor的入口点)。当前向传播完成后,在后向传播中评估该图以计算梯度。
需要注意的是,每次迭代都会重新创建图形,这正是允许使用任意Python控制流语句的原因,这可以在每次迭代时改变图形的整体形状和大小。不必在开始训练之前对所有可能的路径进行编码,即您所运行的就是您所区分的。
一些操作需要在前向传递期间保存中间结果,以便执行反向传递。例如,函数F(X)保存输入X计算梯度。
在自定义 PythonFunction时,可以使用 save_for_backward()在前向传递期间保存张量并 在后向传递期间检索saved_tensors。
对于 PyTorch 定义的操作(例如torch.pow()),张量会根据需要自动保存。grad_fn可以通过查找以前缀开头的属性来探索某个张量保存了哪些张量_saved。
x = torch.randn(5, requires_grad=True) y = x.pow(2) print(x.equal(y.grad_fn._saved_self)) # True print(x is y.grad_fn._saved_self) # True
在前面的代码中,引用与y.grad_fn._saved_self相同的 Tensor 对象。但情况可能并非总是如此。例如:
x = torch.randn(5, requires_grad=True) y = x.exp() print(y.equal(y.grad_fn._saved_result)) # True print(y is y.grad_fn._saved_result) # False
在后台,为了防止引用循环,PyTorch在保存时打包了张量,并将其解包到不同的张量中以供读取。在这里,您从访问中获得的张量y.grad_fn._saved_result是一个不同的张量对象y(但它们仍然共享相同的存储)。
一个张量是否会被打包到一个不同的张量对象中取决于它是否是它自己的grad_fn的输出,这是一个在实现过程中可能会发生变化的细节,用户不应该依赖它。
并行计算简介在利用PyTorch做深度学习的过程中,可能会遇到数据量较大无法在单块GPU上完成,或者需要提升计算速度的场景,这时就需要用到并行计算。
并行计算可以使PyTorch在编写完模型之后,让多个GPU来参与训练,减少训练时间。
为什么需要CUDACUDA是GPU的提供商——NVIDIA提供的GPU并行计算框架。对于GPU本身的编程,使用的是CUDA语言来实现的。在PyTorch使用 CUDA表示要开始要求模型或者数据开始使用GPU了。在编写程序中,当我们使用了 .cuda() 时,其功能是让我们的模型或者数据从CPU迁移到GPU(0)当中,通过GPU开始计算。
注:
使用GPU时使用的是.cuda()而不是使用.gpu()。这是因为当前GPU的编程接口采用CUDA,但是市面上的GPU并不是都支持CUDA,只有部分NVIDIA的GPU才支持,AMD的GPU编程接口采用的是OpenCL,在现阶段PyTorch并不支持。
数据在GPU和CPU之间进行传递时会比较耗时,我们应当尽量避免数据的切换。
GPU运算很快,但是在使用简单的操作时,我们应该尽量使用CPU去完成。
当我们的服务器上有多个GPU,需指明使用的GPU是哪一块,如果不设置的话,tensor.cuda()方法会默认将tensor保存到第一块GPU上,等价于tensor.cuda(0),这将会导致爆出out of memory的错误。我们可以通过以下两种方式继续设置。
#设置在文件最开始部分 import os os.environ["CUDA_VISIBLE_DEVICE"] = "2" # 设置默认的显卡 CUDA_VISBLE_DEVICE=0,1 python train.py # 使用0,1两块GPU现在主流的并行方式——Data parallelism
数据并行指的是不再拆分模型,训练时模型都是一整个模型;但是将输入的数据拆分,即同一个模型在不同GPU中训练一部分数据,然后再分别计算一部分数据之后,只需要将输出数据做一个汇总,然后再反向传输。
参考链接:
https://pytorch.org/docs/stable/notes/autograd.html
https://datawhalechina.github.io/thorough-pytorch/第二章/index.html