基础操作
数据类型
pytorch常用的数据类型如下:
描述 | 数据类型 | CPU张量 | GPU张量 |
---|---|---|---|
16位半浮点 | torch.half | torch.HalfTensor | torch.cuda.HalfTensor |
32位浮点 | torch.float | torch.FloatTensor | torch.cuda.FloatTensor |
64位浮点 | torch.double | torch.DoubleTensor | torch.cuda.DoubleTensor |
8位无符号整型 | torch.uint8 | torch.ByteTensor | torch.cuda.ByteTensor |
8位整型 | torch.int8 | torch.CharTensor | torch.cuda.CharTensor |
16位整型 | torch.int16 or torch.short | torch.ShortTensor | torch.cuda.ShortTensor |
32位整型 | torch.int32 or torch.int | torch.IntTensor | torch.cuda.IntTensor |
64位整型 | torch.int64 or torch.long | torch.LongTensor | torch.cuda.LongTensor |
a.type() 查看变量类型;a.cuda() CPU—>GPU;a.cpu() GPU—>CPU;len(a) 返回a的第一维
a.dim() 或 len(a.shape) 返回张量维度;a.size() 或 a.shape 返回张量大小;a.numel() 返回元素个数
数据生成
数据转换
方法一:
# 直接转换
a = a.long(),a.int(),a.float(), a.double()...
方法二:
# 直接转换
a = a.type(torch.FloatTensor),a.type(torch.DoubleTensor)...
方法三:
# 将a转换为与b的类型相同
a = torch.randint(1,6,[2,3]) # torch.LongTensor
b = torch.rand(4,3) # torch.FloatTensor
a = a.type_as(b)
print(a.type()) # torch.FloatTensor
索引和切片
维度变换
(1)变形
a.view() 函数和a.reshape() 函数两者没有区别,但是要注意view()之后之前的维度就没有了,所以要根据自己的需求判断是否要存储之前的维度。
a = torch.rand(6,7,3)
print(a.reshape(3,6,7).shape) # torch.Size([3, 6, 7])
print(a.view(2,3,7,3,1).shape) # torch.Size([2, 3, 7, 3, 1])
(2)插入/压缩维度
a.unsqueeze() 函数 / a.squeeze() 函数
unsqueeze()参数范围从0~a.dim()+1
squeeze()只能压缩等于1的维度,若不给参数则压缩所有等于1的维度
# eg1:为[4,32,14,14]张量加上bias
a = torch.rand(32)
print(a.unsqueeze(0).unsqueeze(2).unsqueeze(3).shape) # torch.Size([1, 32, 1, 1]), 之后再用expand()函数
# eg2:压缩
f = torch.rand(1,32,1,14)
print(f.squeeze().shape) # torch.Size([32, 14]), 不给参数,压缩所有等于1的维度
print(f.squeeze(dim=0).shape) # torch.Size([32, 1,14])
print(f.squeeze(dim=1).shape) # torch.Size([1, 32, 1, 14]), 只能压缩等于1的维度
(3)转置
a.t() 函数,a.transpose() 函数,a.permute() 函数
# t()函数 只适用于2D张量
a = torch.rand(32,21)
print(a.t().shape) # torch.Size([21, 32])
# transpose(dim1,dim2) 交换dim1和dim2
a = torch.rand(4,3,32,21)
print(a.transpose(0,3).shape) # torch.Size([21, 3, 32, 4])
# permute(, 对应a的维度个数a.dim() , ,) 交换任意维度
a = torch.rand(4,3,32,21)
print(a.permute(1,0,3,2).shape) # torch.Size([3, 4, 21, 32])
# 把a的第1维放在第0维,第0维放在第一维,以此类推
(4)扩张
a.expand() 函数(推荐):节省内存,更快速。只能为等于1的维度扩张,-1表示维度不变。
a.repeat() 函数:会把所有的维度都真实copy一遍,参数表示在每个维度上copy几次,1表示维度不变,可以随意复制(更自由)
# 接上面,为[4,32,14,14]张量加上bias
a = torch.rand(32)
b = a.unsqueeze(0).unsqueeze(2).unsqueeze(3)
print(b.expand([4,-1,14,14]).shape) # torch.Size([4, 32, 14, 14]), 参数-1表示维度不变
print(b.repeat([4,1,14,14]).shape) # torch.Size([4, 32, 14, 14]), 参数1表示维度不变
print(b.repeat([4,2,14,14]).shape) # torch.Size([4, 64, 14, 14])
进阶操作
boardcast机制
当两个维度不同的张量进行运算时,pytorch会自动调用boardcast机制对张量先进行变形再运算。例如需求:一个学校有6个年级,每个年级7个班,每个学生都有3门课程,案例如下
#eg1: 对全校所有学生的所有课程都加5分
a = torch.rand(6,7,3)
b = torch.tensor(5)
print((a+b).shape) # torch.Size([6, 7, 3])
#eg2: 对学生的每个课程加不同的分数
a = torch.rand(6,7,3)
b = torch.rand(1,3)
print((a+b).shape) # torch.Size([6, 7, 3])
#eg3: 学校偏心,对每个班的加分不同
a = torch.rand(6,7,3)
b = torch.rand(7,1)
print((a+b).shape) # torch.Size([6, 7, 3])
#eg4: 极端例子,展示的boardcast机制的使用限制
a = torch.rand(2,1,7,3)
b = torch.rand(6,1,3)
print((a+b).shape) # torch.Size([2, 6, 7, 3])
如eg4所示,限制有以下两点:
1. 两个张量从最后一维开始,向前匹配
2. 只有某维度的大小是0或者1时,才能进行扩张
合并和分割
(1)合并
torch.cat() 函数,需保证除了合并维度外的其他维度size一致,默认dim=0
a = torch.rand(2,7,4,2)
b = torch.rand(2,7,3,2)
print(torch.cat([a,b],dim=2).shape) # torch.Size([2, 7, 7, 2])
(2)分割
torch.stack() 函数,保证两个合并张量size完全一致
a = torch.rand(2,7,4,2)
b = torch.rand(2,7,4,2)
c = torch.stack([a,b],dim=2)
print(c.shape) # torch.Size([2, 7, 2, 4, 2])
print(torch.all(torch.eq(c[:,:,0,:,:],a))) # True
print(torch.all(torch.eq(c[:,:,1,...],b))) # True
数学运算
(1)运算
加减乘除
符号 | 运算 |
---|---|
+ 等价于 torch.add() | 加法 |
- 等价于 torch.sub() | 减法 |
* 等价于 torch.mul() | 乘法 |
/ 等价于 torch.div() | 除法 |
** | 乘方 |
@ 等价于 torch.matmul() | 矩阵乘 |
torch.exp(a) | e a |
torch.log(a) | ln(a) |
比较大小
符号 | 运算 |
---|---|
a>0等价于torch.gt(a,0) | 大于 |
==等价于torch.eq(),torch.equal() | 等于 |
>= !=(都可以用符号表示) | 大于等于,不等于… |
torch.eq()和torch.equal()区别如下:
a = torch.randint(1,9,[2,4]) # torch.LongTensor
b = torch.randint(1,9,[2,4])
print(torch.eq(a,b)) # 返回矩阵
# tensor([[ True, False, False, False],
# [False, False, False, False]])
print(torch.equal(a,b)) # 返回一个值
# False
(2)近似
round() 四舍五入,trunc() 截取整数部分,frac() 截取小数部分
a = torch.tensor(3.14159)
print('floor:%f,ceil:%f,round:%f,trunc:%f,frac:%f'%(a.floor(),a.ceil(),a.round(),a.trunc(),a.frac()))
# 输出 floor:3.000000,ceil:4.000000,round:3.000000,trunc:3.000000,frac:0.141590
(3)裁剪
a.clamp(min,max) 函数,保证a的值在min~max之间
a = torch.randint(1,10,[3,4])
print(a)
print(a.clamp(5))
print(a.clamp(3,6))
输出:
tensor([[6, 1, 1, 5],
[5, 6, 5, 2]])
tensor([[6, 5, 5, 5],
[5, 6, 5, 5]])
tensor([[6, 3, 3, 5],
[5, 6, 5, 3]])
统计属性
(1) 范数
a.norm(几范数,dim=) 对a的第几维求几范数
a = torch.randint(1,6,[2,3]) # torch.LongTensor
a = a.float() #转为float才能求范数
print(a)
# tensor([[4., 3., 1.],
#[5., 4., 5.]])
print(a.norm(2)) # tensor(9.5917)
print(a.norm(1,dim=0)) # tensor([9., 7., 6.])
这里注意一点,a是2*3的矩阵,dim=0时消掉第0维,也就是获得3列的一范数。(这里我也很晕@@,有时候是对着那一维求解,有时候是消去,应该是需要死记硬背吧,下面介绍的这些统计函数都是消去)
(2)平均、累加乘
a.mean() 平均; a.sum() 累加; a.prod() 累乘
a = torch.randint(1,6,[2,3]) # torch.LongTensor
a = a.float()
print(a)
# tensor([[4., 3., 4.],
# [4., 3., 1.]])
print(a.mean(dim=0)) #tensor([4.0000, 3.0000, 2.5000])
print(a.sum(dim=0)) #tensor([8., 6., 5.])
print(a.norm(1,dim=0)) #tensor([8., 6., 5.])
print(a.prod()) #tensor(576.)
NOTE: dim=规则同上
(3)最大最小
a.max() 最大值,a.min() 最小值,a.argmin() 最大值的索引,a.argmax() 最小值的索引,a.tpok() 前k个最大值/最小值,a.kthvalue() 第k个最小的值。
值,索引=a.max(dim=),当输出为两个参数时,必须要加dim否则报错
a = torch.randint(1,9,[2,3]) # torch.LongTensor
print(a)
# tensor([[8, 2, 4],
# [7, 2, 2]])
print(a.max()) # tensor(8)
print(a.max(dim=1))
#values=tensor([8, 7]),
#indices=tensor([0, 0]))
value,index = a.max(dim=1)
print(value,index) # tensor([8, 7]) tensor([0, 0])
值,索引=a.max(dim=,keepdim=True) 用于设置保持维度。
print(a)
#tensor([[1, 7, 2],
# [7, 3, 3]])
value,index = a.min(dim=1)
print(value) #tensor([1, 3])
value,index = a.min(dim=1,keepdim=True) #保持维度
print(value) # tensor([[1],
# [3]])
a.argmax() 求最大值的索引
print(a.argmax()) #tensor(1)
print(a.argmax(dim=1)) #tensor([1, 0])
值,索引=a.topk(n,dim=,largest=True) 求前n个最大T/最小值F,默认largest=True求最大
# tensor([[7, 8, 7],
# [4, 4, 8]])
print(a.topk(2,dim=1))
# torch.return_types.topk(values=tensor([[8, 7],[8, 4]]),indices=tensor([[1, 0], [2, 0]]))
print(a.topk(2,dim=1,largest = False))
# torch.return_types.topk(values=tensor([[7, 7],[4, 4]]),indices=tensor([[0, 2],[0, 1]]))
值,索引=a.kthvalue(n,dim=1) 求第n个小的值,默认dim=1
a = torch.randint(1,9,[3,6]) # torch.LongTensor
print(a)
# tensor([[3, 2, 4, 8, 2, 7],
# [6, 5, 3, 4, 4, 2],
# [2, 7, 6, 2, 4, 6]])
print(a.kthvalue(2))
# torch.return_types.kthvalue(
# values=tensor([2, 3, 2]),
# indices=tensor([4, 2, 3]))
高阶操作
(1)torch.where(condition,x,y)
官网介绍:
若condition==T则取x,否则取y
a = torch.randint(1,9,[2,4]) # torch.LongTensor
b = torch.randint(1,9,[2,4])
print(a)
#tensor([[2, 7, 3, 8],
# [6, 8, 3, 8]])
print(b)
#tensor([[1, 2, 1, 1],
# [1, 2, 2, 3]])
print(torch.where(a>3,a,b))
#tensor([[1, 7, 1, 8],
# [6, 8, 2, 8]])
(2)torch.gather(input,dim,index,out=None)
根据index索引值选取input中的元素,按dim组成新的张量,新张量的大小与index大小相同。
a = torch.tensor([[7, 1, 6],
[8, 4, 4]])
print(torch.gather(a,0,torch.tensor([[0,1,0], [1,0,1]])))
#tensor([[7, 4, 6], 第一行是a[0][0],a[1][2],a[0][3]
# [8, 1, 4]]) 第二行是a[1][1],a[0][2],a[1][3]
# dim=0时,第一维是index;第二维是列索引
print(torch.gather(a,1,torch.tensor([[0,0,1], [1,0,2]]))) # dim=1按行选取
#tensor([[7, 7, 1], 第一行是a[0][0],a[0][0],a[0][1]
# [4, 8, 4]]) 第二行是a[1][1],a[1][0],a[1][2]
# dim=1时,第一维是行索引;第二维是index
Note: input和index的维度一致,但是index.size(d) <= input.size(d)
持续更新。。。。