Pytorch 常用函数之一 _ 数据类型

#Pytorch

编程语言和自然语言一样,不理解的词越多,对全文的理解就越差。掌握必要的基础知识,让后期看代码更加流畅。

机器学习需要掌握数据处理工具 Pandas、Numpy,同理,深度学习也需要掌握相应的工具,在 Pytorch 中数据存储在 Tensor 之中,本篇将介绍它们的基本用法以及与之相关的常用函数。

查看版本信息

包含头文件

1
1.	import torch  

1.查看 torch 版本

1
1.	print(torch.__version__)  

2.查看 CUDA 版本

1
1.	print(torch.version.cuda)  

GPU 相关操作

1. 查看当前是否支持 GPU

1
1.	device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  

2.GPU 相关的数据转换

1
2
3
4
5
1.	a = torch.Tensor([5])  
2. b = a.to('cuda') # 转成在 GPU 上运行的类型
3. b = a.cuda() # 同上
4. c = b.to('cpu') # 转成在 CPU 上运行的类型
5. c = b.cpu() # 同上

3. 查看 GPU 状态

1
2
3
4
1.	print(torch.cuda.device_count()) # 查看可用 GPU 个数  
2. print(torch.cuda.current_device()) # 查看当前使用的 GPU ID
3. print(torch.cuda.get_device_capability(0)) # 查看 ID 为 0 的 CUDA 容量
4. print(torch.cuda.get_device_name(0)) # 查看设备名

4. 清空 GPU 缓存

1
1.	print(torch.cuda.empty_cache()) # 清空缓存  

Tensor

Tensor 用于表示矩阵(多维数据),类似 Numpy 的 ndarray,它可以使用 GPU 加速。从 Pytorch 0.4.0 之后,Variable 与 Tensor 合并(Variable 仍存在,但很少使用)。

创建 Tensor 时参数 requires_grad 默认为 False,若设为 True,则可实现自动求导的功能,梯度保存在其内部变量 grad 中,计算梯度的方法存储在 grad_fn 中。

1.生成 Tensor

用 Tensor 方法将其它格式数据转换成张量,转换内容一般是 list 或数组格式:

1
2
3
4
1.	a = torch.Tensor([[1,2],[3,4],[5,6]]) # 生成 3,2 维Tensor    
2. b = torch.zeros(3,5) # 生成内容为全0的 3,5 维Tensor
3. c = torch.rand(3,5) # 生成内容为 0-1 随机数的 3,5 维Tensor
4. d = c.clone() # 将c中内容复制到 d, 新旧内容指向不同的地址空间

2.修改 Tensor

用赋值的方法即可修改张量,比如将上面生成张量中位置 1,1 的元素赋值成 50。

1
1.	a[1,1]=50  

3. 查看 Tensor 状态

查看 Tensor 数据类型,大小及元素个数

1
2
3
4
5
6
1.	a = torch.Tensor([5])    
2. print(a.type()) # torch.FloatTensor,默认类型为FloatTesor
3. print(a.size()) # torch.Size([1])
4. print(a.shape) # torch.Size([1])
5. print(a.numel()) # 1,查看元素个数
6. print(a.dim()) # 1, 查看维度

4.类型转换

Tensor 与其它数据类型相互转换

1
2
3
4
5
6
1.	a = torch.Tensor([5]) # tensor([5.])
2. b = a.numpy() # 转换成numpy.array类型 [5.]
3. c = a.item() # 转换成单个值 5.0
4. d = torch.from_numpy(b) # 转换成Tensor tensor([5.])
5. e = d.int() # 转换成 IntTensor tensor([5], dtype=torch.int32)
6. f = d.tolist() # 转换成list [5.0]

维度变换

1.增加维度

在深度学习过程中,现有的数据格式和模型要求的格式往往不同,层与层之间的数据也需要转换后才能对接,维度转换是最常用的方法。

squeeze 意为压缩,即去掉维度,unsqueeze 则相反,为添加维度。

1
1.	unsqueeze(input, dim, out=None)   

用于增添第 dim 维度为 1。具体用法见以下示例:

1
2
3
4
5
6
1.	a = torch.Tensor([1,2,3])  
2. print(a, a.shape) # tensor([1., 2., 3.]) torch.Size([3])
3. b = torch.unsqueeze(a, 1)
4. print(b, b.shape) # tensor([[1.],[2.],[3.]]) torch.Size([3, 1])
5. c = torch.unsqueeze(a, 0)
6. print(c, c.shape) # tensor([[1., 2., 3.]]) torch.Size([1, 3])

2.减小维度

1
1.	squeeze(input, dim=None, out=None)   

用于删除第 dim 个维度,如果当前不包括指定的维度,则不会删除。如果不指定 dim,函数将删除值为 1 的维度。

本例中延用上例中的数据:

1
2
3
1.	print(torch.squeeze(c,0))  # tensor([1., 2., 3.])  
2. print(torch.squeeze(b,1)) # tensor([1., 2., 3.])
3. print(torch.squeeze(b)) # tensor([1., 2., 3.])

3.转换维度

比 squeeze 和 unsqueeze 更简单的方法是直接把张量转换成指定维度,使用 view 函数实现,它类似于 numpy 的 reshape,Tensor 也提供 reshape 方法。

1
1.	view(*shape)   

将张量转换成指定的形状,示例:

1
2
3
4
5
1.	x = torch.Tensor([1,2,3,4])  
2. print(x.view(2,2)) # tensor([[1., 2.], [3., 4.]])
3. print(x.view(1,4)) # tensor([[1., 2., 3., 4.]])
4. print(x.view(1,-1)) # 设为-1时自动计算该维度大小 tensor([[1., 2., 3., 4.]])
5. print(x.view(4)) # tensor([1., 2., 3., 4.])

4.cat 拼接

cat 函数用于在指定维度上拼接多个张量。

1
1.	cat(tensors, dim=0, out=None)   

将 tensors 中的多个张量按 dim 指定的维度拼接成一个张量,拼接后总维数不变。

1
2
3
4
5
6
7
8
9
10
1.	x = torch.Tensor([[1,2],[3,4]])  
2. y = torch.Tensor([[5,6],[7,8]])
3. print(torch.cat((x,y),0))
4. # tensor([[1., 2.],
5. # [3., 4.],
6. # [5., 6.],
7. # [7., 8.]])
8. print(torch.cat((x,y),1))
9. # tensor([[1., 2., 5., 6.],
10. # [3., 4., 7., 8.]])

一般面对的数据最多三维,并以一两维居多,可将其理解为横向加或者纵向加。

5.stack 拼接

与 cat 拼接不同的是,stack 拼接后维度增加,其用法如下:

1
1.	stack(tensors, dim=0, out=None)  

示例:

1
2
3
4
5
6
7
8
1.	x = torch.Tensor([1,2])  
2. y = torch.Tensor([3,4])
3. print(torch.stack((x,y),dim=0))
4. # tensor([[1., 2.],
5. # [3., 4.]])
6. print(torch.stack((x,y),dim=1))
7. # tensor([[1., 3.],
8. # [2., 4.]])

从输出内容可以看到,拼接后张量变成了两维,dim=0 是最常用的方法,它直接把两个张量拼在一起,当 dim=1 时,拼接时转换了位置。

注意:想把 list(tensor, tensor) 变为二维 tensor,使用 stack 即可

6.transpose 两维度互换

1
1.	transpose(input, dim0, dim1)  

互换 dim0, dim1 两个维度,具体用法如下:

1
2
3
4
1.	x = torch.Tensor([[1,2],[3,4]])  
2. print(torch.transpose(x,0,1))
3. # tensor([[1., 3.],
4. # [2., 4.]])

7.perumute 多维度互换

permute 与 transpose 功能类似,但更加灵活,它可以指定多个维度互换。

1
2
3
4
1.	x = torch.Tensor([[1,2],[3,4]])  
2. print(torch.transpose(x,0,1))
3. # tensor([[1., 3.],
4. # [2., 4.]])

用于将张量转换成 dim 指定的维度。

1
2
3
1.	x = torch.rand(2,3,4)  
2. print(x.shape, x.permute(2,1,0).shape)
3. # torch.Size([2, 3, 4]) torch.Size([4, 3, 2])

本例先产生了一组 3 维的随机数,每个维度的元素个数分别是 2,3,4,然后使用 permute 将其第 2 维转成第 0 维,第 1 维不变,第 0 维转成第 2 维,从打印信息可以看到各维元素个数的变化。permute 常用于对转换图片格式。

8.维度扩展

增加 Tensor 中元素的个数,其内容与被扩展的内容一致。

1
2
1.	a = torch.Tensor([5])  
2. print(a.expand(1, 2)) # tensor([[5., 5.]])

求导

下例中使用了 torch.tensor 而非 torch.Tensor,torch.Tensor 是 Pytorch 中的类,确切地说是 FloatTensor 的别名;而 torch.tensor() 是函数,它更加灵活,使用方法如下:

1
1.	torch.tensor(data, dtype=None, device=None, requires_grad=False)  

它可以创建各种类型的 Tensor 数据。

下面声明三个变量 x,a,b,用它们计算变量 y,之后用 y.backward() 求 y 对 x,a,b 三个变量的偏导数,这是深度学习中常说的“反向”过程。结果存储在变量的 grad 元素中,如 x.grad。

1
2
3
4
5
6
7
8
9
1.	x = torch.tensor([1.0], requires_grad=True)    
2. a = torch.tensor([2.0], requires_grad=True)
3. b = torch.tensor([3.0], requires_grad=True)
4. y = a * x + b
5. y.backward()
6. print(x.grad) # 输出结果: tensor([2.])
7. print(a.grad) # 输出结果: tensor([1.])
8. print(b.grad) # 输出结果: tensor([1.])
9. print(b.data) # 输出结果: tensor([3.])

从输出结果可以看到,Tensor 包含两个元素,data 是它的 Tensor 值,grad 保存的是求得的偏导数。

剥离无梯度变量

detach 方法用于从普通 Tensor 中剥离出无梯度的变量。下面延用上例求导后有梯度的数据 b。

1
2
3
1.	print(b) # tensor([3.], requires_grad=True)  
2. print(b.detach()) # tensor([3.])
3. print(b.detach_()) # tensor([3.])

detach 和 detach_ 的区别是 detach 获取 b 的 data 数据,而 detach_ 则是将 b 中的 grad_fn 设置为 None,requires_grad 设置为 False,从而改变了 b 的内容。

Parameter

一般模型参数都是 torch.nn.parameter.Parameter 类型的数据,它继承了 Tensor,主要不同是 requires_grad 默认为 True,以便于模型调参。

常在两种场景中使用 Parameter,一种是 fine-tune 精调时冻结模型中某些层的参数;另一种是自己实现一些特殊的结构,如构建 Attention 时,用 Parameter 创建需要调节的参数。

1.创建 Parameter 数据

1
2
1.	p = torch.nn.Parameter(torch.randn(2))   
2. print(p) # tensor([1.2087, 1.2607], requires_grad=True)

2. 查看模型的 Parameter 参数,大小及冻结情况

Pytorch 模型的基类是 Module,其中维护一个名为 _parameters 的字典,它包含每一个子元素的名字 (key) 和 value 参数 (value)。如需要冻结某层,将其 require_grad 设为 False 即可。

1
2
3
4
5
6
1.	model = torch.nn.Linear(1,1)  
2. for name, param in model.named_parameters():
3. print(name, param.size(), param.requires_grad)
4. # 输出结果:
5. # weight torch.Size([1, 1]) True
6. # bias torch.Size([1]) True