高级索引
PyTorch在0.2版本中完善了索引操作,目前已经支持绝大多数numpy的高级索引。高级索引可以看成是普通索引操作的扩展,但是高级索引操作的结果一般不和原始的Tensor贡献内出。
x = t.arange(0,27).view(3,3,3)
x
tensor([[[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.]],
[[ 9., 10., 11.],
[ 12., 13., 14.],
[ 15., 16., 17.]],
[[ 18., 19., 20.],
[ 21., 22., 23.],
[ 24., 25., 26.]]])
x[[1, 2], [1, 2], [2, 0]] # x[1,1,2]和x[2,2,0]
tensor([ 14., 24.])
x[[2, 1, 0], [0], [1]] # x[2,0,1],x[1,0,1],x[0,0,1]
tensor([ 19., 10., 1.])
x[[0, 2], ...] # x[0] 和 x[2]
tensor([[[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.]],
[[ 18., 19., 20.],
[ 21., 22., 23.],
[ 24., 25., 26.]]])
Tensor类型
tensor数据类型
Data type | dtype | CPU tensor | GPU tensor |
---|---|---|---|
32-bit floating point | torch.float32 or torch.float |
torch.FloatTensor |
torch.cuda.FloatTensor |
64-bit floating point | torch.float64 or torch.double |
torch.DoubleTensor |
torch.cuda.DoubleTensor |
16-bit floating point | torch.float16 or torch.half |
torch.HalfTensor |
torch.cuda.HalfTensor |
8-bit integer (unsigned) | torch.uint8 |
torch.ByteTensor |
torch.cuda.ByteTensor |
8-bit integer (signed) | torch.int8 |
torch.CharTensor |
torch.cuda.CharTensor |
16-bit integer (signed) | torch.int16 or torch.short |
torch.ShortTensor |
torch.cuda.ShortTensor |
32-bit integer (signed) | torch.int32 or torch.int |
torch.IntTensor |
torch.cuda.IntTensor |
64-bit integer (signed) | torch.int64 or torch.long |
torch.LongTensor |
torch.cuda.LongTensor |
各数据类型之间可以互相转换,type(new_type)
是通用的做法,同时还有float
、long
、half
等快捷方法。CPU tensor与GPU tensor之间的互相转换通过tensor.cuda
和tensor.cpu
方法实现,此外还可以使用tensor.to(device)
。Tensor还有一个new
方法,用法与t.Tensor
一样,会调用该tensor对应类型的构造函数,生成与当前tensor类型一致的tensor。torch.*_like(tensora)
可以生成和tensora
拥有同样属性(类型,形状,cpu/gpu)的新tensor。 tensor.new_*(new_shape)
新建一个不同形状的tensor。
# 设置默认tensor,注意参数是字符串
t.set_default_tensor_type('torch.DoubleTensor')
a = t.Tensor(2,3)
a.dtype # 现在a是DoubleTensor,dtype是float64
torch.float64
# 恢复之前的默认设置
t.set_default_tensor_type('torch.FloatTensor')
# 把a转成FloatTensor,等价于b=a.type(t.FloatTensor)
b = a.float()
b.dtype
torch.float32
c = a.type_as(b)
c
tensor([[ 0., 0., 0.],
[ 0., 0., 0.]])
a.new(2,3) # 等价于torch.DoubleTensor(2,3),建议使用a.new_tensor
tensor([[ 4.6390e-310, 1.4147e+161, 1.4917e+20],
[ 2.0093e+174, 1.4327e+228, 1.3404e-317]], dtype=torch.float64)
t.zeros_like(a) #等价于t.zeros(a.shape,dtype=a.dtype,device=a.device)
tensor([[ 0., 0., 0.],
[ 0., 0., 0.]], dtype=torch.float64)
t.zeros_like(a, dtype=t.int16) #可以修改某些属性
tensor([[ 0, 0, 0],
[ 0, 0, 0]], dtype=torch.int16)
t.rand_like(a)
tensor([[ 0.8882, 0.7037, 0.5756],
[ 0.7113, 0.2868, 0.7597]], dtype=torch.float64)
a.new_ones(4,5, dtype=t.int)
tensor([[ 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1]], dtype=torch.int32)
a.new_tensor([3,4]) #
tensor([ 3., 4.], dtype=torch.float64)
逐元素操作
这部分操作会对tensor的每一个元素(point-wise,又名element-wise)进行操作,此类操作的输入与输出形状一致。常用的操作如表3-4所示。
函数 | 功能 |
---|---|
abs/sqrt/div/exp/fmod/log/pow… | 绝对值/平方根/除法/指数/求余/求幂… |
cos/sin/asin/atan2/cosh… | 相关三角函数 |
ceil/round/floor/trunc | 上取整/四舍五入/下取整/只保留整数部分 |
clamp(input, min, max) | 超过min和max部分截断 |
sigmod/tanh… | 激活函数 |
对于很多操作,例如div、mul、pow、fmod等,PyTorch都实现了运算符重载,所以可以直接使用运算符。如a ** 2
等价于torch.pow(a,2)
, a * 2
等价于torch.mul(a,2)
。
其中clamp(x, min, max)
的输出满足以下公式:
clamp
常用在某些需要比较大小的地方,如取一个tensor的每个元素与另一个数的较大值。
a = t.arange(0, 6).view(2, 3)
t.cos(a)
tensor([[1.0000000000, 0.5403022766, -0.4161468446],
[-0.9899924994, -0.6536436081, 0.2836622000]])
a % 3 # 等价于t.fmod(a, 3)
tensor([[ 0., 1., 2.],
[ 0., 1., 2.]])
a ** 2 # 等价于t.pow(a, 2)
tensor([[ 0., 1., 4.],
[ 9., 16., 25.]])
# 取a中的每一个元素与3相比较大的一个 (小于3的截断成3)
print(a)
t.clamp(a, min=3)
tensor([[ 0., 1., 2.],
[ 3., 4., 5.]])
tensor([[ 3., 3., 3.],
[ 3., 4., 5.]])
b = a.sin_() # 效果同 a = a.sin();b=a ,但是更高效节省显存
a
tensor([[0.0000000000, 0.8414709568, 0.9092974067],
[0.1411200017, -0.7568024993, -0.9589242935]])
归并操作
此类操作会使输出形状小于输入形状,并可以沿着某一维度进行指定操作。如加法sum
,既可以计算整个tensor的和,也可以计算tensor中每一行或每一列的和。
常用归并操作
函数 | 功能 |
---|---|
mean/sum/median/mode | 均值/和/中位数/众数 |
norm/dist | 范数/距离 |
std/var | 标准差/方差 |
cumsum/cumprod | 累加/累乘 |
以上大多数函数都有一个参数**dim
**,用来指定这些操作是在哪个维度上执行的。关于dim(对应于Numpy中的axis)的解释众说纷纭,这里提供一个简单的记忆方式:
假设输入的形状是(m, n, k)
- 如果指定dim=0,输出的形状就是(1, n, k)或者(n, k)
- 如果指定dim=1,输出的形状就是(m, 1, k)或者(m, k)
- 如果指定dim=2,输出的形状就是(m, n, 1)或者(m, n)
size中是否有"1",取决于参数keepdim
,keepdim=True
会保留维度1
。注意,以上只是经验总结,并非所有函数都符合这种形状变化方式,如cumsum
。
b = t.ones(2, 3)
b.sum(dim = 0, keepdim=True)
tensor([[ 2., 2., 2.]])
# keepdim=False,不保留维度"1",注意形状
b.sum(dim=0, keepdim=False)
tensor([ 2., 2., 2.])
b.sum(dim=1)
tensor([ 3., 3.])
a = t.arange(0, 6).view(2, 3)
print(a)
a.cumsum(dim=1) # 沿着行累加
tensor([[ 0., 1., 2.],
[ 3., 4., 5.]])
tensor([[ 0., 1., 3.],
[ 3., 7., 12.]])