阅读 510

使用CNN,RNN和HAN进行文本分类的对比报告

介绍

你好,世界!!我最近加入Jatana.ai 担任NLP研究员(实习生and),并被要求使用深度学习模型研究文本分类用例。

在本文中,我将分享我的经验和学习,同时尝试各种神经网络架构。

我将介绍3种主要算法,例如:

  1. 卷积神经网络(CNN)
  2. 递归神经网络(RNN)
  3. 分层注意网络(HAN)

对具有丹麦语,意大利语,德语,英语和土耳其语的数据集进行文本分类。

我们来吧。✅

关于自然语言处理(NLP)

在不同业务问题中广泛使用的

自然语言处理和监督机器学习(ML)
任务之一是“文本分类”,它是监督机器学习任务的一个例子,因为包含文本文档及其标签的标记数据集用于训练分类器。

文本分类的目标是自动将文本文档分类为一个或多个预定义类别。

文本分类的一些示例是:

  • 从社交媒体中了解受众情绪(😁😐😥)
  • 检测垃圾邮件和非垃圾邮件
  • 自动标记客户查询
  • 将新闻文章分类为预定义主题

文本分类是学术界和工业界非常活跃的研究领域。在这篇文章中,我将尝试介绍一些不同的方法,并比较它们的性能,其中实现基于Keras

所有源代码和实验结果都可以在jatana_research 存储库中找到

端到端文本分类管道由以下组件组成:

  1. 培训文本:它是我们的监督学习模型能够学习和预测所需课程的输入文本。
  2. 特征向量:特征向量是包含描述输入数据特征的信息的向量。
  3. 标签:这些是我们的模型预测的预定义类别/类
  4. ML Algo:这是我们的模型能够处理文本分类的算法(在我们的例子中:CNN,RNN,HAN)
  5. 预测模型:在历史数据集上训练的模型,可以执行标签预测。

分析我们的数据:

我们使用3种类型的数据集,其中包含各种类,如下表所示:

使用卷积神经网络(CNN)的文本分类:

CNN是一类深度前馈人工神经网络(节点之间的连接

形成循环)并使用多层感知器的变体,其设计需要最少的预处理。这些灵感来自动物视觉皮层。

我参考了Yoon Kim 论文和Denny Britz撰写的这篇博客

CNN通常用于计算机视觉,但它们最近已应用于各种NLP任务,结果很有希望 🙌

让我们简要地看一下当我们通过图表在文本数据上使用CNN时会发生什么。当检测到特殊模式时,每个卷积的结果都将触发。通过改变内核的大小并连接它们的输出,你可以自己检测多个大小的模式(2,3或5个相邻的单词).Patterns可以是表达式(单词ngrams?),如“我讨厌”,“非常好“因此CNN可以在句子中识别它们而不管它们的位置如何。

在本节中,我使用简化的CNN来构建分类器。所以首先使用Beautiful Soup来删除一些HTML标签和一些不需要的字符。

def clean_str(string):
    string = re.sub(r“\\”,“”,string)     
    string = re.sub(r“\'”,“”,string)     
    string = re.sub(r“\” “,”,“string”     
    return string.strip()。lower()

texts = []; labels = [] 

for i in range(df.message.shape [0]):
    text = BeautifulSoup(df.message [i ])
    text.append(clean_str(str(text.get_text()。encode())))

for for in df ['class']:
    labels.append(i)
复制代码

这里我使用了Google Glove 6B vector 100d。其官方文件:

'''
GloVe是一种无监督学习算法,用于获取单词的向量表示。对来自语料库的聚合全局词 - 词共现统计进行训练,并且所得到的表示展示词向量空间的有趣线性子结构。
“””

对于未知单词,以下代码将随机化其向量。下面是一个非常简单的卷积架构,使用了总共​​128个过滤器,大小为5,最大池为5和35,遵循此博客的示例。

sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
embedded_sequences = embedding_layer(sequence_input)
l_cov1= Conv1D(128, 5, activation='relu')(embedded_sequences)
l_pool1 = MaxPooling1D(5)(l_cov1)
l_cov2 = Conv1D(128, 5, activation='relu')(l_pool1)
l_pool2 = MaxPooling1D(5)(l_cov2)
l_cov3 = Conv1D(128, 5, activation='relu')(l_pool2)
l_pool3 = MaxPooling1D(35)(l_cov3)  # global max pooling
l_flat = Flatten()(l_pool3)
l_dense = Dense(128, activation='relu')(l_flat)
preds = Dense(len(macronum), activation='softmax')(l_dense)
复制代码

这是CNN模型的架构。

使用递归神经网络(RNN)进行文本分类:

回归神经网络(RNN)是一类神经网络,其中节点之间的连接形成沿着一序列的有向图的。这允许它展示时间序列的动态时间行为。

使用外部嵌入的知识可以提高RNN的精确度,因为它集成了关于单词的新信息(词汇和语义),这些信息已经在一个非常大的数据集上训练和提炼。预先训练嵌入我们将要使用的是GloVe

RNN可能看起来很吓人😱。虽然它们很难理解,但它们非常有趣。它们封装了一个非常漂亮的设计,克服了传统神经网络在处理序列数据时出现的缺点:文本,时间序列,视频,DNA序列等。

RNN是一系列神经网络块,它们像链一样彼此链接。每个人都将消息传递给继任者。如果你想深入了解内部机制,我强烈推荐Colah的博客

使用Beautiful Soup也可以完成相同的预处理。我们将处理文本数据,这是一种序列类型。单词的顺序对意义非常重要。希望RNN能够处理这个问题并捕获长期依赖关系。

要在文本数据上使用Keras,我们首先必须对其进行预处理。为此,我们可以使用Keras的Tokenizer类。该对象采用num_words参数作为参数,这是基于字频率进行标记化后保留的最大字数。

MAX_NB_WORDS = 20000
tokenizer = Tokenizer (num_words=MAX_NB_WORDS) tokenizer.fit_on_texts(texts)
复制代码

一旦将标记化器安装在数据上,我们就可以使用它将文本字符串转换为数字序列。这些数字代表字典中每个单词的位置(将其视为映射)。

  • 在本节中,我将尝试使用递归神经网络和基于注意力的LSTM编码器来解决该问题。
  • 通过使用LSTM编码器,我们打算在运行前馈网络进行分类之前,对递归神经网络的最后一个输出中的文本的所有信息进行编码。
  • 这与神经翻译机器和序列学习序列非常相似。以下是段落和文档的分层神经自动编码器的图。
  • 我在Keras中使用LSTM层来实现这一点。除了正向LSTM之外,这里我使用了双向LSTM并连接了LSTM输出的最后一个输出。
  • Keras提供了一个非常好的包装器,称为双向,这将使这种编码工作毫不费力。您可以在此处查看示例代码
sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
embedded_sequences = embedding_layer(sequence_input)
l_lstm = Bidirectional(LSTM(100))(embedded_sequences)
preds = Dense(len(macronum), activation='softmax')(l_lstm)
model = Model(sequence_input, preds)
model.compile(loss='categorical_crossentropy',optimizer='rmsprop',  metrics=['acc'])
复制代码

这是RNN模型的架构。

使用分层注意网络(HAN)的文本分类:

我参考了这篇研究论文“ 分层注意网络文档分类”。它可以成为使用HAN进行文档分类的绝佳指南。使用Beautiful Soup也可以进行相同的预处理。我们将使用的预训练嵌入是GloVe

  • 在这里,我正在构建一个Hierarchical LSTM网络。我必须将数据输入构造为3D而不是2D,如上面两节所述。
  • 因此输入张量将是[每批评论数,句子数,每个句子中的单词数]。
tokenizer = Tokenizer(nb_words=MAX_NB_WORDS)
tokenizer.fit_on_texts(texts)
data = np.zeros((len(texts), MAX_SENTS, MAX_SENT_LENGTH), dtype='int32')
for i, sentences in enumerate(reviews):
    for j, sent in enumerate(sentences):
        if j< MAX_SENTS:
            wordTokens = text_to_word_sequence(sent)
            k=0
            for _, word in enumerate(wordTokens):
                if(k<MAX_SENT_LENGTH and tokenizer.word_index[word]<MAX_NB_WORDS):
                    data[i,j,k] = tokenizer.word_index[word]
                    k=k+1
复制代码

在此之后,我们可以使用Keras魔术函数TimeDistributed构建如下的Hierarchical输入层。我们也可以参考这篇文章

embedding_layer=Embedding(len(word_index)+1,EMBEDDING_DIM,weights=[embedding_matrix],
input_length=MAX_SENT_LENGTH,trainable=True)
sentence_input = Input(shape=(MAX_SENT_LENGTH,), dtype='int32')
embedded_sequences = embedding_layer(sentence_input)
l_lstm = Bidirectional(LSTM(100))(embedded_sequences)
sentEncoder = Model(sentence_input, l_lstm)

review_input = Input(shape=(MAX_SENTS,MAX_SENT_LENGTH), dtype='int32')
review_encoder = TimeDistributed(sentEncoder)(review_input)
l_lstm_sent = Bidirectional(LSTM(100))(review_encoder)
preds = Dense(len(macronum), activation='softmax')(l_lstm_sent)
model = Model(review_input, preds)
复制代码

这是HAN模型的架构。

结果

以下是准确度Loss和损失pl的图表

观察👇:

  • 基于上述图表,CNN已经获得了良好的验证准确性和高一致性,RNN和HAN也实现了高精度,但它们在所有数据集中并不一致。
  • 发现RNN是生产就绪场景中最糟糕的架构。
  • CNN模型在训练时间方面优于其他两个模型(RNN和HAN),但是如果我们有庞大的数据集,HAN可以比CNN和RNN表现更好。
  • 对于训练样本较多的数据集1和数据集2,HAN已经达到最佳验证准确度,而当训练样本非常低时,HAN没有表现出那么好(数据集3)。
  • 当训练样本较少时(数据集3),CNN已达到最佳验证准确度。

绩效改进:

为了达到最佳表现😉,我们可以:

  1. 微调超参数:超参数是在训练之前设置的变量,用于确定网络结构以及网络的训练方式。(例如:学习率,批量大小,时期数)。微调可以通过以下方式完成:手动搜索,网格搜索,随机搜索......
  2. 改进文本预处理:可以根据数据集的需要更好地预处理输入数据,例如删除一些特殊符号,数字,停用词等等...
  3. 使用Dropout Layer : Dropout是正则化技术,可避免过度拟合(提高验证精度),从而提高泛化能力。

基础设施设置

所有上述实验均在具有Nvidia Tesla K80 GPU的 8核vCPU上进行

此外,所有实验均在Rahul Kumar guidance 的指导下进行。

此外,我还要感谢Jatana.ai 为我提供了一个非常好的基础设施和全程支持😃。

感谢 Rahul Kumar

英文原文:Report on Text Classification using CNN, RNN & HAN

更多文章欢迎访问: www.apexyun.com

公众号:银河系1号

联系邮箱:public@space-explore.com
(未经同意,请勿转载)


关注下面的标签,发现更多相似文章
评论