矩阵是什么
从 Bit 到 AGI · 第二章:数学(Math) · 矩阵是什么
上一篇说:一个样本是一个向量。实际训练时,我们同时处理 32、256 甚至 4096 个样本——这就需要把向量按行或按列排成表格。这个表格就是矩阵。本篇讲清矩阵的定义、在内存里的布局,以及它与神经网络权重的一一对应关系。学会用 两个整数描述一层线性变换,是读任何 modeling_*.py 的基本功。后续矩阵乘、注意力、FFN 的 shape 推导,全部建立在「矩阵 = 二维浮点表」这一共识上。
直觉:向量组成的 spreadsheet
Excel 里一张表:每行是一个用户,每列是一个特征。机器学习里的矩阵完全一样——行 = 样本(或 token),列 = 特征(或神经元)。
神经网络的权重本质上就是矩阵:全连接层 把 维输入变成 维输出。Transformer 的 Q/K/V 投影、FFN 的两层线性变换,全是矩阵乘法。
定义
矩阵是 个实数排成的矩形数组:
- :第 行、第 列的元素。
- 行向量: 的第 行,。
- 列向量: 的第 列,。
转置 交换行列:。
例子
例 1:batch 输入矩阵
: 个样本,每个 维。
import numpy as np
B, d = 32, 768
X = np.random.randn(B, d) # shape (32, 768)
print(X.shape) # 32 行 = 32 个向量
print(X[0]) # 第 0 个样本,768 维向量例 2:线性层权重
PyTorch 中 nn.Linear(in_features=768, out_features=3072) 的权重 weight.shape == (3072, 768)——即 。前向计算:,输出 。
| 对象 | 形状 | 含义 |
|---|---|---|
| batch 输入 | ||
| 可学习权重 | ||
| batch 输出 |
量化:内存与参数量
矩阵 的存储(float32):
| 矩阵 | 形状 | float32 参数量 | 显存 |
|---|---|---|---|
| 小线性层 | 589,824 | ≈ 2.25 MiB | |
| FFN 第一层 | 45,088,768 | ≈ 172 MiB | |
| LLaMA-7B 全部权重 | — | ≈ 7B | ≈ 14 GiB (fp16) |
矩阵-向量乘 ()的 FLOPs:(每个输出元素 次乘加)。
NumPy 默认 row-major(C 序):同一行元素在内存中连续。第一章讲过 contiguous 数组对 GPU 很重要——非连续矩阵乘会触发隐式拷贝,拖慢训练。
工程视角:权重即矩阵
打开 model.state_dict(),你会看到成百上千个 key,每个 value 几乎都是二维或更高维张量。layers.0.self_attn.q_proj.weight 形状 (4096, 4096)——这就是一个方阵,4096×4096 = 16,777,216 个参数,bf16 下约 32 MiB 单层单投影。
7B 模型 ≈ 32 层 Transformer,每层含 Q/K/V/O 四个 投影、FFN 两个 矩阵——参数量主要来自这些重复堆叠的矩阵。读 config.json 时:hidden_size、num_hidden_layers、intermediate_size 三个数乘乘除除,就能粗算总参数。
稀疏矩阵在经典 ML 里常见(词袋 TF-IDF);深度 LLM 权重是稠密的,每个元素都可训练。量化(INT8/INT4)不改变「逻辑上是矩阵」,只是把每个 用更少 bit 存储——第四章以后推理章节会详讲。
矩阵转置在 API 设计里处处可见:NumPy A.T、PyTorch W.t()。Attention 里 故意把 key 转置,使 元素变成 query 与 key 的点积——shape 对不上时,90% 是转置写错。
# 检查 Linear 层参数量
import torch.nn as nn
layer = nn.Linear(768, 3072)
params = layer.weight.numel() + layer.bias.numel()
print(f"params={params:,}, mem_bf16={params*2/1024**2:.2f} MiB")常见误区
- 与 不是一回事:转置改变形状;矩阵乘法 要求 的列数 = 的行数。
- PyTorch Linear 的 weight 是 ,不是 。读
shape时别凭直觉。 - 「大矩阵 = 大模型」:7B 参数 ≈ 70 亿个 float,主要是大量 和 的权重矩阵堆叠。
动手试一试
def matrix_stats(m: int, n: int, bytes_per_elem: int = 2) -> dict:
params = m * n
mem_mib = params * bytes_per_elem / (1024 ** 2)
flops_mv = 2 * m * n # matrix-vector multiply
return {"params": params, "mem_MiB": mem_mib, "flops_mv": flops_mv}
# Transformer FFN: 4096 -> 11008 -> 4096
w1 = matrix_stats(11008, 4096)
w2 = matrix_stats(4096, 11008)
print(f"FFN 两层权重合计 ≈ {(w1['mem_MiB'] + w2['mem_MiB']):.0f} MiB (bf16)")深入一层:分块与视图
大矩阵不必一次载入 GPU:按行块(数据并行)或列块(模型并行)切分。Megatron tensor parallel 把 列切到 8 卡,每卡算局部 GEMM 再 all-reduce——逻辑仍是一个矩阵乘,物理是分块。
视图(view)不拷贝:X.view(B, -1) 把图片 batch 展平为 。transpose 可能不连续,.contiguous() 才保证 row-major——第一章与本章衔接。
单位矩阵 :对角 1、其余 0,。残差连接 在 Jacobian 层面加 ,特征值谱整体右移——训练更稳。
低秩分解:,,,。LoRA 即此思路;全秩 是工业默认,微调时用低秩增量省显存。
条件数(下节特征值详讲): 求逆时, 大 → 数值解敏感。线性方程 的 solver 与神经网络无关,但Hessian 条件数影响优化——同一套矩阵分析语言。
与第一章的衔接
第一章:float 数组在内存 row-major 连续存放。矩阵即「 行向量首尾相接」——reshape(m, n) 不改变底层 bytes,只改解释。GPU kernel 要求 leading dimension 连续;transpose 后 GEMM 前常 .contiguous(),否则隐式拷贝拖慢数倍。
Batch 维 是「第三维」:逻辑上 个矩阵,物理上常 (B, m, n) 一块分配——与 SIMD、CUDA grid 的 batch 并行一致。
读者备忘
矩阵 = 二维权重表 = 。 PyTorch Linear 的 weight.shape 是 (out_features, in_features)。参数量 = 行 × 列;一次前向该层 GEMM FLOPs ≈ 。读 checkpoint 时 state_dict 里二维 tensor 几乎都是权重矩阵;一维是 bias 或 norm 的 。
本章内容面向程序员:公式可手推,数字可心算,代码可运行。遇到符号不熟时,先查本篇定义表,再查总结篇速查表,不必一次背熟全部细节。
复习建议:先通读直觉与定义,再跑代码块验证数字,最后看读者备忘与小结。与第一章的 float 数组、SIMD、GPU 并行对照阅读,印象更深。后续章节会在 Transformer、训练、推理中反复调用本章符号,值得在笔记里自建一张 shape/FLOPs 速查表。
小结
矩阵是向量的二维排列, 有 个元素。在 AI 里:batch 输入、权重、注意力得分表都是矩阵。参数量 = 元素个数;显存 ≈ 参数量 × 每元素字节数。下一篇讲为什么矩阵乘法是神经网络和 GPU 的核心运算——矩阵定义了「存什么」,GEMM 定义了「怎么算」。
→ 下一篇:为什么矩阵乘法这么重要