在计算机科学、深度学习(如 PyTorch、TensorFlow)以及 AI 编译器(如 MLIR、XLA)的语境下,Tensor(张量)是承载一切 AI 计算的核心数据结构。
如果用最通俗的话来定义:Tensor 就是一个“穿了铠甲”的多维数据容器。
无论是在显卡(GPU)里狂飙的矩阵乘法,还是在 AI 编译器里流转的中间表示(IR),理解 Tensor 都可以从它的外在数学形态和底层物理存储两个维度展开。
1. 外在形态:高维数据的“多面手”
从数学和编程的角度来看,Tensor 是对标量、向量和矩阵的高维泛化。你可以通过它的维度(Rank / Dimension)来直观认识它:
- 0 维张量 (Rank 0) —— 标量 (Scalar):就是一个孤零零的数字。例如:
1.0。 - 1 维张量 (Rank 1) —— 向量 (Vector):一排数字组成的数组。例如:一行特征值
[1.0, 2.0, 3.0]。 - 2 维张量 (Rank 2) —— 矩阵 (Matrix):有行有列的表格。
- 3 维张量 (Rank 3):像一本“书”,有长、宽、页数。在计算机视觉中,一张彩色图片(长×\times×宽×\times×RGB 3通道)就是一个 3 维 Tensor。
- 4 维张量 (Rank 4):像一排“书架”。在深度学习训练时,我们往往把多张图片打包成一个批次(Batch Size×\times×通道数×\times×高×\times×宽),这就是一个标准的 4 维 Tensor。
Tensor 的三大核心DNA:
- Shape(形状):每一维度的元素个数。比如形状为
[3, 224, 224]的 Tensor。- DataType(数据类型):里面存的是什么数字,比如
f32(单精度浮点数)、i8(量化整数)。- Layout(内存布局):决定了高维数据是怎么平铺在物理内存里的。
2. 物理本质:在内存里,它只是一条“直线”
这是非编译器开发者最容易忽视的一点:虽然 Tensor 在数学上是高维的,但计算机的物理内存(显存/内存)永远是一维线性的。
当你在 PyTorch 里定义一个[2, 3]的矩阵时,在显存里它其实只是连续躺着的 6 个数字。
为了让你能在上层用tensor[i][j]方便地访问数据,Tensor 的底层结构体(如 MLIR 中的MemRefDescriptor或 PyTorch 的底层实现)通常包含了以下几个核心指针和参数:
- Base Pointer(基地址指针):指向这块连续物理内存的起点。
- Offset(偏移量):从起点开始往后数多少个元素才是真正的数据。
- Strides(步长):这是高维映射到一维的魔法所在。步长决定了当你把某个维度的坐标+1+1+1时,底层指针需要在物理内存上向前跳跃多少个格子。
💡 举个例子(步长魔术)
假设有一个形状为[2, 3]的二维 Tensor,在物理内存里存的顺序是[A, B, C, D, E, F]。
它的步长(Strides)是[3, 1]。
- 当你想找
tensor[0][1]时,物理位置等于0×3+1×1=10 \times 3 + 1 \times 1 = 10×3+1×1=1,对应B。 - 当你想找
tensor[1][0](第二行第一列)时,物理位置等于1×3+0×1=31 \times 3 + 0 \times 1 = 31×3+0×1=3,指针直接跳过 3 个格子,对应D。
这也是为什么在 AI 框架里做Tensor 转置(Transpose/Permute)往往快得不可思议——因为编译器根本没有去挪动显存里的数字,它只是悄悄把步长(Strides)的数值从[3, 1]改成了[1, 3],就把矩阵给旋过来了!
3. 在 AI 编译器(如 MLIR)中,Tensor 是如何被操纵的?
在你之前关心的编译系统(Compiler)世界里,Tensor 的生命周期会经历从抽象语义到硬件贴身肉搏的降级(Lowering)过程:
① 高层图阶段:纯粹的数学符号
在线性代数层(如 MLIR 的linalg方言),Tensor 仅仅是一个值(Value)。它是不可变的,只表示数据流:
// 语义:两个张量相加,生成一个新的张量 %result = linalg.add ins(%t1, %t2 : tensor<2x3xf32>) -> tensor<2x3xf32>在这个阶段,编译器只关心算子的数学融合(比如把 Add 和 ReLU 融合成一个算子),不需要关心内存怎么分配。
② 中间解构阶段:Bufferization(内存化)
硬件不懂什么叫抽象的“值”,硬件需要具体的“地址”。于是编译器会运行一个关键的 Pass 叫Bufferization,把抽象的tensor转换成手握物理内存指针的memref(内存引用):
// 语义:在堆区分配一块 2x3 的 f32 物理内存,把相加结果写进去 %mem = memref.alloc() : memref<2x3xf32>③ 低层降级阶段:硬件指令
最终,这个memref会被进一步 Lower 成 LLVM IR,变成裸指针,并在最终生成汇编代码时,映射为 GPU 的LD/ST(加载/存储)指令或 CPU 的 SIMD(单指令多数据)向量寄存器操作。
总结
Tensor是整个现代人工智能帝国的砖瓦。在应用层,它是科学家玩弄高维数据的数学画板;在底层,它是编译器优化专家和硬件工程师通过指针、步长(Strides)和连续内存块压榨计算性能的终极战场。正是因为 Tensor 能够把复杂的现实世界(图像、语言、音频)高度抽象成规整的数字阵列,显卡和 AI 芯片才能毫无顾忌地全速轰鸣。