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

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

查看版本信息

包含头文件

1.  import torch

1.查看torch版本

1.  print(torch.__version__)

2.查看CUDA版本

1.  print(torch.version.cuda)

GPU相关操作

1. 查看当前是否支持GPU

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

2.GPU相关的数据转换

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.  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.  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.  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.  a[1,1]=50

3. 查看Tensor状态
查看Tensor数据类型,大小及元素个数

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.  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.  unsqueeze(input, dim, out=None)

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

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.  squeeze(input, dim=None, out=None)

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

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.  view(*shape)

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

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.  cat(tensors, dim=0, out=None)

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

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.  stack(tensors, dim=0, out=None)

示例:

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时,拼接时转换了位置。

6.transpose两维度互换

1.  transpose(input, dim0, dim1)

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

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.  x = torch.Tensor([[1,2],[3,4]])  
2.  print(torch.transpose(x,0,1))  
3.  # tensor([[1., 3.],  
4.  #        [2., 4.]])

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

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.  a = torch.Tensor([5])  
2.  print(a.expand(1, 2)) # tensor([[5., 5.]])

求导

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

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.  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.  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.  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.  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