BARTpho 越南语预训练序列到序列模型:架构原理、分词器设计与 Transformers 实战指南
BARTpho 是首个面向越南语的大规模单语预训练序列到序列(sequence-to-sequence)模型,基于 BART 的 large 架构与去噪预训练方案构建,特别适合文本摘要、掩码填充等生成式 NLP 任务。本文以本仓库的 BARTpho 官方文档为主体,结合 tokenization_bartpho.py 源码与 test_tokenization_bartpho.py 测试用例,带你完整掌握 BARTpho 的加载、推理、掩码填充与双词汇表分词器原理。
模型概述:BARTpho_word 与 BARTpho_syllable
BARTpho 由 Nguyen Luong Tran、Duong Minh Le 与 Dat Quoc Nguyen 在论文 BARTpho: Pre-trained Sequence-to-Sequence Models for Vietnam(2021)中提出,模型贡献者与原始代码作者为 dqnguyen。BARTpho 提供两个公开版本:
- BARTpho_word:基于词(word)粒度切分的版本;
- BARTpho_syllable:基于音节(syllable)粒度切分的版本。
两者都是越南语上首个公开的大规模单语预训练序列到序列模型,沿用 BART 的 large 架构与去噪预训练方案,因此在生成类任务上具有天然优势。原论文实验表明,在越南语文本摘要下游任务上,无论自动评估还是人工评估,BARTpho 均优于强基线 mBART,并刷新了当时的最先进水平(SOTA)。需要说明的是,上述对比结论源自论文原文表述,仓库内并不包含相应基准测试代码。
在本仓库中,BARTpho 在 models/bartpho/ 目录下以 tokenizer 模块形式实现(models/bartpho/init.py 仅导出 BartphoTokenizer),并在 models/auto/tokenization_auto.py 中注册了 ("bartpho", "BartphoTokenizer") 映射,因此可通过 AutoTokenizer 直接加载。
快速上手:加载模型与提取特征
BARTpho 可以直接通过 AutoModel / AutoTokenizer 加载官方预训练权重(如 vinai/bartpho-syllable),与 Transformers 生态无缝集成。以下示例完整继承自官方文档,并补充了必要的导入说明:
import torch
from transformers import AutoModel, AutoTokenizer
# 加载模型与分词器(首次运行会自动从 Hub 下载权重)
bartpho = AutoModel.from_pretrained("vinai/bartpho-syllable")
tokenizer = AutoTokenizer.from_pretrained("vinai/bartpho-syllable")
# 一段越南语示例文本
line = "Chúng tôi là những nghiên cứu viên."
# 分词并构造模型输入(返回 PyTorch 张量)
input_ids = tokenizer(line, return_tensors="pt")
with torch.no_grad():
# 注意:模型的输出现在是元组(tuple)形式
features = bartpho(**input_ids)
若你使用 TensorFlow 2.0+,可通过 TFAutoModel 获得等价体验:
from transformers import TFAutoModel
bartpho = TFAutoModel.from_pretrained("vinai/bartpho-syllable")
input_ids = tokenizer(line, return_tensors="tf")
features = bartpho(**input_ids)
从源码看,BartphoTokenizer 的 model_input_names 为 ["input_ids", "attention_mask"](见 tokenization_bartpho.py),即分词器只产出 input_ids 与 attention_mask 两类输入,不产出 token type ids——因为 BARTpho 不使用 segment 区分(对应源码中 create_token_type_ids_from_sequences 恒返回全零列表)。
使用技巧:以 mBART 类替代 BART 类完成掩码填充
BARTpho 沿用了 mBART 的实践:使用 BART 的 large 架构,并在编码器与解码器之上各额外叠加一层 Layer Normalization。因此,直接使用 BART 专属类会与权重结构不匹配,应遵循官方文档的建议——将 BART 专属类替换为对应的 mBART 专属类。例如用 MBartForConditionalGeneration 替代 BartForConditionalGeneration。
下面是官方文档给出的掩码填充(masked language modeling)完整示例,演示如何预测 <mask> 位置的候选词:
from transformers import MBartForConditionalGeneration
bartpho = MBartForConditionalGeneration.from_pretrained("vinai/bartpho-syllable")
tokenizer = AutoTokenizer.from_pretrained("vinai/bartpho-syllable")
TXT = "Chúng tôi là <mask> nghiên cứu viên."
input_ids = tokenizer([TXT], return_tensors="pt")["input_ids"]
# 前向传播得到 logits
logits = bartpho(input_ids).logits
# 定位 <mask> 对应的索引
masked_index = (input_ids[0] == tokenizer.mask_token_id).nonzero().item()
# 取出该位置的分布并取 top-5 候选
probs = logits[0, masked_index].softmax(dim=0)
values, predictions = probs.topk(5)
print(tokenizer.decode(predictions).split())
需要说明的是:MBartForConditionalGeneration 类定义于本仓库的 models/mbart/ 模块中,它承载了 BARTpho 实际使用的模型权重结构。该提示的核心逻辑是——BARTpho 的"大架构 + 额外层归一化"与 mBART 一脉相承,因此凡是需要实例化模型的地方,都应优先使用 mBART 系类(如 MBartForConditionalGeneration、MBartModel)。
文本摘要实战示例
官方英文文档还提供了一个基于 AutoTokenizer + BartForConditionalGeneration 的越南语文本摘要示例(模型使用 vinai/bartpho-word)。这里结合文档说明,完整给出可复现的摘要流程:
from transformers import AutoTokenizer, BartForConditionalGeneration
tokenizer = AutoTokenizer.from_pretrained("vinai/bartpho-word")
model = BartForConditionalGeneration.from_pretrained("vinai/bartpho-word", device_map="auto")
text = """
Quang tổng hợp hay gọi tắt là quang hợp là quá trình thu nhận và chuyển hóa năng lượng ánh sáng Mặt trời của thực vật,
tảo và một số vi khuẩn để tạo ra hợp chất hữu cơ phục vụ bản thân cũng như làm nguồn thức ăn cho hầu hết các sinh vật
trên Trái Đất. Quang hợp trong thực vật thường liên quan đến chất tố diệp lục màu xanh lá cây và tạo ra oxy như một sản phẩm phụ
"""
inputs = tokenizer(text, return_tensors="pt").to(model.device)
# beam search 解码生成摘要
outputs = model.generate(inputs["input_ids"], num_beams=2, min_length=0, max_length=20)
tokenizer.batch_decode(outputs, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
其中 device_map="auto" 用于自动分配设备(多卡/CPU 场景),num_beams=2 表示束搜索宽度,max_length=20 限制摘要长度。从源码结构看,生成所需的 generate 方法继承自 PreTrainedModel 的通用生成接口,其参数体系(beam search、长度惩罚等)与仓库其他条件生成模型完全一致,详见 generation/ 目录。
分词器原理:双词汇表设计
BARTpho 的分词是理解其设计的关键。官方文档明确指出:该实现仅通过 monolingual_vocab_file 处理分词,其结构如下(见 tokenization_bartpho.py):
VOCAB_FILES_NAMES = {"vocab_file": "sentencepiece.bpe.model", "monolingual_vocab_file": "dict.txt"}
即 BARTpho 需要两个词汇文件:
| 文件 | 默认文件名 | 作用 |
|---|---|---|
vocab_file |
sentencepiece.bpe.model |
预训练 SentencePiece 模型,来自多语言 XLM-RoBERTa(mBART 同样使用),包含约 25 万(250K)种 token 类型,负责子词切分 |
monolingual_vocab_file |
dict.txt |
单语词汇表,从上述 250K 多语言词汇中抽取的越南语专属 token 子集,负责 token 到 ID 的映射 |
这种双词汇表设计带来一个重要能力:如果其他语言也希望复用该 SentencePiece 子词切分机制,只需将 monolingual_vocab_file 替换为针对目标语言定制的单语词汇表,即可继续复用 BartphoTokenizer。文档中明确记载了这一扩展用法,这也是本分词器最具移植性的特性。
BartphoTokenizer 参数详解
BartphoTokenizer 继承自 XLMRobertaTokenizer 的适配实现,底层基于 SentencePiece,同时继承自 tokenization_utils_sentencepiece.py 中的 SentencePieceBackend(其本身继承 PreTrainedTokenizer)。其构造参数如下(依据 tokenization_bartpho.py 与类 docstring):
| 参数 | 默认值 | 说明 |
|---|---|---|
vocab_file |
必填 | 预训练 SentencePiece 模型路径,即多语言 XLM-RoBERTa / mBART 使用的 250K 词汇表 |
monolingual_vocab_file |
必填 | 单语词汇表路径,为越南语从 250K 词汇中抽取出的专用子集 |
bos_token |
"<s>" |
序列开始 token;构建带特殊 token 的序列时实际使用 cls_token |
eos_token |
"</s>" |
序列结束 token;构建带特殊 token 的序列时实际使用 sep_token |
sep_token |
"</s>" |
分隔 token,用于拼接多段序列(如问答的 question/context) |
cls_token |
"<s>" |
分类 token,用于序列分类场景,是带特殊 token 序列的首个 token |
unk_token |
"<unk>" |
未知 token,词汇表外的 token 会被映射为该 token 的 ID |
pad_token |
"<pad>" |
填充 token,用于 batch 内不同长度序列对齐 |
mask_token |
"<mask>" |
掩码 token,用于掩码语言建模;构造时会被包装为 AddedToken(mask_token, lstrip=True, rstrip=False),即掩码前保留空格、按普通词处理 |
sp_model_kwargs |
None |
透传给 SentencePieceProcessor.__init__() 的关键字参数 |
其中 sp_model_kwargs 支持三类核心用法(来自类 docstring):
enable_sampling:启用子词正则化(subword regularization);nbest_size:unigram 采样参数(对 BPE-Dropout 无效)。nbest_size = {0, 1}不采样;> 1从 nbest 结果中采样;< 0视为无限,使用 forward-filtering-and-backward-sampling 从全假设格(lattice)中采样;alpha:unigram 采样的平滑参数,对 BPE-dropout 而言是合并操作的丢弃概率。
源码级实现:fairseq 词汇表与特殊 token 对齐
阅读 tokenization_bartpho.py 的初始化逻辑,可以发现其内部维护了一套独立的 fairseq 风格词汇表,与 SentencePiece 原生词表并存:
- 构建 fairseq 词表(第 127-140 行):先将
bos/pad/eos/unk/sep/cls六个特殊 token 依次编号(0 起始),再逐行读取monolingual_vocab_file(每行取第一个字段作为 token)追加编号,最后补上mask_token,生成fairseq_tokens_to_ids与其反向映射fairseq_ids_to_tokens。 - 重写 ID 转换(第 253-271 行):
_convert_token_to_id优先查 fairseq 词表,未命中返回unk_token_id;_convert_id_to_token直接查 fairseq 反向映射;vocab_size与get_vocab均以 fairseq 词表为准。 - 对齐 added tokens(第 273-289 行,
_align_added_tokens_with_fairseq_vocab):父类SentencePieceBackend会用 SentencePiece 的 ID 填充_added_tokens_*,该方法将其重新映射到缩减后的 fairseq 词典 ID 上,确保所有 token 在任何转换路径下 ID 一致,避免"两个词汇表"导致的不一致问题。 - 特殊 token 序列格式(第 160-184 行):单序列格式为
<s> X </s>,序列对格式为<s> A </s></s> B </s>;get_special_tokens_mask与create_token_type_ids_from_sequences与之严格对应。 - 词汇保存(第 291-320 行):
save_vocabulary会同时输出sentencepiece.bpe.model与dict.txt两个文件;当 SentencePiece 模型无法以文件形式访问时,会通过sp_model.serialized_model_proto()序列化写出。
此外,该类带有 @requires(backends=("sentencepiece",)) 装饰器(第 31 行),SentencePieceBackend.__init__ 中也会执行 requires_backends(self, "sentencepiece"),因此使用前需确保环境已安装 sentencepiece 依赖。
测试验证:分词行为的一致性保障
仓库在 test_tokenization_bartpho.py 中提供了针对该分词器的完整测试,可作为你验证环境的参考:
from_pretrained_id = "vinai/bartpho-syllable":以官方 syllable 权重作为from_pretrained的集成验证目标;test_rust_tokenizer = False:BARTpho 仅有慢速(slow)分词器,无 Rust 快速版本;test_sentencepiece = True:启用 SentencePiece 相关通用测试;test_full_tokenizer:用测试夹具(fixture)验证 "This is a là test" 被切分为▁This ▁is ▁a ▁l à ▁t est,且 ID 序列与预期完全一致(第 60-78 行);get_input_output_texts验证越南语字符là不在单语词汇表时会回退为<unk><unk>,印证了_convert_token_to_id的未命中回退逻辑。
测试中使用的 SentencePiece 夹具位于 tests/fixtures/test_sentencepiece_bpe.model,测试会动态构造临时 dict.txt 单语词汇文件(见 get_tokenizer 方法),完整覆盖了双词汇表加载路径。
小结
BARTpho 通过"BART large 架构 + 额外层归一化 + mBART 类适配 + 双词汇表 SentencePiece 分词器"的组合,为越南语生成式 NLP 提供了开箱即用的预训练方案。上手时只需记住三条核心准则:模型加载用 AutoModel/AutoTokenizer(或 TensorFlow 的 TFAutoModel)指向 vinai/bartpho-{word,syllable} 检查点;模型实例化用 mBART 系类替代 BART 系类;如需迁移到其他语言,替换 monolingual_vocab_file 即可复用分词器。结合本仓库 tokenization_bartpho.py 与 test_tokenization_bartpho.py 的源码与测试,你可以在越南语摘要、掩码填充等任务上快速落地,并深入理解其与 XLM-RoBERTa/mBART 词汇体系的渊源。
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 StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
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