首页
/ Transformers 中的 Byte Latent Transformer(BLT)完全指南:熵驱动动态分块的字节级大模型架构

Transformers 中的 Byte Latent Transformer(BLT)完全指南:熵驱动动态分块的字节级大模型架构

2026-09-06 18:51:58作者:虞亚竹Luna

本指南以 BLT 模型文档 为核心骨架,深入剖析 BLT(Byte Latent Transformer)在 transformers 仓库中的落地实现:从双模型架构、熵驱动的动态 Patching、字节级 Tokenizer,到完整可运行的加载推理代码与全部配置参数。读者读完本文后,将能够用 AutoModelForCausalLM 一键加载与生成 BLT 检查点,并具备依据源码调优分块策略、理解四段式前向链路(Local Encoder → Global Transformer → Local Decoder + Patcher)的实战能力。

什么是 BLT:放弃固定词表的字节级大模型

BLT(Byte Latent Transformer)由论文 Byte Latent Transformer: Patches Scale Better Than Tokens 提出,是首个在规模化训练中达到并超过词表分词(tokenization-based)LLM 性能的字节级语言模型。与主流 LLM 依赖学习得到的子词词表(如 BPE、SentencePiece)不同,BLT 直接以 UTF-8 原始字节作为输入,并引入**可变长度、动态分块的 Patch(块)**作为核心计算单元。

论文摘要揭示了其三个关键主张:

  • 动态分块即动态算力分配:Patch 的切分依据“下一字节的熵(entropy)”进行,数据越复杂(高熵)区域分得越短的 Patch、获得更多计算与模型容量;数据越可预测(低熵)区域分得越长的 Patch,从而提升效率。这使得在推理成本固定的前提下,同时增大 Patch 与模型规模可以获得比词表模型更优的扩展性(scaling)。
  • 字节级可扩展性:论文公布了首个 FLOP 受控的字节级模型扩展研究,规模达到 8B 参数、4T 训练字节,证明了无需固定词表即可规模化训练原始字节模型。
  • 训练与推理效率的双重提升:在数据可预测时动态选取长 Patch 带来效率收益,同时在推理与长尾泛化上表现出定性提升。

transformers 中,BLT 于 2025-09-19 合入(论文 2024-12-13 发布),由社区贡献者 itazap 移植,官方参考实现来自 Meta 的 facebookresearch/blt。仓库内的实现代码位于 src/transformers/models/blt/,测试位于 tests/models/blt/test_modeling_blt.py,模型文档即本文对应的 docs/source/en/model_doc/blt.md

核心架构:双模型与四组件

BLT 不是单个 Transformer,而是由两个独立训练的模型构成的双模型体系:

1. Patcher(熵模型) 一个规模更小的 Transformer,职责是逐个字节预测下一字节的分布并计算熵,据此确定 Patch 边界、切分输入序列。在 BltModel 实现 中,当 patch_in_forward=True 时该模型会在前向阶段被创建并立即冻结(置为 eval() 且全部参数 requires_grad=False,见 BltModel.__init__),使其只作为熵估计器参与推理,不参与主模型反向传播。

2. Main Transformer Model(主模型) 真正处理 Patch 表示的主力模型,内部进一步拆分为三个子模块:

  • Local Encoder(局部编码器):在字节级别处理序列,与 Patch 嵌入做交叉注意力(cross-attention),把每个字节的隐状态归约到所属 Patch,形成 Patch 级表示。从源码看(BltLocalEncoder),字节嵌入经由 hash 增强后的向量通过自注意力层,再由 patch_reducescatter_reduce(..., reduce="amax") 将同属一个 Patch 的字节状态聚合为单一 Patch 嵌入。
  • Global Transformer(全局 Transformer):在 Patch 级别运行,对 Patch 序列执行全量注意力,负责跨 Patch 的语义建模。其输入尺寸约为局部编解码器的数倍(默认配置见下文)。
  • Local Decoder(局部解码器):通过交叉注意力把全局 Patch 表示“解压”回原始字节序列并逐字节输出。它还有一个残余连接分支(cross_attn_decoder),在实现中保持与原始 BLT 一致的交叉注意力风格。

主模型对字节输入还会应用基于哈希的嵌入增强(hash-based embedding)compute_hash_embeddings 使用多项式滚动哈希(rolling_polynomial_hash,素数基 prime = 1000000007)对字节做滑动窗口分组的 n-gram 哈希,再将这些哈希 ID 映射为额外的嵌入加到基础字节嵌入上,帮助模型高效识别与编码输入中重复出现的字节级模式。

字节级 Tokenizer:没有词表的分词器

BLT 的 Tokenizer 与传统分词器有本质区别:它不做学习式词表切分,仅把文本转为 UTF-8 字节并把每个字节映射成一个 token ID,因此不存在 vocabulary。这带来了两条直接推论:

  • 任意文本(含未见过的语言、表情、代码)都能被无损表示,不存在 OOV(词表外词)问题;
  • 模型词表大小被固定为 260 = 256 种字节取值 + 少量控制符,这在各子配置的 vocab_size: int = 260 中清晰可见。

动态 Patching 如何工作

熵驱动的动态分块是 BLT 的灵魂。核心逻辑集中在 BltPatcher.patch_lengths_from_entropiesmodeling_blt.py),其流程为:

  1. Patcher 前向输出每个字节位置的 logits,通过 torch.distributions.Categorical(...).entropy() 得到逐字节预测熵;
  2. 忽略 BOS 之后,逐字节判断 entropy > threshold,把超过阈值的位置标记为“新 Patch 起点”(意味着该处数据难以预测、需要更精细的处理);
  3. 起点之间即为一个 Patch,从而把可预测的长串合并为长 Patch、把高熵区切碎为短 Patch;
  4. 若配置了 max_patch_length,则由 process_patch_lengths 把超长 Patch 进一步切分并将结果按 batch 对齐。

测试 tests/models/blt/test_modeling_blt.py 给出了向量化验证:输入 patch 长度 [[0,5,9,0],[4,0,13,1]]max_patch_length=4 时,输出被拆分为 [[4,1,4,4,1,0],[4,4,4,4,1,1]],可见长 Patch 被拆成多个 ≤4 的段并做右对齐 padding。

BltConfig 中控制分块行为的关键字段(来自 configuration_blt.py):

配置参数 默认值 作用
patch_in_forward True 是否在前向阶段执行 patching;为 False 时 Patcher 不参与,如测试中为隔离验证而关闭
patch_size 4 分块使用的基础 Patch 尺寸
patching_mode "entropy" 分块模式,当前默认熵驱动;若非熵模式则退化为全 1 长度(逐字节一个 Patch)
patching_threshold 1.335442066192627 熵阈值,超过该值的字节位置成为新 Patch 起点,决定“短补丁”切换的敏感度
patching_batch_size 1 Patching 过程的批大小
max_patch_length None 单个 Patch 允许的最大长度,超长时自动切分

主配置还会下发给四个子模块配置:patcher_config(默认 BltPatcherConfig:hidden=768、14 层、12 头、中间层 2048);encoder_config(默认 BltLocalEncoderConfig:hidden=1024、1 层、16 头,cross_attn_all_layers=False);global_config(默认 BltGlobalTransformerConfig:hidden=2048、25 层、16 头、中间层 5632);decoder_config(默认 BltLocalDecoderConfig:hidden=1024、9 层、16 头,cross_attn_all_layers=True)。各子配置也可直接以字典传入 BltConfig,框架会自动完成实例化并继承主配置的 initializer_range

cross_attn_k(默认 2)与 encoder_hash_byte_group_size(默认 [3,4,5,6,7,8])值得专门说明:前者决定局部层与全局层之间交叉注意力的扩展系数,直接影响 hidden_size * cross_attn_k 的投影通道数;后者是局部编码器 hash 分组的字节组大小列表,默认覆盖 3 到 8 字节的 n-gram。BltConfig.__post_init__ 会依据二者动态判定是否需要在全局 Transformer 前插入 token 嵌入投影(7B 规模存在维度不匹配时才需要)。

快速开始:加载与推理

官方推荐使用 Auto API 加载社区发布的开源检查点(以 itazap/blt-1b-hf 为例):

from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("itazap/blt-1b-hf")
model = AutoModelForCausalLM.from_pretrained(
    "itazap/blt-1b-hf",
    device_map="auto",
)

prompt = "my name is"
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

NUM_TOKENS_TO_GENERATE = 200
generated_ids = model.generate(
    **inputs, max_new_tokens=NUM_TOKENS_TO_GENERATE, do_sample=False, use_cache=False
)

print(tokenizer.decode(generated_ids[0]))

几点实战提醒,均有源码或测试佐证:

  • 必须使用真实字节 ID 输入:由于 BLT 前向依赖 hash 嵌入,inputs_embedsinput_ids 无法产生等价结果。相关测试(如 test_generate_from_inputs_embedstest_inputs_embeds_matches_input_ids)在 tests/models/blt/test_modeling_blt.py 中被显式跳过并注明原因,因此请始终走 input_ids 路径。
  • use_cache=False 是官方测试的常规设定:虽然模型实现了基于 EncoderDecoderCache 的自回归缓存(BLT 并非编码器-解码器模型,却特意复用编码器-解码器缓存结构来承载“字节缓存 + Patch 缓存”两部分 KV,源码注释有明确说明),但集成测试(test_modeltest_model_bf16test_model_eager)均以 use_cache=False 运行并校验了精确文本输出。用户可在显存允许时按需开启 use_cache=True
  • 注意力实现建议:官方测试在 fp32/fp16/bf16 下同时验证了 sdpaeager 两种路径(test_model_logitstest_model_eager 使用同一提示词与 200 token 生成并断言输出)。加载时可显式传 attn_implementation="sdpa""eager"。模型的文档徽章也标注了 FlashAttention 与 SDPA 支持。

生成示例与输出验证

BltForCausalLM 的 docstring 中给出带采样配置的完整示例:

from transformers import AutoTokenizer, BltForCausalLM

model = BltForCausalLM.from_pretrained("itazap/blt-1b-hf")
tokenizer = AutoTokenizer.from_pretrained("itazap/blt-1b-hf")

prompt = "If I had to write a haiku, it would be:"
inputs = tokenizer(prompt, return_tensors="pt")

# Generate
generate_ids = model.generate(inputs.input_ids, max_length=40, do_sample=True, temperature=0.6)
result = tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
print(result)
# 示例输出:
# If I had to write a haiku, it would be: "Snowflakes gently fall" - simple, yet peaceful.
# I love the idea of snowflakes gently falling, each one

解码时推荐显式传 skip_special_tokens=Trueclean_up_tokenization_spaces=False,与测试断言保持一致。

BltModel 前向链路:从字节到下一个字节

结合 BltModel.forward 可以梳理出 BLT 一次前向的完整数据流,它同时包含“字节序列”与“Patch 序列”两条贯穿始终的轨道:

  1. 字节嵌入:对 input_ids 计算哈希增强嵌入 encoder_embeds
  2. 熵分块:当 patch_in_forward=Truepatching_mode="entropy" 时,冻结的 Patcher 依据配置的 patch_size / threshold / max_patch_length 输出 patch_lengths;由 _patch_ids_from_lengths 生成逐字节归属的 patch ID;
  3. 字节因果自注意力 + Patch 归约BltLocalEncoder 在字节序列上做因果自注意力,并将字节状态按 patch ID 归约、投影为 Patch 表示(patch_reduce 采用 amax 归约 + 跨层交叉注意力叠加,见其内部对 patch_embedding_projectionBltCrossAttention 的组合);
  4. Patch 级全量注意力BltGlobalTransformer 对 Patch 序列执行因果注意力,得到全局 Patch 表示;
  5. Patch 解压回字节BltLocalDecoder 以全局 Patch 表示为 key/value,通过交叉注意力(配合 _prepare_patch_cross_attention_mask 生成的 patch↔sequence 双向掩码)把信息“下发”到字节位置,输出逐字节 logits,BltForCausalLM 再用 lm_head 映射为 260 维概率分布。模型还暴露了输入输出嵌入的操作接口(get_input_embeddings/set_input_embeddings)。

掩码构造与 Mllama 同源(_prepare_patch_cross_attention_mask 注释明确说明“following mllama's robust approach”),支持 patches_as_queries 角色互换与 cross_attn_k 倍数重复,最终把布尔可注意矩阵反转为 -inf 掩码供注意力模块使用。

配置详解:BltConfig 与四个子配置

BltConfigmodel_type = "blt")通过 sub_configs 机制把四个独立子配置嵌套挂载,configuration_blt.py 中注册关系为:patcher_config → BltPatcherConfigencoder_config → BltLocalEncoderConfigdecoder_config → BltLocalDecoderConfigglobal_config → BltGlobalTransformerConfig。任意子配置为 None 或字典时,都会被自动补齐为默认配置对象(继承主配置的 initializer_range)。

直接构造纯随机模型以验证配置可行:

from transformers import BltModel, BltConfig

# Initializing a Blt configuration
configuration = BltConfig()

# Initializing a model from the configuration
model = BltModel(configuration)

# Accessing the model configuration
configuration = model.config

tests/models/blt/test_modeling_blt.py 的微型测试配置可见子配置组合的约束关系:测试中 hidden_size=16、全局模型 hidden_size=32(约为局部层的两倍)、decoder_config["hidden_size_global"] 必须与全局 Transformer 输出尺寸一致、cross_attn_k=2 且 hash 分组收敛为 [2,3]、hash 词表 64。若要自定义模型规模,需要保持“decoder 的 hidden_size_global = global 输出维度”这一对齐关系。

主配置完整字段速查

字段 默认值 说明
vocab_size 260 256 字节 + 控制符的字节词表大小
max_position_embeddings 4096 最大位置编码长度
use_cache True 是否使用 KV 缓存
cross_attn_k 2 局部层↔全局层交叉注意力扩展系数
encoder_hash_byte_group_vocab 500002 编码器 hash 字节组的哈希词表大小
encoder_hash_byte_group_nb_functions 1 hash 函数数量(多于素数表 12 项时循环取用)
rope_parameters / rope_theta 默认 RoPE,θ=500000 各子配置均带 default_theta = 500000.0,与 Llama 族一致的旋转位置编码
initializer_range 0.02 初始化尺度基准

权重初始化细节

BLT 的初始化策略是原版 ByteLatentTransformer 的精确保留(见 BltPreTrainedModel._init_weights 注释):Embedding 权重按 1/sqrt(hidden_size) 的标准差做截断正态初始化;注意力 q/k/v 投影与 MLP 输入侧投影按 dim**-0.5 截断正态(边界 ±3σ);FFN 输出投影使用 out_std = down_proj.weight.shape[1]**-0.5;RMSNorm 权重置 1、偏置置 0。

底层实现组件速览

BLT 的模块命名与 Llama 家族高度同源但存在明确差异,理解它们有助于排查与二次开发:

  • BltRMSNorm:RMSNorm,前向中强制以 fp32 计算方差(提升数值稳定性);
  • BltMLP:SiLU 门控 MLP(gate/up/down 三投影),与 LLaMA 风格一致;
  • BltRotaryEmbedding:RoPE 实现不同于 Llama——torch.repeat_interleave(freqs, 2, dim=-1) 采用交织(interleave)而非拼接(cat)方式展开 cos/sin,rotate_half 也相应改为奇偶抽取旋转(注释明确标注 “diff from Llama”)。因此在自行转换权重时不可与 Llama 混用;
  • BltTransformerLayer:继承了 GradientCheckpointingLayer 的通用 Transformer 层,由自注意力、RMSNorm、MLP 与残余连接构成,同时被四个子模块复用;
  • BltSelfAttention / BltCrossAttention:都经 ALL_ATTENTION_FUNCTIONS.get_interface 动态分派 eager/SDPA 等注意力实现;BltCrossAttention 对 q/k 额外套了 RMSNorm(q_norm/k_norm),其输出自带残余连接(attn_output + hidden_states),且非因果(is_causal=False);
  • 多 KV 头:各子配置默认 num_key_value_heads=None 即退化为与 num_attention_heads 相同(MHA),前向经 repeat_kv 广播。

模块级能力方面,BltPreTrainedModel 支持梯度检查点与 SDPA(_supports_sdpa=True),FLASH/FLEX 注意力标记为不支持(_supports_flash_attn=False);模型拆分(_no_split_modules 含 Transformer 层与交叉注意力层)支持多 GPU/offload 加载,device_map="auto" 因此可用。

高级注意点与限制(源码实测结论)

  • 量化缓存不可用:BLT 内部使用 EncoderDecoderCache(自注意力缓存 + 交叉注意力缓存),test_generate_with_quant_cache 因此被跳过,即无法与量化 KV 缓存(quant cache)组合使用。
  • assisted decoding 与静态缓存边界:受限于 EncoderDecoderCache 交叉注意力路径的 KV 长度与因果掩码在回滚时的一致性,assisted/投机解码相关测试被标记为跳过;官方测试同样跳过 sdpa_can_dispatch_on_flash(BLT 恒有 attention_mask 输入),但 cache_implementation="static" 在 bf16 下通过集成验证(test_model_bf16_static_cache)。
  • 输出记录能力:模型类声明了 _can_record_outputs,可分别记录局部编码器与全局 Transformer 的注意力权重与各层隐状态(hidden_statesattentions),便于调试与可视化。
  • 训练自定义模型:若从零训练 BLT,需要先有收敛的 Patcher(熵模型),再冻结其训练主模型,因为推理时分块完全依赖 Patcher 的熵质量;BltForCausalLM 的损失经 loss_function 基于逐字节 logits 与 labels 计算(-100 处被掩码忽略),训练与一般因果 LM 一致。

综上,BLT 在 transformers 中的接入是完整的“研究到工程”闭环:模型文档(blt.md)、配置(configuration_blt.py)、建模(modeling_blt.py)、权重转换(convert_blt_weights_to_hf.py)与慢速/集成测试齐备。若要进一步探索熵模型与主模型训练的独立权重(两模型独立训练),可研读其 modular 源文件 modular_blt.py;实际推理则推荐直接从 Hub 拉取含完整两套权重的社区检查点,一条 from_pretrained 即可体验字节级动态分块模型在长尾与推理效率上的差异。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388