机器学习需要掌握数据处理工具Pandas、Numpy,同理,深度学习也需要掌握相应的数据处理工具,在Pytorch中数据存储在张量Tensor和变量Variable之中,本篇将介绍它们的基本用法以及与之相关的常用函数。
掌握必要的基础知识,让后期看代码更加流畅,避免陷入太多细节。
Tensor 张量
Tensor用于表示矩阵(多维数据),类似Numpy的ndarray,不同的是,可以使用GPU加速。
1.生成张量
import torch
用Tensor方法将其它格式数据转换成张量:
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。
a[1,1]=50
print(a)
# 输出结果:
# tensor([[ 1., 2.],
# [ 3., 50.],
# [ 5., 6.]])
3.类型转换
张量与numpy数据相互转换
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数据格式
if torch.cuda.is_available(): # 如果支持cuda硬件加速
d = a.cuda()
Variable变量
Variable是神经网络计算图中特有的概念,它提供了自动求导的功能。
1.类型转换
将Tensor转成Variable
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。
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则相反,为添加维度。
unsqueeze(input, dim, out=None)
用于增添第dim维度为1。具体用法见以下示例:
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.减小维度
squeeze(input, dim=None, out=None)
用于删除第dim个维度,如果当前不包括指定的维度,则不会进行删除。如果不指定dim,函数将删除值为1的维度。
本例中延用上例中的数据:
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。
view(*shape)
将张量转换成指定的形状,示例:
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函数用于在指定维度上拼接多个张量。
cat(tensors, dim=0, out=None)
将tensors中的多个张量按dim指定的维度拼接成一个张量,拼接后总维数不变。
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拼接后维度增加,其用法如下:
stack(tensors, dim=0, out=None)
示例:
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两维度互换
transpose(input, dim0, dim1)
互换dim0, dim1两个维度,具体方法见示例:
x = torch.Tensor([[1,2],[3,4]])
print(torch.transpose(x,0,1))
# tensor([[1., 3.],
# [2., 4.]])
7.perumute多维度互换
permute与transpose功能类似,但更加灵活,它可以指定多个维度互换。
permute(dim)
用于将张量转换成dim指定的维度。
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维,从打印信息中可以看到各维元素个数的变化。