FastText的内部机制

简介: 文章来源:https://towardsdatascience.com/fasttext-under-the-hood-11efc57b2b3译者 | Revolverfasttext是一个被用于对词向量和句子分类进行高效学习训练的工具库,采用c++编写,并支持训练过程中的多进程处理。

文章来源:https://towardsdatascience.com/fasttext-under-the-hood-11efc57b2b3

译者 | Revolver

fasttext是一个被用于对词向量和句子分类进行高效学习训练的工具库,采用c++编写,并支持训练过程中的多进程处理。你可以使用这个工具在监督和非监督情况下训练单词和句子的向量表示。这些训练出来的词向量,可以应用于许多处理数据压缩的应用程序,或者其他模型的特征选择,或者迁移学习的初始化。

FastText支持使用negative sampling,softmax或层次softmax损失函数等方法来训练CBOW或Skip-gram模型。我已经使用了fastText对一个规模有千万个单词的语料库进行语义词向量训练,对于它的表现以及它对原任务的扩展,我都感到非常满意。在此之前,我很难找到除了 getting started之外的关于fasttext的相关说明文档,因此在这篇文章中,我将带您了解fastText的内部原理以及它是如何工作的。对word2vec模型如何工作的理解是需要的,克里斯·麦考密克的文章(见链接)很好地阐述了word2vec模型。

一、运行fasttext

我们可以通过下面这条命令来用fastText训练一个Skip-gram模型:

$ fasttext skipgram -input data.txt -output model

data.txt是一个包含一串文本序列的输入文件,输出模型保存在model.bin文件下,词向量则保存在model.vec中。

二、表示方法

fasttext可以在词向量的训练和句子分类上取得非常好的表现,尤其表现在对罕见词进行了字符粒度上的处理。

每个单词除了单词本身外还被表示为多个字符级别的n-grams(有时也称为N元模子)。例如,对于单词matter,当n = 3时,fasttext对该词对字符ngram就表示为<ma, mat, att, tte, ter, er>。其中<和>是作为边界符号被添加,来将一个单词的ngrams与单词本身区分开来。再举个例子,如果单词mat属于我们的词汇表,则会被表示为<mat>。这么做刚好让一些短词以其他词的ngram出现,有助于更好学习到这些短词的含义。从本质上讲,这可以帮助你捕捉后缀/前缀的含义。

可以通过-minn-maxn这两个参数来控制ngrams的长度,这两个标志分别决定了ngrams的最小和最大字符数,也即控制了ngrams的范围。这个模型被认为是一个词袋模型,因为除了用于选择n-gram的滑动窗口外,它并没有考虑到对单词的内部结构进行特征选择。它只要求字符落在窗口以内,但并不关心ngrams的顺序。你可以将这两个值都设为0来完全关闭n-gram,也就是不产生n-gram符号,单纯用单词作为输入。当您的模型中的“单词”不是特定语言的单词时或者说字符级别的n-gram没有意义的时候,这会变得很有用。最常见的例子是当您将id作为您的单词输入。在模型更新期间,fastText会学习到每个ngram以及整个单词符号的权重。

三、读取数据

虽然fastText的训练是多线程的,但是读取数据却是通过单线程来完成。而文本解析和分词则在读取输入数据时就被完成了。让我们来看看具体是怎么做到的:

FastText通过-input参数获取一个文件句柄用于输入数据。FastText不支持从stdin读取数据,它初始化两个向量word2int_words_来跟踪输入信息。word2int_是一个字符串到数值的映射集,索引键是单词字符串,根据字符串哈希值可以得到一个数值作为它的值,同时这个数值恰好就对应到了words_数组(std:::vector)的索引。words_ 数组在读取输入时根据单词出现的顺序递增创建索引,每个索引对应的值是一个结构体entry,这个entry封装了单词的所有信息。条目包含以下信息:

 

struct entry {

  std::string word;

  int64_t count;

  entry_type type;

  std::vector<int32_t> subwords;

};

 

在这个entry里,word是单词的字符串表示形式,count是各个单词在输入序列里的出现频次,entry_type的值是word或label中的一个,label选项仅在有监督情况下有效。所有的输入符号,包括entry_type都存储在同一个词典中,这使得扩展fastText来包含其他类型的实体变得更加容易(我将在后续的文章中详细讨论这一点)。最后,subword是一个包含一个单词所有的n-grams的向量。这个subword也会在读取输入数据时被创建,然后被传递到训练过程中。

word2int_的大小为MAX_VOCAB_SIZE = 30000000,这是一个硬编码的数字。当在大型语料库上进行训练时,这个大小可以是受限制的,但也可以在保持性能的同时有效地增加。word2int_数组的索引是由字符串得到的整数哈希值,并且是0和MAX_VOCAB_SIZE之间的唯一数字。如果出现哈希冲突,得到的哈希值已经存在,那么这个值就会增加,直到我们找到一个唯一的id来分配给一个单词为止。

因此,一旦词汇表的大小达逼近MAX_VOCAB_SIZE,算法性能就会显著下降。为了防止这种情况,每当哈希值的大小超过MAX_VOCAB_SIZE的75%时,fastText就会对词汇表进行删减。删减过程是这样的,首先增加单词最小计数阈值来重新确定一个单词是否有资格出现在单词表里,然后对词典里所有计数小于这个的单词进行删减。当添加一个新单词时,会检查这个单词对应的哈希值是否超过75%阈值,因此这种自动删减可以在文件读取过程的任何阶段进行。

除了自动删减过程,对于已经存在于词汇表里的单词的最小计数是通过使用-minCount和-minCountLabel(用于监督训练)这两个参数来控制的。基于这两个参数的删减在整个训练文件被处理之后进行。如果单词表的总数已经触发了前面所说的因哈希值太大发生的自动删减,那么您的词典可能就需要手动设置一个较高值的minCount阈值了。但无论如何,你都必须手动指定minCount阈值,才能确保较低词频的单词不会被用作输入的一部分。

在求解负采样损失函数过程中,一个大小NEGATIVE_TABLE_SIZE = 10000000负采样单词表会被构造。注意它的大小是MAX_VOCAB_SIZE的三分之一。该表是从每个词词频的平方根的一元模型分布(unigram distribution)中进行采样构造的,这确保了每个词出现在负采样单词表中的次数与它的频率的平方根成正比。接着再对该表打乱词序以确保其随机性。

图一 U(w)是一个特定单词的计数,W是所有单词计数的集合

接下来,一个用于删除高频词的采样表会被构建,这个表在the original word2vec extension paper这篇论文的2.3节中有大概描述。这背后的思想是,高频词所能提供的信息比罕见的单词更少,而且高频词即使在遇见到更多相同单词的实例后,它们的词向量也不会发生太大的变化。

该论文提出了一种删除训练词的方法,通过下面公式计算训练词被丢弃的概率:克里斯·麦考密克

图二 t为所选阈值,f(w)为单词w的出现频率

作者认为t = 10e-5是一个较为合理的默认值。该公式丢弃了丢弃频率大于阈值的词,并在有效对低频词进行采样的同时又保持了它们的相对频率,从而抑制了高频词的夸大作用。

但另一方面,FastText又重新定义了这种分布。

图三 t = 10e-4为所选阈值,f(w)为单词w的出现频率

默认的阈值可以通过 -t 手动设置。阈值t在fastText中的含义和最初的word2vec论文中的含义有所不同,你应该针对自己的应用程序进行调优。

在训练阶段,只有当从(0,1)的均匀分布中随机抽取一个值的大小大于单词被丢弃的概率时,该单词才会被丢弃。下面是在默认阈值情况下,单词被丢弃概率与词频f(w)的关系。如图所示,随着单词频率的增加,被抽到的概率大于被丢弃的概率P(w)的概率增加。因此,随着单词频率的增加,被丢弃的概率也增加。注意这只适用于无监督模型,在有监督模型中,单词不会被丢弃。

图四 fasttext中默认阈值下单词被丢弃概率与词频f(w)的关系

如果我们用-pretrainedVectors参数初始化训练,输入文件中的值将被用于初始化输入层向量。如果未指定,一个维度MxN的矩阵将会被创建,其中M = MAX_VOCAB_SIZE + bucket_size, N = dimbucket_size是一个数组的长度大小,这个数组是为所有的ngrams符号分配的。它通过-bucket标志进行设置,默认设置为2000000

所有的ngrams在矩阵里的位置信息是通过取得ngram字符串的哈希值(同一个哈希函数)来进行初始化的,并将对该哈希值取模之后的值填到初始化后的矩阵中,其位置对应到MAX_VOCAB_SIZE + hash。注意到在ngrams空间中可能存在哈希冲突,但对于原始单词来说则是不存在这种情况。这也会影响到模型的性能。

Dim表示训练中隐藏层的维度,因此词向量的维度可以通过-dim参数进行设置,默认值为100。矩阵的每个值被初始化为0到1/dim之间的均匀实数分布。

四、训练

一旦输入层和隐藏层向量被初始化成功,多个训练线程就会启动。线程数量由-thread参数指定。所有训练线程都共享一个指向输入层和隐藏层向量矩阵的指针。所有线程都从输入文件中读取数据,并使用读取到的每一行来更新模型,其实也就相当于批次大小为1的随机梯度下降法。如果遇到换行字符,或者读入的单词数量超过允许的行最大数量,则会截断该行的后续输入。这里通过MAX_LINE_SIZE设置,默认值为1024。

CBOW模型和Skip-gram模型都会同时对一段上下文文本的权重进行更新,这段文本的单词数量是1到-ws(参数设置)之间的随机均匀分布,也就是说窗口大小是随机的。

损失函数的目标向量是这样计算的,先对每个输入向量作归一化计算,再把归一化后的所有向量求和可得。输入向量是原始单词以及该词的所有ngrams的向量表示。通过计算这个损失函数,可以在前向传播的过程中设置权重,然后又一路将影响反向传播传递到输入层的向量。在反向传播过程中对输入向量权重的调整帮助我们学到了使得共现相似性(co occurrence similarity)最大化的词向量。学习速率参数-lr会决定每条特定的实例样本对权重的影响究竟有多大。

图五 无监督Skip-gram fastText模型的拓扑结构

模型的输入层权重、隐藏层权重以及传入的参数都会保存在.bin格式的文件中,-saveOutput标志控制了是否输出一个包含隐藏层向量的word2vec文件格式的.vec文件。

我希望这篇文章能帮助我们了解fasttext的内部工作原理。我个人已经通过使用这个库取得了很多成功,并强烈推荐你用它去解决你的问题。在下一篇文章中,我将讨论我为fastText添加的一些可以泛化它的能力的附加功能。敬请继续关注。

目录
相关文章
|
2月前
|
机器学习/深度学习 人工智能 算法
模型无关的局部解释(LIME)技术原理解析及多领域应用实践
在当前数据驱动的商业环境中,人工智能(AI)和机器学习(ML)已成为各行业决策的关键工具,但随之而来的是“黑盒”问题:模型内部机制难以理解,引发信任缺失、监管合规难题及伦理考量。LIME(局部可解释模型无关解释)应运而生,通过解析复杂模型的个别预测,提供清晰、可解释的结果。LIME由华盛顿大学的研究者于2016年提出,旨在解决AI模型的透明度问题。它具有模型无关性、直观解释和局部保真度等优点,在金融、医疗等领域广泛应用。LIME不仅帮助企业提升决策透明度,还促进了模型优化和监管合规,是实现可解释AI的重要工具。
117 9
|
7天前
|
机器学习/深度学习 人工智能 自然语言处理
LEC: 基于Transformer中间层隐藏状态的高效特征提取与内容安全分类方法
通过利用Transformer中间层的隐藏状态,研究提出了层增强分类(LEC)技术,该技术能够以极少的训练样本和参数实现高效的内容安全和提示注入攻击分类,显著提升了模型的性能,并验证了其跨架构和领域的泛化能力。
37 11
LEC: 基于Transformer中间层隐藏状态的高效特征提取与内容安全分类方法
|
5月前
|
机器学习/深度学习 移动开发 自然语言处理
【YOLOv8改进 - 注意力机制】ContextAggregation : 上下文聚合模块,捕捉局部和全局上下文,增强特征表示
【YOLOv8改进 - 注意力机制】ContextAggregation : 上下文聚合模块,捕捉局部和全局上下文,增强特征表示
|
4月前
|
机器学习/深度学习 自然语言处理
ChatGPT 等相关大模型问题之Attention 机制的定义如何解决
ChatGPT 等相关大模型问题之Attention 机制的定义如何解决
|
5月前
|
机器学习/深度学习 计算机视觉
【YOLOv8改进 - 注意力机制】Gather-Excite : 提高网络捕获长距离特征交互的能力
【YOLOv8改进 - 注意力机制】Gather-Excite : 提高网络捕获长距离特征交互的能力
|
5月前
|
机器学习/深度学习 计算机视觉
【YOLOv8改进 - 注意力机制】DoubleAttention: 双重注意力机制,全局特征聚合和分配
YOLOv8专栏探讨了该目标检测模型的创新改进,如双重注意力块,它通过全局特征聚合和分配提升效率。该机制集成在ResNet-50中,在ImageNet上表现优于ResNet-152。文章提供了论文、代码链接及核心代码示例。更多实战案例与详细配置见相关CSDN博客链接。
|
5月前
|
机器学习/深度学习 算法 计算机视觉
【YOLOv8改进 - 注意力机制】RCS-OSA :减少通道的空间对象注意力,高效且涨点
YOLOv8专栏探讨了YOLO系列的创新改进,提出RCS-YOLO模型,它在脑肿瘤检测中超越YOLOv6/v7/v8,精度提升1%,速度增快60%(达到114.8 FPS)。RCS-OSA模块结合RepVGG/ShuffleNet优点,通过通道重参数化和混洗优化卷积,提升速度和准确性。代码和论文可在提供的链接获取。
|
5月前
|
机器学习/深度学习 资源调度 Java
【YOLOv8改进 - 注意力机制】GC Block: 全局上下文块,高效捕获特征图中的全局依赖关系
YOLOv8专栏探讨了目标检测的创新改进,如整合NLNet和SENet优势的GCBlock,用于高效全局上下文建模。GCNet在多个识别任务中表现优越,同时降低了计算成本。文章提供了论文、代码链接及详细实现,包括特征的全局建模、变换和融合步骤。核心GCBlock代码展示了其结构。更多实战案例和配置见相关链接。
|
6月前
|
机器学习/深度学习 自然语言处理 并行计算
YOLOv8改进 | 注意力机制 | 在主干网络中添加MHSA模块【原理+附完整代码】
Transformer中的多头自注意力机制(Multi-Head Self-Attention, MHSA)被用来增强模型捕捉序列数据中复杂关系的能力。该机制通过并行计算多个注意力头,使模型能关注不同位置和子空间的特征,提高了表示多样性。在YOLOv8的改进中,可以将MHSA代码添加到`/ultralytics/ultralytics/nn/modules/conv.py`,以增强网络的表示能力。完整实现和教程可在提供的链接中找到。
|
6月前
|
编解码 算法 计算机视觉
YOLOv8数据增强预处理方式详解:包括数据增强的作用,数据增强方式与方法
YOLOv8数据增强预处理方式详解:包括数据增强的作用,数据增强方式与方法