想象你搬进一栋会变形的公寓楼。物业说:这栋楼共有 3 层,每层 4 个房间;过了两天,又说:咱们重新隔一下,改成 2 层,每层 6 个房间。房间总数还是 12 间,变的只是“怎么数”。深度学习里的张量,就是这种会变形的公寓楼。张量的“阶”,是楼有几个方向——0 阶是一间屋,1 阶是一条走廊,2 阶是一层楼面,3 阶以上是一整栋楼甚至一片小区。张量的“形状”则是楼书里的户型图,它清楚写着每个方向各有多少间房。这篇文章就用“看楼”的思路,带你拆解标量、向量、矩阵、高阶张量、shape、reshape、转置,以及绕不开的 batch、channel、height、width 和内存布局。读完你会发现,一串 shape 摆在眼前,你就能立刻在脑中画出那栋清晰的楼。

岗位关联

职业价值:张量和 shape 是深度学习框架里最基础也最容易翻车的概念。把阶与形状彻底搞懂,读模型源码、调试维度报错、设计网络结构时都能省下大量时间,是从“会调接口”走向“真正懂框架”的关键一步。

目录
  1. 可视化演示
  2. 一、张量阶层:从单间到高楼
  3. 二、形状解读:给维度当翻译官
  4. 三、变形容器:reshape 和 view 怎么改形状
  5. 四、转置操作:换个方向看世界
  6. 五、深度维度:深度学习里的常见张量形状
  7. 六、内存布局:房间里真实住址
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示0D到4D张量的阶与形状结构,动态演示Reshape形状变换与转置维度交换,交互切换模式理解张量维度操作。

本节配有交互动效(进入视口后自动加载,约 3KB)。

张量阶:从标量到高阶张量 青色为0D标量(单一数值,如loss) 浅青为1D向量(特征序列) 橙色为2D矩阵(权重矩阵) Order = len(shape), 0D:() 1D:(n) 2D:(m,n) 3D:(d,h,w) 4D:(N,C,H,W) 张量阶是形状元组的长度,0D标量到4D批次张量逐级递增,每增加一阶多一层嵌套

一、张量阶层:从单间到高楼

万物有基础单位,数据也一样。一个单独的数,好比一栋公寓楼里最孤单的单间——它没有走廊,没有楼层,自己就是整栋“楼”。在张量世界里,我们叫它 0 阶张量(标量)。继续把很多单间排成一排,就出现了走廊,这是一阶张量(向量)。再把这些走廊一格格铺开成一整层楼面,就是二阶张量(矩阵)。如果再把多层楼叠起来,就自然进入了 3 阶、4 阶直至更高阶。

所谓“阶”(rank),指的就是张量有多少个轴(axis),也就是它的“方向数”。判断阶非常简单:看它的形状(shape)这个元组里装了几个数字。数字个数是几,阶就是几。官方文档管这个叫“张量的维度数”,本质就是那串 shape 的长度。

框架返回的 shape 永远是一个 tuple(元组)。例如 shape 为 (3, 4) 代表 2 阶(矩阵),shape 为 (2, 3, 4) 代表 3 阶(三个轴分别是 2、3、4)。注意:单个数字的向量 shape 是 (n,),而不是 (n)——不要忘记这个逗号,它表示“这是一个一维向量”,而不是一个 1 行 n 列的矩阵。

所以,以后看到一个张量,先在脑海里问三个问题:这栋“楼”有几个方向(几阶)?每个方向上有几间房(轴长)?总共多少间房(元素总数)?三个问题答上来,这栋楼的结构就彻底清楚了。

r=len⁡(s),s=(d1,d2,⋯ ,dr)r = \operatorname{len}(\boldsymbol{s}), \qquad \boldsymbol{s} = (d_1, d_2, \cdots, d_r)
公式解释:一个张量的阶(rank)r,就等于它的形状元组 s 里数字的个数。s 里每个数字代表一个轴的长度。
  1. $\boldsymbol{s}$(形状元组)像公寓楼的户型图,用圆括号包起来的数字序列,例如 (2, 3, 4) 表示三个方向的房间数。
    s=(d1,d2,⋯ ,dr)\boldsymbol{s} = (d_1, d_2, \cdots, d_r)
  2. $\operatorname{len}(\boldsymbol{s})$(长度函数)数这个元组里有几个数字,这个数字就是阶。
    r=len⁡(s)r = \operatorname{len}(\boldsymbol{s})
  3. $d_i$(轴长)第 i 个方向上有多少个格子,也就是第 i 个轴的长度。
    di=第 i 个轴的长度d_i = \text{第 } i \text{ 个轴的长度}

二、形状解读:给维度当翻译官

物业发你一张户型图,上面写:共 2 个分段,每段 3 层,每层 4 个房间。这行字就是 shape:(2, 3, 4)。读 shape 就像翻译楼书,把数字按照顺序还原成“第一个方向多少、第二个方向多少”,而不是把它们当成两个毫不相干的随机数。

在代码里,shape 是一个 tuple,每个位置叫一个轴(axis),左起第 0 个、第 1 个……对应下标从 0 开始。比如 shape[0] 是第一个轴长度,shape[1] 是第二个。元素总数通过各轴长连乘得到,框架里通常叫 numel 或 size。

动态维度是另一个常见话题:训练时 batch size 常常留空或用 -1 占位,运行时才知道。例如 (None, 3, 224, 224) 在代码里常写成 (batch, 3, 224, 224)。虽然实际值运行时才定,但语义已经明确:第 0 轴表示一批有多少个样本。

把 shape 读成一句话是最实用的习惯:“第 0 轴 2,第 1 轴 3,第 2 轴 4”。只要把每个轴的含义钉死在脑中,任何报错信息里出现的 (2, 3, 4) 都能立刻具象成那栋熟悉的楼。

N=∏i=1rdi=d1×d2×⋯×drN = \prod_{i=1}^{r} d_i = d_1 \times d_2 \times \cdots \times d_r
公式解释:张量的元素总数 = 每个轴的长度连乘。房间总数就是这么算出来的。
  1. $N$(元素总数)张量里一共有多少个数,也就是整栋楼里所有房间的数量。
    N=d1×d2×⋯×drN = d_1 \times d_2 \times \cdots \times d_r
  2. $\prod_{i=1}^{r}$(连乘符号)把从第 1 个到第 r 个轴的长度依次相乘。
    N=∏i=1rdiN = \prod_{i=1}^{r} d_i
  3. $d_i$(轴长)第 i 个维度的大小,例如 shape=(2,3,4) 时,$d_1=2, d_2=3, d_3=4$。
    di=第 i 个维度的大小d_i = \text{第 } i \text{ 个维度的大小}

三、变形容器:reshape 和 view 怎么改形状

物业说:咱们把每层 4 间房改成每层 2 间套房,房间总数不变。这正是一个 reshape 的动作:重新划分房间格局,总数守恒。记住 reshape 的唯一规则——新形状的各轴长度乘积必须等于旧形状的各轴长度乘积。所以 (2, 3, 4) 可以变成 (6, 4)、(12, 2)、(3, 8)……因为 2×3×4 = 24。反之,如果新形状的乘积不等于 24,框架会直接报错。

PyTorch 的 reshape 很智能:能复用现有内存就复用(不拷贝),不能复用就悄悄拷贝。它的兄弟 view 更严格,只能在内存连续时复用内存,否则抛错。这就是为什么常见的报错是:“view size is not compatible with input size“。此外,unsqueeze 给张量增加一个长度为 1 的轴,squeeze 去掉长度为 1 的轴——相当于在楼里加或去掉”只有一间的杂物层”,数据一字未动。

想快速把整栋楼拉成一条长走廊,交给 flatten。它等价于把房间按顺序拆下来排成一排,让全连接层一口气数完所有房间。记住:reshape 改“格局”,view 改“视角”,unsqueeze/squeeze 改“楼层语义”,三者都不是对数据施暴。

d1×d2×⋯×dr=e1×e2×⋯×esd_1 \times d_2 \times \cdots \times d_r = e_1 \times e_2 \times \cdots \times e_s
公式解释:reshape 前后的总乘积必须完全相等,这是 reshape 的“守恒律”。
  1. $d_1 \times \cdots \times d_r$(原形状的积)reshape 之前,每个轴长度依次相乘,得到旧元素总数。
    旧元素总数=d1×d2×⋯×dr\text{旧元素总数} = d_1 \times d_2 \times \cdots \times d_r
  2. $e_1 \times \cdots \times e_s$(新形状的积)reshape 之后,每个轴长度依次相乘,得到新元素总数。
    新元素总数=e1×e2×⋯×es\text{新元素总数} = e_1 \times e_2 \times \cdots \times e_s
  3. 等号(守恒律)两者必须相等,否则 reshape 无意义。
    ∏i=1rdi=∏j=1sej\prod_{i=1}^{r} d_i = \prod_{j=1}^{s} e_j

四、转置操作:换个方向看世界

物业说:从明天起,“层”改为“列”来编号。原本第 2 层第 5 间房,现在记成第 5 列第 2 层。房间没变,坐标系转了 90°。这就是转置。矩阵转置是最简单的版本:把 A 的行、列互换,公式说明一切。

高阶张量用 transpose(dim0, dim1) 交换任意两个轴,或用 permute(……) 重排全部轴。注意:转置不是 reshape!reshape 只是“重新分组”,转置是“换坐标系”。比如 shape (2,3,4) 转置第 1、2 轴后得到 (2,4,3),元素位置完全不同。转置后的张量通常是“非连续视图”:数据没有真的搬,只是换了个“看”的方式,所以后续 view 可能失效,需要 contiguous() 重新整理内存。

老话重提:转置是转图纸,contiguous 是请搬家公司。使用高维张量时,别一看 shape 对就放心大胆 view——先问一句:这栋楼的“房产证”上,门牌号真的连续吗?

(A⊤)ij=Aji(A^{\top})_{ij} = A_{ji}
公式解释:转置后新矩阵的第 i 行第 j 列元素,等于原矩阵第 j 行第 i 列元素。下标对调,位置互换。
  1. $A^{\top}$(转置矩阵)把矩阵 A 的行和列对调后得到的新矩阵,就像把户型图旋转 90°。
    A⊤=转置后的矩阵A^{\top} = \text{转置后的矩阵}
  2. $(A^{\top})_{ij}$(新矩阵的元素)转置后第 i 行第 j 列的元素。
    (A⊤)ij=新矩阵的 (i,j) 位置(A^{\top})_{ij} = \text{新矩阵的 } (i,j) \text{ 位置}
  3. $A_{ji}$(原矩阵的元素)它来自原矩阵第 j 行第 i 列,位置正好相反。
    Aji=原矩阵的 (j,i) 位置A_{ji} = \text{原矩阵的 } (j,i) \text{ 位置}

五、深度维度:深度学习里的常见张量形状

深度学习的训练数据,就像一个小区的几栋楼:一栋楼是一张样本图(batch),楼的颜色属性是通道(channel),高度是楼层数(height),宽度是每层的房间数(width)。于是图像张量在多数框架里长成四个轴。

两种主流约定并存:NCHW 和 NHWC。PyTorch 默认 NCHW,早期 TensorFlow 常推荐 NHWC。两者只是轴顺序不同,数据含义完全一样——就像同一栋楼从不同方向画设计图。

为什么要关心顺序?因为内存布局会跟着顺序变。NCHW 下通道在空间维度之前,有利于某些矩阵运算库;NHWC 下空间维度连续,对部分 CPU 实现更友好。实际项目里两者互换只靠一行 permute(0, 2, 3, 1) 或 transpose。给模型喂数据前,永远先念一遍 shape 再动手。看到 (32, 3, 224, 224),要能立刻说出来:“32 张图、3 个通道、高 224、宽 224”。能把 shape 说出口,代码就不会迷路。

XNCHW:  (N,C,H,W)XNHWC:  (N,H,W,C)X_{\text{NCHW}}: \; (N, C, H, W) \qquad X_{\text{NHWC}}: \; (N, H, W, C)
公式解释:同一个图像张量,NCHW 和 NHWC 只是四个轴的排列顺序不同。
  1. $N$(批量样本)一批处理多少张图,相当于小区里有多少栋楼。
    N=batch size(样本数)N = \text{batch size(样本数)}
  2. $C$(通道数量)图像有几个颜色通道,例如 RGB 的 C=3。
    C=channel 数(颜色层数)C = \text{channel 数(颜色层数)}
  3. $H$(图像高度)图像纵向有多少像素,相当于楼有几层。
    H=height(高度像素数)H = \text{height(高度像素数)}
  4. $W$(图像宽度)图像横向有多少像素,相当于每层几间房。
    W=width(宽度像素数)W = \text{width(宽度像素数)}

六、内存布局:房间里真实住址

最后一个问题与“看楼”无关,而是“怎么走楼”。门牌号先发完整个一层,再上第二层,叫行优先(row-major);先发 1 号房,接着跑遍所有楼层发 2 号房,叫列优先(column-major)。PyTorch 默认行优先存储。对于形状为 $(d_1, d_2, \ldots, d_r)$、索引为 $(i_1, i_2, \ldots, i_r)$ 的元素,行优先的内存偏移为:

框架内部用 stride(步长)表示每个轴前进一个单位需要跨过多少内存单元。连续张量的 stride 由上式算出;转置后,stride 的顺序被打乱,访问性能下降。GPU/CPU 计算时,连续内存能充分利用缓存,同一批操作可能快出数倍。所以发现张量“不连续”时,及时调用 contiguous() 是在给硬件省时间。

门牌顺不顺,直接决定你找房快不快。这就是为什么转置之后要记得把数据“搬顺”——懂内存布局的人,写出来的网络不仅能跑,还会跑得特别快。

offset=∑k=1r(ik∏j=k+1rdj)\text{offset} = \sum_{k=1}^{r} \left( i_k \prod_{j=k+1}^{r} d_j \right)
公式解释:内存偏移量 = 每个坐标 × 它后面所有轴长度的乘积,再把所有项相加。
  1. $i_k$(第 k 个索引)当前元素在第 k 个轴上的坐标,比如 (1, 2, 0) 里的 1、2、0。
    ik=第 k 个轴的坐标i_k = \text{第 } k \text{ 个轴的坐标}
  2. $\prod_{j=k+1}^{r} d_j$(后缀连乘)排在当前轴之后的所有轴长度连乘,代表“在这个轴上走一步要跨过多少房间”。
    后缀容量=dk+1×dk+2×⋯×dr\text{后缀容量} = d_{k+1} \times d_{k+2} \times \cdots \times d_r
  3. $\sum_{k=1}^{r}$(求和)把每个轴的贡献累加起来,就是最终内存位置。
    offset=i1×d2⋯dr+i2×d3⋯dr+⋯+ir\text{offset} = i_1 \times d_2 \cdots d_r + i_2 \times d_3 \cdots d_r + \cdots + i_r

AI 应用场景

场景1:图像数据预处理通道换位

阶段:数据预处理

解决的问题:OpenCV 读图天然得到 H×W×C 的数组(高、宽、通道),而 PyTorch 模型期望 N×C×H×W。直接喂会报维度错误,或者形状对不上但语义错乱。传统方式要写一堆 for 循环转数据,低效且易错。

具体案例:图像分类项目里加载 1000 张图片,每张 (224, 224, 3)。先 permute(2, 0, 1) 把通道挪到第 0 轴,变成 (3, 224, 224);再 unsqueeze(0) 补上 batch 轴,最终得到 (1, 3, 224, 224),一次性输给 ResNet。就像把楼从“平面图”翻成“立面图”,一句代码就能完成。

场景2:推理引擎里保持连续内存

阶段:模型部署与推理优化

解决的问题:网络里多次 transpose 后,张量成为非连续视图。某些算子(如 view/flatten)报错或变慢,推理延迟升高。传统做法是到处加 clone(),浪费内存且容易破坏梯度。

具体案例:Transformer 推理中,多头注意力频繁 transpose(0, 1),后续 reshape 视图时崩溃。工程师在关键层前加一行 contiguous(),显式整理内存,推理延迟下降 30%。这就是把打乱的门牌号重新理顺,让硬件少走弯路。

场景3:特征图展平接全连接层

阶段:模型结构设计

解决的问题:CNN 输出 (B, C, H, W) 的特征图,全连接层需要 (B, feature) 的二维输入。新手常把 batch 维弄丢,或者忘记元素总数匹配。

具体案例:图像分类网络最后一层卷积输出 (32, 512, 7, 7),用 reshape(32, -1) 展平成 (32, 25088),再送入分类头。-1 让框架自动计算该维大小,bulletproof。就像把整栋楼的房间拆成一条长走廊,一个动作搞定。

Python 演示

python28 行
import torch x = torch.arange(24)print("原始张量共有元素:", x.numel()) a = x.reshape(2, 3, 4)print("reshape(2,3,4):", a.shape, "元素总数:", a.numel()) b = a.transpose(1, 2)print("transpose(1,2):", b.shape, "stride:", b.stride()) try:    b.view(6, 4)except RuntimeError as e:    print("非连续视图 view 直接报错:", e) c = b.contiguous().view(6, 4)print("contiguous 后 view(6,4):", c.shape) img = torch.randn(4, 3, 32, 32)print("图像张量 NCHW:", img.shape) img_nhwc = img.permute(0, 2, 3, 1)print("permute 后 NHWC:", img_nhwc.shape) y = x.view(1, 24).squeeze(0)z = y.unsqueeze(0).unsqueeze(-1)print("增删维度:", y.shape, "->", z.shape)
目的:用 PyTorch 把本文所有概念一次性串起来:numel 数房间、reshape 重排、transpose 交换轴、非连续视图为何 view 报错、contiguous 搬家公司,以及 NCHW/NHWC 互换和维度增删。
  1. x = torch.arange(24)造出 0 到 23 共 24 个“房间”,作为实验楼。
  2. a = x.reshape(2, 3, 4)24 个房间重排成 2 段、3 行、4 列,总数不变。
  3. b = a.transpose(1, 2)交换第 1、2 个轴,门牌顺序被打乱,stride 变化。
  4. print("非连续视图 view 直接报错:", e)展示不连续时 view 的经典翻车现场。
  5. c = b.contiguous().view(6, 4)先请“搬家公司”理顺内存,再放心 view。
  6. img.permute(0, 2, 3, 1)一行代码把 NCHW 改成 NHWC,换轴不换数据。
  7. x.view(1, 24).squeeze(0)演示加/去长度为 1 的轴,数据一个字都不变。

常见误区

误区我以为 reshape 就是 view,view 就是 reshape,反正输出 shape 都一样,随便用哪个都行。

正解两者差别在“是否复制数据”。view 是站在同一栋楼里换一个视角,不搬任何房间;reshape 像物业重新隔墙,必要时会悄悄复制一份数据。当张量由转置产生、内存不连续时,view 会直接报错,而 reshape 能自动兜底。

为何常见:两个方法的输出看起来一模一样,平时看不出区别,一到非连续张量上就翻车。

误区所谓转置,不就把 shape 从 (2,3) 改成 (3,2) 吗?和 reshape 差不多。

正解转置不是简单换 shape 数字,而是交换元素位置,让原来 (i,j) 位置的元素去新矩阵的 (j,i) 位置。reshape 只是保留原排列顺序重新分组。两者结果可能形状一样,但内容排列完全不同。

为何常见:PyTorch 打印出来都是同一组数字,不深入看排列顺序就看不出差别。

误区一听到 4 维、5 维张量就觉得那是四维空间里的东西,普通人根本搞不懂。

正解在深度学习里,维度大多是“方便的编号”。比如 (batch, seq_len, embedding) 只是把“句子、词位置、词向量”三个语义装进三个轴。本质上还是同一套公寓楼编号规则,和抽象的“高维空间”没有必然关系。

为何常见:线性代数课把高维空间讲得太玄,容易让人把它想象成某种神秘数学。

误区反正都是改形状,顺序无所谓,最后 shape 对就行。

正解顺序会直接影响元素排列和内存布局。例如 x.reshape(6,4).transpose(0,1) 与 x.transpose(0,1).reshape(4,6) 的内容顺序完全不同。前者先按行重排再交换轴,后者先交换轴再重新分组,每一步的输入都是上一步的输出。

为何常见:看到形状都是 (4,6) 就觉得等价,没去看里面的元素到底怎么排的。

面试题

Q1. 在 PyTorch 中,标量张量的 shape 是什么?

单选题 · easy

  • A.()(空元组)← 正确答案
  • B.(1,)(单元素)
  • C.(0,)(零长度)
  • D.(None,)(未知维度)

答案:A。标量只有一个数,没有轴,所以 shape 是空元组 (),阶为 0。可以把 () 想象成“没有楼层的独栋小楼”,只有一间房。B 是含 1 个元素的向量,C 是长度 0 的向量,D 是动态形状占位,都不对标量。

Q2. 张量的“阶”指的是什么?

单选题 · easy

  • A.元素的个数
  • B.数值的范围
  • C.维度轴的数量← 正确答案
  • D.存储的字节数

答案:C。阶(rank)是张量有多少个轴,也就是形状元组里数字的个数。元素个数是“房间总数”,数值范围是数据本身的量纲,存储字节数取决于数据类型。这就像楼层数是“有几层”,跟每层家具多少、用什么材料无关。

Q3. shape=(2, 3, 4) 的张量里有多少个元素?

单选题 · easy

  • A.9 个
  • B.12 个
  • C.24 个← 正确答案
  • D.48 个

答案:C。元素总数等于各轴长度连乘:2×3×4=24。这本质上就是“全楼房间数 = 每层间数 × 层数 × 栋数”的乘法。

Q4. 把 shape=(6,) 的张量 reshape 成 (2, 3),总元素个数是多少?

单选题 · mid

  • A.2 个
  • B.3 个
  • C.6 个← 正确答案
  • D.12 个

答案:C。reshape 只能改变“房间怎么分组”,不能改变房间总数。原张量 6 个元素,reshape 成 (2,3) 后仍然是 6 个。记住守恒律:新形状连乘必须等于旧形状连乘,2×3=6。

Q5. 关于矩阵转置,下面哪些说法正确?

多选题 · mid

  • A.转置后下标交换位置← 正确答案
  • B.两次转置返回原矩阵← 正确答案
  • C.转置后形状保持相同
  • D.转置不改变元素总个数← 正确答案

答案:ABD。A 对,转置的定义就是 $(A^T)_{ij}=A_{ji}$;B 对,转置两次回到原矩阵,像把图纸转回来;C 错,A 是 m×n 时 A^T 是 n×m,形状通常不同;D 对,元素总量永远是 mn,房间数不变。

Q6. 图像张量使用 NCHW 格式时,中间两个维度表示什么?

单选题 · mid

  • A.批次和通道
  • B.通道和高度← 正确答案
  • C.高度和宽度
  • D.批次和宽度

答案:B。NCHW 对应 batch、channel、height、width,中间两位是 C 和 H,即通道数和高度。把四个字母逐个念出来,答案就清楚了;这正是“先念 shape 再动手”的好习惯。

Q7. 一个 shape=(5, 4, 3) 的张量执行 permute(2,1,0) 后,新形状是?

单选题 · mid

  • A.(3, 4, 5)← 正确答案
  • B.(4, 5, 3)
  • C.(5, 3, 4)
  • D.(3, 5, 4)

答案:A。permute(2,1,0) 表示把原第 2 个轴放到最前,第 1 个轴保持中间,第 0 个轴放最后。原轴长是 5、4、3,所以新形状是 (3, 4, 5)。就像把楼的正视图、侧视图、俯视图调换顺序看,楼本身没变,但“第几轴代表什么”变了。

Q8. 关于 reshape、view 和 transpose,下面哪些说法正确?

多选题 · mid

  • A.reshape 前后元素总数一定不变← 正确答案
  • B.transpose 操作会立刻复制底层内存
  • C.转置后的张量一定是连续视图
  • D.view 操作一般不会拷贝数据← 正确答案

答案:AD。A 对,reshape 守恒律永远成立;B 错,transpose 通常返回视图,不立即拷贝;C 错,转置通常得到非连续视图;D 对,view 共享内存、不复制数据。可以理解为:view 只是换双眼睛看同一栋楼。

Q9. shape=(2, 3, 4) 的行优先存储中,索引 (1, 2, 0) 对应的内存偏移量是?

单选题 · hard

  • A.12
  • B.16
  • C.20← 正确答案
  • D.24

答案:C。行优先偏移 = 1×(3×4) + 2×4 + 0 = 12+8+0 = 20。这就是“每走一步跨过多少房间”的连乘规则:第 0 轴步长 12,第 1 轴步长 4,第 2 轴步长 1。记住公式,别靠猜。

Q10. 关于非连续张量,下面哪些说法正确?

多选题 · hard

  • A.转置经常产生非连续视图← 正确答案
  • B.非连续张量调用 view 可能失败← 正确答案
  • C.非连续张量永远无法变回连续
  • D.非连续张量可调用 contiguous() 修正← 正确答案

答案:ABD。A 对,transpose 通常生成 stride 打乱的非连续视图;B 对,view 要求内存连续,非连续时直接报错;C 错,contiguous() 就是“搬家公司”,能把数据重新落成连续;D 对,这正是修正非连续布局的标准手段。