自然语言处理之fastText

    xiaoxiao2021-04-15  419

    一、整体结构

    fastText的代码整体结构如下图所示:

    1、fastText简介

    fastText是一个快速文本分类算法,与基于神经网络的分类算法相比有两大优点: 1、fastText在保持高精度的情况下加快了训练速度和测试速度 2、fastText不需要预训练好的词向量,fastText会自己训练词向量 3、fastText两个重要的优化:Hierarchical Softmax、N-gram

    2、fastText模型架构

    fastText模型架构和word2vec中的CBOW很相似,不同之处是fastText预测标签而CBOW预测的是中间词,即模型架构类似但是模型的任务不同。下面我们先看一下CBOW的架构:

    word2vec将上下文关系转化为多分类任务,进而训练逻辑回归模型,这里的类别数量|V|词库大小。通常的文本数据中,词库少则数万,多则百万,在训练中直接训练多分类逻辑回归并不现实。word2vec中提供了两种针对大规模多分类问题的优化手段,negative sampling 和hierarchical softmax。在优化中,negative sampling只更新少量负面类,从而减轻了计算量。hierarchical softmax将词库表示成前缀树,从树根到叶子的路径可以表示为一系列二分类器,一次多分类计算的复杂度从|V|降低到了树的高度

    fastText模型架构:其中x1,x2,…,xN−1,xN表示一个文本中的n-gram向量,每个特征是词向量的平均值。这和前文中提到的cbow相似,cbow用上下文去预测中心词,而此处用全部的n-gram去预测指定类别

    3、层次softmax

    softmax函数常在神经网络输出层充当激活函数,目的就是将输出层的值归一化到0-1区间,将神经元输出构造成概率分布,主要就是起到将神经元输出值进行归一化的作用在标准的softmax中,计算一个类别的softmax概率时,我们需要对所有类别概率做归一化,在这类别很大情况下非常耗时,因此提出了分层softmax(Hierarchical Softmax),思想是根据类别的频率构造霍夫曼树来代替标准softmax,通过分层softmax可以将复杂度从N降低到logN,下图给出分层softmax示例: 在层次softmax模型中,叶子结点的词没有直接输出的向量,而非叶子节点都有响应的输在在模型的训练过程中,通过Huffman编码,构造了一颗庞大 Huffman树,同时会给非叶子结点赋予向量。我们要计算的是目标词w的概率,这个概率的具体含义,是指从root结点开始随机走,走到目标词w的概率。因此在途中路过非叶子结点(包括root)时,需要分别知道往左走和往右走的概率。

    4、N-gram特征

    n-gram是基于语言模型的算法,基本思想是将文本内容按照子节顺序进行大小为N的窗口滑动操作,最终形成窗口为N的字节片段序列。而且需要额外注意一点是n-gram可以根据粒度不同有不同的含义,有字粒度的n-gram和词粒度的n-gram。

    二、fastText实战篇

    1、fastText环境要求

    fastText需要运行在MacOS或Linux上,因为fastText使用了C++11,因此需要很好支持C++11的编译器,支持的编译器包括: (1) gcc-4.6.3 或者更新版本 (2) clang-3.3 或者更新版本编译是使用Makefile执行的,因此你需要有一个工作的make,对于单词相似度评估脚本则需要如下环境: (1) python2.6 或者更新 (2) numpy 和 spicy

    2、在本地快速搭建fastText 为了搭建fastText,打开命令窗口依次执行以下命令

    $ git clone https://github.com/facebookresearch/fastText.git $ cd fastText $ make

    上述命令将为所有类和主二进制fastText生成目标文件,如果你不打算使用默认的系统范围编译器,可以更新Makefile(CC和include)开头定义的两个宏

    3、fastText-文本分类

    首先我们需要做的便是安装搭建fastText,需要系统支持c++ 11的c++编译器,先从GitHub上下载fastText到本地(版本在更新,可以到GitHub上查看最近版本进行下载): $ wget https://github.com/facebookresearch/fastText/archive/v0.1.0.zip 然后将下载的zip文件夹进行解压,解压后进入目录对fastText项目执行make命令进行编译(因此这里便需要你的系统有支持c++11的编译器) $ unzip v0.1.0.zip $ cd fastText-0.1.0 $ make 在根目录下运行名为fasttext的二进制文件,便会打印出fastText支持的各种不同的命令,如:supervised进行模型训练,quantize量化模型以减少内存使用,test进行模型测试,predict预测最可能的标签等,运行结果如下所示: >> ./fasttext usage: fasttext <command> <args> The commands supported by fasttext are: supervised train a supervised classifier quantize quantize a model to reduce the memory usage test evaluate a supervised classifier predict predict most likely labels predict-prob predict most likely labels with probabilities skipgram train a skipgram model cbow train a cbow model print-word-vectors print word vectors given a trained model print-sentence-vectors print sentence vectors given a trained model nn query for nearest neighbors analogies query for analogies

    每个命令分别为:

    supervised: 训练一个监督分类器 quantize:量化模型以减少内存使用量 test:评估一个监督分类器 predict:预测最有可能的标签 predict-prob:用概率预测最可能的标签 skipgram:训练一个 skipgram 模型 cbow:训练一个 cbow 模型 print-word-vectors:给定一个训练好的模型,打印出所有的单词向量 print-sentence-vectors:给定一个训练好的模型,打印出所有的句子向量 nn:查询最近邻居 analogies:查找所有同类词

    4、获取数据及数据预处理

    我们需要带有标签的数据去训练我们的监督学习的分类器,本教程中,我们使用cooking相关数据构建我们的分类器,因此首先我们下载数据,数据网址为stackexchange,进行如下命令操作: wget https://dl.fbaipublicfiles.com/fasttext/data/cooking.stackexchange.tar.gz tar xvzf cooking.stackexchange.tar.gz head cooking.stackexchange.txt 通过head命令便可看到文档形式,文档的每一行都包含一个标签,标签后面跟着相应的单词短语,所有的标签都以__label__前缀开始,这事fastText便是标签和单词短语的方式,训练的模型便是预测文档中给定单词短语预测其对应的标签。在训练分类器之前,我们需要将数据分割成训练集和验证集,我们将使用验证集来评估学习到的分类器对新数据的性能好坏,先通过下面命令来查看文档中总共含有多少数据: >> wc cooking.stackexchange.txt 15404 169582 1401900 cooking.stackexchange.txt

    可以看到我们数据中总共包含了15404个示例,我们把文档分成一个包含12404个示例的训练集和一个包含3000个示例的验证集,执行如下命令:

    head -n 12404 cooking.stackexchange.txt > cooking.train tail -n 3000 cooking.stackexchange.txt > cooking.valid

    5、使用fastText快速搭建分类器

    接下来我们便开始训练我们的模型,首先执行如下命令进行模型的训练: >> ./fasttext supervised -input cooking.train -output model_cooking Read 0M words Number of words: 14598 Number of labels: 734 Progress: 100.0% words/sec/thread: 75109 lr: 0.000000 loss: 5.708354 eta: 0h0m input命令选项指示训练数据,-output选项指示的是保存的模型的位置,在训练结束后,文件model_cooking.bin是在当前目录中创建的,model_cooking.bin便是我们保存训练模型的文件。模型训练好之后,我们可以交互式测试我们的分类器,即单独测试某一个句子所属的类别,可以通过以下命令进行交互式测试: >> ./fasttext predict model_cooking.bin -

    输入以上命令后,命令行会提示你输入句子,然后我们可以进行如下句子测试:

    Which baking dish is best to bake a banana bread ?

    上面句子可以得到预测的标签是baking,显然这个预测结果是正确的,我们再进行尝试

    Why not put knives in the dishwasher?

    上面句子预测的标签是food-safety,可以看出是不相关的,显然预测的不正确,为了验证学习到的分类模型的好坏,我们在验证集上对它进行测试,观察模型的精准率precision和召回率recall:

    >> ./fasttext test model_cooking.bin cooking.valid N 3000 P@1 0.124 R@1 0.0541 Number of examples: 3000

    6、模型优化

    上面通过使用默认参数运行fastText训练得到的模型在分类新问题上效果很差,接下来我们通过更改默认参数来提高性能。 数据预处理:查看数据,我们发现有些单词包含大写字母和标点符号,因此改善模型性能的第一步就是应用一些简单的预处理,预处理可以使用命令行工具例如sed、tr来对文本进行简单的标准化操作,执行命令如下: >> cat cooking.stackexchange.txt | sed -e "s/\([.\!?,'/()]\)/ \1 /g" | tr "[:upper:]" "[:lower:]" > cooking.preprocessed.txt >> head -n 12404 cooking.preprocessed.txt > cooking.train >> tail -n 3000 cooking.preprocessed.txt > cooking.valid

    接下来我们在预处理的数据集上进行模型训练并进行测试,命令如下:

    >> ./fasttext supervised -input cooking.train -output model_cooking Read 0M words Number of words: 9012 Number of labels: 734 Progress: 100.0% words/sec/thread: 82041 lr: 0.000000 loss: 5.671649 eta: 0h0m h-14m >> ./fasttext test model_cooking.bin cooking.valid N 3000 P@1 0.164 R@1 0.0717 Number of examples: 3000

    观察上面的结果,由于对数据预处理,词典变小了,由原来的14K个单词变成了9K,精准率也上升了4%,因此数据预处理起到了一定的效果。

    更多的训练次数和更大的学习率:

    在默认情况下,fastText在训练期间对每个训练用例仅重复使用五次,这太小,因为我们的训练集只有12k训练样例,因此我们可以通过-epoch选项增加每个样例的使用次数,命令如下: >> ./fasttext supervised -input cooking.train -output model_cooking -epoch 25 Read 0M words Number of words: 9012 Number of labels: 734 Progress: 100.0% words/sec/thread: 77633 lr: 0.000000 loss: 7.147976 eta: 0h0m

    然后测试模型查看效果:

    >> ./fasttext test model_cooking.bin cooking.valid N 3000 P@1 0.501 R@1 0.218 Number of examples: 3000 从上面测试效果可以看出,精准率和召回率都有了大幅度提升,可见增加每个样例的使用次数对于数据集少的情况下效果提升明显。另一个增强算法能力是改变模型的学习速度即学习速率,这对应于处理每个示例后模型的更改程度,当学习率为0时意味着模型根本不会发生改变,因此不会学到任何东西,良好的学习率值在0.1-1.0的范围内,下面我们通过设置算法学习率为learning rate = 1.0进行模型训练: >> ./fasttext supervised -input cooking.train -output model_cooking -lr 1.0 Read 0M words Number of words: 9012 Number of labels: 734 Progress: 100.0% words/sec/thread: 81469 lr: 0.000000 loss: 6.405640 eta: 0h0m >> ./fasttext test model_cooking.bin cooking.valid N 3000 P@1 0.563 R@1 0.245 Number of examples: 3000

    可以看到效果比上面增加epoch还要好,下面我们来将二者结合起来:

    >> ./fasttext supervised -input cooking.train -output model_cooking -lr 1.0 -epoch 25 Read 0M words Number of words: 9012 Number of labels: 734 Progress: 100.0% words/sec/thread: 76394 lr: 0.000000 loss: 4.350277 eta: 0h0m >> ./fasttext test model_cooking.bin cooking.valid N 3000 P@1 0.585 R@1 0.255 Number of examples: 3000

    下面我们来增加一些新的方式来进一步提升模型的性能。

    word n-grams:

    此方案中,我们使用单词bigrams而不是仅仅是unigrams来提高模型的性能,这对于词序很重要的分类问题尤其重要,例如情感分析。n-gram是基于语言模型的算法,基本思想是将文本内容按照子节顺序进行大小为N的窗口滑动操作,最终形成窗口为N的字节片段序列。训练模型命令如下: >> ./fasttext supervised -input cooking.train -output model_cooking -lr 1.0 -epoch 25 -wordNgrams 2 Read 0M words Number of words: 9012 Number of labels: 734 Progress: 100.0% words/sec/thread: 75366 lr: 0.000000 loss: 3.226064 eta: 0h0m >> ./fasttext test model_cooking.bin cooking.valid N 3000 P@1 0.599 R@1 0.261 Number of examples: 3000

    通过几个步骤,可以看出我们将模型精准率从12.4%提升到了59.9%。


    最新回复(0)