TextCNN文本分类实战

一、数据集介绍

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

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

 

二、TextCNN模型介绍

将卷积神经网络CNN应用到文本分类任务,利用多个不同size的kernel来提取句子中的关键信息(类似 n-gram 的关键信息),从而能够更好地捕捉局部相关性。

 

三、实战

(一)环境

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/'

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.数据截断、补全

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)

5.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)

6.模型构建

(1)输入层

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

(2)Embedding层(Embedding)

[batch_size, maxlen] -> [batch_size, maxlen, embedding_dims],将字进行embedding_dims长度的编码,embedding_dims上述取50。

(3)卷积层(Conv1D)

卷积具有局部特征提取的功能,用 CNN 来提取句子中类似 n-gram 的关键信息。

每个卷积核的大小为[filter_size, embedding_dims],filter_size相当于n-gram中的n的大小,一般为[3,4,5],表示相邻几个词之间有词序关系。每个filter计算完成之后得到一个列向量,表示该filter从句子中提取的特征,有多少卷积核就能提取多少种特征,上述有3个filter。

filter_size=3的卷积操作后,生成一个100-3+1=98长度的向量,共有128个这样的卷积核,因此[batch_size, maxlen, embedding_dims] -> [batch_size, 98, 128]。filter_size=4的卷积操作后,生成一个100-4+1=97长度的向量,共有128个这样的卷积核,因此[batch_size, maxlen, embedding_dims] -> [batch_size, 97, 128]。filter_size=5的卷积操作后,生成一个100-5+1=96长度的向量,共有128个这样的卷积核,因此[batch_size, maxlen, embedding_dims] -> [batch_size, 96, 128]。

(4)池化层(GlobalMaxPooling1D)、拼接(Concatenate)

因为在卷积层过程中我们使用了不同高度的卷积核,使得我们通过卷积层后得到的向量维度会不一致,所以在池化层中,我们使用GlobalMaxPooling1D全局最大池化,对每个特征向量池化成一个值,即抽取每个特征向量的最大值表示该特征,而且认为这个最大值表示的是最重要的特征。因此3个卷积结果池化后都变成了[batch_size, :, 128] -> [batch_size, 128]。取最后一维拼接起来,得到[batch_size, 128] -> [batch_size, 384]。在池化层到全连接层之前可以加上dropout防止过拟合。

(5)全连接层(Dense)

[batch_size, 384] -> [batch_size, 3],使用softmax作为激活函数进行输出。可以使用L2正则化防止过拟合。

class TextCNN(tf.keras.Model):

    def __init__(self,
                 maxlen, max_features, embedding_dims):
        super(TextCNN, self).__init__()
        self.maxlen = maxlen
        self.max_features = max_features
        self.embedding_dims = embedding_dims
        self.kernel_sizes = [3, 4, 5]
        self.embedding = tf.keras.layers.Embedding(self.max_features, self.embedding_dims, input_length=self.maxlen)
        self.convs = []
        self.max_poolings = []
        for kernel_size in self.kernel_sizes:
            self.convs.append(tf.keras.layers.Conv1D(128, kernel_size, activation='relu'))
            self.max_poolings.append(tf.keras.layers.GlobalMaxPooling1D())
        self.concat =  tf.keras.layers.Concatenate()
        self.classifier = tf.keras.layers.Dense(3, activation='softmax')

    def call(self, inputs):
        embedding = self.embedding(inputs)
        convs = []
        for i in range(len(self.kernel_sizes)):
            c = self.convs[i](embedding)
            c = self.max_poolings[i](c)
            convs.append(c)
        x = self.concat(convs)
        output = self.classifier(x)
        return output

7.模型训练

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 = TextCNN(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()

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TextCNN(Convolutional Neural Network)是一种用于文本分类的神经网络模型。它基于卷积神经网络,可以对输入的文本进行特征提取和分类。 TextCNN的输入是一个文本,通常由单词或字符组成的序列。首先,将文本中的每个单词(或字符)表示为一个向量。这可以使用预训练的词向量模型(如Word2Vec)得到,也可以通过随机初始化向量并通过反向传播进行训练得到。 接下来,将这些单词向量输入到一维卷积层中。卷积层是通过滑动窗口在输入序列上进行局部感知,提取特定的文本特征。每个窗口的大小可以根据具体任务和数据集的需求进行调整。卷积操作产生了一系列的特征图,其中每个特征图对应不同的特征。 在卷积层之后,可以使用最大池化(MaxPooling)操作进一步提取最重要的特征。最大池化操作获取特征图中的最大值,以减少特征向量的维度。这样做的好处是提供了一种不变性,即无论特征在文本中的位置如何变化,还是可以被捕捉到。 在进行池化操作之后,将得到的特征向量连接起来,进一步经过全连接层进行分类。全连接层将特征映射到最终的类别概率分布上,可以使用Softmax函数来将输出值转化为概率。 TextCNN模型的训练过程通常使用交叉熵损失函数,并通过反向传播算法进行参数优化。可以使用梯度下降等算法对模型进行训练。 总结来说,TextCNN是一种用于文本分类的深度学习模型。它通过卷积操作和池化操作提取文本的特征,并通过全连接层进行分类。这种模型具有参数少、计算速度快、能够捕捉到文本的局部信息等优势,被广泛应用于自然语言处理领域的文本分类任务中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值