文档分类FastText模型 (pytorch实现)

FastText简介

FastText与之前介绍过的CBOW架构相似,我们先来会议一下CBOW架构,如下图:

在这里插入图片描述

CBOW的任务是通过上下文去预测中间的词,具体做法是使用滑动窗口内部的词的embedding的均值作为中间词的embedding。

FastText的任务是通过文章中的词去预测文章的类别(文档分类),具体做法是使用文章中的所有词的embedding的均值作为文章的embedding。最后从隐层再经过一次的非线性变换得到输出层的label。

CBOW和FastText的相似之处:

  1. 每个特征都是词向量的平均值。

总结一下CBOW和FastText的不同之处:

  1. FastText是有监督学习,而CBOW是无监督学习
  2. FastText是预测文章的label,而CBOW是预测中心词
  3. FastText使用的是文章中所有词的embedding,而CBOW使用的是中心词所在滑动窗口内其他所有词的embedding

从模型架构上来说,沿用了CBOW的单层神经网络的模式,不过fastText的处理速度才是这个算法的创新之处。

fastText模型的输入是一个词的序列(一段文本或者一句话),输出是这个词序列属于不同类别的概率。在序列中的词和词组构成特征向量,特征向量通过线性变换映射到中间层,再由中间层映射到标签。fastText在预测标签时使用了非线性激活函数,但在中间层不使用非线性激活函数。

fastText是一个快速文本分类算法,与基于神经网络的分类算法相比有两大优点:

  1. fastText在保持高精度的情况下加快了训练速度和测试速度
  2. fastText不需要预训练好的词向量,fastText会自己训练词向量
  3. fastText两个重要的优化:Hierarchical Softmax、N-gram

fastText方法包含三部分,模型架构,层次SoftmaxN-gram特征。

层次softmax

分层 softmax(Hierarchical Softmax)是一种用于加速词嵌入模型训练的技术,特别是在训练大型词汇表时。它通过将词汇表组织成一棵二叉树(通常是霍夫曼树),从而将原来的线性 softmax 运算转换为对树结构进行的多次二元分类,从而减少了计算量。

在这里插入图片描述

构建哈夫曼树

  • 首先,根据词汇表中每个词的词频构建一棵霍夫曼树。
  • 霍夫曼树是一种最优的二叉树,它通过最小化编码长度来实现对频繁出现的词进行更短的编码,以及对不太频繁出现的词进行较长的编码。

在这里插入图片描述

对数学模型进行改造

  • 对于一个普通的 softmax 模型,它的输出层是一个与词汇表大小相同的全连接层,需要对所有词汇进行一次计算。
  • 而在分层 softmax 中,将词汇表组织成二叉树,每个内部节点代表一个二元分类任务。模型的输出层不再是一个全连接层,而是根据霍夫曼树的结构构建的一系列内部节点。

预测过程

  • 在预测过程中,对于给定的目标词,从树的根节点开始,根据二元分类的规则逐级向下遍历,直到达到叶子节点,从而确定目标词的概率分布。
  • 通过遍历的路径,可以确定目标词在霍夫曼树中的编码,从而得到目标词的概率分布。

我们发现对于每一个节点,都是一个二分类[0,1],也就是我们可以使用sigmod来处理节点信息;
θ ( x ) = 1 1 + e − x \theta \left(x \right)=\frac{1}{1+e{-x}} θ(x)=1+ex1
此时,当我们知道了目标单词x,之后,我们只需要计算root节点,到该词的路径累乘,即可. 不需要去遍历所有的节点信息,时间复杂度变为O(log2(V))。

N-gram特征

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

#我爱中国
2-gram特征为:我爱 爱中 中国
3-gram特征为:我爱中 爱中国

#我 爱 中国
2-gram特征为:我/爱 爱/中国
3-gram特征为:我//中国

从上面来看,使用n-gram有如下优点

  1. 为罕见的单词生成更好的单词向量:根据上面的字符级别的n-gram来说,即是这个单词出现的次数很少,但是组成单词的字符和其他单词有共享的部分,因此这一点可以优化生成的单词向量。
  2. 在词汇单词中,即使单词没有出现在训练语料库中,仍然可以从字符级n-gram中构造单词的词向量。
  3. n-gram可以让模型学习到局部单词顺序的部分信息, 如果不考虑n-gram则便是取每个单词,这样无法考虑到词序所包含的信息,即也可理解为上下文信息,因此通过n-gram的方式关联相邻的几个词,这样会让模型在训练的时候保持词序信息。

但正如上面提到过,随着语料库的增加,内存需求也会不断增加,严重影响模型构建速度,针对这个有以下几种解决方案:
1、过滤掉出现次数少的单词
2、使用hash存储
3、由采用字粒度变化为采用词粒度

FastText代码(文档分类)
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np


class Config(object):
    """配置参数"""

    def __init__(self):
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  # 设备
        self.dropout = 0.5  # 随机失活
        self.require_improvement = 1000  # 若超过1000batch效果还没提升,则提前结束训练
        self.num_classes = 10  # 类别数
        self.n_vocab = 10000  # 词表大小,在运行时赋值
        self.num_epochs = 20  # epoch数
        self.batch_size = 128  # mini-batch大小
        self.pad_size = 32  # 每句话处理成的长度(短填长切)
        self.learning_rate = 1e-3  # 学习率
        self.embed = 300  # 字向量维度
        self.hidden_size = 256  # 隐藏层大小
        self.n_gram_vocab = 250499  # ngram 词表大小


'''Bag of Tricks for Efficient Text Classification'''


class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)
        self.embedding_ngram2 = nn.Embedding(config.n_gram_vocab, config.embed)
        self.embedding_ngram3 = nn.Embedding(config.n_gram_vocab, config.embed)
        self.dropout = nn.Dropout(config.dropout)
        self.fc1 = nn.Linear(config.embed * 3, config.hidden_size)
        self.fc2 = nn.Linear(config.hidden_size, config.num_classes)

    def forward(self, x):
        out_word = self.embedding(x[0])  # x[0] [batch_size,sentence_len] 经过embedding变为 [batch_size,sentence_len,wmbed_size] torch.Size([128, 32, 300])
        out_bigram = self.embedding_ngram2(x[2])  # torch.Size([128, 32, 300])
        out_trigram = self.embedding_ngram3(x[3])  # torch.Size([128, 32, 300])
        out = torch.cat((out_word, out_bigram, out_trigram), -1)  # torch.Size([128, 32, 900])
        out = out.mean(dim=1)  # torch.Size([128, 900]),沿着第二个维度(即特征维度)对每个样本的特征值进行平均池化
        out = self.dropout(out)  # torch.Size([128, 900])
        out = self.fc1(out)  # torch.Size([128, 900])经过fc1 torch.Size([128, 256])
        out = F.relu(out)  # torch.Size([128, 256])
        out = self.fc2(out)  # torch.Size([128, 256])经过fc1 torch.Size([128, 10])
        return out

config=Config()
model=Model(config)
print(model)

输出:

Model(
  (embedding): Embedding(10000, 300, padding_idx=9999)
  (embedding_ngram2): Embedding(250499, 300)
  (embedding_ngram3): Embedding(250499, 300)
  (dropout): Dropout(p=0.5, inplace=False)
  (fc1): Linear(in_features=900, out_features=256, bias=True)
  (fc2): Linear(in_features=256, out_features=10, bias=True)
)
  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FastText是Facebook开发的一种文本分类算法,它通过将文本分解成n-gram特征来表示文本,并基于这些特征训练模型PyTorch是一个流行的深度学习框架,可以用于实现FastText文本分类算法。 以下是使用PyTorch实现FastText文本分类的基本步骤: 1. 数据预处理:将文本数据分成训练集和测试集,并进行预处理,如分词、去除停用词、构建词典等。 2. 构建数据集:将预处理后的文本数据转换成PyTorch中的数据集格式,如torchtext中的Dataset。 3. 定义模型:使用PyTorch定义FastText模型模型包括嵌入层、平均池化层和全连接层。 4. 训练模型:使用训练集训练FastText模型,并在验证集上进行验证调整超参数。 5. 测试模型:使用测试集评估训练好的FastText模型的性能。 以下是一个简单的PyTorch实现FastText文本分类的示例代码: ```python import torch import torch.nn as nn import torch.optim as optim from torchtext.legacy.data import Field, TabularDataset, BucketIterator # 数据预处理 TEXT = Field(tokenize='spacy', tokenizer_language='en_core_web_sm', include_lengths=True) LABEL = Field(sequential=False, dtype=torch.float) train_data, test_data = TabularDataset.splits( path='data', train='train.csv', test='test.csv', format='csv', fields=[('text', TEXT), ('label', LABEL)] ) TEXT.build_vocab(train_data, max_size=25000, vectors="glove.6B.100d") LABEL.build_vocab(train_data) # 定义模型 class FastText(nn.Module): def __init__(self, vocab_size, embedding_dim, output_dim): super().__init__() self.embedding = nn.Embedding(vocab_size, embedding_dim) self.fc = nn.Linear(embedding_dim, output_dim) def forward(self, x): embedded = self.embedding(x) pooled = embedded.mean(0) output = self.fc(pooled) return output # 训练模型 BATCH_SIZE = 64 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') train_iterator, test_iterator = BucketIterator.splits( (train_data, test_data), batch_size=BATCH_SIZE, sort_within_batch=True, device=device ) model = FastText(len(TEXT.vocab), 100, 1).to(device) optimizer = optim.Adam(model.parameters()) criterion = nn.BCEWithLogitsLoss().to(device) for epoch in range(10): for batch in train_iterator: text, text_lengths = batch.text labels = batch.label optimizer.zero_grad() output = model(text).squeeze(1) loss = criterion(output, labels) loss.backward() optimizer.step() with torch.no_grad(): total_loss = 0 total_correct = 0 for batch in test_iterator: text, text_lengths = batch.text labels = batch.label output = model(text).squeeze(1) loss = criterion(output, labels) total_loss += loss.item() predictions = torch.round(torch.sigmoid(output)) total_correct += (predictions == labels).sum().item() acc = total_correct / len(test_data) print('Epoch:', epoch+1, 'Test Loss:', total_loss / len(test_iterator), 'Test Acc:', acc) ``` 这个示例代码使用了torchtext库来处理数据集,并定义了一个FastText模型模型包括一个嵌入层、一个平均池化层和一个全连接层。模型在训练集上训练,并在测试集上进行测试,并输出测试集的损失和准确率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值