在 Transformers 中使用 Ernie 4.5:百度 ERNIE-4.5-0.3B 架构解析、文本生成与源码级实践指南
导读
本文面向希望在 Hugging Face Transformers 框架中加载、运行并深入理解百度 Ernie 4.5 文本基础模型(非 MoE、约 0.3B 参数)的开发者。你将掌握 Ernie4_5 系列在 transformers 仓库中的接入位置、用 AutoTokenizer + AutoModelForCausalLM 完成对话式文本生成的标准流程、Ernie4_5Config 全部关键超参数的作用,以及该模型基于 Llama 核心、叠加 GQA、全维度 RoPE、RMSNorm 与多种注意力后端与并行方案的源码级架构事实。文中所有实现细节均可追溯到仓库内 configuration_ernie4_5.py 与 modeling_ernie4_5.py 等真实文件。
Ernie 4.5 模型族与本模型定位
Ernie 4.5 模型于 2025 年随百度 Ernie 4.5 模型族发布。该模型族包含多种不同的架构与参数规模;本文档介绍的 ernie4_5 特指面向文本的基础(base)模型、不包含混合专家(MoE)结构、总参数量约 0.3B 的变体,其核心主干采用标准的 Llama 解码器架构。
从仓库源码结构可以确认,ernie4_5 在 transformers 中与同族其他架构分开维护:文本 MoE 变体见 ernie4_5_moe.md,多模态 MoE 变体见 ernie4_5_vl_moe.md。在自动映射层中三者被分别注册为不同的 model_type:ernie4_5 映射到 Ernie4_5Model / Ernie4_5ForCausalLM,而 ernie4_5_moe 与 ernie4_5_vl_moe 则各自指向独立的实现类(见 modeling_auto.py 与 modeling_auto.py),这意味着你可以通过 AutoModelForCausalLM 或 AutoConfig 依据 Hub 上的 model_type 字段自动分派到正确实现。
从模块组织看,models/ernie4_5 目录下共有五个文件:
- configuration_ernie4_5.py —— 定义
Ernie4_5Config; - modeling_ernie4_5.py —— 定义
Ernie4_5Model、Ernie4_5ForCausalLM、Ernie4_5PreTrainedModel等; - modular_ernie4_5.py —— modular 源文件,正式建模代码由它生成(文件头注释明确提示不得直接手工编辑生成文件);
- convert_ernie4_5_tokenizer.py —— 用于把 ERNIE 原生词表转换为 HF fast tokenizer 的脚本。
关键架构事实(源码可验证)
通过阅读 modular 源文件 modular_ernie4_5.py 可以看到,Ernie4_5 的实现大量复用了 Llama 与 Olmo 的既有模块:
Ernie4_5ForCausalLM继承自LlamaForCausalLM(modular 中以class Ernie4_5ForCausalLM(LlamaForCausalLM)定义,等价于Ernie4_5PreTrainedModel + GenerationMixin的实现);Ernie4_5MLP继承LlamaMLP,但按config.use_bias为gate_proj / up_proj / down_proj三个线性层显式传入偏置开关;Ernie4_5Attention继承LlamaAttention,四个投影层同样遵循use_bias,并固定attention_dropout = 0.0;Ernie4_5RotaryEmbedding复用 Olmo 的旋转位置编码方式;- 正式生成的 modeling_ernie4_5.py 头部声明“由 modular 文件自动生成”,若需改动应修改 modular 源文件,这正是 transformers 官方推荐的 modular 建模流程的实际案例。
也就是说:Ernie 4.5(0.3B 文本版)在架构上是一个“Llama 内核 + Ernie 4.5 特性”的组合,便于复用 Llama 生态中已经充分验证的 KV Cache、注意力后端与生成逻辑。
快速上手:对话文本生成
模型权重由百度官方发布在 Hugging Face Hub,标识符为 baidu/ERNIE-4.5-0.3B-PT(该 checkpoint 在配置类的 @auto_docstring 装饰器中也有引用,见 configuration_ernie4_5.py)。文档给出的标准用法如下:
from transformers import AutoModelForCausalLM, AutoTokenizer
model_name = "baidu/ERNIE-4.5-0.3B-PT"
# 加载 tokenizer 与模型(device_map="auto" 会自动放置到可用设备)
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map="auto",
)
# 准备对话消息
prompt = "Hey, are you conscious? Can you talk to me?"
messages = [{"role": "user", "content": prompt}]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
model_inputs = tokenizer([text], add_special_tokens=False, return_tensors="pt").to(model.device)
# 执行文本补全
generated_ids = model.generate(
**model_inputs,
max_new_tokens=32,
)
output_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist()
# 解码生成结果
generate_text = tokenizer.decode(output_ids, skip_special_tokens=True)
这段代码的要点:
- 先
apply_chat_template再做add_special_tokens=False的二次分词。ERNIE 系列走的是 Llama 风格分词器,其对话格式需要先由模板把messages展开为带特殊 token 的纯文本,再编码为输入;若直接对原始 prompt 编码,会丢失User: / Assistant:的角色结构。 - 切片截取:
generated_ids[0][len(model_inputs.input_ids[0]):]只保留新生成的 token,避免把输入 prompt 重复解码进结果。 skip_special_tokens=True会剔除<|end_of_sentence|>等特殊 token(详见下文词表说明)。
集成测试给出的预期输出
仓库中的慢速集成测试 test_modeling_ernie4_5.py 以几乎相同的调用方式对 baidu/ERNIE-4.5-0.3B-PT(revision="refs/pr/3")进行验证,并断言了确定性生成结果。测试还展示了更完整的配置:
tokenizer = AutoTokenizer.from_pretrained("baidu/ERNIE-4.5-0.3B-PT", revision="refs/pr/3")
model = Ernie4_5ForCausalLM.from_pretrained(
"baidu/ERNIE-4.5-0.3B-PT",
device_map="auto",
dtype=torch.bfloat16, # 显式使用 bf16 精度加载
)
- 测试覆盖了
cuda与xpu两种后端(通过Expectations分别存放期望文本),说明该模型在 CUDA 与 Intel/XPU 加速卡上都应能复现一致输出; - 测试对同一 prompt 在
max_new_tokens=128, do_sample=False下验证输出文本,可作为你本地跑通后核对行为是否一致的参照; dtype=torch.bfloat16是官方集成测试选用的默认加载精度。
关于 tokenizer 与对话模板的补充事实
官方 checkpoint 仓库本身已提供可直接使用的 HF tokenizer。若需要从 ERNIE 原生格式重建 HF fast tokenizer,可参考仓库内的 convert_ernie4_5_tokenizer.py,其要点包括:
- 以 Llama 分词器为基础加载,设置
pad_token="<unk>"、cls_token="<|begin_of_sentence|>"、sep_token="<|end_of_sentence|>"、mask_token="<mask:1>",并关闭自动加 BOS(add_bos_token=False); - 定义
model_max_length = 131072,与配置中的max_position_embeddings=131072保持一致; - 额外把
<mask:4>~<mask:7>注册为特殊 token; - 内置一个
DEFAULT_CHAT_TEMPLATE:系统消息直接续写文本,用户消息加User:前缀,助手消息加Assistant:前缀并以<|end_of_sentence|>结尾,生成阶段再追加Assistant:作为生成起始。这也是apply_chat_template背后的具体模板逻辑。
该脚本通过 --repo_name(默认 baidu/ERNIE-4.5-0.3B-Base-PT)、--output_dir、--push_to_hub 三个命令行参数控制源仓库、输出位置与是否直推 Hub。
深入理解 Ernie4_5Config:超参数全景
Ernie4_5Config 继承 PreTrainedConfig,model_type = "ernie4_5"。以下默认值全部来自 configuration_ernie4_5.py,对应“0.3B 规模”的官方结构:
| 参数 | 默认值 | 含义与作用 |
|---|---|---|
vocab_size |
103424 | 词表大小,embed_tokens 与 lm_head 的输出维度 |
hidden_size |
1024 | 隐藏层维度,所有注意力/MLP 投影的输入输出宽度 |
intermediate_size |
3072 | MLP 中间层宽度(约为 hidden_size 的 3 倍) |
num_hidden_layers |
18 | 解码器层数 |
num_attention_heads |
16 | Q 注意力头数 |
num_key_value_heads |
2 | KV 头数,小于 Q 头数即启用分组查询注意力(GQA) |
hidden_act |
"silu" | 激活函数,配合 SiLU 的 SwiGLU 型 MLP |
max_position_embeddings |
131072 | 最长序列 131072(128K),也是 RoPE 缓存上限 |
initializer_range |
0.02 | 参数初始化标准差 |
rms_norm_eps |
1e-5 | RMSNorm 的分母 epsilon |
use_cache |
True | 是否缓存 past_key_values 以加速自回归生成 |
pad_token_id |
0 | <unk>/填充 token |
bos_token_id |
1 | 句首 token |
eos_token_id |
2 | 句尾 token <|end_of_sentence|> |
tie_word_embeddings |
True | 输入嵌入与 lm_head 权重绑定共享 |
head_dim |
128 | 单头维度,独立于 hidden_size 显式给出(hidden 1024 / 16 头恰为 64,故 head_dim=128 说明 Ernie 4.5 的头宽并非由整除推导的默认值,必须显式配置) |
use_bias |
False | 所有线性投影(含 MLP 与注意力 q/k/v/o)是否加偏置,默认不加 |
rope_parameters |
None | RoPE 参数(含 rope_type、rope_theta 等),可由 Hub 配置注入 |
default_theta |
500000.0 | 类属性:未显式给出 theta 时的默认 RoPE 基频 |
keys_to_ignore_at_inference |
["past_key_values"] |
推理时忽略的键 |
配置中的两个类级细节值得注意:
use_bias是唯一被单独写入 docstring 的差异化参数:默认False,即全部投影都不带偏置项——这是区别于许多开源 Llama 变体(部分实现线性层带 bias)的关键行为。若想复现自定义实验可显式打开。rope_parameters作为RopeParameters对象接收rope_type与rope_theta。Ernie4_5RotaryEmbedding.__init__中通过config.rope_parameters["rope_type"]决定采用默认 RoPE 还是其他高级类型(如 dynamic rope),见 modeling_ernie4_5.py;默认基频即上表default_theta = 500000,这一远超常见 10000 的基频与 128K 超长上下文直接相关。
__post_init__ 中还会做两项补齐:若 num_key_value_heads is None 则回退为等于 num_attention_heads(退化为 MHA);若 head_dim 未给出则由 hidden_size // num_attention_heads 推算(见 configuration_ernie4_5.py)。
通过 AutoConfig 读取与修改配置
Ernie4_5Config 已注册进自动映射,可这样直接构造或加载:
from transformers import AutoConfig, Ernie4_5Model, Ernie4_5Config
# 直接以默认参数(0.3B 风格)构造
configuration = Ernie4_5Config()
# 从已发布 checkpoint 读取配置
# configuration = AutoConfig.from_pretrained("baidu/ERNIE-4.5-0.3B-PT")
# 由配置初始化一个随机权重模型(用于自定义实验/继续预训练)
model = Ernie4_5Model(configuration)
# 再次取出配置核对
configuration = model.config
源码级架构拆解:从模块复用走向完整链路
逐层结构与前向流程
按 modeling_ernie4_5.py 定义,模型自底向上为:
Ernie4_5RMSNorm(modeling_ernie4_5.py):T5 风格 RMSNorm 实现——先将隐藏态提升到float32计算方差、rsqrt归一化后再乘可学习weight并回落到原 dtype;被@use_kernel_forward_from_hub("RMSNorm")装饰,允许从 Hub 拉取替换内核。Ernie4_5Attention(modeling_ernie4_5.py):多头注意力。num_key_value_groups = num_attention_heads // num_key_value_heads(默认 16/2=8),缩放因子scaling = head_dim ** -0.5,is_causal = True。q/k/v/o 四投影均由use_bias控制;attention_dropout=0。Ernie4_5MLP(modeling_ernie4_5.py):SwiGLU 结构down_proj(act_fn(gate_proj(x)) * up_proj(x)),激活取自ACT2FN[config.hidden_act](默认 silu)。Ernie4_5DecoderLayer(modeling_ernie4_5.py):标准 pre-norm 残差解码层——input_layernorm→ 自注意力 → 残差相加 →post_attention_layernorm→ MLP → 残差相加。该类继承GradientCheckpointingLayer,天然支持梯度检查点。Ernie4_5Model(modeling_ernie4_5.py):词嵌入(nn.Embedding,以pad_token_id为 padding_idx)→ 循环num_hidden_layers个解码层 → 末端norm,再配合全局rotary_emb;前向内部通过create_causal_mask生成因果掩码,用DynamicCache管理 KV 缓存,返回BaseModelOutputWithPast。Ernie4_5ForCausalLM(modeling_ernie4_5.py):在Ernie4_5Model之上叠加无偏置的lm_head(hidden → vocab),forward支持labels计算因果语言建模损失,logits_to_keep控制只对末尾若干位置投影以节省计算。其_tied_weights_keys声明lm_head.weight与model.embed_tokens.weight绑定共享,与配置tie_word_embeddings=True一致。
Ernie 4.5 特有的 RoPE:全维度 + 全精度
Ernie 4.5 的旋转位置编码在源码中体现了两处与“教科书版”的差异,是理解其长上下文能力的关键:
- 全维度旋转:
apply_rotary_pos_emb中先对 cos/sin 执行cos[..., : cos.shape[-1] // 2].repeat_interleave(2, dim=-1),将“半维度”形式的旋转矩阵展开为与 q/k 对齐的“全维度交织”形式,再与rotate_half配合完成旋转——代码注释明确标注这是 “glm rope style (with full dim)”; - 全精度计算:q、k 与 cos、sin 均被
.float()提升后相乘,最终才回落到original_dtype,避免低精度下旋转数值漂移;RoPE 生成侧(Ernie4_5RotaryEmbedding.forward)同样用maybe_autocast(... enabled=False)强制 float32 计算 cos/sin(见 modeling_ernie4_5.py 与 modeling_ernie4_5.py)。
注意力后端、训练与并行特性(能力矩阵)
Ernie4_5PreTrainedModel 上声明了一组能力标记(见 modeling_ernie4_5.py):
_supports_flash_attn = True、_supports_sdpa = True、_supports_flex_attn = True:FlashAttention、PyTorch SDPA 与 Flex Attention 后端全部可用(对应模型文档页顶部的 FlashAttention / SDPA 徽章);启用方式为model = AutoModelForCausalLM.from_pretrained(..., attn_implementation="flash_attention_2")或"sdpa";supports_gradient_checkpointing = True:支持梯度检查点训练;_can_compile_fullgraph = True:支持 torch.compile;- 注意力函数通过
ALL_ATTENTION_FUNCTIONS.get_interface(...)按config._attn_implementation分发,默认的 eager 实现见eager_attention_forward(modeling_ernie4_5.py),其中 softmax 强制 float32 后回落——与上文全精度偏好一脉相承。
在并行维度,Ernie 4.5 是标准的“一条龙式”模型文件示例:
- 张量并行(TP)在配置类内置
base_model_tp_plan(见 configuration_ernie4_5.py):q/k/v 与 MLP 的gate/up投影按colwise切分,o 与down投影按rowwise归约;Ernie4_5ForCausalLM额外定义_tp_plan = {"lm_head": "colwise_gather_output"}; - 流水线并行(PP)由
base_model_pp_plan与_pp_plan描述各阶段输入输出; - FSDP 通过
_fsdp_plan = {"lm_head": "keep_full_weight"}指定权重保持策略。
测试覆盖与工程验证
单测侧,Ernie4_5ModelTester / Ernie4_5ModelTest 复用了通用的因果语言模型测试基类 CausalLMModelTester / CausalLMModelTest(见 test_modeling_ernie4_5.py),可自动获得包括前向、GQA 缓存、torch.compile、CPU offload 等在内的大批量通用用例;同时测试类显式把 model_split_percents 调整为 [0.5, 0.7, 0.8](原注释说明是为规避因果掩码 buffer 的边界情况,将默认 0.9 下调为 0.8)。若你在自己的机器上验证该模型,可直接运行:
python -m pytest tests/models/ernie4_5/test_modeling_ernie4_5.py -k "not slow"
常见问题与实操提示
-
Q:为什么示例中要对同一个 prompt 先
apply_chat_template再分词? ERNIE 的生成模板需要完整展开system / user / assistant三种角色标记。用tokenize=False得到模板文本后,再以add_special_tokens=False编码,可避免重复插入 BOS;解码侧skip_special_tokens=True负责清理<|end_of_sentence|>等 token。 -
Q:Ernie 4.5 支持多长的上下文? 配置
max_position_embeddings=131072(128K token),配合rope_theta=500000的大基频。注意 RoPE 默认外推能力有限,若需超过训练长度请结合rope_type(dynamic rope 等)策略使用;模型卡文档页顶部也仅标注了 FlashAttention、SDPA 与张量并行支持,未承诺任何上下文扩展性能。 -
Q:为什么
num_key_value_heads=2而num_attention_heads=16? 这是标准的 GQA 设计:8 组 Q 共享 1 个 KV 头,在保证效果接近 MHA 的同时显著减少 KV 缓存显存占用,对 128K 超长生成尤为重要。 -
Q:能否本地加载而不依赖网络? 可以。首次执行
from_pretrained会把权重缓存到本地,之后可离线使用;也可在受控环境中先预下载模型与 tokenizer 再离线加载。 -
Q:训练/微调该模型应如何设置?
Ernie4_5ForCausalLM.forward支持传入labels直接返回语言建模损失(modeling_ernie4_5.py),可配合 transformersTrainer或TrainingArguments使用;训练侧建议开启梯度检查点,并可自由切换 SDPA / FlashAttention 后端。
小结
本文以百度 Ernie 4.5 0.3B 文本基础模型为主线,从官方使用代码出发,先后覆盖了:模型族内部 ernie4_5 与 MoE/多模态变体的定位差异;AutoModelForCausalLM + apply_chat_template 的对话生成标准范式及其集成测试佐证;Ernie4_5Config 全部关键超参数表与两处容易被忽略的设计(use_bias、head_dim/rope_theta);以及从 modular 建模、Llama 模块复用、GQA + 全维度全精度 RoPE、三后端注意力到 TP/PP/FSDP 并行方案的整体源码事实。需要进一步扩展细节时,可直接研读同族的 Ernie 4.5 Moe 与 Ernie 4.5 VL MoE,或对照其底层 Llama 主干文档 Llama。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00