Files
FunASR/docs/model_registration_zh.md

125 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 模型注册
[English](model_registration.md) | [文档](tutorial/README_zh.md) | [训练](training_zh.md) | [历史注册教程](tutorial/Tables_zh.md)
注册把 Python 实现与配置名称连接起来,不会下载权重、自动兼容任意 Transformers 模型、提供训练或导出能力,也不代表质量认证。本指南依据当前仓库的[注册表](../funasr/register.py)、[AutoModel](../funasr/auto/auto_model.py)、[模型加载器](../funasr/download/download_model_from_hub.py)和[动态导入工具](../funasr/utils/dynamic_import.py)。
## 名称与导入顺序
对构造前已导入的类使用 `@tables.register("model_classes", "YourUniqueModelName")`,其中 `tables` 来自 `funasr.register`。第二个参数是区分大小写的精确注册键,省略时使用 Python 类名。装饰器返回原类,并通过 `inspect` 记录源码位置,所以应把示例定义在可导入的 `.py` 文件中,而非仅在 REPL 或动态生成类中定义。
注册键保存在进程级字典中。同名键会被覆盖,只记录 debug 日志而不报错,因此导入顺序会影响行为。使用组织或项目专属名称并增加冲突检查,不要给无关自定义模型使用 `SenseVoiceSmall`、`Paraformer`、`FunASRNano` 等已有名称。`tables.print("model")` 显示注册元数据,`tables.model_classes[name]` 给出当前生效实现。
其他表包括 `encoder_classes`、`decoder_classes`、`frontend_classes`、`tokenizer_classes`、`dataset_classes`、`index_ds_classes`、`batch_sampler_classes`。每个调用方都有自己的接口约定,注册 encoder 不等于注册完整 `AutoModel` 模型。注册器也允许创建新表,表名拼错可能生成无人使用的表,而不是报错。
## 最小本地接口示例
在临时目录中创建可导入的 `custom_model_demo.py`,内容如下,然后在已安装当前 checkout 的环境执行 `python custom_model_demo.py`。它只回显文本,不执行语音识别;不需要权重、音频、模型下载或 GPU。保留一个参数是因为当前 `AutoModel.inference` 会读取 `next(model.parameters()).device`,无参数的玩具模型会在此失败。
```python
import torch
from funasr import AutoModel
from funasr.register import tables
MODEL_NAME = "DocsEchoModelV1"
if MODEL_NAME in tables.model_classes:
raise RuntimeError(f"Registry collision: {MODEL_NAME}")
@tables.register("model_classes", MODEL_NAME)
class DocsEchoModel(torch.nn.Module):
def __init__(self, **kwargs):
super().__init__()
self.anchor = torch.nn.Parameter(torch.zeros(1), requires_grad=False)
def inference(
self, data_in, data_lengths=None, key=None,
tokenizer=None, frontend=None, **kwargs,
):
results = [
{"key": sample_key, "text": str(value)}
for sample_key, value in zip(key, data_in)
]
return results, {}
if __name__ == "__main__":
model = AutoModel(
model=MODEL_NAME,
model_conf={},
device="cpu",
disable_update=True,
disable_pbar=True,
)
result = model.generate(input=["hello", "world"], data_type="text")
assert [row["text"] for row in result] == ["hello", "world"]
assert all(isinstance(row["key"], str) for row in result)
print([row["text"] for row in result])
```
最后输出应为 `['hello', 'world']`。这只是接口连通性验证,专项文档测试会在临时文件中针对当前源码执行这段代码,不验证语音模型。
`model_conf={}` 是有意传入的:只要该键存在,`AutoModel.build_model` 就跳过 hub/配置解析。因此这里的 `model` 是已注册类名,不是目录或 hub ID。必须先自行导入模块;在该直接构造路径中添加 `remote_code` 不会触发导入。解析后的 kwargs 覆盖合并到 `model_conf`,一起传给构造器,包括已构造的 tokenizer/frontend、设备、词表与输入维度。请像真实模型一样接收相应命名参数及 `**kwargs`。
## 推理与训练接口
| 接口 | 当前源码约定 |
| --- | --- |
| 模型对象 | 通常为 `torch.nn.Module`,需要支持 `.to(...)`、`.eval()`、`.parameters()`;构造配置由模型决定。 |
| `inference` 输入 | 不使用 VAD 时,AutoModel 把输入组织成 `data_in` 和 `key` 列表,在 `torch.no_grad()` 下调用 `model.inference(**batch, **kwargs)`。单条 `data_type="fbank"` 输入会直接传入特征对象,并设 `data_lengths=input_len`。tokenizer/frontend 是已构造对象或 `None`。 |
| 模型层返回值 | 返回二元组 `(results, meta_data)`,其中 `results` 是 `list[dict]`,`meta_data` 是字典。ASR 结果使用字符串 `key`、`text` 并保持输入顺序与标识。不能只返回结果字典列表,否则 AutoModel 会把第一条当成整个 batch 结果。 |
| 元数据 | 可包含 `load_data`、`extract_feat`、`batch_data_time`。音频的 `batch_data_time` 是以秒为单位的正时长,不能填毫秒或零,零会导致计时代码除零。省略时使用内部 `-1` 哨兵值,如上述非音频示例,并不代表有效速度测量。 |
| 公开返回值 | `AutoModel.generate(...)` 返回展开后的结果列表。时间戳等附加字段由模型决定,注册并不承诺这些字段。VAD、标点、说话人和流式集成还需额外兼容实现与独立测试。 |
| 训练 | 实现可微 `forward`,命名张量参数应匹配 dataset collator。[训练器](../funasr/train_utils/trainer_ds.py)解包 `(loss, stats, weight)`;[SenseVoice](../funasr/models/sense_voice/model.py)和 [Nano](../funasr/models/fun_asr_nano/model.py)使用 `force_gatherable`。玩具模型故意不实现训练 forward。 |
| 导出 | [导出工具](../funasr/utils/export_utils.py)调用模型的 `export`,再使用 `export_dummy_inputs`、输入输出名称、动态轴等模型专属方法。注册本身不会实现这些方法。 |
自定义模型仍需自行实现所需的音频加载、特征处理、分词、解码及 batching。参考相近模型的接口,不能在缺少实现时宣称具有其能力。训练还需适配数据集与损失函数,参见[训练指南](training_zh.md)。
## 加载已审查代码与权重
有两条不同路径:
1. **直接注册构造:**先导入模块,再像玩具示例一样传注册键和 `model_conf`。需要权重时提供兼容的 tokenizer/frontend/配置及真实存在的 `init_param`。该路径不执行 hub 代码导入。
2. **模型目录解析:**传已审查的本地目录或 hub ID,不传 `model_conf`。加载器读取 `configuration.json` 文件元数据或 `config.yaml`,解析类名和资产并加载权重。简单的本地 `config.yaml` 目录通常还需要 `model.pt` 及配置引用的分词器、前端文件。任意 HF 权重文件夹不会自动成为 FunASR 模型目录。
第二条路径的 ModelScope 接口如下,它不是无需准备即可运行的例子。`models/custom-asr` 必须已有兼容且审查过的配置和权重,`custom_asr_model.py` 必须注册配置指定的精确键:
```python
from funasr import AutoModel
model = AutoModel(
model="./models/custom-asr",
hub="ms",
trust_remote_code=True,
remote_code="./custom_asr_model.py",
device="cpu",
disable_update=True,
)
print(model.generate(input="data/audio/heldout.wav"))
```
当前 `download_from_ms` 在 `trust_remote_code=True` 时导入 `remote_code`,未指定时默认为模块名 `model`。导入器支持模块/文件路径及 URL 下载,把目录加入 `sys.path` 后按文件基本名导入。相对路径按工作目录解析,不会自动相对权重目录解析。文件基本名冲突及 Python 导入缓存可能选中已加载模块,应使用独立模块名并验证当前类。该辅助函数打印导入异常而不重新抛出,应检查错误日志与注册结果。
**`hub="hf"` 路径不同:**本 checkout 的 `download_from_hf` 在信任开关下可安装模型依赖,但不调用 `import_module_from_path`,不能假定它会执行 `remote_code`。在 `hub="hf"` 构造前显式导入已审查模块,或使用完整配置的直接注册构造路径。两条路径的本地 `config.yaml` 回退对 `init_param` 也不同:ModelScope 保留已有且存在的显式路径,Hugging Face 则指定目录内 `model.pt`。必须检查解析后的真实路径,不要假定 checkpoint 覆盖始终有效。
## 真实示例与边界
- [SenseVoiceSmall 实现](../funasr/models/sense_voice/model.py)展示注册、训练、推理和导出集成,但需保持其模型配置与分词器假设。
- [Nano demo1.py](../examples/industrial_data_pretraining/fun_asr_nano/demo1.py)使用 `trust_remote_code=True`、`remote_code="./model.py"`、`hub="ms"`,要求 recipe 工作目录。其[本地实现](../examples/industrial_data_pretraining/fun_asr_nano/model.py)注册 `FunASRNano` 并导入同目录的 `ctc`、`tools` 模块,可能覆盖[内置实现](../funasr/models/fun_asr_nano/model.py)。两者并非对所有功能可互换,尤其不能假定保留内置 LoRA,应检查实际类和权重键。
- [MOSS 适配器](../funasr/models/moss_transcribe_diarize/model.py)集成第三方 OpenMOSS 模型,其 `forward` 明确拒绝训练。注册模型不意味着支持微调或导出。
- [原始注册教程](tutorial/Tables_zh.md)和[通用教程](tutorial/README_zh.md)保留为历史入口;示例有差异时,以这里说明的当前源码行为为准。
## 安全与验证
`trust_remote_code=True` 允许执行 Python;hub 加载器还可能安装模型目录的 `requirements.txt`。本地目录不天然可信。审核源码、依赖与权重序列化方式,使用隔离环境,不加载不可信的 pickle checkpoint。不要把不可信 URL、模块名或配置直接接入流程。远程 revision 行为不可靠时保留带哈希的已审查本地快照;这里的 `model_revision` 并非所有加载路径都能统一固定版本。
加载前检查当前注册键、类和源码位置。确认模型、配置、分词器兼容,并检查缺失或多余权重:AutoModel 的 `ignore_init_mismatch` 默认为 true,直接传入不存在的 `init_param` 会打印错误,不保证构造失败。应自行验证 checkpoint 存在。训练、导出、部署前分别测试单条、多条、异常输入与目标流水线。FunASR 软件的 MIT 许可证不替代模型或上游组件的许可。
运行专项语法、仓库链接和不下载模型的玩具接口测试:
```bash
python -m pytest -q tests/test_training_docs_contract.py
```
这些检查不认证任意自定义代码、真实 ASR 质量、GPU 训练、真实 checkpoint 恢复或导出兼容性。