【AI专栏】图解深度学习-AI infra工程师必知必会 - 第 01 章:模型到底是什么?
博主介绍:程序喵大人
- 35 - 资深C/C++/Rust/Android/iOS客户端开发
- 10年大厂工作经验
- 嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手
- 《C++20高级编程》《C++23高级编程》等多本书籍著译者
- 更多原创精品文章,首发gzh,见文末
- 👇👇记得订阅专栏,以防走丢👇👇
😉C++基础系列专栏
😃C语言基础系列专栏
🤣C++大佬养成攻略专栏
🤓C++训练营
👉🏻个人网站

很多人用了很久深度学习,但如果你问他"模型在计算机里到底是什么",他会开始含糊——“就是一个神经网络嘛”、“就是个 AI 嘛”。这一章我们就把这个问题说清楚。
画面里这台标着"MODEL"的机器就是本课的主角。车间里的所有东西都是为了描述它:左边墙上那张蓝图是网络结构,地面传送带上的零件箱是参数权重,传送带从入口走到出口的过程是一次推理。蓝色机器人导师站在旁边,扮演车间主任——它会贯穿这个系列的每一张图。
这一章只讲清楚一件事:模型 = 参数权重 + 网络结构。这个等式听起来平平无奇,但 AI Infra 工程师每天的工作——加载模型、规划显存、估算推理速度——全部从这里开始。你每次 load 的 .safetensors 文件,就是这台机器的零件包。
接下来 7 张图,把这台机器拆开看:零件是什么,蓝图定义了什么,数据怎么在里面流动,以及这台机器出厂时的包装里到底装了什么。
一、模型 = 参数权重 + 网络结构

左边那个金属零件箱里装着密密麻麻的方块,每个方块上写着一个浮点数:0.31415、-0.2718、1.618……这就是参数权重。纯粹的数字,没有语义标签,不告诉你"这个数是用来干什么的"。箱子侧面标着 weights。
右边那张蓝图上画着节点和箭头:输入层指向隐藏层,隐藏层指向输出层。这就是网络结构——定义数据要经过哪些计算步骤、以什么顺序流动。蓝图标着 architecture。
两者加在一起,右边那台机器才能运转。有结构没有参数,是一台空机器;有参数没有结构,是一箱散零件,哪也装不上去。
这在工程上很容易理解:比如你从 HuggingFace 下载模型时至少需要两类文件——.safetensors 是参数,config.json 是结构。
以主流的开源模型 Qwen/Qwen2-7B 为例,其核心结构配置文件 config.json的关键内容如下:
{
"architectures": ["Qwen2ForCausalLM"],
"attention_dropout": 0.0,
"bos_token_id": 151643,
"eos_token_id": 151643,
"hidden_act": "silu",
"hidden_size": 3584,
"initializer_range": 0.02,
"intermediate_size": 18944,
"max_position_embeddings": 131072,
"max_window_layers": 28,
"model_type": "qwen2",
"num_attention_heads": 28,
"num_hidden_layers": 28,
"num_key_value_heads": 4,
"rms_norm_eps": 1e-06,
"rope_theta": 1000000.0,
"sliding_window": 131072,
"tie_word_embeddings": false,
"torch_dtype": "bfloat16",
"transformers_version": "4.37.2",
"use_cache": true,
"use_sliding_window": false,
"vocab_size": 152064
}
在这份配置文件中,有四个核心参数直接定义了模型的网络规格:num_hidden_layers(28 层)、hidden_size(3584 维)、num_attention_heads(28 个注意力头)以及 vocab_size(152064 词)。推理框架正是依赖这几个关键字段,才能在内存中对权重文件(.safetensors)进行正确的张量映射与形状校验(shape validation)。此外,注意到 num_key_value_heads 被设为 4,这远小于注意力头数 num_attention_heads 的 28。这表明该模型采用了分组查询注意力(Grouped-Query Attention, GQA)设计,能大幅节省推理时的 KV Cache 显存占用,具体的显存计算我们会在第 05 章:数值精度与显存账本详细拆解。至于其他的字段,如 rope_theta 用于控制旋转位置编码的 base 值、rms_norm_eps 用于指定归一化的微小项、torch_dtype 指定了默认的数据精度,这些都属于控制数学算子与数值行为的底层参数。框架在加载模型时会自动读取并解析它们,除了修改规格或解决兼容性问题外,日常推理工程中我们极少需要手动干预。
很多人下载了权重文件却忘了配置文件,加载报错,就是因为只拿了零件箱,没拿装配图。"模型"这个词有时指整体,有时仅指参数(比如"换个模型试试"通常是说换权重),需要注意分辨语境。
二、一个最小的"模型":一次矩阵乘法

我们把所有花哨的概念剥掉,一个"模型"最小能小到什么程度呢?
操作台左边传入一个零件箱,装着输入向量 [x₁, x₂, x₃],3 个格子、3 个数字。工位中央是一块参数板,3×2 的数字网格,写着具体数值。右边出来一个更小的零件箱,输出向量 [y₁, y₂],2 个格子。台面上贴着公式卡片:y = W × x。
这就是一个完整的模型,有参数(W 矩阵里的 6 个数字),有结构(一次矩阵乘法),有输入,有输出。GPT、Stable Diffusion 再复杂,底层也是这个操作的大规模叠加——矩阵乘法套矩阵乘法,中间插入激活函数和归一化层。
看看这个例子的规模:输入 3 维,参数矩阵 3×2,输出 2 维。参数量 = 3 × 2 = 6 个浮点数。FP32 存储的话,权重显存 = 6 × 4 字节 = 24 字节。真实模型只是把这个数字放大了几十亿倍而已,但计算逻辑没有啥变化。
矩阵乘法还顺带决定了一件事:shape 怎么变换。输入 shape 是 (3,),参数 shape 是 (3, 2),输出 shape 就是 (2,)。别急,这种 shape 变换的逻辑会在第 02 章:Tensor 与 shape展开来讲。
三、参数是什么:一堆数字而已

上面那张图参数矩阵里有 6 个数字,这里把视角拉开一点点,看看真实模型里参数的规模。
零件箱里有密密麻麻的方块:-0.34、1.27、0.05、-2.11……机器人导师拿起其中一个,旁边放大镜里显示"FP32:4 字节 / 一个参数"。后面货架上还摞着 Layer 2、Layer 3 的箱子。
0.73 是什么意思呢?没啥意思。它只是在训练过程中被数据反复调整后稳定下来的数值。参数没有人类可读的语义,意义来自它们在网络中的集体作用,不是单个数字本身。
当我们说"7B 模型",就是说这个零件箱里有 70 亿个方块。FP32 存储的话,70 亿 × 4 字节 ≈ 28 GB;换成 FP16(每个参数 2 字节),就是 14 GB。参数数量 × 字节数 = 权重显存,这是 AI Infra 工程师最常用的速算公式,第 05 章:数值精度与显存账本会把完整的显存账本算清楚。
这些数字从哪来的呢?训练——也就是拿大量数据反复调整,让模型输出越来越接近正确答案。训练完成后数字被冻结,打包成文件,推理时只读不改。参数按层组织,层名通常是 layer.0.weight、layer.1.weight 这样,对应图里一个个零件箱。
四、网络结构是什么:一张计算图

零件箱看完了,现在看挂在墙上的蓝图。
这张工程图纸上有 5 个圆形节点,用箭头连着,每条箭头旁标着操作名称:矩阵乘、ReLU、LayerNorm。右侧有一行注释:"结构只定义怎么算,不定义算什么数字。“旁边放着一个空零件箱,标签上这些"参数另外装”。
网络结构是一张有向图:节点是算子(计算操作),边是数据流方向。数据从输入节点进来,依次经过每个算子,走到输出节点。整张图定义了怎么算、按什么顺序算、shape 在每步怎么变换。
最关键的一点:结构和参数是独立的。同一张蓝图可以装入不同规格的零件,这就是为什么 Llama-7B 和 Llama-13B 可以共享结构定义(层的种类和连接方式相同),只是参数矩阵的尺寸不一样。你在 HuggingFace 下载模型时,config.json 里的 num_layers、hidden_size、num_attention_heads 就是在描述这张蓝图的规格——层数多少、每层多宽、注意力头有几个。
结构还决定了一件工程师很在意的事:shape 怎么在每一层之间流动。输入进来是什么 shape,经过矩阵乘之后变成什么 shape,再经过 LayerNorm 之后又是什么 shape——这条链完全由结构定义,和参数里的具体数值无关。
五、推理一次发生了什么

零件箱装好,蓝图挂上,现在启动传送带。
数据从左边入料口进来,经过工位 A(矩阵乘)、工位 B(激活 ReLU)、工位 C(LayerNorm),从右边出料口出来,标着"输出 / 预测结果"。每个工位侧面嵌着参数板,小字写着"参与计算,不改变"。全程一个大蓝色箭头指向右——单向,没有回头路。
这就是推理(inference),深度学习里也叫 forward pass。整个过程有三个特征值得记住:数据只向前走,不存在反向路径;参数只参与计算,推理过程中不被修改;同样的输入经过同样的参数,输出是确定的。
每一层的输出叫做激活值(activations),是临时的中间结果。推理时 GPU 上需要存两样东西:权重(参数矩阵)和当前层的激活值。因为不需要梯度、不需要优化器状态,推理的显存占用比训练干净很多。
六、训练和推理,两件完全不同的事

上方蓝色传送带是推理,箭头干净指向右边"预测结果"。下方橙色传送带是训练,走完一遍之后,从"误差"处长出一条反馈回路,反向打回每个工位,参数板上有齿轮旋转——参数在更新。中间对比卡片写着:推理 = 前向;训练 = 前向 + 反向。
推理你已经知道了。训练多了一大步:走完传送带拿到输出后,先算"答得有多差"(loss / 损失),然后沿传送带反向传回,计算每个参数应该怎么调整(梯度),最后用优化器把参数更新一遍。走一遍叫一个 iteration,走几万遍、几百万遍,参数才能稳定下来——那就是训练好的模型。
二者在显存账单差别很大,推理只需要权重加当前激活值,而训练要留住所有层的激活值(反向传播要用),还要额外存梯度和优化器状态,总显存可以是推理的 3~4 倍甚至更多。这就是为什么 AI Infra 工程师上来第一个问题是"训练还是推理"——两件事的资源规划完全是两个量级。
这里先放这个对比概念。第 04 章:训练 vs 推理会把 forward pass、loss、backward pass、梯度、优化器状态逐一展开。
七、模型文件里装了什么

前面讲了模型是什么、怎么跑。最后落地到一个实际问题:你从 HuggingFace 下载一个模型,那个文件夹里到底装了什么?
集装箱内部分两格:
左边大格标"weights",叠满了零件箱,贴着 layer.0.weight、layer.1.weight……一直到 layer.31.weight,文件格式 .safetensors。这是参数权重,训练产出的全部浮点数,按层打包。
右边小格标"config",一张配置卡片,写着 "num_layers": 32、"hidden_size": 4096、"vocab_size": 32000,格式 .json。这是网络结构定义,告诉框架怎么把那些数字组装成一台完整的机器。
集装箱正面贴着 7B ≈ 14 GB(FP16)——参数量乘以字节数,就是权重文件的大小。实际文件夹里还可能有 tokenizer 文件(词表)、generation_config 等,但核心就是这两类:weights 文件大(几 GB 到几百 GB),config 文件小(几 KB)。
两者分离带来一个工程便利:同一套结构可以搭配不同的参数。Llama-2-7B 和 Llama-2-7B-Chat 共享结构定义,参数不同(Chat 版本经过了额外的对齐训练)。换权重文件就行,不用改代码。
以后我们下载模型时有两件事要记得检查:第一,权重文件是否完整(大模型通常被拆成多个 shard,全下完才能加载);第二,config 是否和权重版本匹配(版本对不上会 shape 就会报错)。
码字不易,欢迎大家点赞,关注,评论,谢谢!
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)