Transformers 原生集成 GLM-4:模型架构解读、GlmConfig 配置与 glm-4-9b-chat 推理实战
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
本文以 Hugging Face Transformers 官方文档 docs/source/en/model_doc/glm.md 为骨架,结合本仓库src/transformers/models/glm/下的真实实现,系统讲解 GLM-4 系列模型在 Transformers 中的架构设计、GlmConfig全部关键参数,以及如何基于 ChatML 格式完成glm-4-9b-chat的加载与生成推理。读完本文,你将掌握 GLM-4 的源码组织结构、逐参数配置方法,以及一套可直接运行的对话推理代码。
GLM-4 是什么:从 ChatGLM 家族到本次集成
glm.md明确说明:GLM-4 由THUDM 与智谱 AI(ZhipuAI)团队在论文ChatGLM: A Family of Large Language Models from GLM-130B to GLM-4 All Tools(发布于 2024-06)中提出,本仓库于 2024-10 完成社区集成。
根据论文摘要,ChatGLM 是一个持续迭代的大语言模型家族,报告重点围绕 GLM-4 系列展开,包含GLM-4、GLM-4-Air、GLM-4-9B等版本,它们在超过 10 万亿 token 的中英文为主语料(外加 24 种语言的小规模语料)上完成预训练,并通过"监督微调 + 人类反馈学习"的多阶段后训练实现高质量对齐。GLM-4 All Tools 进一步对齐了工具调用能力(网页浏览、Python 解释器、文生图模型与用户自定义函数)。文档同时提到该系列已开源包括 ChatGLM-6B(三代)、GLM-4-9B(128K、1M 上下文版本)、GLM-4V-9B、WebGLM、CodeGeeX 等模型。
在本仓库语境下,GLM-4 并非"远程代码(remote code)"式接入,而是拥有完整原生实现:模型代码位于 src/transformers/models/glm/modeling_glm.py,配置类位于 src/transformers/models/glm/configuration_glm.py,同时配套权重转换脚本 src/transformers/models/glm/convert_glm_weights_to_hf.py 与完整测试套件 tests/models/glm/test_modeling_glm.py。
从代码生成方式看,modeling_glm.py由 src/transformers/models/glm/modular_glm.py 自动生成——文件头部有明确的 "Do NOT edit this file manually" 告警。该 modular 文件显示,GLM-4 的实现大量复用 Llama 与 Phi-3 的既有代码骨架:GlmMLP直接继承自Phi3MLP,GlmForCausalLM、GlmForSequenceClassification、GlmForTokenClassification分别继承自 Llama 的对应类,仅注意力模块与 RoPE 旋转位置编码做了定制。这也意味着 GLM-4 的推理体验与行为会与这些成熟架构高度一致。
架构核心:基于 GQA + 部分旋转 RoPE 的稠密解码器
阅读 modeling_glm.py 的源码,GLM-4 是一个仅解码器(decoder-only)的自回归稠密模型,逐层结构如下:
embed_tokens(词嵌入) → 40 × GlmDecoderLayer → GlmRMSNorm →(可选 lm_head)每个GlmDecoderLayer(见 modeling_glm.py#L295-L335)采用Pre-Norm + 残差结构:
input_layernorm归一化 → 多头自注意力;- 残差相加;
post_attention_layernorm归一化 →GlmMLP;- 残差相加。
GQA 分组查询注意力与偏置细节
GlmAttention(modeling_glm.py#L209-L271)实现了标准 GQA(Grouped-Query Attention):查询头数为num_attention_heads,而键/值头数仅为num_key_value_heads(默认 2),num_key_value_groups = num_attention_heads // num_key_value_heads;推理时通过repeat_kv(modeling_glm.py#L125-L134)把 KV 头复制回全量头数再计算注意力。
与常见 Llama 变体不同的是:GLM-4 的q_proj/k_proj/v_proj投影层携带 bias(由config.attention_bias控制,默认True),而o_proj与 MLP 投影均无 bias。eager_attention_forward(modeling_glm.py#L137-L159)在 fp32 上做 softmax 以提升数值稳定性。
SwiGLU 门控 MLP 与分段写法
GlmMLP(modeling_glm.py#L48-L63)采用 SwiGLU 门控结构:单个gate_up_proj把隐层映射到2 * intermediate_size,然后chunk(2, dim=-1)拆成 gate 与 up 两路,乘以 SiLU 激活后由down_proj投影回hidden_size。官方配置中intermediate_size=13696,而GlmConfig的 TP(张量并行)计划为此特别标注了 "我们因chunk操作需要复制/切分输入输出" 的注释(见 configuration_glm.py#L42-L49)。
RMSNorm 与部分旋转 RoPE
GlmRMSNorm(modeling_glm.py#L274-L292)是无偏置的均方根归一化,计算在 fp32 下完成,参数rms_norm_eps默认取1.5625e-7。
GLM-4 RoPE 最独特的点在于partial rotary(部分旋转):compute_default_rope_parameters(modeling_glm.py#L86-L104)先以head_dim * partial_rotary_factor计算实际参与旋转的维度,partial_rotary_factor默认0.5(见GlmConfig.__post_init__中kwargs.setdefault("partial_rotary_factor", 0.5),configuration_glm.py#L76-L80),即每个注意力头的 128 维中仅前 64 维注入位置信息。配套的apply_rotary_pos_emb(modeling_glm.py#L169-L206)使用**交错(interleave)而非拼接(concat)**的旋转排列,并把张量切成 rot/pass 两段,只对前段做旋转后拼接还原。这与 GlmRotaryEmbedding 中 "Interleave them instead of usual shape" 的注释一致。
GlmConfig 参数速查:默认值与设计含义
GlmConfig(model_type 为glm)继承自PreTrainedConfig。以官方发布配置(对应THUDM/glm-4-9b-chat检查点)为准,全部核心字段及默认值如下表:
| 参数 | 默认值 | 含义 |
|---|---|---|
vocab_size | 151552 | 词表大小 |
hidden_size | 4096 | 隐藏层维度 |
intermediate_size | 13696 | MLP 中间维度 |
num_hidden_layers | 40 | 解码器层数 |
num_attention_heads | 32 | 查询头数 |
num_key_value_heads | 2 | KV 头数(GQA 压缩) |
head_dim | 128 | 每头维度 |
hidden_act | "silu" | 激活函数 |
attention_dropout | 0.0 | 注意力 dropout |
max_position_embeddings | 131072 | 最大序列长度(128K) |
initializer_range | 0.02 | 参数初始化范围 |
rms_norm_eps | 1.5625e-7 | RMSNorm 数值稳定项 |
use_cache | True | 是否缓存 KV |
tie_word_embeddings | False | 是否共享词嵌入与 LM 头 |
rope_parameters | None | RoPE 超参字典 |
pad_token_id | 151329 | pad token |
eos_token_id | None→ 由__post_init__设为[151329, 151336, 151338] | EOS 序列 |
bos_token_id | None | BOS(对话首 token 由 ChatML 模板处理) |
attention_bias | True | Q/K/V 投影是否带 bias |
需要特别注意的运行时行为(全部有源码可查):
- 多 EOS:
__post_init__中当eos_token_id未显式指定时,会被替换为三个 token[151329, 151336, 151338](configuration_glm.py#L78-L80),这是 GLM-4 使用 ChatML 多终止符的特性; - partial rotary 默认值兜底:为了向后兼容,
__post_init__会自动补上partial_rotary_factor=0.5; - 推理忽略键:
keys_to_ignore_at_inference = ["past_key_values"],确保past_key_values不会随输出一起被序列化(configuration_glm.py#L41)。
实战:加载 glm-4-9b-chat 并进行对话推理
文档给出了最简洁的推理入口——使用AutoModelForCausalLM+AutoTokenizer加载官方对话模型THUDM/glm-4-9b-chat。GLM-4 对话使用ChatML 消息格式(含system/user/assistant角色与专用终止符),正确做法是借助分词器的apply_chat_template自动组装提示词,而不是手工拼接模板。
下面这段代码完整继承自glm.md,并做了最小必要补充以保证可直接运行(同样适用于单卡、多卡场景):
from transformers import AutoModelForCausalLM, AutoTokenizer model = AutoModelForCausalLM.from_pretrained("THUDM/glm-4-9b-chat", device_map="auto", trust_remote_code=True) tokenizer = AutoTokenizer.from_pretrained("THUDM/glm-4-9b-chat") prompt = "Give me a short introduction to large language model." messages = [{"role": "user", "content": prompt}] # 用 ChatML 模板生成带生成标记的完整文本 text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) model_inputs = tokenizer([text], return_tensors="pt").to(model.device) generated_ids = model.generate(model_inputs.input_ids, max_new_tokens=512, do_sample=True) # 去掉输入前缀,只保留新生成的 token generated_ids = [output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)] response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] print(response)几个可以按需调整的关键点:
max_new_tokens=512限制本次新生成的最大 token 数;do_sample=True开启随机采样,若需要确定性输出可改do_sample=False;device_map="auto"会在多 GPU 环境中自动做层切分;trust_remote_code=True用于兜底加载 Hub 上的辅助配置代码;- 多轮对话只需不断向
messages追加assistant与新的user消息后重新apply_chat_template即可。
若想跳过对话模板、以"纯文本续写"方式测试模型,可参考GlmForCausalLMdocstring 中演示的简单流程(modeling_glm.py#L461-L477):
from transformers import AutoTokenizer, GlmForCausalLM model = GlmForCausalLM.from_pretrained("meta-glm/Glm-2-7b-hf") tokenizer = AutoTokenizer.from_pretrained("meta-glm/Glm-2-7b-hf") prompt = "Hey, are you conscious? Can you talk to me?" inputs = tokenizer(prompt, return_tensors="pt") generate_ids = model.generate(inputs.input_ids, max_length=30) tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]四种面向任务的入口:从因果 LM 到序列标注
glm.md的 autodoc 区块共列出四类可实例化的 API,本仓库中对应类均在 modeling_glm.py 中导出:
| 类 | 用途 | 实现要点(源码依据) |
|---|---|---|
GlmModel | 基础解码器,输出隐状态 | 由embed_tokens+ 40 层GlmDecoderLayer+ 末尾GlmRMSNorm+GlmRotaryEmbedding构成(modeling_glm.py#L357-L428) |
GlmForCausalLM | 对话 / 文本生成,返回词表 logits | 额外带无 bias 的lm_head,支持labels计算交叉熵损失(modeling_glm.py#L431-L503) |
GlmForSequenceClassification | 整句分类(情感等) | GenericForSequenceClassification泛型混入类(modeling_glm.py#L506-L507) |
GlmForTokenClassification | 序列标注(NER 等) | GenericForTokenClassification泛型混入类(modeling_glm.py#L510-L511) |
高效生成相关的实现细节
- logits 裁剪:
GlmForCausalLM.forward接收logits_to_keep(默认 0),仅对最后若干位置计算 LM logits,显著降低长上下文下的显存与算力开销(modeling_glm.py#L490-L491); - 词嵌入独立:
tie_word_embeddings默认False,即lm_head为独立权重;不过_tied_weights_keys仍登记了与embed_tokens的映射关系,方便用户自行开启权重绑定(modeling_glm.py#L433)。
特性支持矩阵与并行方案:FlashAttention、SDPA 与 TP/PP
glm.md页首的徽章标明了 GLM-4 集成支持 FlashAttention、SDPA 与张量并行,这与源码中的能力声明完全对应:
GlmPreTrainedModel声明了_supports_flash_attn = True、_supports_sdpa = True、_supports_flex_attn = True,并支持_can_compile_fullgraph全图编译与梯度检查点(supports_gradient_checkpointing = True,modeling_glm.py#L338-L354);- 注意力实现通过
ALL_ATTENTION_FUNCTIONS.get_interface(config._attn_implementation, eager_attention_forward)统一分发(modeling_glm.py#L254-L256),因此可在from_pretrained时通过attn_implementation="flash_attention_2" / "sdpa" / "eager"切换后端; - 张量并行(TP)计划:
base_model_tp_plan描述 Q/K/V 投影做colwise、o_proj做rowwise、MLP 因chunk语义做colwise_gather_output/rowwise_split_input的切分策略(configuration_glm.py#L42-L49); - 流水线并行(PP)计划:
base_model_pp_plan给出embed_tokens、layers、norm各阶段输入输出张量的交接约定(configuration_glm.py#L50-L54); _no_split_modules = ["GlmDecoderLayer"]让层内不跨设备切分,是 device_map 自动分层的依据。
回归验证:集成测试在做什么
仓库用 tests/models/glm/test_modeling_glm.py 保证实现的正确性,其中有两层测试值得关注:
- 通用小模型测试:
GlmModelTester/GlmModelTest复用仓库统一的CausalLMModelTest体系做大规模随机化前向/梯度测试,并强制attention_dropout = 0.0——测试注释说明这是为了兼容 TP 反向传播测试的 RNG 一致性(test_modeling_glm.py#L41-L57); - 慢速集成测试(@slow):以
THUDM/glm-4-9b(revisionrefs/pr/15)为基准,分别以 fp16 / bf16 / eager / sdpa / flash_attention_2 后端跑generate,并断言 batch 解码文本与期望输出逐字一致(test_modeling_glm.py#L59-L183)。
这说明四种注意力后端在 GLM-4 上被持续验证为输出一致,是你在生产环境切换attn_implementation时的可靠性依据。
小结与延伸阅读
一句话概括本仓库的 GLM-4 集成:以 Llama 解码器骨架为基座,叠加 GLM 特有的 128K 上下文、ChatML 三终止符、GQA 与"前 64 维参与旋转"的部分 RoPE 与带 bias 注意力,并通过 modular 机制统一维护。
如果你想继续深挖,推荐按以下路径阅读当前仓库:
- 配置全文:src/transformers/models/glm/configuration_glm.py
- 模型主实现:src/transformers/models/glm/modeling_glm.py
- 复用了哪些 Llama/Phi-3 骨架:src/transformers/models/glm/modular_glm.py
- 官方 checkpoint 到 HF 格式的权重转换:src/transformers/models/glm/convert_glm_weights_to_hf.py
- 各注意力后端回归测试:tests/models/glm/test_modeling_glm.py
以上内容均以docs/source/en/model_doc/glm.md为主线整理,参数默认值与行为细节均可通过上述源码文件核对,可放心作为二次开发与模型部署的参考资料。
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考