Open In Colab 要在GitHub上执行或查看/下载此笔记本

文本分词

为什么我们需要分词?

几乎所有语言都有大量的可能词汇。因此,处理文本的机器学习任务必须支持可能包含数千个单词的大型词汇表。然而,处理如此大的词汇表是至关重要的。输入和输出嵌入(例如one-hot-vectors)通常是巨大的向量,导致内存消耗和内存使用增加。更重要的是,使用如此稀疏和高维的嵌入进行学习可能不是最优的。

一个简单的替代方法可以是简单地使用字符而不是单词。 后一种方法缓解了上述一些问题,但 它需要处理更长的序列(从机器学习的角度来看,这也是至关重要的)。

我们能在单词和字符之间找到一个折衷方案吗?是的,这正是分词器试图做的事情。

一种流行的技术称为基于规则的分词(例如spaCy),允许根据语法规则、空格和标点符号将文本分割成更小的块。不幸的是,这种方法依赖于语言,必须为每种考虑的语言进行设置……

另一种结合词级和字符级分词优势的解决方案是一种名为子词分词的混合解决方案,它基于这样一个原则:常用词不应被分割成更小的子词,而稀有词应被分解为有意义的(即更常见的)子词。

SpeechBrain 目前依赖于一个自定义的 SentencePiece 分词器 集成,该分词器将输入视为原始输入流。支持以下分词器算法:

  1. BPE.

  2. Unigram (子词正则化).

SentencePiece 分词器可在 speechbrain.tokenizer.SentencePiece 中找到。接下来,我们将描述所有上述技术,但首先,让我们安装 SpeechBrain。

%%capture
# Installing SpeechBrain via pip
BRANCH = 'develop'
!python -m pip install git+https://github.com/speechbrain/speechbrain.git@$BRANCH

# Clone SpeechBrain repository
!git clone https://github.com/speechbrain/speechbrain/
%cd /content/speechbrain/

我们还下载一个csv文件来训练我们的分词器。

%%capture
!wget https://www.dropbox.com/s/atg0zycfbacmwqi/dev-clean.csv

在SpeechBrain中训练sentencepiece分词器

SentencePiece 是一个可以用少量参数实例化的类

  • model_dir: 这是保存训练好的分词器模型的目录。模型将保存为 model_dir/model_type_vocab_size.model

  • vocab_sizes: 它是所选分词器类型(BPE, Unigram)的词汇表大小。对于字符分词,vocab_size 是可选的,而对于 BPE 和 unigram 分词,vocab_size 是必需的。

  • csv_train: 这是用于学习分词器的csv文件的路径。

  • csv_read: 这是数据条目(csv 头),包含 csv 文件中的单词序列。

  • model_type: 它可以是:word, char, bpe, 或 unigram 分词。

现在让我们将其应用到我们的 dev-clean.csv。

import torch
from speechbrain.tokenizers.SentencePiece import SentencePiece
spm = SentencePiece(model_dir="tokenizer_data",
                    vocab_size=2000,
                    annotation_train="dev-clean.csv",
                    annotation_read="wrd",
                    model_type="bpe",
                    annotation_list_to_check=["dev-clean.csv"])
%less tokenizer_data/2000_bpe.vocab

如你所见,SetencePiece 库是一个无监督的文本分词器和去分词器。一些标记包含表示空格的 _ 符号。句子片段去分词将简单地合并标记序列,并将 _ 替换为空格。

高级参数

  • character_coverage: 这是模型覆盖的字符数量(值在[0.98 - 1]之间)。默认值:对于字符集较小的语言为1.0。对于字符集丰富的语言,如日语或中文,可以设置为0.995。

  • bos_id/eos_id/pad_id/unk_id: 允许用户为bos/eos/pad unk标记定义特定的索引

  • split_by_whitespace: 此参数允许sentencepiece提取填字游戏片段并将空格视为唯一标记。

  • num_sequences: 最多使用 num_sequences 来训练分词器(限制大型数据集的训练文本)。

  • csv_list_to_check: 用于检查从分词器中恢复单词准确性的CSV文件列表。

  • user_defined_symbols: 它是一个字符串列表(用逗号‘,’分隔),用于强制插入特定的词汇。

例如,如果我们将character_coverage设置为0.98并减少vocab_size

spm = SentencePiece(model_dir="tokenizer_data",
                    vocab_size=500,
                    annotation_train="dev-clean.csv",
                    annotation_read="wrd",
                    model_type="unigram",
                    character_coverage=0.98,
                    annotation_list_to_check=["dev-clean.csv"])

正如我们所看到的,我们无法从文本中恢复所有单词,因为缺少一些字符。

在SpeechBrain中加载预训练的句子片段分词器

加载sentencepiece分词器非常简单。我们只需要指定模型的路径、vocab_sizemodel_type

spm = SentencePiece(model_dir="tokenizer_data",
                    vocab_size=2000,
                    model_type="bpe")

现在,我们可以直接使用从tokenizer_data/2000_bpe.model加载的分词器。这个功能对于复制结果非常有用。例如,你可以将你的分词器上传到互联网上,其他人可以下载它以获得与你相同的分词结果。

如何使用sentencepiece

SentencePiece 对象可在 speechbrain.tokenizer.SentencePiece.sp 中找到。通过访问此对象,您可以轻松执行分词和去分词。如果您对 SentencePiece 的所有功能感兴趣,请随时阅读 官方教程

让我们尝试对一些文本进行分词和去分词!

# Encode as pieces
print(spm.sp.encode_as_pieces('THIS IS A TEST'))
# Encode as ids
print(spm.sp.encode_as_ids('THIS IS A TEST'))
# Decode from ids
print(spm.sp.decode_ids([244, 177, 3, 1, 97]))
# Decode from pieces
print(spm.sp.decode_pieces(['▁THIS', '▁IS', '▁A', '▁T', 'EST']))

使用SpeechBrain SentencePiece与Pytorch

我们设计了SentencePiece包装器,以便与我们的数据转换管道(参见教程)联合使用,从而处理张量。 为此,提供了两种选项:

  1. 选项1:直接从单词张量生成标记张量 + 一个名为 int2lab 的外部字典(将你的张量映射到单词)。

  2. 选项2:如果您使用我们的DynamicDataset,DynamicItem将自动生成令牌张量。

选项1的示例

# INPUTS
# word vocab
dict_int2lab = {1: "HELLO", 2: "WORLD", 3: "GOOD", 4:"MORNING"}
# wrd tensors
wrd_tensor = torch.Tensor([[1, 2, 0], [3,4,2]])
# relative lens tensor (will help for dealing with padding)
lens_tensor = torch.Tensor([0.75, 1.0])

我们的SentencePiece可以像任何其他pytorch函数一样调用,将张量传递给call方法。参数如下: batch : 它是一个word_ids张量(即你的单词)。形状:[batch_size, max_seq_lenght] batch_lens: 它是一个相对长度张量。形状:[batch_size] int2lab: 将word_ids映射到单词的字典。 task: “encode”: 将单词批次张量转换为标记张量。 “decode”: 将标记张量转换为单词序列列表。 “decode_from_list”: 将标记序列列表转换为单词序列列表。

encoded_seq_ids, encoded_seq_lens = spm(
        wrd_tensor,
        lens_tensor,
        dict_int2lab,
        "encode",
    )
# tokens tensor
print(encoded_seq_ids)
# relative lens token tensor
print(encoded_seq_lens)

然后我们可以通过简单地指定"decode"给函数来解码它!

# decode from torch tensors (batch, batch_lens)
words_seq = spm(encoded_seq_ids, encoded_seq_lens, task="decode")
print(words_seq)

选项2的示例

注意:请先阅读我们的数据输入输出教程,以便完全理解接下来的内容。

在这里,我们使用一个分词器来即时对从.csv文件中获取的文本进行分词。在下面的示例中,我们将其与SpeechBrain的data_io管道结合使用。

首先,我们从我们的csv文件中定义一个DynamicItemDataset:

import speechbrain as sb
train_set = sb.dataio.dataset.DynamicItemDataset.from_csv(
        csv_path="dev-clean.csv",
)
%less dev-clean.csv

然后,我们定义text_pipeline(即对每个小批量中收集的样本调用的内容)。在text_pipeline中,我们只需调用我们的tokenizer来获取标记化的文本!

    @sb.utils.data_pipeline.takes("wrd")
    @sb.utils.data_pipeline.provides(
        "wrd", "tokens_list", "tokens"
    )
    def text_pipeline(wrd):
        yield wrd
        tokens_list = spm.sp.encode_as_ids(wrd)
        yield tokens_list
        tokens = torch.LongTensor(tokens_list)
        yield tokens

更多关于SpeechBrain的内容,用于完成数据管道的最终处理:

train_set.add_dynamic_item(text_pipeline)
train_set.set_output_keys(["wrd", "tokens", "tokens_list"])

最后,我们创建一个包含定义转换(即分词器)的数据加载器。

train_dataloader = sb.dataio.dataloader.make_dataloader(train_set, batch_size=1)

现在,我们可以简单地获取我们的标记化样本 !!

b = next(iter(train_dataloader))
print(b.wrd)
print(b.tokens)
print(b.tokens_list)

引用SpeechBrain

如果您在研究中或业务中使用SpeechBrain,请使用以下BibTeX条目引用它:

@misc{speechbrainV1,
  title={Open-Source Conversational AI with {SpeechBrain} 1.0},
  author={Mirco Ravanelli and Titouan Parcollet and Adel Moumen and Sylvain de Langen and Cem Subakan and Peter Plantinga and Yingzhi Wang and Pooneh Mousavi and Luca Della Libera and Artem Ploujnikov and Francesco Paissan and Davide Borra and Salah Zaiem and Zeyu Zhao and Shucong Zhang and Georgios Karakasidis and Sung-Lin Yeh and Pierre Champion and Aku Rouhe and Rudolf Braun and Florian Mai and Juan Zuluaga-Gomez and Seyed Mahed Mousavi and Andreas Nautsch and Xuechen Liu and Sangeet Sagar and Jarod Duret and Salima Mdhaffar and Gaelle Laperriere and Mickael Rouvier and Renato De Mori and Yannick Esteve},
  year={2024},
  eprint={2407.00463},
  archivePrefix={arXiv},
  primaryClass={cs.LG},
  url={https://arxiv.org/abs/2407.00463},
}
@misc{speechbrain,
  title={{SpeechBrain}: A General-Purpose Speech Toolkit},
  author={Mirco Ravanelli and Titouan Parcollet and Peter Plantinga and Aku Rouhe and Samuele Cornell and Loren Lugosch and Cem Subakan and Nauman Dawalatabad and Abdelwahab Heba and Jianyuan Zhong and Ju-Chieh Chou and Sung-Lin Yeh and Szu-Wei Fu and Chien-Feng Liao and Elena Rastorgueva and François Grondin and William Aris and Hwidong Na and Yan Gao and Renato De Mori and Yoshua Bengio},
  year={2021},
  eprint={2106.04624},
  archivePrefix={arXiv},
  primaryClass={eess.AS},
  note={arXiv:2106.04624}
}