Pytorch_ 数据基础

#Pytorch

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

掌握必要的基础知识,让后期看代码更加流畅,避免陷入太多细节。

Tensor 张量

Tensor 用于表示矩阵(多维数据),类似 Numpy 的 ndarray,不同的是,可以使用 GPU 加速。

1.生成张量

1
import torch

用 Tensor 方法将其它格式数据转换成张量:

1
2
3
4
5
6
7
8
a = torch.Tensor([[1,2],[3,4],[5,6]])
print(a)
print(a.size())
# 输出结果:
# tensor([[1., 2.],
# [3., 4.],
# [5., 6.]])
# torch.Size([3, 2])

另外,也可以使用 torch.zeros(),torch.randn() 生成张量。

2.修改张量

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

1
2
3
4
5
6
a[1,1]=50
print(a)
# 输出结果:
# tensor([[ 1., 2.],
# [ 3., 50.],
# [ 5., 6.]])

3.类型转换

张量与 numpy 数据相互转换

1
2
3
4
5
6
7
8
9
10
b = a.numpy()
print(b)
# [[ 1. 2.]
# [ 3. 50.]
# [ 5. 6.]]
c = torch.from_numpy(b)
print(c)
# tensor([[ 1., 2.],
# [ 3., 50.],
# [ 5., 6.]])

转换成 GPU 上运行的 cuda 数据格式

1
2
if torch.cuda.is_available(): # 如果支持cuda硬件加速
d = a.cuda()

Variable 变量

Variable 是神经网络计算图中特有的概念,它提供了自动求导的功能。

1.类型转换

将 Tensor 转成 Variable

1
2
from torch.autograd import Variable
b = Variable(a, requires_grad=True)

使用了参数 requires_grad,用于指定是否求梯度,默认为 False。

2.求导

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

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

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

常用的数据处理函数

1.增加维度

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

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

1
unsqueeze(input, dim, out=None) 

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

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

2.减小维度

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

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

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

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

3.转换维度

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

1
view(*shape) 

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

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

4.cat 拼接

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

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

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

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

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

5.stack 拼接

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

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

示例:

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

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

6.transpose 两维度互换

1
transpose(input, dim0, dim1)

互换 dim0, dim1 两个维度,具体方法见示例:

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

7.perumute 多维度互换

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

1
permute(dim) 

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

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

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