DataWhale在线阅读地址:https://datawhalechina.github.io/thorough-pytorch/

PyTorch

PyTorch是由Facebook人工智能研究小组开发的一种基于Lua编写的Torch库的Python实现的深度学习库,目前已被广泛应用,并正在取代TensorFlow的主导地位。

1.优势

1)简洁易理解

2)上手难度小

3)有良好的文档和社区支持,更新有保障

4)项目开源

5)更好的代码调试

6)愈加完善的库

2.安装(将在下一文中记录过程)

2.1Anaconda的安装

2.2 查看显卡

2.3 安装PyTorch

2.4 PyCharm安装

3.学习资源

1)Awesome-pytorch-list:目前已获12K Star,包含了NLP,CV,常见库,论文实现以及Pytorch的其他项目。

2)PyTorch官方文档:官方发布的文档,十分丰富。

3)Pytorch-handbook:GitHub上已经收获14.8K,pytorch手中书。

4)PyTorch官方社区:PyTorch拥有一个活跃的社区,在这里你可以和开发pytorch的人们进行交流。

5)PyTorch官方tutorials:官方编写的tutorials,可以结合colab边动手边学习

6)动手学深度学习:动手学深度学习是由李沐老师主讲的一门深度学习入门课,拥有成熟的书籍资源和课程资源,在B站,Youtube均有回放。

7)Awesome-PyTorch-Chinese:常见的中文优质PyTorch资源。

4.基础知识

4.1 张量

张量是基于向量和矩阵的推广,核心是一个数据容器,多数情况下只包含数字。

张量维度 代表含义
0维张量 代表的是标量(数字)
1维张量 代表的是向量
2维张量 代表的是矩阵
3维张量 时间序列数据 股价 文本数据 单张彩色图片(RGB)
4维张量 图像集合
5维张量 视频

4.2 Tensor

torch.Tensor 是存储和变换数据的主要工具,功能类似NumPy的多维数组。

1)创建tensor

①随机初始化矩阵

1
2
3
import torch
x = torch.rand(4, 3)
print(x)
1
2
3
4
tensor([[0.7569, 0.4281, 0.4722],
[0.9513, 0.5168, 0.1659],
[0.4493, 0.2846, 0.4363],
[0.5043, 0.9637, 0.1469]])

②全零矩阵

torch.zeros()构建

torch.zero_()转换

torch.zeros_like()转换

1
2
3
import torch
x = torch.zeros(4, 3, dtype=torch.long)
print(x)
1
2
3
4
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])

③ 张量的构建

1)使用数据直接构建

1
2
3
import torch
x = torch.tensor([5.5, 3])
print(x)
1
tensor([5.5000, 3.0000])

2)基于已经存在的 tensor,创建一个 tensor

1
2
3
4
5
6
7
8
9
10
11
12
13
x = x.new_ones(4, 3, dtype=torch.double) 
# 创建一个新的全1矩阵tensor,返回的tensor默认具有相同的torch.dtype和torch.device
# 也可以像之前的写法 x = torch.ones(4, 3, dtype=torch.double)
print(x)

x = torch.randn_like(x, dtype=torch.float)
# 重置数据类型
print(x)
# 结果会有一样的size
# 获取它的维度信息

print(x.size())
print(x.shape)
1
2
3
4
5
6
7
8
9
10
11
12
13
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)

tensor([[ 2.7311, -0.0720, 0.2497],
[-2.3141, 0.0666, -0.5934],
[ 1.5253, 1.0336, 1.3859],
[ 1.3806, -0.6965, -1.2255]])

torch.Size([4, 3])
torch.Size([4, 3])
#返回的torch.Size其实是一个tuple,⽀持所有tuple的操作。我们可以使用索引操作取得张量的长、宽等数据维度。
函数 功能
Tensor(sizes) 基础构造函数
tensor(data) 类似于np.array
ones(sizes) 全1
zeros(sizes) 全0
eye(sizes) 对角为1,其余为0
arange(s,e,step) 从s到e,步长为step
linspace(s,e,steps) 从s到e,均匀分成step份
rand/randn(sizes) rand是[0,1)均匀分布;randn是服从N(0,1)的正态分布
normal(mean,std) 正态分布(均值为mean,标准差是std)
randperm(m) 随机排列

④张量的操作

1)加法

1
2
3
4
5
6
7
8
9
10
11
import torch
# 方式1
y = torch.rand(4, 3)
print(x + y)

# 方式2
print(torch.add(x, y))

# 方式3 in-place,原值修改
y.add_(x)
print(y)
1
2
3
4
5
6
7
8
9
10
11
12
tensor([[ 2.8977,  0.6581,  0.5856],
[-1.3604, 0.1656, -0.0823],
[ 2.1387, 1.7959, 1.5275],
[ 2.2427, -0.3100, -0.4826]])
tensor([[ 2.8977, 0.6581, 0.5856],
[-1.3604, 0.1656, -0.0823],
[ 2.1387, 1.7959, 1.5275],
[ 2.2427, -0.3100, -0.4826]])
tensor([[ 2.8977, 0.6581, 0.5856],
[-1.3604, 0.1656, -0.0823],
[ 2.1387, 1.7959, 1.5275],
[ 2.2427, -0.3100, -0.4826]])

2)索引

结果与原数据共享内存,使用copy()则不会修改源数据。

1
2
3
4
import torch
x = torch.rand(4,3)
# 取第二列
print(x[:, 1])
1
tensor([-0.0720,  0.0666,  1.0336, -0.6965])
1
2
3
4
y = x[0,:]
y += 1
print(y)
print(x[0, :]) # 源tensor也被改了了
1
2
tensor([3.7311, 0.9280, 1.2497])
tensor([3.7311, 0.9280, 1.2497])

3)维度变换

*torch.view() 共享内存,可理解为view()仅仅是改变了对这个张量的观察角度。

1
2
3
4
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # -1是指这一维的维数由其他维度决定
print(x.size(), y.size(), z.size())
1
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])

*torch.reshape() 不推荐

*推荐方案:先用 clone() 创造一个张量副本然后再使用 torch.view()进行函数维度变换。

我们可以使用.item()来获得元素tensor的value,而不获得其他性质。

⑤广播机制

形状不同的 Tensor 按元素运算时,可能会触发 广播机制 :先复制元素使这两个 Tensor 形状相同,后再按元素运算。

5.自动求导

autograd包为张量上的所有操作提供自动求导机制。它是在运行时定义的框架,这意味着反向传播是根据代码运行决定,并且每次迭代可以不同。

torch.Tensor是这个包的核心类。如果设置它的属性.requires_gradTrue,那么它将会追踪对于该张量的所有操作。当完成计算后可以通过调用.backward(),来自动计算所有的梯度。这个张量的所有梯度将会自动累加到.grad属性。在 y.backward() 时,如果 y 是标量,则不需要为 backward() 传入任何参数;否则,需要传入一个与 y 同形的Tensor。

防止跟踪:调用.detach()方法;将代码块包装在 with torch.no_grad():中。

6.并行计算

遇到数据量较大或者需要提升计算速度的场景时需要 并行计算。

并行计算可充分利用GPU的性能,能提高效率。

CUDA是NVIDIA提供的GPU并行计算框架,我们可使用.cuda(),让我们的模型或者数据从CPU迁移到GPU(0)当中,通过GPU开始计算。

并行方法:

网络结构分布到不同的设备中(Network partitioning)——GPU的通信在密集任务中困难,此方式正被遗弃;

同一层的任务分布到不同数据中(Layer-wise partitioning)——同步任务加重时会出现第一种方式同样的问题;

不同的数据分布到不同的设备中,执行相同的任务(Data parallelism)——拆分数据,主流方式。