【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除
标题
222、【AI】【模型部署】模型的影子:解剖 Qwen2.5-0.5B 模型目录
背景
上篇 blog
【AI】【模型部署】跑起第一个模型(下):Notebook 里首次推理
在 Notebook 里三格跑通了推理:from_pretrained(本地目录)0.4s 加载分词器与模型,apply_chat_template把一句中文渲染成 35 个 token,generate贪心生成 52 tokens(3.1s、16.9 tok/s);还提到词表 151936、config 声明"qwen2、24 层、hidden 896"。本篇停下手动推理,回头解剖那个约 1GB 的模型目录:config.json 怎么决定网络结构、model.safetensors 里那 290 个张量是谁、词表文件怎么把文字变成数字——搞清"一个开源模型到底由什么组成"
模型部署
221 里一行from_pretrained就把模型用了起来,但目录里那 11 个文件各司何职还不透明。本篇逐个拆开:这 1GB 本质上是三样东西——一组"怎么搭"的声明、一堆"是多少"的权重、一张"文字↔数字"的词表。
📁目录全景:1GB 被分给谁
缓存目录(实测ls -lh):
config.json 659 B 架构与超参声明 generation_config.json 242 B 生成参数默认值 model.safetensors 943 MB 全部权重 tokenizer.json 6.8 MB 分词器(可执行定义) vocab.json 2.7 MB 词表:token → id merges.txt 1.6 MB BPE 合并规则 tokenizer_config.json 7.2 KB 特殊 token 配置 README.md / LICENSE / … 说明与许可目录共 11 个文件、约 954MB。除了 model.safetensors 占 943MB,其余全是 KB/MB 级文本/JSON——权重是绝对大头,这与"参数 × 每参数字节 = 文件体积"(220 验算过)一致。好处是:除了那个二进制大文件,其余都能直接打开人读,调试时不必上专用工具。
🧩config.json:一份"怎么搭网络"的图纸
全文 659 字节,展开后是几十个键值对,关键字段实测值:
| 字段 | 值 | 含义 |
|---|---|---|
architectures | Qwen2ForCausalLM | 用哪个实现类搭网络 |
model_type | qwen2 | 架构族 |
num_hidden_layers | 24 | Transformer 层数 |
hidden_size | 896 | 每层向量宽度 |
num_attention_heads/num_key_value_heads | 14 / 2 | GQA:KV 头远少于 Q 头,省显存 |
intermediate_size | 4864 | FFN 中间扩宽维度 |
vocab_size | 151936 | 词表大小 |
max_position_embeddings | 32768 | 最长支持 32K token |
torch_dtype | bfloat16 | 权重的存储精度 |
tie_word_embeddings | true | 输入/输出词嵌入共享一份 |
{"model_type":"qwen2","num_hidden_layers":24,"hidden_size":896,"vocab_size":151936,"torch_dtype":"bfloat16"}221 里
from_pretrained加载只需 0.4s 的答案就在这:模型代码是通用的,读到这份图纸才现场决定"搭 24 层、每层宽 896"。换一个 config,同样的代码就搭出另一个模型。
把这些数字拼起来,能画出数据流的骨架:一个词查embed_tokens得到 896 维向量 → 依次流过24 层(每层做自注意力 + 经 4864 宽度的 MLP)→ 最后一层输出与词嵌入共享的lm_head比对词表,得到下一个词的概率。前向路径的每一步,都能在上文的张量清单里找到对应的那一坨参数。另外 config 里还记着transformers_version: "4.43.1"(模型用的库版本)——实测在本机transformers 5.16.1下仍能正常加载,说明新版本库对旧模型保持向后兼容,这也是"下载后直接 from_pretrained"能成立的原因。
🧩model.safetensors:943MB、290 个张量
用 safetensors 打开这个单文件,能看到 290 个命名的张量(实测统计,按家族归并):
总参数量 494,032,768 = 0.494 B model.embed_tokens.weight x1 136,134,656 # = 151936 × 896 model.layers.<n>.input_layernorm x24 21,504 model.layers.<n>.self_attn.q/k/v/o… x24 (注意力四投影) model.layers.<n>.mlp.gate/up/down_proj x24×3 104,595,456 # 每层各 ~104M model.norm.weight x1 896几个值得注意的规律:
- 名字即路径:
model.layers.5.mlp.gate_proj.weight表示"第 5 层、MLP、gate 投影、权重"——从张量名能反推出网络接线图; - 词嵌入 136M = 151936 × 896,正好是"每个 token 一个 896 维向量";
- 24 层的 MLP 三个投影每层各 ~1 亿参数,加起来是大头——解码时最重的计算就发生在这里;
- 14 个 Q 头共享 2 个 KV 头(GQA,分组查询注意力):多头注意力里只有少量 KV 投影,生成长文本时省下大量 KV 缓存内存;
- 总参数0.494B与"0.5B"的命名吻合,佐证 943MB ≈ 0.494B × 2 字节(bf16);
- 清单里没有独立的 lm_head:
tie_word_embeddings=true表示输出词表投影与输入词嵌入共享同一张embed_tokens 权重,省下 136M 参数——这也是 222 前一张 config 表里那个布尔字段的直接体现。
safetensors相对早年的.bin(pickle)更安全(不带可执行序列化、带校验和),已是主流新格式。
🧩词表三件套:文字怎么变成数字
模型不认识汉字,只认数字 id。这层翻译由三个文件完成:
| 文件 | 角色 |
|---|---|
vocab.json | 词表:子词 token → id(实测 151643 条基础词条,加上特殊 token 补满 vocab_size 151936) |
merges.txt | BPE 合并规则(首几行如Ġ Ġ、i n),决定生词如何拆成子词 |
tokenizer.json | 完整可执行的分词器定义(含特殊 token、模板) |
# vocab.json 形如 "!": 0 "\"": 1 # merges.txt 形如(空格表示词内部位置) Ġ Ġ ĠĠ ĠĠ i n221 那句 20 字中文被切成 35 个 token,就是先经 merges/vocab 拆成子词、再映射成 id 序列;
<|im_end|>这类特殊符号则占 vocab_size 尾部的号段。词表是模型与文字世界之间的字典,随模型一起发布、不能换用别的模型的。
补两个实测细节:tokenizer_config.json里eos_token为<|im_end|>(对话结束符,221 生成到它就停)、pad_token为<|endoftext|>;model_max_length=131072是分词器侧声明的上限,与 config.json 的max_position_embeddings=32768并存——实际按哪个截断,取决于运行时读取的配置。
📦部署视角一句话:目录整体就是"模型"
把三块合起来看——config(怎么搭)+ safetensors(是多少)+ 词表(怎么读文字)——一个开源模型的全部就在这个目录里。这也解释了部署的本质:
- 想"部署这个模型",本质是把这个目录搬到目标机器(或放进 OSS 后由平台拉取),再让目标机的 transformers 用 config 搭网、灌权重、配词表;
- GPU 服务器/DLC/EAS 做的事情,第一步永远是"先把模型文件就位"——与 220 在本机做的下载是同一件事,只是机器换成了云端;
- 内存账也由此可算:0.494B 参数按 bf16(2 字节/参)需约 1GB 内存、按 fp32(4 字节/参)约 2GB——0.5B 本机能跑,换 7B 就约 14GB(bf16),只能上 GPU/分布式。
三种视角就此对齐:文档视角看 config.json 知道"怎么搭",数据视角看 290 个张量知道"是多少",语言视角看词表知道"怎么读文字"。目录理解透了,"部署"只剩最后一道工序——让这台"会说话的文件堆"对外提供接口。下一篇把它从 Notebook 里搬出来,包成一个能被 HTTP 调用的推理服务。
📌一句话记忆
一个开源模型目录 ≈ 1GB = 三样东西:config.json(怎么搭:qwen2、24 层、hidden 896、14/2 头、vocab 151936、bf16)+ model.safetensors(是多少:单文件 290 个张量、共 0.494B 参数、名字即网络接线)+ 词表三件套(文字↔数字字典:vocab.json/merges.txt/tokenizer.json);部署模型的本质就是把这三样"图纸+权重+字典"整体搬到目标机器,让 transformers 照图重装。
OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
【AI】【模型部署】从 Notebook 到接口:把模型包成 HTTP 推理服务