fastText文本分类实战_fatext做文本分类实战_麦格芬230的博客-程序员秘密

技术标签: 自然语言处理  

一、数据集介绍

本项目的数据集来自于DataFountain——疫情期间网民情绪识别。即给定微博ID和微博内容,设计算法对微博内容进行情绪识别,判断微博内容是积极的、消极的还是中性的。

链接:https://www.datafountain.cn/competitions/423/datasets

 
二、fastText模型介绍

fastText能够做到效果好,速度快,主要依靠两个秘密武器:一是利用了词内的n-gram信息(subword n-gram information),二是用到了层次化Softmax回归(Hierarchical Softmax)的训练trick。

Subword n-gram lnformation:对于输入的上下文中的每一个词,都进行基于的n-gram,之后将所有的n-gram和原词相加,来代表上下文信息。这种做法的好处是英文单词中,可以由前缀或者后缀等语言形态上的相似性,在词与词之间建立联系。

Hierarchical Softmax:层次化的Softmax的思想实质上是将一个全局多分类的问题,转化成为了若干个二元分类问题,从而将计算复杂度从O(V)降到O(logV)。

CBOW和fastText两者的不同主要体现在如下几个方面: 

输入层:CBOW的输入是目标单词的上下文并进行one-hot编码,fastText的输入是多个单词embedding向量,并将单词的字符级别的n-gram向量作为额外的特征;

从输入层到隐藏层,CBOW会将上下文单词向量叠加起来并经过一次矩阵乘法(线性变化)并应用激活函数,而fastText省略了这一过程,直接将embedding过的向量特征求和取平均;

输出层,一般的CBOW模型会采用Softmax作为输出,而fastText则采用了Hierarchical Softmax,大大降低了模型训练时间;

CBOW的输出是目标词汇,fastText的输出是文档对应的类标。

 

三、实战

(一)环境

Python 3.7

Tensorflow 2.1.0

(二)代码

1.导包

from tensorflow.compat.v1 import ConfigProto
from tensorflow.compat.v1 import InteractiveSession

config = ConfigProto()
config.gpu_options.allow_growth = True
session = InteractiveSession(config=config)
import pandas as pd
import numpy as np
import tensorflow as tf
import os

import tensorflow.keras.backend as K
from sklearn.model_selection import StratifiedKFold

import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline

print(tf.__version__)
print(tf.test.is_gpu_available())

2.读入数据

TRAIN_PATH = './data/train_dataset/'
TEST_PATH = './data/test_dataset/'

ngram_range = 2
max_features = 5000
maxlen = 100
batch_size = 32
embedding_dims = 50
epochs = 2


input_categories = '微博中文内容'
output_categories = '情感倾向'

df_train = pd.read_csv(TRAIN_PATH+'nCoV_100k_train.labled.csv',engine ='python',encoding='utf-8')
df_train = df_train[df_train[output_categories].isin(['-1','0','1'])]
df_test = pd.read_csv(TEST_PATH+'nCov_10k_test.csv',engine ='python',encoding='utf-8')
df_sub = pd.read_csv(TEST_PATH+'submit_example.csv',encoding='utf-8')
print('train shape =', df_train.shape)
print('test shape =', df_test.shape)

3.Text to Sequence

# 将缺失值填充为-1
all_train_data = df_train[[input_categories, output_categories]].fillna('-1')
all_test_data = df_test[[input_categories]].fillna('-1')
# 将文本做分字处理
all_train_data[input_categories] = all_train_data[input_categories].map(lambda x: " ".join(x))
all_test_data[input_categories] = all_test_data[input_categories].map(lambda x: " ".join(x))
# 将文本转换成序列
tokenizer = tf.keras.preprocessing.text.Tokenizer(num_words=max_features, lower=False, filters="")
tokenizer.fit_on_texts(all_train_data[input_categories].tolist()+all_test_data[input_categories].tolist())

train_ = tokenizer.texts_to_sequences(all_train_data[input_categories].values)
test_ = tokenizer.texts_to_sequences(all_test_data[input_categories].values)

4.N-gram 特征提取

(1)构建 n-gram 集合

def create_ngram_set(input_list, ngram_value=2):
    return set(zip(*[input_list[i:] for i in range(ngram_value)]))

(2)向序列后追加 n-gram 特征

def add_ngram(sequences, token_indice, ngram_range=2):
    new_sequences = []
    for input_list in sequences:
        new_list = input_list[:]
        for ngram_value in range(2, ngram_range + 1):
            for i in range(len(new_list) - ngram_value + 1):
                ngram = tuple(new_list[i:i + ngram_value])
                if ngram in token_indice:
                    new_list.append(token_indice[ngram])
        new_sequences.append(new_list)

    return new_sequences

(3)将 n-gram 特征添加到词汇表中

if ngram_range > 1:
    print('Adding {}-gram features'.format(ngram_range))
    ngram_set = set()
    for input_list in train_:
        for i in range(2, ngram_range + 1):
            set_of_ngram = create_ngram_set(input_list, ngram_value=i)
            ngram_set.update(set_of_ngram)

    start_index = max_features + 1
    token_indice = {v: k + start_index for k, v in enumerate(ngram_set)}
    indice_token = {token_indice[k]: k for k in token_indice}

    max_features = np.max(list(indice_token.keys())) + 1
    
    train_ = add_ngram(train_, token_indice, ngram_range)
    test_ = add_ngram(test_, token_indice, ngram_range)

5.数据截断、补全

pad_sequences(),该函数是将序列转化为经过填充以后的一个长度相同的新序列新序列。

padding:'pre'或'post',确定当需要补0时,在序列的起始还是结尾补。

truncating:'pre'或'post',确定当需要截断序列时,从起始还是结尾截断。

train_ = tf.keras.preprocessing.sequence.pad_sequences(train_, maxlen=maxlen,
                                                      padding='pre',truncating='pre',value=0.0)
test_ = tf.keras.preprocessing.sequence.pad_sequences(test_, maxlen=maxlen,
                                                     padding='pre',truncating='pre',value=0.0)

6.label处理

LabelEncoder(),将离散型的数据转换成 0 到 n−1 之间的数。

 
from sklearn.preprocessing import LabelEncoder
from tensorflow.keras.utils import to_categorical
lb = LabelEncoder()
train_label = lb.fit_transform(all_train_data[output_categories].values)

7.模型构建

(1)输入层

[batch_size, maxlen] -> [batch_size, maxlen],每个句子固定maxlen个词,上述取100。

(2)Embedding层(Embedding)

Embedding层的输入是一批句子,每个句子由一个字索引序列构成。Embedding层将每个字映射成EMBEDDING_DIM维的向量。[batch_size, maxlen] -> [batch_size, maxlen, embedding_dims],将字进行embedding_dims长度的编码,embedding_dims上述取50。

(3)隐含层(GlobalAveragePooling1D)

隐含层对一个句子中所有字的向量进行叠加平均,GlobalAveragePooling1D全局平均池化类可以实现这个功能,[batch_size, :, embedding_dims] -> [batch_size, embedding_dims]。

(4)全连接层(Dense)

真实的fastText这层是Hierarchical Softmax,因为tf.keras原生并没有支持Hierarchical Softmax,所以这里使用softmax作为激活函数进行输出,[batch_size, embedding_dims] -> [batch_size, 3]。

class FastText(tf.keras.Model):

    def __init__(self,
                 maxlen, max_features, embedding_dims):
        super(FastText, self).__init__()
        self.maxlen = maxlen
        self.max_features = max_features
        self.embedding_dims = embedding_dims
        self.embedding = tf.keras.layers.Embedding(self.max_features, self.embedding_dims, input_length=self.maxlen)
        self.avg_pooling = tf.keras.layers.GlobalAveragePooling1D()
        self.classifier = tf.keras.layers.Dense(3, activation='softmax')

    def call(self, inputs):

        embedding = self.embedding(inputs)
        x = self.avg_pooling(embedding)
        output = self.classifier(x)
        return output

8.模型训练

StratifiedKFold用法类似Kfold,但是他是分层采样,确保训练集,测试集中各类别样本的比例与原始数据集中相同。

gkf = StratifiedKFold(n_splits=5).split(X=all_train_data[input_categories].fillna('-1'), y=all_train_data[output_categories].fillna('-1'))

valid_preds = []
test_preds = []
for fold, (train_idx, valid_idx) in enumerate(gkf):
    train_inputs = train_[train_idx]
    train_outputs = to_categorical(train_label[train_idx])

    valid_inputs = train_[valid_idx]
    valid_outputs = to_categorical(train_label[valid_idx])
    
    model = FastText(maxlen, max_features, embedding_dims)
    optimizer = tf.keras.optimizers.Adam(learning_rate=1e-5)
    train_dataset = tf.data.Dataset.from_tensor_slices((train_inputs,train_outputs)).shuffle(buffer_size=1000).batch(1)
    valid_dataset = tf.data.Dataset.from_tensor_slices((valid_inputs,valid_outputs)).batch(1)
    
    
    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['acc']) 

    model.fit(train_dataset, validation_data= valid_dataset, epochs=epochs)
    test_preds.append(model.predict(test_))
    K.clear_session()

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42295205/article/details/105272751

智能推荐

keepalived安装问题解决方法_weixin_33770878的博客-程序员秘密

keepalived安装时出现的问题及其解决办法1、Keepalived安装错误一例(make错误)(本部分拾人牙慧)/usr/include/sys/types.h:235: 错误:与 ‘blkcnt_t’ 类型冲突/usr/src/kernels/2.6.18-238.19.1.el5-i686//include/linux/types.h:142: 错误...

Nginx以及反向代理_IT修真院的博客-程序员秘密

这里是修真院后端小课堂,每篇分享文从【背景介绍】【知识剖析】【常见问题】【解决方案】【编码实战】【扩展思考】【更多讨论】【参考文献】八个方面深度解析后端知识/技能,本篇分享的是:【 Nginx以及反向代理】大家好,我是IT修真院郑州分院第6期的学员李亚衡,一枚正直纯洁善良的JAVA程序员今天给大家分享一下,修真院官网JAVA任务三,深度思考中的知识点——Nginx以及反向代...

通过AD域验证登录Linux系统(Linux安装sssd加入Windows AD域)_linux加入ad域_昭哥-HYZ的博客-程序员秘密

centos系列linux系统通过安装sssd服务,实现Linux加入Windows AD域环境,实现通过域账户登录Linux系统,实现统一认证,便于账户管理和信息安全,主要涉及安装sssd服务,配置sssd.conf、以及通过visudo命令配置sudoers文件。

CTF入门必看_进一寸有一寸的欢喜077的博客-程序员秘密

知乎小白关于ctf竞赛训练 积累的资料一个巧合的机会,成为了CTF夺旗爱好者,一个ctf小白。从12年开始国内大大小小的CTF比赛我都看过,那会还没有统一叫CTF,都是叫 网络攻防赛、信息安全赛之类的,目的就是为了通过技术手段找到最终的key(现在的CTF中叫做flag)。只是到了后来慢慢的可能受到DEFCON CTF的影响国内所有的安全竞赛也统一叫做CTF竞赛了。国内外比较知名的比赛:X...

Centos7 最小安装 , 配置无线网络_centos7.9最小化安装网卡驱动_jscsd226的博客-程序员秘密

// 关闭NetworkManager服务systemctl stop NetworkManager// 配置无线网卡wpa_supplicant -B -i wlp3s0 -c < (wpa_passphrase “网络名称” “网络密码”)// 自动获取IP地址dhclient wlp3s0// 查看是否成功获取ip地址,如果使用ifconfig命令需要安装net-tools...

随便推点

Java数组的声明、初始化、数组的遍历方法_bigbee2333的博客-程序员秘密

数组的声明可以使用下面两种形式声明数组: int [ ] a 或 int a [ ]数组的初始化通常使用new运算符创建数组:int [ ] a = new int[100] 这条语句创建了一个可以存储100个整数的数组,数组长度不要求是常量,new int[n]会创建一个长度为n的数组。直接给数组赋值int [ ] Arrary = { 0,1,2,3,4,5,6...

12 种主流编程语言输出“ Hello World ”,把我给难住了!_CSDN 程序人生的博客-程序员秘密

作为一名程序员,在初步学习编程想必都绕不开一个最为基础的入门级示例“Hello World”,那么,你真的了解各个语言“Hello World”的正确写法吗?在我们刚开始...

git branch 管理分支(超详细)_帐妖的博客-程序员秘密

这是git操作最大的一块儿,来吧,继续学习。直至现在为止,我们的项目版本库一直都是只有一个分支 master。在 git 版本库中创建分支的成本几乎为零,所以,不必吝啬多创建几个分支。下面列举一些常见的分支策略,仅供大家参考:创建一个属于自己的个人工作分支,以避免对主分支 master 造成太多的干扰,也方便与他人交流协作。当进行高风险的工作时,创建一个试验性的分支,扔掉一个烂摊子总...

1.4-多个Connection_一个系统需要多少connection_qq_27664967的博客-程序员秘密

多个连接,数据库,模式和主从复制设置使用多个连接在单个连接中使用多个数据库在单个连接中使用多个模式主从复制使用多个连接使用多个数据库的最简单方法是创建不同的连接:import {createConnections} from "typeorm";const connections = await createConnections([{ name: "db1Connection", type: "mysql", host: "localhost", po

神码ai人工智能写作机器人_10个使用人工智能和机器学习的WordPress插件_cumohuo9136的博客-程序员秘密

Do you want to use artificial intelligence and machine learning technologies on your WordPress site? There is a chance that you might already be using one. In this article, we will share some WordPres...

打印杨辉三角的C程序_杨辉三角课本上的程序_zhangchao3322218的博客-程序员秘密

//打印杨辉三角#include #define N 12long combi(int n, int r){    int i;    long p = 1;    for(i = 1; i         p = p * (n-i+1) / i;

推荐文章

热门文章

相关标签