对Tensor的操作很多,从接口角度来划分,可以分为两类:
(1)torch.function;(2)tensor.function
这些操作对大部分Tensor都是等价的,如:torch.add(x,y)与x.add(y)等价。
如果从修改方式的角度来划分,可以分为以下两类。
(1)不修改自身数据,如x.add(y),x的数据不变,返回一个新的Tensor。
(2)修改自身数据,如x.add_(y)(运行符带下划线后缀),运算结果存在x中,x被修改。
import torch
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
z = x.add(y)
print(z)
print(x)
x.add_(y)
print(x)
函数 | 功能 |
---|---|
Tensor(*size) | 直接从参数构造一个的张量,支持List,Numpy数组 |
eye(row, column) | 创建指定行数,列数的二维单位Tensor |
linspace(start, end, steps) | 从start到end,均匀切分成steps份 |
logspace(start, end steps) | 从 1 0 s t a r t 10^{start} 10start到 1 0 e n d 10^{end} 10end,均分分成steps份 |
rand/randn(*size) | 生成 [ 0 , 1 ) [0,1) [0,1)均匀分布/标准正态分布数据 |
ones(*size) | 返回指定shape的张量,元素初始为1 |
zeros(*size) | 返回指定shape的张量,元素初始为0 |
ones_like(t) | 返回与T的shape相同的张量,且元素初始为1 |
zeros_like(t) | 返回与T的shape相同的张量,且元素初始为0 |
arange(start, end, step) | 在区间 [ s t a r t , e n d ) [start, end) [start,end)上一间隔step生成一个序列张量 |
from_Numpy(ndarry) | 从ndarry创建一个Tensor |
这里不再给出示例,只说明有关torch.Tensor与torch.tensor的几点区别:
(1)torch.Tensor是torch.empty和torch.tensor之间的一种混合,但是当传入数据时,torch.Tensor使用全局默认dtype(FloatTensor),而torch.tensor是从数据中推断数据类型。
(2)torch.tensor(1)返回一个固定值1,而torch.Tensor(1)返回一个大小为1的张量,它是随机初始化的值。
函数 | 说明 |
---|---|
size() | 返回张量的shape属性值,与函数shape(0.4版新增)等价 |
numel(input) | 计算Tensor元素个数 |
view(*shape) | 修改Tensor的shape,与reshape类似,但view返回的对象与源Tensor共享内存,修改一个,另一个同时修改。Reshape将生成新的Tensor,而且不要求源Tensor是连续的。view(-1)展平数组 |
resize | 类似于view,但在size超出时会重新分配内存空间 |
item | 若Tensor为单元素,则返回python的标量 |
unsqueeze | 在指定维度增加一个“1” |
squeeze | 在指定维度压缩一个"1" |
(1)reshape()可以有torch.reshape(),也可由torch.Tensor.reshape()调用。但view()只可由torch.Tensor.view()来调用。
(2)对于一个将要被view的Tensor,新的size必须与原来的size与stride兼容。否则在view之前必须调用contiguous()方法。
(3)同样也是返回与input数据量相同,但形状不同的Tensor。若满足view的条件,则不会copy,若不满足,则会copy。
(4)如果你只想重塑张量,请使用torch.reshape。如果你还关注内存使用情况并希望确保两个张量共享相同的数据,请使用torch.view。
import torch
x = torch.randn(2, 3)
y = x.view(-1)
z1 = torch.unsqueeze(y, 0)
z2 = torch.unsqueeze(y, 1)
z3 = torch.unsqueeze(y, -1)
z4 = torch.unsqueeze(y, -2)
输出结果
经过实验,发现z1与z4等价(都是16),z2与z3等价(都是61)。这也不难记忆,因为根据函数使用规则,第二个参数只能取[-2, 1]四个整数值,按照大小排列:-2,-1,0,1,依次对应16、61、16、61,交替出现。
Tensor的索引操作与Numpy类似,一般情况下索引结果与源数据共享内存。从Tensor获取元素除了可以通过索引,也可以借助于一些函数。
函数 | 说明 |
---|---|
index_select(input,dim, index) | 在指定维度上选择一些行或列 |
nonzero(input) | 获取非0元素的下标 |
masked_select(input, mask) | 使用二元值进行选择 |
gather(input,dim,index) | 在指定维度上选择数据,输出的形状与index(index的类型必须是LongTensor类型的)一致 |
scatter_(input,dim, index, src) | 为gather的反操作,根据指定索引补充数据 |
import torch
# 设置一个随机种子
torch.manual_seed(100)
# 生成一个形状为2*3的矩阵
x = torch.randn(2, 3)
# 根据索引获取第1行,所有数据
x[0, :]
# 获取最后一列数据
x[:, -1]
# 生成是否大于0的Byter张量
mask = x> 0
# 获取大于0的值
torch.masked_select(x, mask)
# 获取非0下标,即行,列索引
torch.nonzero(mask)
# 获取指定索引对应的值
index = torch.LongTensor([[0, 1, 1]])
torch.gather(x, 0, index)
index = torch.LongTensor([[0, 1, 1], [1, 1, 1]])
a = torch.gather(x, 1, index)
# 把a的值返回到一个2*3的0矩阵中
z = torch.zeros(2, 3)
z.scatter_(1, index, a)
因为时间原因,这里没能详细介绍有关1:index_select、gather函数及其中index参数的用法(也是花了点时间才想明白),这里先强调一点:index参数要求是torch.LongTensor类型的。
吴茂贵,郁明敏,杨本法,李涛,张粤磊. Python深度学习(基于Pytorch). 北京:机械工业出版社,2019.
后面会有单独一篇文章对索引操作函数及其规则做出详细介绍,同时上述程序运行结果也会在该文章中给出。 ↩︎