想象你走进了“Transformer 餐厅”的中央厨房:这里存放着全世界最受欢迎的几百道开源招牌菜,每道菜都是一个完整的“模型族”。如果你是这里的新主厨,第一件事不是急着颠勺,而是看懂厨房的布局——菜谱档案室在哪里、切配间在哪里、传菜口在哪里、点菜单怎么填。HuggingFace 的 Transformers 源码,就是这座厨房的完整图纸。 今天这篇文章,我们用“餐厅”这个比喻,把 src/transformers 的源码结构一层层拆开:models 目录像档案室、tokenization 像切配间、pipelines 像传菜窗口、config 像顾客的点菜单。等你把这份图纸烂熟于心,你也能像资深主厨一样,为这座餐厅提交一道属于自己的新菜——也就是为 Transformers 贡献一个新模型。整个过程不需要炫技,只需要按图索骥,把每一层的职责装进脑袋。

岗位关联

对 AI 从业者来说,看懂 Transformers 源码结构是踏入开源世界的敲门砖:你不仅会“用”模型,还能“造”模型、“交”模型,把个人影响力写进全球数百万开发者每天都在使用的代码库中。

目录
  1. 可视化演示
  2. 仓库总览
  3. 建模层设计
  4. 分词层设计
  5. 流水线层设计
  6. 配置机制
  7. 新增模型清单
  8. 测试与流程
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

模拟Transformers库源码的三层职责划分,展示modeling、tokenization与pipeline层的层次设计与新增模型文件流程,观察代码组织方式。

本节配有交互动效(进入视口后自动加载,约 3KB)。

模式1:源码层次设计 pipeline装配层 modeling模型层 tokenization分词层 layers = config + model + token 以模型族为单位组织,职责清晰分层。

仓库总览

新主厨走进 “Transformer 餐厅” 的后厨,总会先拿到一张平面图:左边是存放几百本菜谱的档案室,中间是每天把整颗食材切成小块的切配间,右侧是顾客点完单后出餐的传菜窗口,角落里还有一个放锅碗瓢盆的杂物间。这张平面图,对应的就是 Transformers 仓库的顶层结构。

在 src/transformers 目录下,models/ 就是那个档案室——几百个模型族各占一格;tokenization 与 tokenization_utils 是切配间的全套刀具;pipelines/ 是传菜窗口,用户喊一声“来份文本分类”,这里就自动把菜端出来;utils/ 和 configuration_utils.py 则是杂物间里最常用的工具。任何一个模型族,都绕不开这三层分工。

这三个核心模块之所以拆开,是因为它们在一条流水线上各司其职:切配间只管把文本变 ID,档案室只负责把 ID 变成预测结果,传菜窗口负责把两端组装成一道完整菜品。用集合的语言看,整个仓库就是每个模型族三件套的并集:

理解了这张平面图,你再往深处走,就不会在后厨里迷路。下一节,我们推开档案室的门,看看一本菜谱具体是怎么写的。

transformers=⋃f∈F(Modelingf∪Tokenizerf∪Configf)\text{transformers}=\bigcup_{f\in\mathcal{F}}\left(\text{Modeling}_{f}\cup\text{Tokenizer}_{f}\cup\text{Config}_{f}\right)
这个公式是说:整个仓库等于“所有模型族 × 每个族三份核心文件”的并集;每新增一个族,等式右边就多一项。
  1. 模型族集合$\mathcal{F}$ 是所有已收录模型族的代号集合,如 BERT、GPT-2、T5、Whisper 等
    F={BERT,GPT-2,T5,… }\mathcal{F}=\{\text{BERT},\text{GPT-2},\text{T5},\dots\}
  2. 建模文件$\text{Modeling}_f$ 表示模型族 $f$ 的模型结构代码,对应 models/xxx/modeling_xxx.py
  3. 分词与配置$\text{Tokenizer}_f$ 与 $\text{Config}_f$ 分别对应同一族的分词器和配置文件
  4. 并集符号$\cup$ 把每个族的三件套“拼进”同一个仓库,缺一不可

建模层设计

档案室里有一个公共书架,放着一本《万能基础菜谱》:它定义了所有菜品都必须遵守的基础规则,比如“如何解冻冷冻食材”(从 Hugging Face Hub 加载权重)、“如何根据点菜单准备原料”(保存到本地)。这本《万能基础菜谱》就是 PreTrainedModel 基类。

每个模型族拿到这本基础菜谱后,会把它扩写成自己的专属菜谱。BERT 的专属菜谱是 modeling_bert.py,里面定义了 BertModel(负责把输入变成一串隐含表征)、BertForSequenceClassification(在隐含表征之上加分类头)、BertForQuestionAnswering 等变体。这些变体层层继承,从通用的 PreTrainedModel,到 BERT 家族的 BertPreTrainedModel,再到具体的任务类。

这样设计的妙处在于:所有模型共用一套“解冻、上锅、装盘”的基础流程,只有食材切片和调味环节各有千秋。用数学符号刻画这条继承链就是:

把这本菜谱翻到"forward"那一页,你会看到一道菜从下锅到装盘的完整流程:输入经过 Embedding、层层 Transformer Block,最后输出 logits。下一节我们去切配间看看食材是如何准备的。

BertForSequenceClassification⪯BertPreTrainedModel⪯PreTrainedModel\text{BertForSequenceClassification}\preceq\text{BertPreTrainedModel}\preceq\text{PreTrainedModel}
$\preceq$ 表示“继承自”:最右边的基类提供通用能力,中间层提供家族共享逻辑,最左边则负责具体任务的差异。
  1. 任务最外层$\text{BertForSequenceClassification}$ 是用户最常直接实例化的类,带任务专属的分类头
    BertForSequenceClassification=BertModel+分类头\text{BertForSequenceClassification}=\text{BertModel}+\text{分类头}
  2. 家族中间层$\text{BertPreTrainedModel}$ 提供 BERT 家族共用的初始化与权重加载入口
  3. 全局基类$\text{PreTrainedModel}$ 是所有模型族的公共祖先,内置 from_pretrained、save_pretrained 等通用 API
  4. 继承方向$\preceq$ 从右向左看,左侧类型可以被当成右侧类型使用,代码复用由此实现

分词层设计

切配间的任务,是把一整颗冬瓜切成大小均匀的小丁。在 Transformers 里,这道工序由 tokenization_xxx.py 负责:它把一句话切成一个个 token,再查词表变成模型能读懂的整数 ID。BERT 家族用的是 WordPiece 算法,遇到不认识的词,会切成更细的子词,比如"transformers"可能变成 "transform" 和 "##ers"。

每个模型族的目录底下都配有两种刀具:BertTokenizer(纯 Python 实现,适合调试)和 BertTokenizerFast(Rust 加速版,适合生产)。它们共享同一份词表文件,但性能相差几十倍。分词器还负责处理特殊符号——[CLS] 表示句首、[SEP] 表示分隔、[PAD] 表示补齐,这些符号都登记在 vocab.txt 里。

分词器把文本变成 ID 的过程,可以抽象成一张查询表上的映射:

切配间切出的菜丁大小,直接影响成品的口感——如果分词器的词表和预训练时不一致,模型吃进去的“菜丁”就变了味。切好的菜丁会交给传菜窗口,我们下一节去看看整套出餐流程。

ids=(v[t1], v[t2], …, v[tn]),ti∈T(s)\text{ids}=\big(v[t_1],\, v[t_2],\, \dots,\, v[t_n]\big),\quad t_i\in\mathcal{T}(s)
意思是:先把文本 $s$ 切成一串 token,再逐个查词表 $v$,得到对应的整数 ID 向量。
  1. 分词函数$\mathcal{T}(s)$ 把原始文本 $s$ 切成 token 序列,输出 $t_1, t_2, \dots, t_n$
    T("我爱AI")=["我","爱","AI"]\mathcal{T}(\text{"我爱AI"})=[\text{"我"},\text{"爱"},\text{"AI"}]
  2. 词表映射$v(t_i)$ 表示在词表中查第 $i$ 个 token 对应的整数 ID
  3. 组合成向量$(v(t_1), v(t_2), \dots, v(t_n))$ 把所有 ID 拼成一个向量,供模型前向计算使用
  4. 下标约束$t_i\in\mathcal{T}(s)$ 强调每个 ID 都来自同一个原始句子的切分结果

流水线层设计

顾客喊一声“来一份情感分析套餐”,传菜窗口不会让顾客自己去后厨切菜、炒菜、摆盘。pipeline 干的就是这件事:它对用户暴露一个极简接口,内部自动帮你把切配(tokenize)、烹饪(forward)、装盘(postprocess)串成一条完整流水线。

在 pipelines/ 目录下,每种任务类型对应一个 Pipeline 类:TextClassificationPipeline、QuestionAnsweringPipeline、ImageClassificationPipeline 等。调用 pipeline("text-classification", model="my-model") 时,它会通过 AutoModel 和 AutoTokenizer 自动找到对应的模型和分词器,再把它们组装起来。

这三个模块的关系非常像数学里的函数复合——前一个函数的输出,恰好是后一个函数的输入:

传菜窗口让顾客省心,但后厨的每条流水线都依赖前两层的默契配合。要理解它们为什么能自动咬合,我们得看看那张贯穿前后的“点菜单”——config 配置。

pipeline=ϕpost∘ϕmodel∘ϕtokenize\text{pipeline}=\phi_{\text{post}}\circ\phi_{\text{model}}\circ\phi_{\text{tokenize}}
$\circ$ 是复合符号,从右往左读:先做分词,再把分词结果喂给模型,最后对模型输出做后处理。
  1. 分词函数$\phi_{\text{tokenize}}$ 负责把文本变成 ID 张量
    ϕtokenize(s)↦input_ids\phi_{\text{tokenize}}(s)\mapsto\text{input\_ids}
  2. 前向函数$\phi_{\text{model}}$ 接收 ID 张量,输出原始 logits 或 hidden states
  3. 后处理函数$\phi_{\text{post}}$ 把模型输出转化为用户友好的结果,如标签和置信度
  4. 复合方向$\circ$ 从右往左依次执行,这就是“三步封装”的数学本质

配置机制

点菜单上写着“少油、多辣、香菜加不加”,顾客不用懂后厨怎么炒,厨师看一眼菜单就能调整全部细节。在 Transformers 里,configuration_xxx.py 就是这张点菜单:它把模型的所有可调参数集中定义在一个 Config 类里,比如隐藏层大小、层数、注意力头数、dropout 概率。

当你执行 model.from_pretrained("bert-base-uncased") 时,库会先下载并解析 config.json,把它还原成 BertConfig 对象,再根据 Config 里的参数搭建模型结构。反过来,model.save_pretrained() 也会把所有参数重新写回 config.json,保证模型能被无损复现。

从源码结构看,config 是建模层和分词层都依赖的“公共语言”——模型初始化需要它,分词器的最大长度配置也来自它。用函数式语言描述:

点菜单的存在,让“做菜”与“点单”彻底解耦。有了这张菜单,新菜品的登记流程就变得极为标准化,我们进入最实战的一节:端上一道新菜到底要改哪些文件。

θ=Φ(c),c⟷config.json\theta=\Phi(c),\qquad c \longleftrightarrow \text{config.json}
模型的全部参数 $\theta$ 由配置对象 $c$ 决定,而 $c$ 与磁盘上的 config.json 可以双向转换。
  1. 模型参数来源$\theta=\Phi(c)$ 表示模型结构中的每个权重维度都由配置对象 $c$ 决定
    θ≡(hidden_size,num_layers,… )\theta\equiv(\text{hidden\_size},\text{num\_layers},\dots)
  2. 配置还原$c\mapsto\text{config.json}$ 表示 save_pretrained 把配置对象序列化成 JSON
  3. 配置加载$\text{config.json}\mapsto c$ 表示 from_pretrained 把 JSON 反序列化回配置对象
  4. 双向箭头$\longleftrightarrow$ 强调保存与加载必须对称,否则模型无法复现

新增模型清单

在 Transformer 餐厅里加一道新菜,绝不只是把炒好的菜端出去。主厨必须同时交上六样东西:配方、切配规程、点单模板、菜单登记页、营养说明、试吃报告。对应到代码仓库,就是新增一个模型族时的那一串文件清单。

具体来说,你需要在 src/transformers/models/xxx/ 下新建 modeling_xxx.py、tokenization_xxx.py、configuration_xxx.py,并补上该目录的 __init__.py;接着在 src/transformers/models/__init__.py 和 src/transformers/__init__.py 里把新类注册进 AutoModel/AutoTokenizer 的映射表;最后还要在 docs/source/ 写模型卡片,在 tests/models/xxx/ 添加测试文件。官方甚至提供了“复制已有模型族再改写”的模板化开发路径,让新增模型的工作量从“从零造轮子”降为“替换同名变量”。

这六个文件构成了一个不可分割的集合:

新菜端上桌前,必须有试吃和质检环节,这正是最后一节要讲的测试与流程。

Nfiles=∣{modeling,tokenization,configuration,register,docs,tests}∣=6N_{\text{files}}=\left|\left\{ \text{modeling},\text{tokenization},\text{configuration},\text{register},\text{docs},\text{tests}\right\}\right|=6
新增模型的最小完备集是 6 个环节,缺一个,这个模型就无法被社区正常使用。
  1. 三个核心文件$\text{modeling}$、$\text{tokenization}$、$\text{configuration}$ 是每道菜的三件套
    三件套=modeling∪tokenization∪configuration\text{三件套}=\text{modeling}\cup\text{tokenization}\cup\text{configuration}
  2. 注册文件$\text{register}$ 指 __init__.py 与 AutoClass 映射,相当于把新菜写进菜单
  3. 外围文件$\text{docs}$ 是使用说明书,$\text{tests}$ 是质量保障
  4. 基数计算$|\cdot|=6$ 表示这个集合恰好有 6 个元素,少一个都凑不齐

测试与流程

高档餐厅推出新菜前,要请品控团队反复试吃:不仅试味道,还要检查食材是否新鲜、摆盘是否统一、出餐时长是否符合标准。Transformers 的测试体系完全复刻了这套机制。

测试代码按模型族隔离在 tests/models/bert/、tests/models/gpt2/ 这样的目录里,每个族至少包含 test_modeling_xxx.py 和 test_tokenization_xxx.py。更关键的是官方还提供了一批“公共测试”(common tests),它们像标准化的卫生检查:统一验证 config 保存与恢复、模型输出与文档一致性、tokenizer 往返编解码是否匹配等通用约定。

当你提交 Pull Request 时,CI 会先跑代码格式检查(如 ruff、black 风格),再运行你所在模型族的测试和公共测试。只有全部变绿,维护者才会把它合并进主分支。测试覆盖率这个概念可以这样理解:

至此,从仓库平面图到建模层、分词层、流水线层、配置机制,再到新增模型的六个文件与测试流程,你已经完整走过了一遍 Transformers 源码结构。下一节我们把这些知识放回真实工作场景,看看它们如何创造生产力。

coverage=executed_linestotal_lines×100%\text{coverage}=\frac{\text{executed\_lines}}{\text{total\_lines}}\times 100\%
覆盖率就是一个模型族目录下,被测试执行到的代码行数占全部代码行数的百分比。
  1. 分子$\text{executed\_lines}$ 是测试运行中实际执行到的代码行数
  2. 分母$\text{total\_lines}$ 是该模型族的全部代码行数
  3. 百分比换算$\times 100\%$ 把比值变成直观的百分数
  4. 质量含义覆盖率越高,说明测试越多地“尝过”每一道工序,回归风险越低

AI 应用场景

场景一:向社区提交全新模型

阶段:模型开发与开源集成

解决的问题:研究团队在论文里提出了新模型架构,但工程侧只有孤立的 PyTorch 代码,模型和分词器各写各的,别人无法使用。循着源码结构的“六件套”清单补齐文件,就能让新模型被全世界一行代码调用。

具体案例:某实验室复现了轻量级模型 "FoBERT",对照 Electra 的建模文件改写 modeling_fobert.py,补上 tokenization_fobert.py、configuration_fobert.py,在 __init__.py 注册到 AutoModel,再跑通公共测试后提交 PR。合并后,任何人执行 from_pretrained("lab/fobert-base") 都能加载它。

场景二:企业内部统一推理服务层

阶段:模型部署与推理

解决的问题:公司内部三个团队用不同框架实现了同一个模型,接口五花八门,业务方接一个模型就要写一套适配代码。把内部模型“磨”成 Transformers 的结构——config 管参数、modeling 管结构、pipeline 管调用——后端团队就能用统一入口接入所有模型。

具体案例:某 AI 中台团队为自研的多模态模型实现了 Modeling 封装与 Tokenizer 封装,注册到 AutoClass 后,业务侧只需 pipeline("image-to-text", model="internal/mm-model") 一行调用,模型上线时间从两周压缩到一天。

场景三:通过贡献代码扩大技术影响力

阶段:开源协作与社区建设

解决的问题:企业想提升技术品牌,却不知从何入手。给 Transformers 贡献一个高质量模型族或补齐某个模型的 tokenizer,企业名字会直接写进 Release Notes,并获得社区 issue 与技术支持的优先响应。

具体案例:某语音公司为 Whisper 中文变体贡献了 tokenization_whisper_cn.py 及配套测试,PR 合并后该模型在 Hub 上日均下载量破万,团队也因此积累了开源信誉,后续招聘时成为闪亮的加分项。

Python 演示

python44 行
"""检查 transformers 代码库中模型族的文件完备性。 新增模型时必须补齐 modeling / tokenization / configuration 等文件,本脚本用于快速盘点哪些族还差哪些文件。"""from pathlib import Path REQUIRED_PREFIXES = [    "modeling_",    "tokenization_",    "configuration_",] def scan_family(models_dir, name):    family_dir = Path(models_dir) / name    files = [p.name for p in family_dir.iterdir() if p.is_file()]    missing = []    for prefix in REQUIRED_PREFIXES:        if not any(f.startswith(prefix) for f in files):            missing.append(prefix + "xxx.py")    if "__init__.py" not in files:        missing.append("__init__.py")    return files, missing def scan_models(base_dir):    models_dir = Path(base_dir) / "models"    if not models_dir.is_dir():        print("找不到 models 目录,请先 clone transformers 仓库")        return    for entry in sorted(models_dir.iterdir()):        if not entry.is_dir():            continue        files, missing = scan_family(models_dir, entry.name)        status = "OK" if not missing else "缺少 " + ", ".join(missing)        print("[{}] {} -> {}".format("v" if not missing else "x", entry.name, status))        for fname in sorted(files):            print("    " + fname)        print() def main():    scan_models("src/transformers") if __name__ == "__main__":    main()
目的:快速扫描 Transformers 仓库的 models 目录,检查每个模型族是否补齐了“三件套”与 __init__.py,帮助贡献者在提交 PR 前自检文件清单。
  1. REQUIRED_PREFIXES = [...]定义模型族必备的三种核心文件前缀,对应菜谱里的三件套
  2. for prefix in REQUIRED_PREFIXES:逐个前缀检查目录下是否存在匹配文件
  3. if "__init__.py" not in files:__init__.py 是模型族的注册入口,缺失会导致导入失败
  4. models_dir = Path(base_dir) / "models"用 pathlib 跨平台拼接路径,避免手写斜杠
  5. scan_models("src/transformers")指定扫描根目录为仓库的源码主目录

常见误区

误区以为在 models 文件夹里新增一个 `modeling_xxx.py` 就算把模型加好,其他文件都不用动。

正解一个模型族是“切配、菜谱、点单、菜单、说明、质检”的完整体系,至少包含 modeling、tokenization、configuration、__init__.py 注册、docs 和 tests 六个环节。最典型的是忘了 __init__.py 与 AutoClass 注册,导致 from transformers import XxxModel 直接报 ImportError。

为何常见:大多数教程只展示 modeling 类的写法,让人误以为源码结构里只有这一层。

误区分词器在切配间,模型在档案室,感觉两者独立,各自跑通就行。

正解两处必须严格对齐。分词器产生的 token ID 如果与预训练时的词表不一致,模型输入分布就被整体“平移”了,训练或推理效果一落千丈。源码里它们同属一个模型族目录,正说明它们是咬合的一对。

为何常见:本地小实验时经常在自建词表上凑合,忽略了预训练模型对 tokenizer 的硬依赖。

误区觉得 `hidden_size` 这类超参直接在代码里定义一个变量就行,没必要放进 Config 类。

正解Transformers 的哲学是“一切可调参数都进 config”。config 像点菜单,代码像菜谱,二者分离后 from_pretrained 才能通过 config.json 完整复现模型;写死参数会导致模型无法保存和加载。

为何常见:刚接触源码结构时,觉得 Config 类只是“多此一举”的样板代码。

误区本地试了一个小例子,结果正常,觉得万事大吉可以直接提交。

正解Transformers 有严格的公共测试(common tests),统一验证配置保存/恢复、tokenizer 往返编码、模型输出形状等通用约定。本地不跑这些,CI 一启动就会立刻变红。

为何常见:新手对公共测试体系不了解,只关注自己改动的那条功能路径。

误区认为自己改的是底层 modeling 代码,pipeline 是高层封装,和贡献无关。

正解新增模型族如果不打通 AutoClass 注册,用户就无法 pipeline("text-classification", model="my-model")。源码结构虽然分层清晰,但层与层之间靠 AutoClass 机制串联,贡献者既要写底层也要接上层。

为何常见:分层设计给人“各层独立”的错觉,忽略了自动装配这条隐性链路。

面试题

Q1. 新增一个模型族,代码应当放在哪个目录?

单选题 · easy

  • A.src/transformers/models← 正确答案
  • B.examples/classification
  • C.tests/training_scripts
  • D.docs/migration_notes

答案:A。模型族的建模、分词、配置文件都集中在 src/transformers/models 下,按家族名建子目录。B 是示例脚本目录,C 是测试目录,D 是迁移文档目录,均不属于模型代码主目录。

Q2. modeling_bert.py 主要负责哪一层?

单选题 · easy

  • A.模型结构定义← 正确答案
  • B.文本切分逻辑
  • C.数据加载处理
  • D.训练损失计算

答案:A。modeling 层是“菜谱本”,专门定义模型结构与前向流程。文本切分在 tokenization 层,数据加载在训练脚本中,训练损失通常在专门的 modeling 任务类或训练脚本里,而不归 modeling_bert.py 管。

Q3. tokenizer 的核心作用是什么?

单选题 · easy

  • A.切分子词并映射← 正确答案
  • B.计算损失梯度
  • C.保存模型权重
  • D.格式化日志输出

答案:A。tokenizer 像切配间,把整段文本切成子词 token,再查词表映射为整数 ID。梯度计算、权重保存、日志格式化分别是训练框架、PreTrainedModel 和日志库的职责。

Q4. 新增模型族通常需要哪三个核心文件?

多选题 · mid

  • A.configuration 配置类← 正确答案
  • B.modeling 模型结构← 正确答案
  • C.tokenization 分词器← 正确答案
  • D.setup.py 安装器

答案:ABC。每个模型族的标准三件套是 modeling、tokenization、configuration,对应 modeling_xxx.py、tokenization_xxx.py、configuration_xxx.py。setup.py 是 Python 包安装配置,不属于模型族内部文件。

Q5. pipeline 的内部处理顺序是?

单选题 · mid

  • A.分词→前向→后处理← 正确答案
  • B.前向→分词→后处理
  • C.后处理→模型→保存
  • D.模型→保存→分词

答案:A。pipeline 是函数复合结构,从右往左执行:tokenize(分词)→ model(前向)→ postprocess(后处理)。其他选项打乱了流水线顺序,无法工作。

Q6. 关于 config 机制,哪些说法正确?

多选题 · mid

  • A.参数可从 config 加载← 正确答案
  • B.模型需要 config 传递← 正确答案
  • C.config 不可被代码覆盖
  • D.权重不可从 Hub 加载

答案:AB。config.json 通过 from_pretrained 加载为配置对象,再传给模型构造函数,所以 A、B 正确。代码可以在实例化后覆盖 config 中的字段值,C 错误;D 显然错误,from_pretrained 正是从 Hub 拉取权重。

Q7. AutoModel 的作用是什么?

单选题 · mid

  • A.按名字自动选类← 正确答案
  • B.自动调优超参数
  • C.自动训练全模型
  • D.自动部署服务

答案:A。AutoModel 是“菜单索引”,它读取 checkpoint 的 config 类型,自动选择对应的模型类。它不负责训练、调参或部署。

Q8. 公共测试(common tests)主要检验什么?

单选题 · hard

  • A.配置保存与恢复← 正确答案
  • B.代码行数控制
  • C.网络带宽占用
  • D.文档字数限制

答案:A。公共测试是“卫生检查”,统一验证 config 保存/恢复、tokenizer 往返、输出结构等通用约定。行数、带宽、字数都不是测试目标。

Q9. 为什么新模型的 tokenizer 不能随意更换?

单选题 · extreme

  • A.ids 与预训练不对齐← 正确答案
  • B.模型会被自动删除
  • C.会改变 GPU 型号
  • D.会提高训练学习率

答案:A。tokenizer 的词表与预训练时紧密绑定,换一个词表即便 token 看起来相同,ID 也会错位,相当于给模型喂了“改过编码的输入”,信号分布被破坏。B、C、D 与分词器毫无逻辑关系。

Q10. 提交 PR 前合适的测试动作包括哪些?

多选题 · hard

  • A.跑对应族测试← 正确答案
  • B.跑公共测试← 正确答案
  • C.只跑自己单测
  • D.检查配置保存恢复← 正确答案

答案:ABD。合格贡献者既要跑 tests/models/xxx/ 下的族测试,也要跑公共测试验证通用约定,还应检查 config 保存与恢复的一致性。只跑自己写的单测不足以覆盖回归风险。