import torch
x = torch.arange(16).reshape(1,4,4)
print(x)
print('--------')
a = x.sum(axis = 1,keepdim=True)
a2 = x.sum(axis = 1,keepdim=False)
a3 = x.sum(axis = 0,keepdim=True)
a4 = x.sum(axis = 0,keepdim=False)
a5 = x.sum(axis = 2,keepdim=True)
print(a)
print(a2)
print('----------')
print(a3)
print(a4)
print(a5)
import torch
x = torch.arange(16).reshape(4,4)
print(x)
print('--------')
a = x.sum(axis = 1,keepdim=True)
a2 = x.sum(axis = 1,keepdim=False)
print(a)
print(a2)
print(x/a)
结合这个两个例子,详细的讲清楚不同情况下axis轴的变化
理解PyTorch中张量的维度操作和沿特定轴的求和确实需要一点时间。让我们通过两个例子逐步解析这些操作,详细讲解不同情况下的轴变化。
第一个例子
import torch
x = torch.arange(16).reshape(1, 4, 4)
print(x)
print('--------')
a = x.sum(axis=1, keepdim=True)
a2 = x.sum(axis=1, keepdim=False)
a3 = x.sum(axis=0, keepdim=True)
a4 = x.sum(axis=0, keepdim=False)
a5 = x.sum(axis=2, keepdim=True)
print(a)
print(a2)
print('----------')
print(a3)
print(a4)
print(a5)
初始张量
tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
这是一个形状为 (1, 4, 4)
的张量。我们可以将其看作一个包含4x4矩阵的批次。
沿轴1求和
x.sum(axis=1, keepdim=True)
沿轴1(即第二个维度,4的方向)求和,并保持维度。
tensor([[[24, 28, 32, 36]]])
形状变为 (1, 1, 4)
。
x.sum(axis=1, keepdim=False)
沿轴1求和,不保持维度。
tensor([[24, 28, 32, 36]])
形状变为 (1, 4)
。
沿轴0求和
x.sum(axis=0, keepdim=True)
沿轴0(即第一个维度,1的方向)求和,并保持维度。
tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
因为原始张量在轴0上只有一个元素,所以结果与原始张量相同,形状为 (1, 4, 4)
。
x.sum(axis=0, keepdim=False)
沿轴0求和,不保持维度。
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
形状变为 (4, 4)
。
沿轴2求和
x.sum(axis=2, keepdim=True)
沿轴2(即第三个维度,4的方向)求和,并保持维度。
tensor([[[ 6],
[22],
[38],
[54]]])
形状变为 (1, 4, 1)
。
关键点
keepdim=True
会保持被求和的维度,结果的维度数不变,只是被求和的维度大小变为1。keepdim=False
则会移除被求和的维度,结果的维度数减少1。
第二个例子
import torch
x = torch.arange(16).reshape(4, 4)
print(x)
print('--------')
a = x.sum(axis=1, keepdim=True)
a2 = x.sum(axis=1, keepdim=False)
print(a)
print(a2)
print(x/a)
初始张量
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
这是一个形状为 (4, 4)
的张量。
沿轴1求和
x.sum(axis=1, keepdim=True)
沿轴1(即第二个维度,4的方向)求和,并保持维度。
tensor([[ 6],
[22],
[38],
[54]])
形状变为 (4, 1)
。
x.sum(axis=1, keepdim=False)
沿轴1求和,不保持维度。
tensor([ 6, 22, 38, 54])
形状变为 (4,)
。
元素除以行和
x / a
tensor([[0.0000, 0.1667, 0.3333, 0.5000],
[0.1818, 0.2273, 0.2727, 0.3182],
[0.2105, 0.2368, 0.2632, 0.2895],
[0.2222, 0.2407, 0.2593, 0.2778]])
这是每个元素除以其对应行的和,结果为:
tensor([[ 0/6, 1/6, 2/6, 3/6],
[ 4/22, 5/22, 6/22, 7/22],
[ 8/38, 9/38, 10/38, 11/38],
[12/54, 13/54, 14/54, 15/54]])
轴(axis)和维度变化总结
- axis=0:沿第一个维度(行)操作,求和后剩下其他维度的和。
- axis=1:沿第二个维度(列)操作,求和后剩下第一维度和第三维度的和。
- axis=2:沿第三个维度(深度)操作,求和后剩下前两个维度的和。
使用 keepdim=True
保持维度时,被求和的维度变为1。使用 keepdim=False
时,被求和的维度被移除。
疑问:
为啥reshape(1, 4, 4)这种的,行反而是列了,,只有reshape(4, 4)的时候,行才是行
张量的结构
先回顾一下基础概念:
- 二维张量(矩阵):具有行和列。
- 三维张量:有多个二维矩阵组成,可以看作是具有“深度”维度的矩阵堆叠。
示例1:二维张量 (4, 4)
import torch
x = torch.arange(16).reshape(4, 4)
print(x)
输出:
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
这个张量的形状是 (4, 4)
,代表一个 4x4 的矩阵:
行是水平方向的:
- 行0:
[ 0, 1, 2, 3]
- 行1:
[ 4, 5, 6, 7]
- 行2:
[ 8, 9, 10, 11]
- 行3:
[12, 13, 14, 15]
- 行0:
列是垂直方向的:
- 列0:
[ 0, 4, 8, 12]
- 列1:
[ 1, 5, 9, 13]
- 列2:
[ 2, 6, 10, 14]
- 列3:
[ 3, 7, 11, 15]
- 列0:
示例2:三维张量 (1, 4, 4)
x = torch.arange(16).reshape(1, 4, 4)
print(x)
输出:
tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
这个张量的形状是 (1, 4, 4)
,代表一个 1x4x4 的三维张量:
- 第一个维度是
1
,表示批次大小。 - 第二个维度是
4
,表示行数(每个矩阵的行)。 - 第三个维度是
4
,表示列数(每个矩阵的列)。
沿轴求和的解释
沿轴1(第二个维度)求和
- 对于二维张量
(4, 4)
:
a = x.sum(axis=1, keepdim=True)
print(a)
输出:
tensor([[ 6],
[22],
[38],
[54]])
- 轴1是行的方向,每行的元素求和:
- [0, 1, 2, 3] => 0+1+2+3 = 6
- [4, 5, 6, 7] => 4+5+6+7 = 22
- [8, 9, 10, 11] => 8+9+10+11 = 38
- [12, 13, 14, 15] => 12+13+14+15 = 54
- 对于三维张量
(1, 4, 4)
:
a = x.sum(axis=1, keepdim=True)
print(a)
输出:
tensor([[[24, 28, 32, 36]]])
- 轴1是第一个矩阵的行方向。每行的元素求和:
- [0, 1, 2, 3] + [4, 5, 6, 7] + [8, 9, 10, 11] + [12, 13, 14, 15]
- 每列求和:24 = 0+4+8+12, 28 = 1+5+9+13, 32 = 2+6+10+14, 36 = 3+7+11+15
为什么看起来“行变成了列”
在 (1, 4, 4)
的三维张量中,第一维度表示的是批次大小,所以看起来每个4x4的矩阵在操作时依然是按二维的方式处理。但因为增加了一个批次维度,导致它在求和操作中表现出与二维张量不同的行为。
具体来说:
- 当沿轴1(第二个维度)求和时,我们对的是每个矩阵的行进行求和操作。
- 而沿轴0(第一个维度)求和时,我们对批次维度进行求和操作。
总结
- 二维张量:行和列的概念是直观的。
- 三维张量:批次维度引入后,行和列的操作看起来会不同,但其实依然是对每个二维矩阵进行操作。
- 沿轴求和时,理解求和的维度是关键。