Press "Enter" to skip to content

使用n-gram在🤗 Transformers中提升Wav2Vec2性能

使用n-gram在🤗 Transformers中提升Wav2Vec2性能 四海 第1张

Wav2Vec2是一种流行的预训练模型,用于语音识别。该模型由Meta AI Research于2020年9月发布,其创新的架构推动了自监督预训练在语音识别方面的进展,例如Ng等人,2021年,Chen等人,2021年,Hsu等人,2021年和Babu等人,2021年。在Hugging Face Hub上,Wav2Vec2最受欢迎的预训练检查点当前每月下载量超过250,000次。

使用连续时间分类(CTC),预训练的类似Wav2Vec2的检查点非常容易在下游语音识别任务上进行微调。简而言之,微调预训练的Wav2Vec2检查点的工作原理如下:

在预训练的检查点之上堆叠一个随机初始化的线性层,并训练它将原始音频输入分类为一系列字母。它通过以下方式实现:

  1. 从原始音频中提取音频表示(使用CNN层),
  2. 使用一堆transformer层处理音频表示的序列,和
  3. 将处理后的音频表示分类为一系列输出字母。

以前的音频分类模型需要额外的语言模型(LM)和字典,以将分类的音频帧序列转换为连贯的转录。Wav2Vec2的架构基于transformer层,因此每个处理后的音频表示都能从其他所有音频表示中获取上下文。此外,Wav2Vec2利用CTC算法进行微调,解决了“输入音频长度”与“输出文本长度”比例不同的对齐问题。

由于具有上下文化的音频分类和没有对齐问题,Wav2Vec2不需要外部语言模型或字典就能产生可接受的音频转录。

正如官方论文的附录C所示,Wav2Vec2在LibriSpeech上表现出色,而无需使用语言模型。然而,从附录中也可以清楚地看出,结合语言模型使用Wav2Vec2可以显著提高性能,特别是当模型仅在10分钟的转录音频上进行训练时。

直到最近,🤗 Transformers库没有提供一个简单的用户界面来使用经过微调的Wav2Vec2和语言模型解码音频文件。这个情况幸运地发生了改变。🤗 Transformers现在提供了与Kensho Technologies的pyctcdecode库的简单集成。本博客文章是一篇逐步的技术指南,解释了如何使用🤗 Datasets和🤗 Transformers创建一个n-gram语言模型,并将其与现有的经过微调的Wav2Vec2检查点结合使用。

我们首先进行以下步骤:

  1. 使用语言模型解码音频与不使用语言模型解码音频有何不同?
  2. 如何获取适合语言模型的数据?
  3. 如何使用KenLM构建n-gram模型?
  4. 如何将n-gram模型与经过微调的Wav2Vec2检查点结合使用?

如果想深入了解Wav2Vec2的工作原理(不是本博客文章所必需的),建议阅读以下资料:

  • wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations
  • Fine-Tune Wav2Vec2 for English ASR with 🤗 Transformers
  • An Illustrated Tour of Wav2vec 2.0

1. 使用Wav2Vec2和语言模型解码音频数据

如在🤗 Transformers的Wav2Vec2示例文档中所示,音频可以进行如下转录。

首先,我们安装datasetstransformers

pip install datasets transformers

让我们加载Librispeech数据集的一个小片段,以展示Wav2Vec2的语音转录能力。

from datasets import load_dataset

dataset = load_dataset("hf-internal-testing/librispeech_asr_demo", "clean", split="validation")
dataset

输出:

    重用数据集librispeech_asr(/root/.cache/huggingface/datasets/hf-internal-testing___librispeech_asr/clean/2.1.0/f2c70a4d03ab4410954901bde48c54b85ca1b7f9bf7d616e7e2a72b5ee6ddbfc)

    数据集({
        特征:['文件','音频','文本','说话者ID','章节ID','ID'],
        行数:73
    })

我们可以选择其中一个73个音频样本并进行播放。

audio_sample = dataset[2]
audio_sample["text"].lower()

输出:

    他告诉我们,这是一年中这个节日季节,圣诞节和烤牛肉在我们面前,从吃和它的结果中提取的比喻最容易出现在脑海中

选择了一个数据样本后,我们现在加载微调模型和处理器。

from transformers import Wav2Vec2Processor, Wav2Vec2ForCTC

processor = Wav2Vec2Processor.from_pretrained("facebook/wav2vec2-base-100h")
model = Wav2Vec2ForCTC.from_pretrained("facebook/wav2vec2-base-100h")

接下来,我们处理数据

inputs = processor(audio_sample["audio"]["array"], sampling_rate=audio_sample["audio"]["sampling_rate"], return_tensors="pt")

将其输入模型

import torch

with torch.no_grad():
  logits = model(**inputs).logits

解码它

predicted_ids = torch.argmax(logits, dim=-1)
transcription = processor.batch_decode(predicted_ids)

transcription[0].lower()

输出:

'他告诉我们,这是一年中这个节日季节,圣诞节和烤牛肉在我们面前,从吃和它的结果中提取的比喻最容易出现在脑海中'

将转录与上述目标转录进行比较,我们可以看到一些单词听起来正确,但拼写不正确,例如:

  • christmaus与christmas
  • rose与roast
  • simalyis与similes

让我们看看是否将Wav2Vec2与n-gram语言模型结合起来可以帮助解决这个问题。

首先,我们需要安装pyctcdecodekenlm

pip install https://github.com/kpu/kenlm/archive/master.zip pyctcdecode

为了演示目的,我们准备了一个新的模型仓库patrickvonplaten/wav2vec2-base-100h-with-lm,其中包含相同的Wav2Vec2检查点,但还有一个额外的4-gram英语语言模型。

这次我们不使用Wav2Vec2Processor,而是使用Wav2Vec2ProcessorWithLM来加载4-gram模型,以及特征提取器和分词器。

from transformers import Wav2Vec2ProcessorWithLM

processor = Wav2Vec2ProcessorWithLM.from_pretrained("patrickvonplaten/wav2vec2-base-100h-with-lm")

与无语言模型解码音频不同,处理器现在直接接收模型的输出logits,而不是上面的argmax(logits)(称为predicted_ids)。原因是在使用语言模型进行解码时,处理器在每个时间步骤上考虑到了所有可能输出字符的概率。让我们看一下logits输出的维度。

logits.shape

输出:

    torch.Size([1, 624, 32])

我们可以看到logits对应于一系列624个向量,每个向量有32个条目。其中的每个32个条目代表模型的32个可能输出字符之一的逻辑概率:

" ".join(sorted(processor.tokenizer.get_vocab()))

输出:

"' </s> <pad> <s> <unk> A B C D E F G H I J K L M N O P Q R S T U V W X Y Z |"

直观地,人们可以理解 Wav2Vec2ProcessorWithLM 的解码过程是通过一个大小为 624×32 的概率矩阵进行波束搜索,同时利用由 n-gram 语言模型给出的下一个字母的概率。

好的,让我们再次运行解码步骤。由于 pyctcdecode 语言模型解码器不会自动将 torch 张量转换为 numpy,因此在进行之前我们需要自己进行转换。

transcription = processor.batch_decode(logits.numpy()).text
transcription[0].lower()

输出:

'他告诉我们,每年的这个节日季节里,圣诞节和玫瑰牛肉在我们面前矗立起来,从吃和吃的结果中得出的比喻最容易出现在脑海中'

太棒了!回想起之前没有语言模型的情况下错误地转录了 facebook/wav2vec2-base-100h 的词语,比如:

  • christmaus vs. christmas
  • rose vs. roast
  • simalyis vs. similes

我们可以再次查看带有 4-gram 语言模型的 facebook/wav2vec2-base-100h 的转录结果。其中有 3 个错误中有 2 个被纠正了;christmas 和 similes 被正确地转录。

有趣的是,rose 的错误转录仍然存在。然而,这并不应该让我们感到意外。没有语言模型的音频解码更容易出现拼写错误,比如 christmaus 或 similes(据我所知,这些词在英语中并不存在)。这是因为语音识别系统几乎完全依赖于给定的声学输入进行预测,而不是真正基于先前和后续预测字母的语言建模上下文1 {}^1 1 。另一方面,如果我们添加一个语言模型,我们可以相当确定语音识别系统将大大减少拼写错误,因为经过良好训练的 n-gram 模型肯定不会预测出拼写错误的单词。但是,rose 是一个合法的英语单词,因此 4-gram 将以不可忽视的概率预测出这个单词。

语言模型本身很可能更偏好于正确的 roast 这个词,因为 roast beef 这个词组在英语中比 rose beef 更常见。因为最终的转录结果是由 facebook/wav2vec2-base-100h 的输出概率和 n-gram 语言模型的概率的加权组合得出的,所以看到 rose 等错误转录的单词是很常见的。

有关如何在使用 Wav2Vec2ProcessorWithLM 进行解码时调整不同参数的更多信息,请查看官方文档。


1 {}^1 1 一些研究表明,诸如 facebook/wav2vec2-base-100h 这样的模型——当足够大且经过充分训练的数据训练时——可以学习到类似于语言模型的中间音频表示之间的语言建模依赖关系。

太棒了,现在您已经了解了添加 n-gram 语言模型的优势,让我们深入了解如何从头开始创建一个 n-gram 和 Wav2Vec2ProcessorWithLM

2. 获取语言模型的数据

对于一个有用的语音识别系统来说,一个语言模型应该支持声学模型(例如 Wav2Vec2)在预测下一个单词(或标记、字母)时,能够对以下分布进行建模:P ( w n ∣ w 0 t − 1 ) \mathbf{P}(w_n | \mathbf{w}_0^{t-1}) P ( w n ​ ∣ w 0 t − 1 ​ ) ,其中 w n w_n w n ​ 是下一个单词,w 0 t − 1 \mathbf{w}_0^{t-1} w 0 t − 1 ​ 是自话语开始以来所有先前转录的单词序列。简单来说,语言模型应该能够在给定所有先前转录的单词的情况下,不论给出给语音识别系统的音频输入如何,很好地预测下一个单词。

一如既往,语言模型的好坏取决于它所训练的数据。在语音识别的情况下,我们应该问自己,语音识别将用于什么类型的数据:对话、有声读物、电影、演讲等等?

语言模型应该擅长建模与语音识别系统的目标转录相对应的语言。为了演示目的,我们在瑞典的 Common Voice 7 上对预训练的 facebook/wav2vec2-xls-r-300m 进行了微调。可以在这里找到微调后的检查点。Common Voice 7 是一个相对众包的语音数据集,我们将在其测试数据上评估模型。

现在让我们在 Hugging Face Hub 上寻找合适的文本数据。我们搜索所有包含瑞典数据的数据集。在浏览数据集时,我们正在寻找一个与 Common Voice 的语音数据相似的数据集。这里的明显选择 oscar 和 mc4 可能不是最合适的,因为它们:

  • 是从网络爬取生成的,可能不太干净,与口语不符
  • 需要大量的预处理
  • 非常大,这对于演示目的不理想😉

在这里,一个看起来合理且相对干净且易于预处理的数据集是 europarl_bilingual,因为它是基于欧洲议会的讨论和演讲的数据集。因此,它应该相对干净且与有声读物数据相符。该数据集最初设计用于机器翻译,因此只能访问翻译对中的目标语言文本(瑞典语 sv )。

target_lang="sv"  # 根据你的目标语言进行更改

让我们下载数据。

from datasets import load_dataset

dataset = load_dataset("europarl_bilingual", lang1="en", lang2=target_lang, split="train")

我们看到数据相当大 – 它有一百多万个翻译。由于它只是文本数据,所以处理起来应该相对容易。

接下来,让我们看看在对瑞典进行微调的 XLS-R 检查点训练时如何预处理数据。通过查看 run.sh 文件,我们可以看到以下字符已从官方转录中删除:

chars_to_ignore_regex = '[,?.!\-\;\:"“%‘”�—’…–]'  # 根据你的微调模型中要忽略的字符进行更改

让我们在这里做同样的操作,以使我们的语言模型的字母表与微调的声学检查点的字母表匹配。

我们可以编写一个单独的映射函数来提取瑞典文本并立即处理它。

import re

def extract_text(batch):
  text = batch["translation"][target_lang]
  batch["text"] = re.sub(chars_to_ignore_regex, "", text.lower())
  return batch

让我们应用 .map() 函数。这应该大约需要 5 分钟。

dataset = dataset.map(extract_text, remove_columns=dataset.column_names)

太棒了。让我们将其上传到 Hub,以便我们可以更好地检查和重用它。

您可以通过执行以下单元格登录。

from huggingface_hub import notebook_login

notebook_login()

输出:

    登录成功
    您的令牌已保存到 /root/.huggingface/token
    通过 git-credential store 进行身份验证,但这不是您的机器上定义的助手。
    如果要将此凭据助手设置为默认值,则可能必须在推送到 Hugging Face Hub 时重新进行身份验证
    在终端中运行以下命令

    git config --global credential.helper store

接下来,我们调用 🤗 Hugging Face 的 push_to_hub 方法将数据集上传到 repo "sv_corpora_parliament_processed"

dataset.push_to_hub(f"{target_lang}_corpora_parliament_processed", split="train")

这很简单!上传新数据集时自动启用数据集查看器非常方便。您现在可以直接在线查看数据集了。

随意查看我们预处理后的数据集,位于 hf-test/sv_corpora_parliament_processed 。尽管我们不是瑞典语的母语者,但我们可以看到数据经过了良好的处理,似乎很干净。

接下来,让我们使用这些数据构建一个语言模型。

3. 使用 KenLM 构建 n-gram

尽管基于 Transformer 架构的大型语言模型已经成为 NLP 的标准,但在提升语音识别系统中,使用 n-gram 语言模型仍然非常常见 – 如第 1 节所示。

再次查看 Wav2Vec2 论文附录 C 的表 9,可以注意到使用基于 Transformer 的语言模型进行解码明显比使用 n-gram 模型取得更好的结果,但 n-gram 和基于 Transformer 的语言模型之间的差异远不及 n-gram 和无语言模型之间的差异显著。

例如,对于仅在 10 分钟上进行微调的大型 Wav2Vec2 检查点,与无语言模型相比,n-gram 可以将词错误率 (WER) 减少约 80%,而基于 Transformer 的语言模型仅能将 WER 再减少 23%。随着声学模型训练的数据越多,相对 WER 的减少也会减少。例如,对于大型检查点,基于 Transformer 的语言模型仅能将 WER 减少 8%,而 n-gram 仍然比无语言模型减少 21% 的 WER。

选择 n-gram 而不是基于 Transformer 的语言模型的原因是 n-gram 的计算成本显著较小。对于 n-gram,检索给定前一个单词的概率几乎只需要像查询查找表或树状数据存储一样计算开销小 – 即相对于现代基于 Transformer 的语言模型来说非常快,后者需要进行完整的前向传递来检索下一个单词的概率。

关于 n-gram 的工作原理以及它们为何(仍然)对语音识别非常有用的更多信息,建议读者参考斯坦福大学的这篇优秀总结。

很好,让我们逐步了解如何构建一个 n-gram。我们将使用流行的 KenLM 库来完成。首先,让我们安装 Ubuntu 库的先决条件:

sudo apt install build-essential cmake libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-test-dev libeigen3-dev zlib1g-dev libbz2-dev liblzma-dev

在下载和解压 KenLM 存储库之前。

wget -O - https://kheafield.com/code/kenlm.tar.gz | tar xz

KenLM 是用 C++ 编写的,因此我们将使用 cmake 来构建二进制文件。

mkdir kenlm/build && cd kenlm/build && cmake .. && make -j2
ls kenlm/build/bin

很好,如我们所见,可执行函数已经成功构建在 kenlm/build/bin/ 下。

KenLM 默认使用 Kneser-Ney 平滑计算 n-gram。创建 n-gram 的所有文本数据都应存储在一个文本文件中。我们下载数据集,并将其保存为 .txt 文件。

from datasets import load_dataset

username = "hf-test"  # 更改为您的用户名

dataset = load_dataset(f"{username}/{target_lang}_corpora_parliament_processed", split="train")

with open("text.txt", "w") as file:
  file.write(" ".join(dataset["text"]))

现在,我们只需运行 KenLM 的 lmplz 命令来构建我们的 n-gram,称为 "5gram.arpa"。由于在语音识别中相对常见,我们通过传递 -o 5 参数来构建一个 5-gram。有关使用 KenLM 可以构建的不同 n-gram 语言模型的更多信息,可以参考 KenLM 的官方网站。

执行下面的命令可能需要一分钟左右。

kenlm/build/bin/lmplz -o 5 <"text.txt" > "5gram.arpa"

输出:

    === 1/5 计数和排序 n-gram ===
    读取 /content/swedish_text.txt
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    tcmalloc: 分配了 1918697472 字节 == 0x55d40d0f0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b28c51e 0x55d40b26b2eb 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    tcmalloc: 分配了 8953896960 字节 == 0x55d47f6c0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26b308 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    ****************************************************************************************************
    一元词令牌 42153890 类型 360209
    === 2/5 计算和排序调整计数 ===
    链大小: 1:4322508 2:1062772928 3:1992699264 4:3188318720 5:4649631744
    tcmalloc: 分配了 4649631744 字节 == 0x55d40d0f0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26b8d7 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    tcmalloc: 分配了 1992704000 字节 == 0x55d561ce0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26bcdd 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    tcmalloc: 分配了 3188326400 字节 == 0x55d695a86000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26bcdd 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    统计信息:
    1 360208 D1=0.686222 D2=1.01595 D3+=1.33685
    2 5476741 D1=0.761523 D2=1.06735 D3+=1.32559
    3 18177681 D1=0.839918 D2=1.12061 D3+=1.33794
    4 30374983 D1=0.909146 D2=1.20496 D3+=1.37235
    5 37231651 D1=0.944104 D2=1.25164 D3+=1.344
    二进制语言模型的内存估计:
    类型      MB
    探测   1884 假设 -p 1.5
    探测   2195 假设 -r models -p 1.5
    trie   922 未进行量化
    trie   518 假设 -q 8 -b 8 进行量化
    trie   806 假设 -a 22 进行数组指针压缩
    trie   401 假设 -a 22 -q 8 -b 8 进行数组指针压缩和量化
    === 3/5 计算和排序初始概率 ===
    链大小: 1:4322496 2:87627856 3:363553620 4:728999592 5:1042486228
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    ####################################################################################################
    === 4/5 计算和写入插值概率 ===
    链大小: 1:4322496 2:87627856 3:363553620 4:728999592 5:1042486228
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    ####################################################################################################
    === 5/5 写入 ARPA 模型 ===
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    ****************************************************************************************************
    名称:lmplz  VmPeak:14181536 kB  VmRSS:2199260 kB    RSSMax:4160328 kB   user:120.598    sys:26.6659 CPU:147.264 real:136.344

太好了,我们已经构建了一个5-gram语言模型!让我们检查一下前几行。

head -20 5gram.arpa

输出:

    \data\
    ngram 1=360208
    ngram 2=5476741
    ngram 3=18177681
    ngram 4=30374983
    ngram 5=37231651

    \1-grams:
    -6.770219   <unk> 0
    0   <s>   -0.11831701
    -4.6095004  återupptagande  -1.2174699
    -2.2361007  av  -0.79668784
    -4.8163533  sessionen   -0.37327805
    -2.2251768  jag -1.4205662
    -4.181505   förklarar   -0.56261665
    -3.5790775  europaparlamentets  -0.63611007
    -4.771945   session -0.3647111
    -5.8043895  återupptagen    -0.3058712
    -2.8580177  efter   -0.7557702
    -5.199537   avbrottet   -0.43322718

有一个小问题,🤗 Transformers稍后可能不会满意。5-gram中正确包含了一个”Unknown”或<unk>标记,以及一个句子的开头标记<s>,但没有句子的结束标记</s>。很遗憾,目前必须在构建之后进行更正。

我们可以通过在开头标记下方添加一行0 </s> -0.11831701来简单地添加句子的结束标记,并将ngram 1的计数增加1。由于文件大约有1亿行,这个命令大约需要2分钟。

with open("5gram.arpa", "r") as read_file, open("5gram_correct.arpa", "w") as write_file:
  has_added_eos = False
  for line in read_file:
    if not has_added_eos and "ngram 1=" in line:
      count=line.strip().split("=")[-1]
      write_file.write(line.replace(f"{count}", f"{int(count)+1}"))
    elif not has_added_eos and "<s>" in line:
      write_file.write(line)
      write_file.write(line.replace("<s>", "</s>"))
      has_added_eos = True
    else:
      write_file.write(line)

现在让我们检查修正后的5-gram。

head -20 5gram_correct.arpa

输出:

    \data\
    ngram 1=360209
    ngram 2=5476741
    ngram 3=18177681
    ngram 4=30374983
    ngram 5=37231651

    \1-grams:
    -6.770219   <unk> 0
    0   <s>   -0.11831701
    0   </s>  -0.11831701
    -4.6095004  återupptagande  -1.2174699
    -2.2361007  av  -0.79668784
    -4.8163533  sessionen   -0.37327805
    -2.2251768  jag -1.4205662
    -4.181505   förklarar   -0.56261665
    -3.5790775  europaparlamentets  -0.63611007
    -4.771945   session -0.3647111
    -5.8043895  återupptagen    -0.3058712
    -2.8580177  efter   -0.7557702

太好了,看起来好多了!我们到此为止已经完成了,现在只需要正确地集成"ngram"pyctcdecode和🤗 Transformers中。

4. 使用 n-gram 结合 Wav2Vec2

在最后一步中,我们想要将 5-gram 包装成一个 Wav2Vec2ProcessorWithLM 对象,使得 5-gram 增强解码像第一部分展示的那样无缝。我们首先下载当前的“无语言模型”的 xls-r-300m-sv 处理器。

from transformers import AutoProcessor

processor = AutoProcessor.from_pretrained("hf-test/xls-r-300m-sv")

接下来,我们提取其分词器的词汇表,因为它代表了 pyctcdecodeBeamSearchDecoder 类的“标签”。

vocab_dict = processor.tokenizer.get_vocab()
sorted_vocab_dict = {k.lower(): v for k, v in sorted(vocab_dict.items(), key=lambda item: item[1])}

“标签”和之前构建的 5gram_correct.arpa 文件是构建解码器所需的全部内容。

from pyctcdecode import build_ctcdecoder

decoder = build_ctcdecoder(
    labels=list(sorted_vocab_dict.keys()),
    kenlm_model_path="5gram_correct.arpa",
)

输出:

    Found entries of length > 1 in alphabet. This is unusual unless style is BPE, but the alphabet was not recognized as BPE type. Is this correct?
    Unigrams and labels don't seem to agree.

我们可以安全地忽略这个警告,现在只需要将刚创建的 decoder ,以及处理器的 tokenizerfeature_extractor 包装到一个 Wav2Vec2ProcessorWithLM 类中。

from transformers import Wav2Vec2ProcessorWithLM

processor_with_lm = Wav2Vec2ProcessorWithLM(
    feature_extractor=processor.feature_extractor,
    tokenizer=processor.tokenizer,
    decoder=decoder
)

我们希望直接将增强语言模型的处理器上传到 xls-r-300m-sv 的模型文件夹中,以便将所有相关文件放在一个地方。

让我们克隆这个仓库,添加新的解码器文件,然后上传它们。首先,我们需要安装 git-lfs

sudo apt-get install git-lfs tree

使用 huggingface_hubRepository 类可以方便地完成克隆和上传建模文件。

如需了解如何使用 huggingface_hub 上传任何文件的更多信息,请参阅官方文档。

from huggingface_hub import Repository

repo = Repository(local_dir="xls-r-300m-sv", clone_from="hf-test/xls-r-300m-sv")

输出:

    Cloning https://huggingface.co/hf-test/xls-r-300m-sv into local empty directory.

克隆了 xls-r-300m-sv 后,让我们将新的带有语言模型的处理器保存到其中。

processor_with_lm.save_pretrained("xls-r-300m-sv")

让我们检查本地仓库。tree 命令还可以方便地显示不同文件的大小。

tree -h xls-r-300m-sv/

输出:

    xls-r-300m-sv/
    ├── [  23]  added_tokens.json
    ├── [ 401]  all_results.json
    ├── [ 253]  alphabet.json
    ├── [2.0K]  config.json
    ├── [ 304]  emissions.csv
    ├── [ 226]  eval_results.json
    ├── [4.0K]  language_model
    │   ├── [4.1G]  5gram_correct.arpa
    │   ├── [  78]  attrs.json
    │   └── [4.9M]  unigrams.txt
    ├── [ 240]  preprocessor_config.json
    ├── [1.2G]  pytorch_model.bin
    ├── [3.5K]  README.md
    ├── [4.0K]  runs
    │   └── [4.0K]  Jan09_22-00-50_brutasse
    │       ├── [4.0K]  1641765760.8871996
    │       │   └── [4.6K]  events.out.tfevents.1641765760.brutasse.31164.1
    │       ├── [ 42K]  events.out.tfevents.1641765760.brutasse.31164.0
    │       └── [ 364]  events.out.tfevents.1641794162.brutasse.31164.2
    ├── [1.2K]  run.sh
    ├── [ 30K]  run_speech_recognition_ctc.py
    ├── [ 502]  special_tokens_map.json
    ├── [ 279]  tokenizer_config.json
    ├── [ 29K]  trainer_state.json
    ├── [2.9K]  training_args.bin
    ├── [ 196]  train_results.json
    ├── [ 319]  vocab.json
    └── [4.0K]  wandb
        ├── [  52]  debug-internal.log -> run-20220109_220240-1g372i3v/logs/debug-internal.log
        ├── [  43]  debug.log -> run-20220109_220240-1g372i3v/logs/debug.log
        ├── [  28]  latest-run -> run-20220109_220240-1g372i3v
        └── [4.0K]  run-20220109_220240-1g372i3v
            ├── [4.0K]  files
            │   ├── [8.8K]  conda-environment.yaml
            │   ├── [140K]  config.yaml
            │   ├── [4.7M]  output.log
            │   ├── [5.4K]  requirements.txt
            │   ├── [2.1K]  wandb-metadata.json
            │   └── [653K]  wandb-summary.json
            ├── [4.0K]  logs
            │   ├── [3.4M]  debug-internal.log
            │   └── [8.2K]  debug.log
            └── [113M]  run-1g372i3v.wandb

    9 directories, 34 files

如图所示,5-gram LM非常庞大——超过4GB。为了减小n-gram的大小并加快加载速度,kenLM允许使用build_binary可执行文件将.arpa文件转换为二进制文件。

让我们在这里使用它。

kenlm/build/bin/build_binary xls-r-300m-sv/language_model/5gram_correct.arpa xls-r-300m-sv/language_model/5gram.bin

输出:

    正在读取xls-r-300m-sv/language_model/5gram_correct.arpa
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    ****************************************************************************************************
    成功

太好了,成功了!让我们删除.arpa文件并检查二进制5-gram LM的大小。

rm xls-r-300m-sv/language_model/5gram_correct.arpa && tree -h xls-r-300m-sv/

输出:

    xls-r-300m-sv/
    ├── [  23]  added_tokens.json
    ├── [ 401]  all_results.json
    ├── [ 253]  alphabet.json
    ├── [2.0K]  config.json
    ├── [ 304]  emissions.csv
    ├── [ 226]  eval_results.json
    ├── [4.0K]  language_model
    │   ├── [1.8G]  5gram.bin
    │   ├── [  78]  attrs.json
    │   └── [4.9M]  unigrams.txt
    ├── [ 240]  preprocessor_config.json
    ├── [1.2G]  pytorch_model.bin
    ├── [3.5K]  README.md
    ├── [4.0K]  runs
    │   └── [4.0K]  Jan09_22-00-50_brutasse
    │       ├── [4.0K]  1641765760.8871996
    │       │   └── [4.6K]  events.out.tfevents.1641765760.brutasse.31164.1
    │       ├── [ 42K]  events.out.tfevents.1641765760.brutasse.31164.0
    │       └── [ 364]  events.out.tfevents.1641794162.brutasse.31164.2
    ├── [1.2K]  run.sh
    ├── [ 30K]  run_speech_recognition_ctc.py
    ├── [ 502]  special_tokens_map.json
    ├── [ 279]  tokenizer_config.json
    ├── [ 29K]  trainer_state.json
    ├── [2.9K]  training_args.bin
    ├── [ 196]  train_results.json
    ├── [ 319]  vocab.json
    └── [4.0K]  wandb
        ├── [  52]  debug-internal.log -> run-20220109_220240-1g372i3v/logs/debug-internal.log
        ├── [  43]  debug.log -> run-20220109_220240-1g372i3v/logs/debug.log
        ├── [  28]  latest-run -> run-20220109_220240-1g372i3v
        └── [4.0K]  run-20220109_220240-1g372i3v
            ├── [4.0K]  files
            │   ├── [8.8K]  conda-environment.yaml
            │   ├── [140K]  config.yaml
            │   ├── [4.7M]  output.log
            │   ├── [5.4K]  requirements.txt
            │   ├── [2.1K]  wandb-metadata.json
            │   └── [653K]  wandb-summary.json
            ├── [4.0K]  logs
            │   ├── [3.4M]  debug-internal.log
            │   └── [8.2K]  debug.log
            └── [113M]  run-1g372i3v.wandb

    9个目录,34个文件

好的,我们将n-gram减少了一半以上,现在不到2GB。在最后一步,让我们上传所有文件。

repo.push_to_hub(commit_message="Upload lm-boosted decoder")

输出:

    Git LFS: (1 of 1 files) 1.85 GB / 1.85 GB
    Counting objects: 9, done.
    Delta compression using up to 2 threads.
    Compressing objects: 100% (9/9), done.
    Writing objects: 100% (9/9), 1.23 MiB | 1.92 MiB/s, done.
    Total 9 (delta 3), reused 0 (delta 0)
    To https://huggingface.co/hf-test/xls-r-300m-sv
       27d0c57..5a191e2  main -> main

就这样。现在您应该能够按照第1节中所示使用5gram进行LM-boosted解码。

xls-r-300m-sv的模型卡片所示,我们的5gram LM-boosted解码器在Common Voice的7个测试集上的WER为18.85%,相对性能约为30%🔥。

Leave a Reply

Your email address will not be published. Required fields are marked *