Pytorch Documentation
PyTorch常用张量切割和拼接方法
Tensor.cat()
(指定维度进行合并)x = torch.randn(B, C, W, H)
y = torch.cat([x, x],dim=-1)
y.shape # [B, C, W, 2H]
Tensor.stack()
(指定并创建一个新维度进行合并)x = torch.randn(B, C, W, H)
y = torch.stack([x, x],dim=0)
y.shape # [2, B, C, W, 2H]
Tensor.split()
(指定并创建一个新维度进行合并)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]
应用示例:
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 A和B组成新的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.view()
(维度合并)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])
Tensor.permute()
(维度交换)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维的数组,类型是
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.contiguous()
Tensor.contiguous()
函数不会对原始数据进行任何修改,而仅仅对其进行复制,并在内存空间上进行对齐,即在内存空间上,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 的归并运算(torch.mean、sum、median、mode、norm、dist、std、var、cumsum、cumprod)
Tensor.max()
(指定某一维取最大值并合并)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()
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]]))
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]])
torch.max()
和torch.min()
input
:表示输入的张量dim
:表示的是索引的维度,0和1分别表示列和行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.]])
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.]])
torch.gt()
torch.lt()
torch.eq()
参考文章:pytorch中torch.gt(),torch.lt(),torch.eq()
torch.where(condition, a, b)
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_(查表取元素)】【可并行计算,提高速度】
torch.nonzero()
+torch.numel()
>>> 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
一般在检测任务中,模型预测的输出都为(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.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.tensor
转Python
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.type(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.]])
Pytorch中的仿射变换(affine_grid)
torch.nn.functional.affine_grid()
torch.nn.functional.grid_sample()
torch.tensor.detach()
(截断某个变量的梯度反传,到此为止;只反传此变量相关的前边部分梯度,之后涉及到该变量的梯度均不反传)
nn.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中每个点的欧式距离)
[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
torch.nn.functional.interpolate()
(各种线性插值函数)
F.interpolate
——数组采样操作# 对一个[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]]])
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])
tensor
和Numpy的ndarrays