基础篇

F08|reshape、转轴、广播:形状变了,内容未必算过

基础篇约 2.1 千字1 组分步图解

从具体对象与小例子开始,理解计算过程与适用条件。

本章目录
动态图解 · F08

改摆法与改数值,分开看

reshape、转置、广播为什么不能互换?

把矩阵想成带地址的格子。reshape改变分组读法;转置改变行列地址对应;广播配合加法等运算改变数值。三者最后可能有相似形状,却不能据此当成同一过程。

reshape保持规定的元素遍历顺序,按另一形状分组。
转置原第i行第j列映射到新第j行第i列。
广播使小张量沿允许的轴参与大张量运算。

输入与适用条件:四帧中的三个对照操作都从原矩阵[[1,2,3],[4,5,6]]开始;每帧明确重置,而不是接力计算。

1 / 4 · 原来的两行

第1步,共4步

窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。

改摆法与改数值,分开看:原来的两行原矩阵 [2,3]123456固定原表;下面不是“先reshape再转置”。

六个数的行优先顺序是1,2,3,4,5,6。接下来进行两种独立操作,均从这张原表出发。

本步状态由图形与说明共同给出。

默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。

为什么需要

形状操作把数据组织成算子需要的格式,减少不必要复制可提高效率。

怎样实现

跟踪下标、步幅和连续性;需要复制时不能只凭“看起来是视图”判断。

可能的代价与误解

把转置后的结果当原表继续相加,会得到另一组数却可能不报错。

如何判断是否做对

对固定整数表逐格比对结果,并检查是否发生内存复制。

为什么深度学习代码里反复改变形状

有些操作需要“一张长表”,有些操作需要“多个头各一张表”。同一批数字可以用不同形状组织,但组织数据与学习新特征不是同一件事。若不分清,你会把一次reshape误读成模型又推理了一次。

reshape是重新分组,不是交换行列

把[[1,2,3],[4,5,6]]按行看成数字序列1、2、3、4、5、6,再改为3行2列,可以得到:

reshape为[3,2]:[[1,2],
                 [3,4],
                 [5,6]]

而同一原矩阵的转置是:

transpose后:  [[1,4],
                 [2,5],
                 [3,6]]

两个结果形状都为[3,2],内容位置却不一样。前者重分组,后者交换“原行”和“原列”的身份。这是许多Attention实现错误的来源。

reshape前后元素数必须一致。12个数可以排成[3,4]或[2,2,3],不能不丢不补地排成[5,5]。代码里的-1有时表示让库按总数推算这一轴,不是负数长度。

多头只是把特征轴分组吗

假设每个位置宽度d=4,有2个头,每头宽度2。投影后的[B,T,4]可以重排成[B,T,2,2],再交换T轴与头轴,成为[B,2,T,2],方便每个头独立计算。

这里“头”指一套Attention中的分组计算单元;具体内容来自已经学习好的投影权重。不是把原始文本分成两半,也不是头0天然负责中文、头1天然负责代码。

为了区分,记H=2为头数、d_h=2为每头宽度,d=H×d_h=4。代码经常用reshape后再transpose或permute(交换若干轴),两个步骤有各自作用。

广播:用一个小对象作用到许多位置

假设X有2行3列,每行都要加偏置[10,20,30]。不必手工复制两行偏置,库可以按广播(broadcasting)规则把这排数应用到每一行:

[[1,2,3],   + [10,20,30] = [[11,22,33],
 [4,5,6]]                    [14,25,36]]

常见广播规则从最右轴对齐:长度相同或某一方长度为1时可匹配。[2,3]与[3]可以;[2,3]与[2]通常不可以。若你要每行加不同的一个数,应把后者组织成[2,1]。

注意力分数可能是[B,H,T,T],某些mask可以带长度为1的头轴来广播,表达“所有头共用这个限制”。但某种形状能广播,不代表语义正确,仍需检查轴身份。

内存布局与视图只需先懂一个原则

张量除了shape,还可用步长(stride)描述沿某轴前进一步在底层存储中跳多远。转轴有时只改变这份说明而不搬动全部数据,这样的结果可能是原数据的视图(view)。

因此某些操作要求内存连续排列,有时需要复制后才能执行;修改共享存储的视图还可能影响原对象。不要把“代码看起来只是换shape”当作一定免费,也不要无条件认为它一定复制。

squeeze通常移除长度为1的轴,unsqueeze增加长度为1的轴。若B恰好为1,随手squeeze可能把批轴也删掉,后续代码在B=1能跑、B=2却失败。显式指定轴比猜形状安全。

运行示例 · F08

reshape与转置:同样四个数为何会形成不同排列

输入与条件。原矩阵是 A=[[1,2],[3,4]],行优先顺序为 1,2,3,4。下面第1—4行是从同一原矩阵A分别出发的四个独立对照,不是把上一行结果直接输入下一行。

步骤与对象内部动作中间结果 / 新状态
1展平再reshape按原顺序放成一行得到 [[1,2,3,4]],只改分组。
2转置旧 (行,列) 换为新 (列,行)得到 [[1,3],[2,4]],元素对应位置真的交换。
3加偏置重新从原矩阵 A 出发(不是从步骤2的转置结果出发),每行加 [10,20]得到 [[11,22],[13,24]],这是广播后的数值运算。
4拆两个头重新从 A 按行展平的 [1,2,3,4] 出发,按连续组切开得到头0 [1,2]、头1 [3,4];还需保持位置轴与头轴对应。
5反例检查想把6个数reshape为 [2,4]目标要8个数,元素总数不等,应拒绝。

把过程连起来。这四行是独立对照,不是连续流水线;不能因为新旧形状相同就认为计算相同。如果真的把“转置A”接着“每行加[10,20]”,结果应是 [[11,23],[12,24]],而非上表第3行的 [[11,22],[13,24]]。

边界与反例。视图是否零拷贝取决于底层步幅和连续性;本例描述逻辑元素排列,不承诺具体框架是否复制。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

课后自检

自检 1

reshape[2,3]到[3,2]与转置一定一样吗?

查看参考答案收起参考答案
不一样。两者可能具有同样的输出形状,但每个元素所在位置不同,正文1到6的例子就是反例。
自检 2

X为[2,3],给每行分别加10和20,应把偏置组织成什么?

查看参考答案收起参考答案
[2,1],即[[10],[20]],让每行的一个数沿列轴广播。

机制依据:[F-TENSOR][F-LINALG]。本节数值与情景除另注外均为原创教学示例;来源不代替中文讲解。

记录保存在本机浏览器。

输入关键词即可检索。

↑ ↓ 选择 Enter 打开Esc 关闭 · 仅本地搜索

阅读设置

阅读设置仅保存在本机浏览器,不上传任何数据。