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的形状、步长、数据类型等信息
- 存储区把真正的数据保存成连续数组