文章目录

  • ​​Tensor​​
  • ​​一、Tensor维度等变换操作​​
  • ​​不同Tensor之间的合并与分离​​
  • ​​高级操作:将两个batch size>1的Tensor中的每一层对应组合在一起​​
  • ​​单个Tensor的维度变换​​
  • ​​Tensor内存优化​​
  • ​​二、Tensor计算​​
  • ​​Tensor乘法​​
  • ​​Tensor 的归并运算​​
  • ​​三、Tensor条件索引等操作​​
  • ​​Tensor排序​​
  • ​​Tensor反转顺序​​
  • ​​Tensor取最大值和最小值并返回索引​​
  • ​​取最大值最小值​​
  • ​​取最大值最小值的索引​​
  • ​​对矩阵指定idx内容进行操作​​
  • ​​idx索引矩阵​​
  • ​​条件对比,返回等大小的Bool矩阵​​
  • ​​统计tensor中满足条件元素的个数​​
  • ​​高级操作:将矩阵中大于某个阈值的元素index返回并取出对应元素组成新的矩阵(适用于深度学习检测类任务后处理)​​
  • ​​四、按照规则生成新的Tensor​​
  • ​​五、Tensor类型转换(与numpy、list、转换float、四舍五入等)​​
  • ​​六、Tensor平移和旋转​​
  • ​​七、Tensor训练​​
  • ​​Module​​
  • ​​一、nn子模块​​
  • ​​计算坐标点距离(欧式距离)​​
  • ​​二、nn.functional​​
  • ​​线性插值​​
  • ​​Pytorch数据相关操作​​
  • ​​生成随机数​​
  • ​​话外​​
  • ​​Numpy中的ndarrays和Torch中的tensor有什么区别?​​

​Pytorch Documentation​

Tensor

一、Tensor维度等变换操作

不同Tensor之间的合并与分离

​​PyTorch常用张量切割和拼接方法​​

x = torch.randn(B, C, W, H)
y = torch.cat([x, x],dim=-1)
y.shape # [B, C, W, 2H]
x = torch.randn(B, C, W, H)
y = torch.stack([x, x],dim=0)
y.shape # [2, B, C, W, 2H]
x = torch.randn(B, C, 400, 200)
out = torch.split(x, split_size_or_sections=[200,200], dim=-2)
out # 是一个tuple,存储了分割后的tensor
out[0].shape # [B, C, 200, 200]
out[1].shape # [B, C, 200, 200]
高级操作:将两个batch size>1的Tensor中的每一层对应组合在一起

应用示例:​​B>1​​ Tensor A: ​​[B, C, H, W]​​,a为每个Tensor的每个batch:​​[1, C, H, W]​​ Tensor B: ​​[B, C, H, W]​​,b为每个Tensor的每个batch:​​[1, C, H, W]​​ 目标 Tensor C: ​​[2*B, C, H, W]​​ 我们需要让Tensor AB组成新的Tensor C,但是Tensor C中每两个Batch中,第一个必须是Tensor A,第二个是Tensor B,即Tensor C的内容应为:​​[[a_1,b_1], [a_2, b_2], ... [a_n, b_n]]​

Bs, Ch, H, W = 2, 1, 1, 1
A = torch.randn((Bs, Ch, H, W))
B = torch.randn((Bs, Ch, H, W))
C = torch.stack([A, B], dim=1).reshape(2*Bs, Ch, H,W)
'''
A: tensor([[[[0.1900]]], # a1
[[[0.1169]]]]) # a2
B: tensor([[[[-0.1072]]], # b1
[[[-1.4745]]]]) # b2
C: tensor([[[[ 0.1900]]], # a1
[[[-0.1072]]], # b1
[[[ 0.1169]]], # a2
[[[-1.4745]]]]) # b2
'''

单个Tensor的维度变换

B, N, C, H, W = feat.shape
feat = feat.view(B, N, C, H*W)

其他小用法:

feat = torch.randn(3, 5)
feat1 = feat.view(3*5)
feat2 = feat1.view(3, 5)
print(feat == feat2)
# tensor([[True, True, True, True, True],
# [True, True, True, True, True],
# [True, True, True, True, True]])
  • ​Tensor.reshape()​​(交换 / 合并 / 扩展 维度)
B, C, H, W = feat.shape # torch.Size([4, 256, 50, 100])
# 使用-1快速合并所有未指定维度
feat.reshape(B, C, -1) # # torch.Size([4, 256, 5000])
B, N, C, H, W = feat.shape
feat = feat.permute(1, 0, 3, 4, 2)
feat.shape # [N, B, H, W, C]
  • ​Tensor.unsqueeze()​​(扩展维度)
C, H, W = feat.shape
feat = feat.unsqueeze(0) # 在第0维扩展一个维度
feat.shape # [1, C, H, W]
  • ​Tensor.squeeze()​​(删除一个空维度)
1, C, H, W = feat.shape
feat = feat.squeeze(0) # 在第0维删除一个空维度
feat.shape # [C, H, W]
  • ​Tensor.repeat()​​(在某一维进行重复扩充)
x = torch.randn(1, 3, 224, 224)
y = x.repeat(3, 1, 1, 1)
y.shape # [3, 3, 224, 224]
  • ​Tensor.range()​​​和​​Tensor.arange()​​(产生一维数组)
  • ​torch.range(1,10)​​​和 ​​torch.arange(10)​​​都产生了一个1维的数组,类型是 ​​<class ‘torch.Tensor’>​
  • 二者不同的是:
  • ​range​​​产生的长度是​​10-1+1=10​​​ 是由1到10组成的1维张量,类型​​float​
  • 而​​arange​​​产生的是​​10-1=9​​​ 由1-9组成的1维度张量 ,类型​​int​
x = torch.range(1,10) # 从1到10
y = torch.arange(1,10)
x # tensor([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])
y # tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])

z = torch.arange(10)
z # tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Tensor内存优化

  • ​Tensor.contiguous()​
  • 功能:​Tensor.contiguous()​​函数不会对原始数据进行任何修改,而仅仅对其进行复制,并在内存空间上进行对齐,即在内存空间上,tensor元素的内存地址保持连续。
  • 意义: 这么做的目的是,在对tensor元素进行转换和维度变换等操作之后,元素地址在内存空间中保证连续性,在后续利用指针对tensor元素进行读取时,能够减少读取便利,提高内存空间优化。

二、Tensor计算

Tensor乘法

  • ​torch.matmul()​
x = torch.randn(1, 3, 4, 3)
y = torch.randn(1, 3, 3, 1)
out = torch.matmul(x, y)
out.shape # [1, 3, 4, 1]

Tensor 的归并运算

​​Tensor 的归并运算(torch.mean、sum、median、mode、norm、dist、std、var、cumsum、cumprod)​​

B, N, C, H, W = feat.shape
feat = feat.max(dim=1)
feat.shape # [B, 1, C, H, W]
  • ​torch.sum()​
  • ​torch.mean()​
  • ​torch.median()​
  • ​torch.mode()​
  • ​torch.norm()​
  • ​torch.dist()​
  • ​torch.std()​
  • ​torch.var()​
  • ​torch.cumsum()​
  • ​torch.cumprod()​

三、Tensor条件索引等操作

Tensor排序

  • ​torch.topk()​​​(可以指定获取前k个最大值的​​value​​​和​​index​​)
  • ​input​​:tensor数据;
  • ​k​​:指明是得到前k个数据以及其index;
  • ​dim​​: 指定在哪个维度上排序, 默认是最后一个维度;
  • ​largest​​:如果为True,按照大到小排序; 如果为False,按照小到大排序;
input = torch.rand((20))  # [20]
# 获取前三最大值
>>> torch.topk(input, k=3)
torch.return_types.topk(
values=tensor([1.2594, 1.0634, 0.9596]),
indices=tensor([18, 1, 17]))
# 获取前三最小值
>>> torch.topk(a, k=3, largest=False)
torch.return_types.topk(
values=tensor([0.1799, 0.2691, 0.3302]),
indices=tensor([15, 13, 12]))
  • ​torch.sort()​
>>> a = torch.Tensor([[5,4,1],[6,3,2]])  
>>> torch.sort(a)
torch.return_types.sort(
values=tensor([[1., 4., 5.],
[2., 3., 6.]]),
indices=tensor([[2, 1, 0],
[2, 1, 0]]))

Tensor反转顺序

  • ​torch.flip()​
>>> x = torch.arange(10).view(2, 5)
>>> x
tensor([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
>>> torch.flip(x, dims=[0]) # 对第0维进行反转
tensor([[5, 6, 7, 8, 9],
[0, 1, 2, 3, 4]])

Tensor取最大值和最小值并返回索引

取最大值最小值
  • ​torch.max()​​​和​​torch.min()​
  • ​input​​:表示输入的张量
  • ​dim​​:表示的是索引的维度,0和1分别表示列和行
  • 返回两个tensor,第一个tensor表示对应维度的最大/小值;第二个tensor表示最大/小值的索引
取最大值最小值的索引
  • ​tensor.argmax()​​​和​​tensor.argmin()​
  • ​dim​​:表示的是索引的维度

对矩阵指定idx内容进行操作

  • ​torch.tensor.index_put()​
x = torch.ones((3, 3))
# index为列表, 存放[x_idx, y_idx]
index = [torch.LongTensor([0, 1, 0, 2]),
torch.LongTensor([0, 2, 2, 1])] # 生成索引
value = torch.Tensor([0, 3, 0, 0])
x1 = x.index_put(index, value)
>>> print(x1)
tensor([[0., 1., 0.],
[1., 1., 3.],
[1., 0., 1.]])

idx索引矩阵

  • ​torch.index_select()​
>>> import torch
>>> a = torch.linspace(1, 12, steps=12).view((4, 3))
>>> print(a)
tensor([[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.],
[10., 11., 12.]])
>>> print(torch.index_select(a, dim=0, torch.tensor([0, 3]))) # 提取第0个维度中的0和3
tensor([[ 1., 2., 3.],
[10., 11., 12.]])

条件对比,返回等大小的Bool矩阵

  • ​torch.gt()​
  • ​torch.lt()​
  • ​torch.eq()​

参考文章:​​pytorch中torch.gt(),torch.lt(),torch.eq()​​

  • ​torch.where(condition, a, b)​
  • 作用:按照一定的规则合并两个tensor类型
  • 输入参数:
  • ​condition​​​:条件限制;如果满足条件,则选择​​a​​​对应的值,否则选择​​b​​对应的值作为输出。
import torch
>>> a = torch.tensor([[0.0349, 0.0670],
[-1.6719, 0.1242]])
>>> b = torch.tensor([[1,1],
[1,1]])
>>> c = torch.where(a>0, a, b) #合并a,b两个tensor,如果a中元素大于0,则c中与a对应的位置取a的值,否则取b的值
tensor([[0.0349, 0.0670],
[1.0000, 0.1242]])

参考文章:​​Pytorch:Tensor的高阶操作【where(按条件取元素)、gather(查表取元素)、scatter_(查表取元素)】【可并行计算,提高速度】​​

统计tensor中满足条件元素的个数

  • ​torch.nonzero()​​​+​​torch.numel()​
  • 需要注意的是,统计时需要将tensor转换为一维向量,否则给出的结果是所有元素的个数,并不是满足条件的元素!
>>> a = torch.tensor([[0.0349,  0.0670],
[-1.6719, 0.1242]])
>>> (a>0).reshape(-1).nonzero().numel()
3
# 错误示例: 没有reshape成一维向量导致输出为所有元素个数。
>>> (a>0).nonzero()
tensor([[0, 0],
[0, 1],
[1, 1]])
>>> (a>0).nonzero().numel()
6
高级操作:将矩阵中大于某个阈值的元素index返回并取出对应元素组成新的矩阵(适用于深度学习检测类任务后处理)

一般在检测任务中,模型预测的输出都为(N, 4+1),N为预测box数,4为x,y,w,h,还有一个为类别。
本次我的点集预测任务中,我的预测结果为(N, 40+1),N为预测instance数,40为20组x,y点,还有一个为类别。
我需要通过confidence滤除掉小于阈值threshold的instance,然后再将其他符合要求的元素组成新的矩阵。

threshold = 0.5
pred_insts.shape # [6, 41]
pred_insts = torch.tensor(pred_insts[:,:-1], dtype=torch.float32) # [6, 40]
pred_confidence = torch.tensor(pred_insts[:,-1:], dtype=torch.float32) # [6, 1]
# 1.与阈值判断大小返回TrueFalse
pred_conf_index = pred_confidence[:,0] > threshold # shape: [6]
# pred_conf_index: tensor([ True, True, False, False, True, False])
# 2.再通过nonzero并返回索引
pred_conf_index = pred_conf_index.nonzero() # shape: [3, 1]
# pred_conf_index: tensor([[0], [1], [4]])
# 3.将其转化为一个一维tensor,方便索引
pred_conf_index = pred_conf_index.squeeze(-1) # shape: [3]
# pred_conf_index: tensor([0, 1, 4])
# 4.利用索引获取符合要求的tensor
pred_insts = pred_insts.index_select(dim=0,index=pred_conf_index) # [3, 40]

四、按照规则生成新的Tensor

  • ​Tensor.new_tensor()​​(生成一个指定大小,全部填充给定值的Tensor)
>>> tensor = torch.ones((2,), dtype=torch.int8)
>>> data = [[0, 1], [2, 3]]
>>> tensor.new_tensor(data)
tensor([[ 0, 1],
[ 2, 3]], dtype=torch.int8)
  • ​Tensor.new_ones()​​(生成一个指定大小,全部填充1的Tensor)
  • ​Tensor.new_zeros()​​(生成一个指定大小,全部填充0的Tensor)
>>> tensor = torch.tensor((), dtype=torch.float64)
>>> tensor.new_zeros((2, 3))
tensor([[ 0., 0., 0.],
[ 0., 0., 0.]], dtype=torch.float64)
  • ​Tensor.new_full()​​(生成一个指定大小,全部填充给定值的Tensor)
>>> tensor = torch.ones((2,), dtype=torch.float64)
>>> tensor.new_full((3, 4), 3.141592)
tensor([[ 3.1416, 3.1416, 3.1416, 3.1416],
[ 3.1416, 3.1416, 3.1416, 3.1416],
[ 3.1416, 3.1416, 3.1416, 3.1416]], dtype=torch.float64)
  • ​torch.linspace()​​(生成线性等间距一维数组)
#生成0到10的4个数构成的等差数列
a = torch.linspace(0,10,steps=4)
a # tensor([ 0.0000, 3.3333, 6.6667, 10.0000])

#生成0到10的5个数构成的等差数列
b = torch.linspace(0,10,steps=5)
b # tensor([ 0.0000, 2.5000, 5.0000, 7.5000, 10.0000])
  • ​torch.arange(start, end, step)​​(生成一维数组,不包含尾部数据)
>>> x = torch.arange(1.0,6.0)

tensor([1., 2., 3., 4., 5.])
  • ​torch.range(start, end, step)​​(生成一维数组,包含尾部数据)
>>> x = torch.range(1.0,6.0)

tensor([1., 2., 3., 4., 5., 6.])

五、Tensor类型转换(与numpy、list、转换float、四舍五入等)

  • ​torch.tensor​​​转​​Python​
  • Tensor变量且只能为包含单个数据
x = torch.tensor([1], dtype=torch.int32)  # torch.int32
>>> x.item()
>>> type(x) # int 1

>>> x.numel() # int 1
  • ​torch.tensor​​​转​​list​
x = torch.randn(B, C, 400, 200)
y = x.numpy().tolist()
y.shape # [B, C, 400, 200]
  • ​numpy​​​转​​torch.tensor​
x = numpy.zeros((B, C, 400, 200))
y = torch.from_numpy(x)
y.shape # [B, C, 400, 200]
  • ​torch.tensor​​​转​​numpy​
x = torch.randn(B, C, 400, 200)
y = x.numpy()
y.shape # [B, C, 400, 200]
  • ​list​​​转​​torch.tensor​
x = list([[1,2], [3,4]])
y = torch.tensor(x) # torch.tensor
y.shape # [2, 2]
  • ​torch.tensor​​转换类型
>>> x = torch.tensor([1], dtype=torch.int32) # torch.int32
>>> x = x.to(dtype=torch.float32)
>>> x.dtype
torch.float32
  • ​torch.tensor​​四舍五入
x = torch.tensor([[0.2, 1.6],
[0.4, 3.2],
[4.2, 2.4]]).round()
tensor([[0., 2.],
[0., 3.],
[4., 2.]])

六、Tensor平移和旋转

​Pytorch中的仿射变换(affine_grid)​

  • ​torch.nn.functional.affine_grid()​
  • ​torch.nn.functional.grid_sample()​

七、Tensor训练

  • ​torch.tensor.detach()​​(截断某个变量的梯度反传,到此为止;只反传此变量相关的前边部分梯度,之后涉及到该变量的梯度均不反传)
  • ​​pytorch函数tensor.detach()​​

Module

一、nn子模块

  • ​nn.Embedding​
  • 定义Embedding并初始化指定的参数:
reference_points = nn.Embedding(50, 2)  # 生成的reference point的shape为[50,2]

# 初始化参数
reference_points.requires_grad_(False) # 首先在更改参数前,需要将其的梯度设置为False
# 给reference point的x设置为[0,1]之间的10个量(不包括0,1),并循环复制5份
reference_points.weight[:,0] = torch.linspace(0,1,12)[1:-1].unsqueeze(0).permute(1,0).repeat(1,5).view(self.num_inst_query, 1).squeeze(-1)
# 给reference point的y设置为[0,1]之间的5个量(不包括0,1),并循环复制10份
reference_points.weight[:,1] = torch.linspace(0,1,7)[1:-1].unsqueeze(0).repeat(10,1).view(self.num_inst_query, 1).squeeze(-1)
reference_points.requires_grad_(True) # 在更改参数之后,需要将其的梯度设置为True,让其可以参数更新

理解:​​pytorch nn.Embedding的用法和理解​​

计算坐标点距离(欧式距离)

  • ​torch.nn.PairwiseDistance()​​(计算两个tensor中每个点的欧式距离
  • 只需要保证输入的两个Tensor’维度一致,且最后一维为2即可,前边的维度可以无限扩展,例如​​[bs, num_pts, 2]​​​或者​​[num_pts, 2]​​。
vec1 # [num_pts, 2]
vec2 # [num_pts, 2]

dist = torch.pairwise_distance(vec1, vec2) # [num_pts]

​​Pytorch计算距离(例如欧式距离)torch.nn.PairwiseDistance​​

二、nn.functional

线性插值

  • ​torch.nn.functional.interpolate()​​(各种线性插值函数)
  • 其他参考文章:​​F.interpolate——数组采样操作​​
  • 插值使用场景:
  • 对于x,y,z等坐标插值:用单线性插值
  • 对图像等2D Tensor插如内容值:用双线性插值
  • 单线性插值示例:
# 对一个[1, N, 2]的坐标序列插值
vec = torch.tensor([
[1,2],
[3,4],
[5,6],
], dtype=torch.float32) # [1, N, 2] N=3

# 插值方式1: 指定需要插值扩展的倍数
vec = vec.permute(0,2,1) # [1, N, 2] -> [1, 2, N],对于1-D的坐标Tensor来说,我们需要插值扩展N
new_vec = F.interpolate(vec,
scale_factor=2,
mode="linear")
new_vec = new_vec.permute(0,2,1) # [1,2N, 2]
>>> new_vec
tensor([[[1.0000, 2.0000],
[1.5000, 2.5000],
[2.5000, 3.5000],
[3.5000, 4.5000],
[4.5000, 5.5000],
[5.0000, 6.0000]]]) # [1,6,2]

# 插值方式2:
new_vec2 = F.interpolate(vec,
size=[10], # 指定需要插值维度对应的输出维度
mode="linear")
new_vec2 = new_vec2.permute(0,2,1) # [1,10, 2]
>>> new_vec2
tensor([[[1.0000, 2.0000],
[1.0000, 2.0000],
[1.5000, 2.5000],
[2.1000, 3.1000],
[2.7000, 3.7000],
[3.3000, 4.3000],
[3.9000, 4.9000],
[4.5000, 5.5000],
[5.0000, 6.0000],
[5.0000, 6.0000]]])

Pytorch数据相关操作

生成随机数

  • ​torch.randperm​​:将0~n-1(包括0和n-1)随机打乱后获得的数字序列,函数名是random permutation缩写。
>>> torch.randperm(10)
tensor([2, 3, 6, 7, 8, 9, 1, 5, 0, 4])
  • ​torch.Generator​
  • 通常不用手动实例化 ​​torch.Generator​​​, 当需要随机数时, PyTorch 会自动创建一个默认的 ​​torch.Generator​​ 实例;
  • 也可以手动指定使用 ​​torch.Generator​​;
# 方式一:自动创建
# 直接获取随机数(自动创建torch.Generator)
torch.manual_seed(0) # 设置随机数种子
torch.initial_seed() # 查看随机数种子 结果为 0
g_1 = torch.default_generator # 获取默认的 Generator 实例
g_1.initial_seed() # 通过实例调用 结果也为 0

# 方式二:手动指定
# 手动创建随机数生成器
G = torch.Generator()
G.manual_seed(1)
torch.randperm(5, generator=G)
# 结果也为 tensor([0, 4, 2, 3, 1])

话外

Numpy中的ndarrays和Torch中的tensor有什么区别?

  • ​​浅谈torch的tensor和Numpy的ndarrays​​