1. torch.max
pytorch 官方文档
pytorch 的 torch.max
函数有两种用法: 一种是不带任何参数的,他返回的是 tensor 中所有元素的最大值;第二种是带参数的,他返回最大值和对应的索引,这里分别介绍
- 第一种 torch.max(input)
返回所有元素的最大值
a = torch.rand((2, 3, 4))
b = torch.max(a)
'''
tensor([[[0.0615, 0.7280, 0.3775, 0.9397],
[0.4438, 0.1904, 0.1330, 0.5213],
[0.5054, 0.9993, 0.3916, 0.7125]],
[[0.2660, 0.9682, 0.8774, 0.0991],
[0.6073, 0.2710, 0.8681, 0.8080],
[0.4416, 0.5851, 0.0409, 0.3030]]])
tensor(0.9993)
'''
- *第二种 torch.max(input, dim, keepdim=False, , out=None)
返回对应维度元素的最大值以及对应的索引
- input: 需要求最大值的 tensor
- dim: 求最大值的维度,参考normalize,第几维度,就是求那一维度的最大值,例如 tensor 维度为(3,4,5),dim=1,那么就是求第一维度,每一组有四个元素的最大值
- keepdim: 是否保持以前的维度数量
a = torch.rand((2, 3, 4))
b = torch.max(a, dim=1)
'''
tensor([[[0.9463, 0.7360, 0.0537, 0.5537],
[0.0405, 0.5534, 0.4716, 0.0500],
[0.2060, 0.6482, 0.8448, 0.0171]],
[[0.7581, 0.5042, 0.1960, 0.0650],
[0.2035, 0.8434, 0.2853, 0.1112],
[0.9866, 0.3353, 0.2400, 0.5643]]])
torch.return_types.max(
values=tensor([[0.9463, 0.7360, 0.8448, 0.5537],
[0.9866, 0.8434, 0.2853, 0.5643]]),
indices=tensor([[0, 0, 2, 0],
[2, 1, 1, 2]]))
'''
这个例子可以看出,dim=1
计算的是 3 那一维的最大值,可以看出 0.9463=max(0.9463, 0.0405, 0.2060)
然后我们通过下面这个例子看一下 keepdim
的作用
c = torch.max(a, dim=1, keepdim=True)
'''
torch.return_types.max(
values=tensor([[[0.9463, 0.7360, 0.8448, 0.5537]],
[[0.9866, 0.8434, 0.2853, 0.5643]]]),
indices=tensor([[[0, 0, 2, 0]],
[[2, 1, 1, 2]]]))
torch.Size([2, 1, 4]) # c[0].size()
'''
可以发现最后 c 的维度还是三维,不过求 max 的那一维度从 3 变成了 1
2. torch.mean
pytorch 官方文档
pytorch 的 torch.mean
函数有两种用法: 一种是不带任何参数的,他返回的是 tensor 中所有元素的均值;第二种是带参数的,他返回某一维度的均值,这里分别介绍
- 第一种 torch.mean(input)
返回所有元素的均值
a = torch.rand(2,2)
b = torch.mean(a)
'''
tensor([[0.8782, 0.3101],
[0.9752, 0.9772]])
tensor(0.7852)
'''
- *torch.mean(input, dim, keepdim=False, , out=None)
返回对应维度元素的均值
- input: 需要求均值的 tensor
- dim: 求均值的维度,参考normalize,第几维度,就是求那一维度的均值,例如 tensor 维度为(3,4,5),dim=1,那么就是求第一维度,每一组有四个元素的均值
- keepdim: 是否保持以前的维度数量,而不是大小
下面举两个例子
a = torch.rand((2,3,4))
b = torch.mean(a, dim=1)
'''
tensor([[[0.9809, 0.6421, 0.6771, 0.9645],
[0.5214, 0.8376, 0.8131, 0.7947],
[0.1607, 0.3469, 0.9644, 0.9500]],
[[0.1877, 0.3958, 0.1021, 0.7560],
[0.4673, 0.8111, 0.9186, 0.6773],
[0.4850, 0.8042, 0.1683, 0.2345]]])
tensor([[0.5543, 0.6088, 0.8182, 0.9031],
[0.3800, 0.6704, 0.3963, 0.5559]])
'''
这个例子可以看出,dim=1
计算的是 3 那一维的最大值,可以看出 0.5543=mean(0.9809, 0.5214, 0.1607),此时维度从(2,3,4)变为了(2,4)
然后我们通过下面这个例子看一下 keepdim
的作用
c = torch.max(a, dim=1, keepdim=True)
'''
tensor([[[0.5543, 0.6088, 0.8182, 0.9031]],
[[0.3800, 0.6704, 0.3963, 0.5559]]])
torch.Size([2, 1, 4]) # c[0].size()
'''
发现最后 c 的维度还是三维,不过求 mean 的那一维度从 3 变成了 1
3. torch.meshgrid
创建网格坐标 torch.meshgrid(*tensors)
- tensors: 两个一维向量,如果是 0 维,当作 1 维处理
返回:两个矩阵
- 第一个矩阵行相同,列是第一个向量的各个元素
- 第二个矩阵列相同,行是第二个向量的各个元素
直接看两个例子理解,第一个展示输入输出,第二个便于理解为什么可以创建网格坐标
- 第一个
x = torch.tensor([1, 2, 3])
y = torch.tensor([4, 5, 6, 7])
grid_x, grid_y = torch.meshgrid(x, y)
print("grid_x: ", grid_x)
print("grid_y: ", grid_y)
print(torch.equal(torch.cat(tuple(torch.dstack([grid_x, grid_y]))), torch.cartesian_prod(x, y)))
'''
grid_x:
tensor([[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]])
grid_y:
tensor([[4, 5, 6, 7],
[4, 5, 6, 7],
[4, 5, 6, 7]])
True
'''
- 第二个演示绘图
可以看到x,y就直接定义了其横纵坐标,下面的x,y,z均为 2 维
xs = torch.linspace(-5, 5, steps=100)
ys = torch.linspace(-5, 5, steps=100)
x, y = torch.meshgrid(xs, ys)
z = torch.sin(torch.sqrt(x * x + y * y))
ax = plt.axes(projection='3d')
ax.plot_surface(x.numpy(), y.numpy(), z.numpy())
plt.show()

4. torch.numel/nelement
返回输入向量的总的元素个数。有两种使用方法,一种是 Tensor 的内置属性 nelement,一种是 torch.numel 方法
- nelement
>>> import torch
>>> a = torch.zeros(4,4)
>>> a.nelement()
16
- torch.numel
>>> import torch
>>> a = torch.zeros(4,4)
>>> torch.numel(a)
16
5. torch.topk
求最大概率的值 torch.topk(input, k, dim=None, largest=True, sorted=True, *, out=None)
topk 最适合的场合是在分类场合,即网络输出多个概率,求哪个概率最大
- input: 输入的 tensor
- k: 排序时指定前 k 的最值
- dim: 指明在哪个维度上进行排序
- largest: 默认为 True,从大到小排序,如果为 False,从小到大排序
- sorted: 返回的结果按照顺序返回
- 求概率值最大的一个
pred = torch.randn((4, 5))
print(pred)
values, indices = torch.topk(pred, 1, dim=1, largest=True, sorted=True)
print(values)
print(indices)
'''
tensor([[ 0.2613, 0.5201, -0.4399, 0.4685, -0.4480],
[ 3.1005, 0.9732, 1.3342, 0.2227, 0.7779],
[-0.0579, -0.6568, -0.0449, -0.9981, -0.5214],
[ 1.0117, -1.8550, -0.3959, -0.2788, 0.0235]])
tensor([[ 0.5201],
[ 3.1005],
[-0.0449],
[ 1.0117]])
tensor([[1],
[0],
[2],
[0]])
'''
- 求概率值最大的前两个
pred = torch.randn((4, 5))
print(pred)
values, indices = torch.topk(pred, 2, dim=1, largest=True, sorted=True) # k=2
print(values)
print(indices)
'''
tensor([[ 0.0563, 0.3252, -1.0762, -0.7007, -1.1439],
[-1.2144, 0.5950, 0.9980, -1.5938, -0.0694],
[ 0.3070, -0.6079, -1.6469, 1.6252, 1.3092],
[-0.8918, -0.5781, -0.9604, 0.1942, 1.2415]])
tensor([[0.3252, 0.0563],
[0.9980, 0.5950],
[1.6252, 1.3092],
[1.2415, 0.1942]])
tensor([[1, 0],
[2, 1],
[3, 4],
[4, 3]])
'''
6. torch.squeeze/unsqueeze
torch.squeeze()
以及 torch.unsqueeze()
函数分别是给目标 tensor 去掉维度只有 1 的那一维或者给目标的某一维度添加一维
- torch.squeeze
将输入的 tensor 中维度为 1 的那一维去除torch.squeeze(input, dim=None)
- input ([Tensor] – the input tensor.
- dim ([int], optional) – if given, the input will be squeezed only in this dimension
>>> x = torch.zeros(2, 1, 2, 1, 2)
torch.Size([2, 1, 2, 1, 2]) # x.size()
>>> y = torch.squeeze(x)
torch.Size([2, 2, 2]) # y.size()
>>> y = torch.squeeze(x, 0)
torch.Size([2, 1, 2, 1, 2]) # y.size()
>>> y = torch.squeeze(x, 1)
torch.Size([2, 2, 1, 2]) # y.size()
''' in-place version '''
>>> x.squeeze_()
- torch.unsqueeze
将 tensor 的某一维增加 1torch.unsqueeze(input, dim=None)
- input [Tensor] – the input tensor.
- dim [int], optional) – the index at which to insert the singleton dimension
>>> x = torch.tensor([1, 2, 3, 4])
torch.Size([4]) # x.size()
>>> y1 = torch.unsqueeze(x, 0)
torch.Size([1, 4]) # y1.size()
>>> y2 = torch.unsqueeze(x, 1)
torch.Size([4, 1]) # y2.size()
''' in-place version '''
x.unsqueeze_(0)
7. torch.repeat_interleave
torch.repeat_interleave(input, repeats, dim=None, *, output_size=None)
- input: 输入 tensor
- repeats: 每个元素的重复次数
- dim: 重复的维度,默认情况,把输入张量展平为向量,然后将每个元素重复 repeats 次
- 默认的,不给 dim 参数,将 tensor 展平
>>> x = torch.tensor([1, 2, 3])
>>> torch.repeat_interleave(x, 2)
tensor([1, 1, 2, 2, 3, 3])
>>> y = torch.tensor([[1, 2], [3, 4]])
>>> torch.repeat_interleave(y, 2)
tensor([1, 1, 2, 2, 3, 3, 4, 4])
- 给定 dim,会在给定的维度将其展平重复,元素是逐个重复的,如下,对 1 重复三次,2 重复三次,以此类推
>>> y = torch.tensor([[1, 2], [3, 4]])
>>> torch.repeat_interleave(y, 3, dim=1)
tensor([[1, 1, 1, 2, 2, 2],
[3, 3, 3, 4, 4, 4]])
- 对不同元素指定重复次数
>>> y = torch.tensor([[1, 2], [3, 4]])
>>> torch.repeat_interleave(y, torch.tensor([1, 2]), dim=0)
tensor([[1, 2],
[3, 4],
[3, 4]])
- 此函数也支持 tensor.repeat_interleave()的形式
>>> x = torch.tensor([1, 2, 3])
>>> x.repeat_interleave(2)
tensor([1, 1, 2, 2, 3, 3])
8. torch.scatter
torch.scatter(input, dim, index, src)
src 中的数据根据 index 中的索引按照 dim 的方向填入到 input 中
- dim ([int]) – the axis along which to index
- index (LongTensor) – the indices of elements to scatter, can be either empty or of the same dimensionality as
src
. When empty, the operation returnsself
unchanged. - src ([Tensor] or [float] – the source element(s) to scatter.
- reduce ([str], optional) – reduction operation to apply, can be either
'add'
or'multiply'
.
看了上述的官方文档还是不理解,我们继续看官方的例子,这里官方只给了三维,我在这里又加入了二维,在这之前有一个规定
- 对任意维度 d:
index.size(d) <= src.size(d)
- 对 d!=dim 的维度:
index.size(d) <= self.size(d)
- 二维举例
self[index[i][j]][j] = src[i][j] # if dim == 0
self[i][index[i][j]] = src[i][j] # if dim == 1
>>> torch.manual_seed(0)
>>> x = torch.arange(0, 12).reshape(2, 6)
>>> x= x.type(torch.float32)
tensor([[ 0., 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10., 11.]])
>>> index = torch.tensor([[0, 1, 2, 0, 0], [2, 0, 0, 1, 2]])
tensor([[0, 1, 2, 0, 0],
[2, 0, 0, 1, 2]])
>>> y = torch.zeros(3, 6)
>>> y = torch.scatter(y, 0, index, x)
tensor([[ 0., 7., 8., 3., 4., 0.],
[ 0., 1., 0., 9., 0., 0.],
[ 6., 0., 2., 0., 10., 0.]])
'''in-place operation'''
>>> yy = torch.zeros(3, 6)
>>> yy.scatter_(0, index, x)
tensor([[ 0., 7., 8., 3., 4., 0.],
[ 0., 1., 0., 9., 0., 0.],
[ 6., 0., 2., 0., 10., 0.]])
下面将上述的执行过程绘制出来
- 第一步
首先下面是我们的初始化,我们初始化了src
,index
,input
并且设置了dim=0
,填充公式为self [ index[i][j] ][j] = src[i][j]
因为dim=0
,所以==需要填充的 input 的行的索引就由 index 数值也就是 index[i][j]来确定,需要填充的 input 的列的索引对应于 index 的列,往 self 里面填充的具体数值由 index 对应的 src 来确定
看下面例子==序号 3==:- 需要填充的 input 的行的索引:
行=index[i][j]=index[0][2]=2
- 需要填充的 input 的列的索引:
列=index 列=j=2
- self 填充的具体数值:
self[行][列]=self[2][2]=src[i][j]=2
- 需要填充的 input 的行的索引:

- 第二步
下面我们继续上述步骤,可发现当我们进行到第六步的时候,index[0][5]
并不存在,所以直接跳过就可以了

- 第三步
在这一步我们将input
填充完毕。如图所示,这里我们取图中的序号 11 进行验证- 需要填充的 input 的行的索引:
行=index[i][j]=index[1][4]=2
- 需要填充的 input 的列的索引:
列=index 列=j=4
- self 填充的具体数值:
self[行][列]=self[2][4]=src[i][j]=10
- 所以在 self 的第二行,第四列填入 10
- 需要填充的 input 的行的索引:

- 问题
为什么在第二步我们遇到的问题吗:当我们进行到序号 6 的时候,index[0][5]
并不存在,我们选择了跳过。可以跳过而没有报错呢,因为最初的文档对src, index, self
的维度有过定义- 对任意维度 d:
index.size(d) <= src.size(d)
- 对 d!=dim 的维度:
index.size(d) <= self.size(d)
所以index
的维度是可以小于src
的维度的,关系如下
- 对任意维度 d:

本文由 Yonghui Wang 创作,采用
知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为:
Dec 19, 2024 12:13 pm