正如numpy包中的array,Pandas包中的Series和Dataframe一样,为了方便计算,Pytorch也在Python数据结构的基础上封装了几个基本的数据结构。
一、张量(Tensor)
没错,就是TensorFlow名字里的Tensor,本来谷歌给TensorFlow命名的时候就是给这个框架赋予了深度学习就是“张量流动”的深刻内涵。因为深度学习处理的数据量和维度都比较大,所以很多深度学习框架借用了张量这个概念作为基本的数据结构。
其实张量虽然听起来非常高大上,数学上也有一些其他的物理世界抽象和运算法则。但是,张量其实就是一个多维的向量,二维张量就是三维向量、一维张量就是二维向量……所以,在深度学习里,我们直接把它看做一个多维的向量就好。
1、创建张量
1)基本创建语法
在Pytorch中,创建张量的方式非常简单,只需要:a = torch.Tensor(参数)
即可。
在这里,如果我们需要创建固定维度大小的张量,那么参数可以写成:(n,m,……)
,如果需要指定每个元素的值,那么就参数就需要写成:([元素1,元素2,元素3,元素4,……])
。
比如,以下是一个创建张量的例子:
import torth
A = torch.Tensor(2,3) #创建一个维度为(2,3)的张量
b = [[1,2,],[3,4],[5,6]]
B = torch.FloatTensor(b)#创建一个元素为b数组中的元素的张量
print(A)
print(A.type())
print(B)
print(B.type())
输出结果如下:
tensor([[ 9.5016e+21, 1.9249e-37, 1.7228e-34],
[ 1.8311e-38, -3.7846e-37, 3.8074e+22]])
torch.FloatTensor
tensor([[1., 2.],
[3., 4.],
[5., 6.]])
torch.FloatTensor
这里可以看到,两种方式创建的张量都是Float类型。因为这种数据类型即保证了一定的精确度,又不是特别占用内存。
当然,在使用过程中,根据自己的实际情况,可以创建指定元素数据类型的张量:
- 元素为32位浮点型的张量(同上边效果是一样的):torch.FloatTensor()
- 元素为64位浮点型的张量:torch.DoubleTensor()
- 元素为整型的张量(32位):torch.IntTensor()
- 元素为16位整型的张量:torch.ShortTensor()
- 元素为64位整型的张量:torch.LongTensor()
如果需要查看某一张量的维度,可以使用A.size()
。
2)创建一些特殊的张量。
① 创建全0张量:A = torch.zeros(n,m)
② 创建全1张量:A = torch.ones(n,m)
③ 创建指定维度的随机数张量:(元素呈正态分布,均值为0,方差为1)A = torch.randn(n,m)
④ 创建指定维度的随机数张量:(元素在0到1之间均匀分布)A = torch.rand(n,m)
⑤ 创建元素以一定步长递变的张量:A = torch.range(起始值,结束值,步长)
注意,这里生成的值是浮点型,步长也可以设置为浮点型。
2、张量运算
为了便于接下来的运算,我们首先生成几个Tensor变量。
import torch
A = torch.Tensor( [[-1,-2],[-3,-4],[-5,-6]])
B = torch.Tensor( [[1,2],[3,4],[5,6]])
C = 2
1)对所有元素取绝对值:torch.abs(A)
ab = torch.abs(A)
print(ab)
输出结果:
tensor([[1., 2.],
[3., 4.],
[5., 6.]])
2)两个张量对应元素相加:torch.add(A,B)
ad1 = torch.add(A,B)
print(ad1)
ad2 = torch.add(A,C)
print(ad2)
输出结果:
tensor([[0., 0.],
[0., 0.],
[0., 0.]])
tensor([[ 1., 0.],
[-1., -2.],
[-3., -4.]])
可以看到,numpy的广播机制在Pytorch中也适用。
3)两个张量对应元素相乘:torch.mul(A,B)
mul1 = torch.mul(A,B)
print(mul1)
mul2 = torch.mul(A,C)
print(mul2)
输出结果:
tensor([[ -1., -4.],
[ -9., -16.],
[-25., -36.]])
tensor([[ -2., -4.],
[ -6., -8.],
[-10., -12.]])
4)两个张量对应元素相除:torch.div(A,B)
div1 = torch.div(A,B)
print(div1)
div2 = torch.div(A,C)
print(div2)
输出结果:
tensor([[-1., -1.],
[-1., -1.],
[-1., -1.]])
tensor([[-0.5000, -1.0000],
[-1.5000, -2.0000],
[-2.5000, -3.0000]])
5)两个张量按照矩阵乘法规则结合:torch.mm(A,B)
特别注意,这个函数要和torch.mul(A,B)
区分,这个函数需要两个张量满足矩阵乘法运算规则才可以运算。
mm = torch.mm(A,torch.t(B))#对B矩阵转置之后与A矩阵相乘
print(mm)
输出结果:
tensor([[ -5., -11., -17.],
[-11., -25., -39.],
[-17., -39., -61.]])
6)显示张量元素的值:torch.clamp(A,min,max)
会使超出[min,max]元素的值被限制在这个范围内。
cla = = torch.clamp(A,-4,-1)
print(cla)
输出结果:
tensor([[-1., -2.],
[-3., -4.],
[-4., -4.]])
另外,还有一些操作,例如:
- 求张量A的n次幂:
torch.pow(A,n)
- 求矩阵和向量的乘积:
torch.mv(A,B)
。其中A是矩阵B是向量,也需要维度符合规则。
通过上边的例子可以看到,torch的张量和numpy数组非常类似。的确,Pytorch中的张量可以理解为可以在GPU上运行的numpy数组。两者也可以通过torch.from_numpy()
,A.numpy
这两个函数相互转换。看下边这个例子:
A = np.array([[1,2,3],[4,5,6]])#生成一个numpy数组
print("A的数据类型是:",type(A)) #将numpy数组转换成torch张量
At = torch.from_numpy(A)
print("At的数据类型是:",type(At))
An = At.numpy() #将torch张量转换成numpy数组
print("An的数据类型是:",type(An))
输出结果如下:
A的数据类型是: <class 'numpy.ndarray'>
At的数据类型是: <class 'torch.Tensor'>
An的数据类型是: <class 'numpy.ndarray'>
二、变量(Variable)
在Pytorch中,张量就是个死气沉沉的数组,只可以执行简单的加减乘除以及矩阵操作,而这对于深度学习是远远不够的。变量赋予了张量自动求导这一深度学习反向传播所需要的重要能力。
其基本原理就是,变量相当于把张量放到了一个计算图中(计算图这概念再TensorFlow中也有,不过TensorFlow中需要用户手动创建计算图,而Pytorch中需要用户执行的操作相对较少)。
要想使用Variable函数,需要先导入自动求梯度包:from torch.autograd import Variable
Variable有三个属性:data,grad和grad_fn。
data属性存放了Variable的张量值,grad属性可以得到这个张量反向传播的梯度,grad_fn可以得到这个Variable的操作【进一步解释】。看这样一个例子:
import torch
from torch.autograd import Variable
x1= Variable(torch.Tensor([3]),requires_grad = True)
y1 = 3*x1 +1
y1.backward()
print(x1.grad)
x2 = Variable(torch.Tensor([3]),requires_grad = True)
y2 = 3*torch.pow(x2,2) +1
y2.backward()
print(x2.grad)
其中,requires_grad = True的意思是在反向传播的时候要对这个变量求梯度。输出如下:
tensor([3.])
tensor([18.])
可以看到,可能有人会觉得,这明显就是对函数和求了个导数嘛,有什么了不起的。但是,Variable最厉害的是对于复杂的函数和复合函数也可以用一条语句求梯度,另外也可以求矩阵的梯度,比如:
import torch
from torch.autograd import Variable
x = Variable(torch.Tensor([1,2,3,4]),requires_grad = True)
y = 3*torch.pow(x,2) +1
y.backward(torch.Tensor([1,1,1,1]))#这里必须要写入参数,与被求导的张量维数相同。
print(x.grad)
输出如下:
tensor([ 6., 12., 18., 24.])
这样,就可以分别得到x = 1,2,3,4时,y的导数值,其中,y.backward(torch.Tensor([1,1,1,1]))
中的[1,1,1,1]
分别会和对应维数得到的导数相乘,代表向量的每个维度反向传播的更新系数。
总结:
本文主要介绍了Pytorch的基本数据类型:Tensor和Variable的使用。