使用张量处理数据
张量(Tensors)类似于numpy中的ndarrays,Tensors可以在GPU中加速运算。
我们首先导入torch
from __future__ import print_function # python2中使用print()的输出函数
import torch
然后我们创建一个3行和4列的2D数组(通常也叫矩阵),并且把每个元素初始化成0
x = torch.zeros(3, 4)
print(x)
0 0 0 0
0 0 0 0
0 0 0 0
[torch.FloatTensor of size 3x4]
类似的,我们可以创建数组每个元素被初始化成1。
x = torch.ones(3, 4)
print(x)
1 1 1 1
1 1 1 1
1 1 1 1
[torch.FloatTensor of size 3x4]
或者从数组直接构造
x = torch.FloatTensor([[1,2],[3,4]])
print(x)
1 2
3 4
[torch.FloatTensor of size 2x2]
我们经常需要创建随机数组,就是说每个元素的值都是随机采样而来,这个经常被用来初始化模型参数。下面创建数组,它的元素服从均值0方差1的正态分布。
y = torch.randn(3, 4)
print(y)
1.8000 -1.2639 -0.5560 0.4861
-0.7101 -0.1594 -0.8752 -0.1776
-0.5662 -0.1355 -1.0900 -0.1244
[torch.FloatTensor of size 3x4]
每个数组的形状可以通过.shape来获取
print(x.size())
(3L, 4L)
它的总元素个数,是形状的累乘。
x_num = x.size(0) * x.size(1)
print(x_num)
12
操作符
PyTorch支持大量的数学操作符,例如按元素加法:
x = torch.FloatTensor([[1,2],[3,4]])
y = torch.FloatTensor([[5,6],[7,8]])
print(x + y) # 或者print(torch.add(x, y))
6 8
10 12
[torch.FloatTensor of size 2x2]
乘法:
print(x * y)
5 12
21 32
[torch.FloatTensor of size 2x2]
指数运算:
print(torch.exp(x))
2.7183 7.3891
20.0855 54.5981
[torch.FloatTensor of size 2x2]
也可以转置一个矩阵然后计算矩阵乘法:
x = torch.FloatTensor([[1,2,3],[4,5,6]])
y = torch.FloatTensor([[7,8,9],[10,11,12]])
print(torch.matmul(x, torch.t(y)))
50 68
122 167
[torch.FloatTensor of size 2x2]
可以索引数组:
x = torch.FloatTensor([[1,2],[3,4]])
print(x[:,1]) #提取第2列
2
4
[torch.FloatTensor of size 2]
形状转换(Broadcasting)
当二元操作符左右两边Tensor形状不一样时,系统会尝试将其复制到一个共同的形状。例如a的第0维是3, b的第0维是1,那么a+b时会将b沿着第0维复制3遍:
a = torch.arange(0, 3).resize_(3, 1)
b = torch.arange(0, 2).resize_(1, 2)
print(a)
print(b)
print(a + b)
0
1
2
[torch.FloatTensor of size 3x1]
0 1
[torch.FloatTensor of size 1x2]
0 1
1 2
2 3
[torch.FloatTensor of size 3x2]
跟NumPy的转换
Tensor可以很方便同numpy进行转换
x = np.ones((2, 3)).astype(np.float32)
y = torch.from_numpy(x) # numpy -> tensor
z = y.numpy() # tensor -> numpy
print(x)
print(y)
print(z)
[[ 1. 1. 1.]
[ 1. 1. 1.]]
1 1 1
1 1 1
[torch.FloatTensor of size 2x3]
[[ 1. 1. 1.]
[ 1. 1. 1.]]
替换操作(In-place)
在前面的样例中,我们为每个操作新开内存来存储它的结果。例如,如果我们写y = x + y, 我们会把y从现在指向的实例转到新建的实例上去。我们可以用Python的id()函数来看这个是怎么执行的:
x = torch.ones(3,4)
y = torch.ones(3,4)
before = id(y)
y = y + x
print(id(y) == before)
False
我们可以把结果通过[:]写到一个之前开好的数组里:
x = torch.ones(3,4)
y = torch.ones(3,4)
z = torch.zeros(x.size())
before = id(z)
z[:] = x + y
print(id(z) == before)
True
但是这里我们还是为x+y创建了临时空间,然后再复制到z。需要避免这个开销,我们可以使用操作符的全名版本中的out参数:
torch.add(x, y, out=z)
如果现有的数组不会复用,我们也可以用y.add_(x)
达到这个目的,类似的操作还有x.copy_(y)
,x.t_()
:
x = torch.ones(3,4)
y = torch.ones(3,4)
before = id(y)
y.add_(x)
print(id(y) == before)
True
截取(Slicing)
截取x的第2、3行:
x = torch.arange(0,9).resize_(3,3)
print(x)
print(x[1:3])
0 1 2
3 4 5
6 7 8
[torch.FloatTensor of size 3x3]
3 4 5
6 7 8
[torch.FloatTensor of size 2x3]
截取x的第2、3列:
x = torch.arange(0,9).resize_(3,3)
print(x)
print(x[:,1:3])
0 1 2
3 4 5
6 7 8
[torch.FloatTensor of size 3x3]
1 2
4 5
7 8
[torch.FloatTensor of size 3x2]
以及直接写入指定位置:
x[1,2] = 9.0
print(x)
0 1 2
3 4 9
6 7 8
[torch.FloatTensor of size 3x3]
多维截取:
print(x[1:2,1:3])
4 9
[torch.FloatTensor of size 1x2]
多维写入:
x[1:2,1:3] = 9.0
print(x)
0 1 2
3 9 9
6 7 8
[torch.FloatTensor of size 3x3]
GPU计算
通过在张量后加上.cuda()
可以把Tensors移动到GPU上
x = torch.arange(0,9).resize_(3,3)
y = torch.arange(1,10).resize_(3,3)
print(x)
print(y)
if torch.cuda.is_available():
x = x.cuda()
y = y.cuda()
print(x)
print(y)
print(x+y)
0 1 2
3 4 5
6 7 8
[torch.cuda.FloatTensor of size 3x3 (GPU 0)]
1 2 3
4 5 6
7 8 9
[torch.cuda.FloatTensor of size 3x3 (GPU 0)]
1 3 5
7 9 11
13 15 17
[torch.cuda.FloatTensor of size 3x3 (GPU 0)]