重要提示

您正在查看 NeMo 2.0 文档。此版本引入了 API 的重大更改和一个新的库 NeMo Run。我们目前正在将所有功能从 NeMo 1.0 移植到 2.0。有关先前版本或 2.0 中尚不可用的功能的文档,请参阅 NeMo 24.07 文档

神经文本规范化模型#

文本规范化是将书面文本转换为其口语形式的任务。例如,$123 应该口语化为 one hundred twenty three dollars,而 123 King Ave 应该口语化为 one twenty three King Avenue。同时,逆问题是将口语序列(例如,ASR 输出)转换为其书面形式。

NeMo 有一个实现,允许您构建一个基于神经系统的系统,该系统能够同时进行文本规范化 (TN) 和逆文本规范化 (ITN)。在高层次上,该系统由两个独立的组件组成

  • DuplexTaggerModel - 基于 Transformer 的标记器,用于识别输入中的“符号”跨度(例如,关于时间、日期或货币金额的跨度)。

  • DuplexDecoderModel - 基于 Transformer 的 seq2seq 模型,用于将符号跨度解码为其适当的形式(例如,TN 的口语形式和 ITN 的书面形式)。

典型的工作流程是首先训练 DuplexTaggerModel 和 DuplexDecoderModel。提供了一个示例训练脚本:duplex_text_normalization_train.py。之后,可以使用这两个训练好的模型来初始化 DuplexTextNormalizationModel,该模型可用于端到端推理。此处提供了评估示例脚本:duplex_text_normalization_test.py。完整流程的推理脚本在此处提供:duplex_text_normalization_infer.py。此脚本从原始文本文件或交互式终端运行推理。术语duplex指的是我们的系统可以训练来同时执行 TN 和 ITN。但是,您也可以专门为其中一项任务训练系统。

快速入门指南#

要交互式运行预训练模型,请参阅 模型推理

可用模型#

预训练模型#

模型

预训练检查点

neural_text_normalization_t5

https://ngc.nvidia.com/catalog/models/nvidia:nemo:neural_text_normalization_t5

数据格式#

DuplexTaggerModel 模型和 DuplexDecoderModel 模型都使用与 Google 文本规范化数据集 相同的文本格式。数据需要存储在 TAB 分隔的文件 (.tsv) 中,其中包含三列。第一列是“符号类”(例如,数字、时间、日期),第二列是书面形式的标记,第三列是口语形式。数据集中的示例如下所示。在该示例中,self 表示口语形式与书面形式相同。

PLAIN       The     <self>
PLAIN       company 's      <self>
PLAIN       revenues        <self>
PLAIN       grew    <self>
PLAIN       four    <self>
PLAIN       fold    <self>
PLAIN       between <self>
DATE        2005    two thousand five
PLAIN       and     <self>
DATE        2008    two thousand eight
PUNCT       .       <self>
<eos>       <eos>

有关 Google 文本规范化数据集的更多信息,请参见论文 RNN Approaches to Text Normalization: A Challenge [NLP-TEXTNORM2]。用于将 Google 文本规范化数据文件拆分为 traindevtest 的脚本可以在这里找到:data/data_split.py

数据预处理#

处理脚本可以在同一文件夹中找到。目前我们只提供英语文本规范化的脚本,请参阅 data/en/data_preprocessing.py。详细信息可以在脚本的顶部找到。预处理脚本的目的是标准化格式,以帮助模型训练。我们还将标点符号类 PUNCT 更改为像普通标记一样处理(标签从 <sil> 更改为 ``<self>),因为我们希望即使在规范化后也保留标点符号。对于文本规范化,避免无法恢复的错误至关重要,这些错误在语言上是连贯的,但不保留语义。我们注意到,由于数据稀缺,模型很难正确地口语化长数字,因此我们将长数字的真实值更改为逐位口语化。我们还忽略了神经口语化中的某些符号类,例如原始数据集中的 ELECTRONICWHITELISTVERBATIMLETTER。相反,我们将 URL/电子邮件地址和缩写标记为普通标记,并使用基于 WFST 的语法单独处理,请参阅 模型推理。这简化了模型的任务,并显着减少了无法恢复的错误。

数据上采样#

数据上采样是增加训练数据以获得更好模型性能的有效方法,尤其是在符号标记的长尾方面。我们使用上采样来训练英语文本规范化模型,请参阅 data/en/upsampling.py。目前,此脚本仅对少数几个类进行上采样,这些类在符号标记中是多样的,但同时在训练数据中代表性不足。对于由 data/data_split.py 创建的 train 文件夹中的所有输入文件,此脚本获取第一个文件并检测其中出现的类模式。对于那些代表性不足的类,定量定义为低于 min_number,扫描其他文件以查找具有缺失模式的句子。这些句子被附加到第一个文件中,然后可以用于训练。详细信息可以在脚本的顶部找到。

Tarred Dataset#

当使用 DistributedDataParallel 进行训练时,每个进程都有其自己的数据集副本。对于大型数据集,这可能并不总是适合 CPU 内存。Webdatasets 通过有效地迭代存储在磁盘上的 tar 文件来规避此问题。每个 tar 文件可以包含数百到数千个 pickle 文件,每个文件包含一个 minibatch。

可以按如下方式创建 Tarred 数据集

python examples/nlp/duplex_text_normalization/data/create_tarred_dataset.py \
    --input_files = "<trained_processed/output-00099-of-00100>" \
    --input_files = "<trained_processed/output-00098-of-00100>" \
    --batch_size = "<batch size>" \
    --out_dir= "<TARRED_DATA_OUTPUT_DIR>"

警告

用于创建 tarred 数据集的批量大小将是训练中使用的批量大小,无论用户在配置 yaml 文件中指定什么。分片数应可被世界大小整除,以确保在工作人员之间均匀分配。如果不可整除,日志记录将发出警告,但训练将继续,但可能在最后一个 epoch 挂起。

模型训练#

提供了一个示例训练脚本:duplex_text_normalization_train.py。用于该示例的配置文件位于 duplex_tn_config.yaml。您可以直接从配置文件更改任何这些参数,或使用命令行参数更新它们。

配置文件包含三个主要部分。第一部分包含标记器的配置,第二部分是关于解码器的,最后一部分是关于数据集的。示例配置文件中的大多数参数都非常不言自明(例如,decoder_model.optim.lr 是指训练解码器的学习率)。我们已将大多数超参数设置为我们发现有效的值(对于 Google TN 数据集的英语和俄语子集)。您可能想要修改的一些参数是

  • lang:数据集的语言。

  • modetnitnjoint,分别用于文本规范化、逆文本规范化或双工模式

  • data.train_ds.data_path:训练文件的路径。

  • data.validation_ds.data_path:验证文件的路径。

  • data.test_ds.data_path:测试文件的路径。

  • data.test_ds.data_path:测试文件的路径。

  • data.test_ds.errors_log_fp:用于记录测试文件错误的文件的路径。

  • tagger_pretrained_model:预训练模型路径或名称(可选)

  • decoder_pretrained_model:预训练模型路径或名称(可选)

  • tagger_model.nemo_path:这是最终训练的标记器模型将保存到的路径。

  • decoder_model.nemo_path:这是最终训练的解码器模型将保存到的路径。

  • tagger_model.transformer:用于初始化标记器模型权重的 huggingface transformer 模型

  • decoder_model.transformer:用于初始化解码器模型权重的 huggingface transformer 模型

训练命令示例

python examples/nlp/duplex_text_normalization/duplex_text_normalization_train.py \
    data.base_dir=<PATH_TO_DATASET_DIR> \
    mode={tn,itn,joint}

有 3 种不同的模式。“tn”模式仅用于训练 TN 系统。“itn”模式用于训练 ITN 系统。“joint”用于训练可以同时执行 TN 和 ITN 的系统。请注意,以上命令将首先训练标记器,然后按顺序训练解码器。

您还可以通过运行以下命令仅训练标记器(而不训练解码器)

python examples/nlp/duplex_text_normalization/duplex_text_normalization_train.py \
    data.base_dir=PATH_TO_DATASET_DIR \
    mode={tn,itn,joint} \
    decoder_model.do_training=false

或者您也可以仅训练解码器(而不训练标记器)

python examples/nlp/duplex_text_normalization/duplex_text_normalization_train.py \
    data.base_dir=PATH_TO_DATASET_DIR \
    mode={tn,itn,joint} \
    tagger_model.do_training=false

要将数据的 tarred 版本与解码器模型一起使用,请将 data.train_ds.use_tarred_dataset 设置为 True 并提供 metadata.json 文件的路径。元数据文件在 tarred 数据集构建期间创建,并存储在 <TARRED_DATA_OUTPUT_DIR>。要启用使用 tarred 数据集进行训练,请添加以下参数

data.train_ds.use_tarred_dataset=True \
data.train_ds.tar_metadata_file=\PATH_TO\<TARRED_DATA_OUTPUT_DIR>\metadata.json

模型推理#

运行完整推理流程

cd NeMo/examples/nlp/duplex_text_normalization;

# run inference in interactive mode using pretrained tagger and decoder models
python duplex_text_normalization_infer.py \
    tagger_pretrained_model=neural_text_normalization_t5 \
    decoder_pretrained_model=neural_text_normalization_t5 \
    inference.from_file=False \
    lang=en \
    mode=tn

要从文件运行推理,请通过以下方式调整之前的命令

inference.from_file=<path_to_file>
inference.interactive=False

此流程包括

  • 基于 WFST 的语法,用于口语化硬类,例如 URL 和缩写。

  • 输入的正则表达式预处理,例如
    • 在字母数字单词中的 - 周围添加空格,例如 2-car -> 2 - car

    • 转换 Unicode 分数,例如 ½ 到 1/2

    • 规范化希腊字母和一些特殊字符,例如 + -> plus

  • Moses [NLP-TEXTNORM1] 输入的分词/预处理

  • 使用神经标记器和解码器进行推理

  • Moses 后处理/去分词

  • 基于 WFST 的语法,用于口语化一些 VERBATIM

  • TTS 的标点符号校正(使输出标点符号与输入形式匹配)

模型架构#

标记器模型首先使用 Transformer 编码器(例如,albert-base-v2)为每个输入标记构建上下文表示。然后,它使用分类头来预测每个标记的标签(例如,如果标记应保持不变,则其标签应为 SAME)。然后,解码器模型获取标记器识别的符号跨度,并将它们转换为适当的形式(例如,TN 的口语形式和 ITN 的书面形式)。解码器模型本质上是基于 Transformer 的编码器-解码器 seq2seq 模型(例如,示例训练脚本默认使用 T5-base 模型)。总的来说,我们的设计部分受到论文 Neural Models of Text Normalization for Speech Applications [NLP-TEXTNORM3] 中提出的基于 RNN 的滑动窗口模型的启发。

我们引入了一种简单而有效的技术,使我们的模型成为双工模型。根据模型处理的任务,我们将适当的前缀附加到输入。例如,假设我们要将文本 I live in 123 King Ave 转换为其口语形式(即,TN 问题),那么我们将简单地将前缀 tn 附加到它,因此我们模型的最终输入实际上将是 tn I live in tn 123 King Ave。类似地,对于 ITN 问题,我们只需将前缀 itn 附加到输入。

为了提高我们模型的有效性和鲁棒性,我们还在训练期间尝试了一些简单的数据增强技术。

用于训练 DuplexTaggerModel 的数据增强(默认设置为 False)#

在 Google 英语 TN 训练数据中,大约 93% 的标记不在任何符号跨度中。换句话说,大多数标记的真实标签都是微不足道的类型(即,SAMEPUNCT)。为了缓解这种类不平衡问题,对于每个具有多个符号跨度的原始实例,我们通过简单地将所有符号跨度连接在一起来创建一个新实例。例如,考虑以下 ITN 实例

原始实例:[The|SAME] [revenues|SAME] [grew|SAME] [a|SAME] [lot|SAME] [between|SAME] [two|B-TRANSFORM] [thousand|I-TRANSFORM] [two|I-TRANSFORM] [and|SAME] [two|B-TRANSFORM] [thousand|I-TRANSFORM] [five|I-TRANSFORM] [.|PUNCT]

增强实例:[two|B-TRANSFORM] [thousand|I-TRANSFORM] [two|I-TRANSFORM] [two|B-TRANSFORM] [thousand|I-TRANSFORM] [five|I-TRANSFORM]

配置文件中的参数 data.train_ds.tagger_data_augmentation 控制是否启用此数据增强。

用于训练 DuplexDecoderModel 的数据增强(默认设置为 True)#

由于标记器可能不完美,因此解码器的输入可能并非全部都是符号跨度。因此,为了使解码器对标记器的潜在错误更具鲁棒性,我们不仅使用符号跨度训练解码器,还使用一些其他更“嘈杂”的跨度进行训练。这样,即使标记器犯了一些错误,最终输出仍然有可能正确。

配置文件中的参数 data.train_ds.decoder_data_augmentation 控制是否启用此数据增强。

参考文献#

[NLP-TEXTNORM1]

Philipp Koehn, Hieu Hoang, Alexandra Birch, Chris Callison-Burch, Marcello Federico, Nicola Bertoldi, Brooke Cowan, Wade Shen, Christine Moran, Richard Zens, Chris Dyer, Ondřej Bojar, Alexandra Constantin, and Evan Herbst. Moses: open source toolkit for statistical machine translation. In Proceedings of the 45th Annual Meeting of the Association for Computational Linguistics Companion Volume Proceedings of the Demo and Poster Sessions, 177–180. Prague, Czech Republic, June 2007. Association for Computational Linguistics. URL: https://aclanthology.org/P07-2045.

[NLP-TEXTNORM2]

Richard Sproat and Navdeep Jaitly. Rnn approaches to text normalization: a challenge. arXiv preprint arXiv:1611.00068, 2016.

[NLP-TEXTNORM3]

Hao Zhang, R. Sproat, Axel H. Ng, Felix Stahlberg, Xiaochang Peng, Kyle Gorman, and B. Roark. Neural models of text normalization for speech applications. Computational Linguistics, pages 293–338, 2019.