Tensor是PyTorch中重要的数据结构,可认为是一个高维数组,可以使用GPU加速。

import torch as t

# 构建5*3矩阵,只是分配了空间,未初始化
x = t.Tensor(5, 3)

# 使用[0, 1]均匀分布随机初始化二维数组
x = t.rand(5, 3)

# 查看x的形状
print(x.size())

y = t.rand(5, 3)

# 加法的第一种写法
x + y

# 加法的第二种写法
t.add(x, y)

# 加法的第三种写法
result = t.Tensor(5, 3) # 预先分配空间
t.add(x, y, out=result) # 输入到result

函数名后面带下划线_的函数会修改Tensor本身。

Tensor和numpy的数组间的互操作非常容易且快速。

a = t.ones(5)
b = a.numpy() # Tensor -> Numpy

b = t.from_numpy(a)

Tensor和numpy对象共享内存,所以它们之间的转换很快,而且几乎不会消耗资源。这也意味着,如果其中一个变了,另外一个也会随之改变。

Tensor可通过.cuda方法转为GPU的Tensor,从而享受GPU带来的加速运算。

if t.cuda.is_available():
    x = x.cuda()
    y = y.cuda()
    x + y

从接口的角度讲,对tensor的操作可分为两类

  • torch.function,如torch.save等
  • tensor.function,如tensor.view等

从存储的角度讲,对tensor的操作又可分为两类

  • 不会修改自身的数据,如a.add(b),加法的结果会返回一个新的tensor
  • 会修改自身的数据,如a.add_(b),加法的结果存储在a中,a被修改了

函数名以_结尾的都是inplace方式,即会修改调用者自己的数据。

在PyTorch中新建tensor的方法。

函数

功能

Tensor(*sizes)

基础构造函数

ones(*sizes)

全1Tensor

zeros(*sizes)

全0Tensor

eye(*sizes)

对角线为1,其它为0

arange(s, e, step)

从s到e,步长为step

linspace(s, e, step)

从s到e,均匀切分成steps份

rand/randn(*sizes)

均匀/标准分布

normal(mean, std)/uniform(from, to)

正态分布/均匀分布

randperm(m)

随机排列

使用Tensor函数新建tensor是最复杂多变的方式,它既可以接收一个list,并根据list的数据新建tensor,也能根据指定的形状新建tensor,还能传入其它的tensor。

# 指定tensor的形状
a = t.Tensor(2, 3)

# 用list的数据创建tensor
b = t.Tensor([[1, 2, 3], [4, 5, 6]])

# 把tensor转为list
b.tolist()

tensor.size()返回torch.Size对象,它是tuple的子类,使用方式与tuple有区别。

b_size = b.size()

# b中元素总个数
b.numel()

# 创建一个和b形状一样的tensor
c = t.Tensor(b_size)

# 创建一个元素为2和3的tensor
d = t.Tensor((2, 3))

除了tensor.size(),还可以利用tensor.shape直接查看tensor的形状,tensor.shape等价于tensor.size()。

t.Tensor(*sizes)创建tensor时,系统不会马上分配空间,只会计算剩余的内存是否足够使用,使用到tensor时才会分配,而其它操作都是在创建完tensor后马上进行空间分配。

其它常用的创建tensor方法:

t.ones(2, 3)
t.zeros(2, 3)
t.arange(1, 6, 2)
t.linspace(1, 10, 3)
t.randn(2, 3)
# 长度为5的随机排列
t.randperm(5)
# 对角线为1,不要求行列书一致
t.eye(2, 3)

通过tensor.view方法可以调整tensor的形状,但必须保证调整前后元素总数一致。view不会修改自身的数据,返回的新tensor与源tensor共享内存,即更改其中一个,另外一个也会跟着改变。

a = t.arange(0, 6)
a.view(2, 3)
# 当某一维为-1的时候,会自动计算它的大小
b = a.view(-1, 3)

实际应用中可能经常需要添加或减少某一维度,这时squeeze和unsqueeze两个函数就排上了用场。

# 在第1维(下标从0开始)上增加1
b.unsqueeze(1)

# 压缩第0维的1
c.squeeze(0)

# 把所有维度为1的压缩
c.squeeze()

resize是另一种可用来调整size的方法,但与view不同,它可以修改tesnor的尺寸。如果新尺寸超过了原尺寸,会自动分配新的内存空间,而如果新尺寸小于原尺寸,则之前的数据依旧会被保存。

b.resize_(1, 3)

# 旧的数据依旧保存着,多出的数据会分配新空间
b.resize_(3, 3)

Tensor支持与numpy.ndarray类似的索引操作,语法上也类似,下面通过一些例子,讲解常用的索引操作。如无特殊说明,索引出来的结果与原tensor共享内存,即修改一个,另一个会跟着修改。

a = t.randn(3, 4)

# 第0行(下标从0开始)
a[0]

# 第0列
a[:, 0]

# 第0行第2个元素
a[0][2]

# 第0行最后一个元素
a[0, -1]

# 前两行
a[:2]

# 前两行,第0,1列
a[:2, 0:2]

# 返回一个ByteTensor
a > 1

# 等价于a.masked_select(a>1)
a[a>1]

# 第0行和第1行
a[t.LongTensor([0, 1])]

常用的选择函数:

函数

功能

index_select(input, dim, index)

在指定维度dim上选取,例如选取某些行、某些列

masked_select(input, mask)

使用ByteTensor进行选取

non_zero(input)

非0元素的下标

gather(input, dim, index)

根据index,在dim维度上选取数据,输出的size与index一样

Tensor有不同的数据类型,每种类型分别对应有CPU和GPU版本。

数据类型

GPU tensor

GPU tensor

32bit浮点

torch.FloatTensor

torch.cuda.FloatTensor

64bit浮点

torch.DoubleTensor

torch.cuda.DoubleTensor

16bit半精度浮点

N/A

torch.cuda.HalfTensor

8bit无符号整型

torch.ByteTensor

torch.cuda.ByteTensor

8bit有符号整型

torch.CharTensor

torch.cuda.CharTensor

16bit有符号整型

torch.ShortTensor

torch.cuda.ShortTensor

32bit有符号整型

torch.IntTensor

torch.cuda.IntTensor

64bit有符号整型

torch.LongTensor

torch.cuda.LongTensor

各类型之间可以互相转换,type(new_type)是通用的做法,同时还有float、long、half等快捷方法。CPU tensor与GPU tensor之间的互相转换通过tensor.cuda和tensor.cpu的方法实现。

# 设置默认tensor,注意参数是字符串
t.set_default_tensor_type('torch.IntTensor')

# a是IntTensor
a = t.Tensor(2, 3)

# 把a转成FloatTensor,等价于b=a.type(t.FloatTensor)
b = a.float()

# c是FloatTensor
c = a.type_as(b)

# 回复默认设置
t.set_default_tensor_type('torch.FloatTensor')

常见的逐元素操作:

函数

功能

abs/sqrt/div/exp/fmod/log/pow

绝对值/平方根/除法/指数/求余/求幂

cos/sin/asin/atan2/cosh

三角函数

ceil/round/floor/trunc

上取整/四舍五入/下取整/只保留整数部分

clamp(input, min, max)

超过min和max部分截断

sigmoid/tanh

激活函数

常用的归并操作:

函数

功能

mean/sum/median/mode

均值/和/中位数/众数

norm/dist

范数/距离

std/var

标准差/方差

cumsum/cumprod

累加/类乘

常用的比较函数:

函数

功能

gt/lt/ge/le/eq/ne

大于/小于/大于等于/小于等于/等于/不等

topk

最大的k个数

sort

排序

max/min

比较两个tensor的最大值和最小值

常用的线性代数函数

函数

功能

trace

对角线元素之和(矩阵的迹)

diag

对角线元素

triu/tril

矩阵的上三角/下三角,可指定偏移量

mm/bmm

矩阵乘法,batch的矩阵乘法

addmm/addbmm/addmv

矩阵运算

t

转置

dot/cross

内积/外积

inverse

求逆矩阵

svd

奇异值分解

tensor分为头信息区和存储区

  • 信息区主要保存着tensor的形状、步长、数据类型等信息
  • 存储区把真正的数据保存成连续数组