如何用较少的读内存文本型乱码完成文本分类任务问题,怎么解决

【实践】用深度学习解决大规模文本分类问题
作者:清凇
阿里巴巴搜索排序算法工程师
AI技术投稿、约稿、请发送邮件至
近来在同时做一个应用深度学习解决淘宝商品的类目预测问题的项目,恰好硕士毕业时论文题目便是文本分类问题,趁此机会总结下文本分类领域特别是应用深度学习解决文本分类的相关的思路、做法和部分实践的经验。
0. 业务问题
淘宝商品的一个典型的例子(见下图),图中商品的标题是“夏装雪纺条纹短袖t恤女春半袖衣服夏天中长款大码胖mm显瘦上衣夏”。淘宝网后台是通过树形的多层的类目体系管理商品的,覆盖叶子类目数量达上万个,商品量也是10亿量级,我们是任务是根据商品标题预测其所在叶子类目。示例中商品归属的类目为“女装/女士精品&&蕾丝衫/雪纺衫”。很显然,这是一个非常典型的短文本多分类问题。接下来分别会介绍下文本分类传统和深度学习的做法,最后简单梳理下实践的经验。
1. 传统文本分类方法
文本分类问题算是自然语言处理领域中一个非常经典的问题了,相关研究最早可以追溯到上世纪50年代。当时是通过专家规则(Pattern)进行分类,甚至在80年代初一度发展到利用知识工程建立专家系统。这样做的好处是短平快的解决top问题,但显然天花板非常低,不仅费时费力,覆盖的范围和准确率都非常有限。
后来伴随着统计学习方法的发展,特别是90年代后互联网在线文本数量增长和机器学习学科的兴起,逐渐形成了一套解决大规模文本分类问题的经典玩法,这个阶段的主要套路是人工特征工程+浅层分类模型。训练文本分类器过程见下图:
整个文本分类问题就拆分成了特征工程和分类器两部分,玩机器学习的同学对此自然再熟悉不过了。
1.1 特征工程
特征工程在机器学习中往往是最耗时耗力的,但却极其的重要。抽象来讲,机器学习问题是把数据转换成信息再提炼到知识的过程,特征是“数据–&信息”的过程,决定了结果的上限,而分类器是“信息–&知识”的过程,则是去逼近这个上限。然而特征工程不同于分类器模型,不具备很强的通用性,往往需要结合对特征任务的理解。
文本分类问题所在的自然语言领域自然也有其特有的特征处理逻辑,传统分本分类任务大部分工作也在此处。文本特征工程分位文本预处理、特征提取、文本表示三个部分,最终目的是把文本转换成计算机可理解的格式,并封装足够用于分类的信息,即很强的特征表达能力。
1.1.1 文本预处理
文本预处理过程是在文本中提取关键词表示文本的过程,中文文本处理中主要包括文本分词和去停用词两个阶段。之所以进行分词,是因为很多研究表明特征粒度为词粒度远好于字粒度,其实很好理解,因为大部分分类算法不考虑词序信息,基于字粒度显然损失了过多“n-gram”信息。
具体到中文分词,不同于英文有天然的空格间隔,需要设计复杂的分词算法。传统算法主要有基于字符串匹配的正向/逆向/双向最大匹配;基于理解的句法和语义分析消歧;基于统计的互信息/CRF方法。近年来随着深度学习的应用,WordEmbedding + Bi-LSTM+CRF方法逐渐成为主流,本文重点在文本分类,就不展开了。而停止词是文本中一些高频的代词连词介词等对文本分类无意义的词,通常维护一个停用词表,特征提取过程中删除停用表中出现的词,本质上属于特征选择的一部分。
经过文本分词和去停止词之后淘宝商品示例标题变成了下图“ / ”分割的一个个关键词的形式:
夏装 / 雪纺 / 条纹 / 短袖 / t恤 / 女 / 春 / 半袖 / 衣服 / 夏天 / 中长款 / 大码 / 胖mm / 显瘦 / 上衣 / 夏
1.1.2 文本表示和特征提取
文本表示:
文本表示的目的是把文本预处理后的转换成计算机可理解的方式,是决定文本分类质量最重要的部分。传统做法常用词袋模型(BOW, Bag Of Words)或向量空间模型(Vector Space Model),最大的不足是忽略文本上下文关系,每个词之间彼此独立,并且无法表征语义信息。词袋模型的示例如下:
( 0, 0, 0, 0, .... , 1, ... 0, 0, 0, 0)
一般来说词库量至少都是百万级别,因此词袋模型有个两个最大的问题:高纬度、高稀疏性。词袋模型是向量空间模型的基础,因此向量空间模型通过特征项选择降低维度,通过特征权重计算增加稠密性。
特征提取:
向量空间模型的文本表示方法的特征提取对应特征项的选择和特征权重计算两部分。特征选择的基本思路是根据某个评价指标独立的对原始特征项(词项)进行评分排序,从中选择得分最高的一些特征项,过滤掉其余的特征项。常用的评价有文档频率、互信息、信息增益、χ?2;统计量等。
特征权重主要是经典的TF-IDF方法及其扩展方法,主要思路是一个词的重要度与在类别内的词频成正比,与所有类别出现的次数成反比。
1.1.3 基于语义的文本表示
传统做法在文本表示方面除了向量空间模型,还有基于语义的文本表示方法,比如LDA主题模型、LSI/PLSI概率潜在语义索引等方法,一般认为这些方法得到的文本表示可以认为文档的深层表示,而word embedding文本分布式表示方法则是深度学习方法的重要基础,下文会展现。
1.2 分类器
分类器基本都是统计分类方法了,基本上大部分机器学习方法都在文本分类领域有所应用,比如朴素贝叶斯分类算法(Na?ve Bayes)、KNN、SVM、最大熵和神经网络等等,传统分类模型不是本文重点,在这里就不展开了。
2. 深度学习文本分类方法
上文介绍了传统的文本分类做法,传统做法主要问题的文本表示是高纬度高稀疏的,特征表达能力很弱,而且神经网络很不擅长对此类数据的处理;此外需要人工进行特征工程,成本很高。而深度学习最初在之所以图像和语音取得巨大成功,一个很重要的原因是图像和语音原始数据是连续和稠密的,有局部相关性,。应用深度学习解决大规模文本分类问题最重要的是解决文本表示,再利用CNN/RNN等网络结构自动获取特征表达能力,去掉繁杂的人工特征工程,端到端的解决问题。接下来会分别介绍:
2.1 文本的分布式表示:词向量(word embedding)
分布式表示(Distributed Representation)其实Hinton 最早在1986年就提出了,基本思想是将每个词表达成 n 维稠密、连续的实数向量,与之相对的one-hot encoding向量空间只有一个维度是1,其余都是0。分布式表示最大的优点是具备非常powerful的特征表达能力,比如 n 维向量每维 k 个值,可以表征 kn 个概念。事实上,不管是神经网络的隐层,还是多个潜在变量的概率主题模型,都是应用分布式表示。下图是03年Bengio在 A Neural Probabilistic Language Model (http://www.jmlr.org/papers/volume3/bengio03a/bengio03a.pdf) 的网络结构:
这篇文章提出的神经网络语言模型(NNLM,Neural Probabilistic Language Model)采用的是文本分布式表示,即每个词表示为稠密的实数向量。NNLM模型的目标是构建语言模型:
词的分布式表示即词向量(word embedding)是训练语言模型的一个附加产物,即图中的Matrix C。
尽管Hinton 86年就提出了词的分布式表示,Bengio 03年便提出了NNLM,词向量真正火起来是google Mikolov 13年发表的两篇word2vec的文章 Efficient Estimation of Word Representations in Vector Space(http://ttic.uchicago.edu/~haotang/speech/.pdf) 和 Distributed Representations of Words and Phrases and their Compositionality (https://papers.nips.cc/paper/5021-distributed-representations-of-words-and-phrases-and-their-compositionality.pdf),更重要的是发布了简单好用的word2vec工具包 (/archive/p/word2vec/),在语义维度上得到了很好的验证,极大的推进了文本分析的进程。下图是文中提出的CBOW 和 Skip-Gram两个模型的结构,基本类似于NNLM,不同的是模型去掉了非线性隐层,预测目标不同,CBOW是上下文词预测当前词,Skip-Gram则相反。
除此之外,提出了Hierarchical Softmax 和 Negative Sample两个方法,很好的解决了计算有效性,事实上这两个方法都没有严格的理论证明,有些trick之处,非常的实用主义。详细的过程不再阐述了,有兴趣深入理解word2vec的,推荐读读这篇很不错的paper:word2vec Parameter Learning Explained(http://www-personal.umich.edu/~ronxin/pdf/w2vexp.pdf)。额外多提一点,实际上word2vec学习的向量和真正语义还有差距,更多学到的是具备相似上下文的词,比如“good”“bad”相似度也很高,反而是文本分类任务输入有监督的语义能够学到更好的语义表示,有机会后续系统分享下。
至此,文本的表示通过词向量的表示方式,把文本数据从高纬度高稀疏的神经网络难处理的方式,变成了类似图像、语音的的连续稠密数据。深度学习算法本身有很强的数据迁移性,很多之前在图像领域很适用的深度学习算法比如CNN等也可以很好的迁移到文本领域了,下一小节具体阐述下文本分类领域深度学习的方法。
2.2 深度学习文本分类模型
词向量解决了文本表示的问题,该部分介绍的文本分类模型则是利用CNN/RNN等深度学习网络及其变体解决自动特征提取(即特征表达)的问题。
2.2.1 fastText
fastText 是上文提到的 word2vec 作者 Mikolov 转战 Facebook 后16年7月刚发表的一篇论文 Bag of Tricks for Efficient Text Classification(https://arxiv.org/pdf/v2.pdf)。把 fastText 放在此处并非因为它是文本分类的主流做法,而是它极致简单,模型图见下:
原理是把句子中所有的词向量进行平均(某种意义上可以理解为只有一个avg pooling特殊CNN),然后直接接 softmax 层。其实文章也加入了一些 n-gram 特征的 trick 来捕获局部序列信息。文章倒没太多信息量,算是“水文”吧,带来的思考是文本分类问题是有一些“线性”问题的部分[from项亮],也就是说不必做过多的非线性转换、特征组合即可捕获很多分类信息,因此有些任务即便简单的模型便可以搞定了。
2.2.2 TextCNN
本篇文章的题图选用的就是14年这篇文章提出的TextCNN的结构(见下图)。fastText 中的网络结果是完全没有考虑词序信息的,而它用的 n-gram 特征 trick 恰恰说明了局部序列信息的重要意义。卷积神经网络(CNN Convolutional Neural Network)(http://colah.github.io/posts/2014-07-Understanding-Convolutions/) 最初在图像领域取得了巨大成功,CNN原理就不讲了,核心点在于可以捕捉局部相关性,具体到文本分类任务中可以利用CNN来提取句子中类似 n-gram 的关键信息。
TextCNN的详细过程原理图见下:
TextCNN详细过程:第一层是图中最左边的7乘5的句子矩阵,每行是词向量,维度=5,这个可以类比为图像中的原始像素点了。然后经过有 filter_size=(2,3,4) 的一维卷积层,每个filter_size 有两个输出 channel。第三层是一个1-max pooling层,这样不同长度句子经过pooling层之后都能变成定长的表示了,最后接一层全连接的 softmax 层,输出每个类别的概率。
特征:这里的特征就是词向量,有静态(static)和非静态(non-static)方式。static方式采用比如word2vec预训练的词向量,训练过程不更新词向量,实质上属于迁移学习了,特别是数据量比较小的情况下,采用静态的词向量往往效果不错。non-static则是在训练过程中更新词向量。推荐的方式是 non-static 中的 fine-tunning方式,它是以预训练(pre-train)的word2vec向量初始化词向量,训练过程中调整词向量,能加速收敛,当然如果有充足的训练数据和资源,直接随机初始化词向量效果也是可以的。
通道(Channels):图像中可以利用 (R, G, B) 作为不同channel,而文本的输入的channel通常是不同方式的embedding方式(比如 word2vec或Glove),实践中也有利用静态词向量和fine-tunning词向量作为不同channel的做法。
一维卷积(conv-1d):图像是二维数据,经过词向量表达的文本为一维数据,因此在TextCNN卷积用的是一维卷积。一维卷积带来的问题是需要设计通过不同 filter_size 的 filter 获取不同宽度的视野。
Pooling层:利用CNN解决文本分类问题的文章还是很多的,比如这篇 A Convolutional Neural Network for Modelling Sentences(https://arxiv.org/pdf/.pdf)最有意思的输入是在 pooling 改成 (dynamic) k-max pooling ,pooling阶段保留 k 个最大的信息,保留了全局的序列信息。比如在情感分析场景,举个例子:
“ 我觉得这个地方景色还不错,但是人也实在太多了 ”
虽然前半部分体现情感是正向的,全局文本表达的是偏负面的情感,利用 k-max pooling能够很好捕捉这类信息。
2.2.3 TextRNN
尽管TextCNN能够在很多任务里面能有不错的表现,但CNN有个最大问题是固定 filter_size 的视野,一方面无法建模更长的序列信息,另一方面 filter_size 的超参调节也很繁琐。CNN本质是做文本的特征表达工作,而自然语言处理中更常用的是递归神经网络(RNN, Recurrent Neural Network),能够更好的表达上下文信息。具体在文本分类任务中,Bi-directional RNN(实际使用的是双向LSTM)从某种意义上可以理解为可以捕获变长且双向的的 “n-gram” 信息。
双向LSTM算是在自然语言处理领域非常一个标配网络了,在序列标注/命名体识别/seq2seq模型等很多场景都有应用,下图是Bi-LSTM用于分类问题的网络结构原理示意图,黄色的节点分别是前向和后向RNN的输出,示例中的是利用最后一个词的结果直接接全连接层softmax输出了。
2.2.4 TextRNN + Attention
CNN和RNN用在文本分类任务中尽管效果显著,但都有一个不足的地方就是不够直观,可解释性不好,特别是在分析badcase时候感受尤其深刻。而注意力(Attention)机制是自然语言处理领域一个常用的建模长时间记忆机制,能够很直观的给出每个词对结果的贡献,基本成了Seq2Seq模型的标配了。实际上文本分类从某种意义上也可以理解为一种特殊的Seq2Seq,所以考虑把Attention机制引入近来,研究了下学术界果然有类似做法。
Attention机制介绍:
详细介绍Attention恐怕需要一小篇文章的篇幅,感兴趣的可参考14年这篇paper NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE(https://arxiv.org/pdf/.pdf)
以机器翻译为例简单介绍下,下图中xt是源语言的一个词,yt是目标语言的一个词,机器翻译的任务就是给定源序列得到目标序列。翻译t的过程产生取决于上一个词 yt-1 和源语言的词的表示 hj(xj的 bi-RNN 模型的表示),而每个词所占的权重是不一样的。比如源语言是中文 “我 / 是 / 中国人” 目标语言 “i / am / Chinese”,翻译出“Chinese”时候显然取决于“中国人”,而与“我 / 是”基本无关。下图公式, αij 则是翻译英文第 i 个词时,中文第 j 个词的贡献,也就是注意力。显然在翻译“Chinese”时,“中国人”的注意力值非常大。
Attention的核心point是在翻译每个目标词(或 预测商品标题文本所属类别)所用的上下文是不同的,这样的考虑显然是更合理的。
TextRNN + Attention 模型:
我们参考了这篇文章Hierarchical Attention Networks for Document Classification(https://www.cs.cmu.edu/~diyiy/docs/naacl16.pdf),下图是模型的网络结构图,它一方面用层次化的结构保留了文档的结构,另一方面在word-level和sentence-level。淘宝标题场景只需要 word-level 这一层的 Attention 即可。
加入Attention之后最大的好处自然是能够直观的解释各个句子和词对分类类别的重要性。
2.2.5 TextRCNN(TextRNN + CNN)
我们参考的是中科院15年发表在AAAI上的这篇文章 Recurrent Convolutional Neural Networks for Text Classification 的结构:
利用前向和后向RNN得到每个词的前向和后向上下文的表示:
这样词的表示就变成词向量和前向后向上下文向量concat起来的形式了,即:
最后再接跟TextCNN相同卷积层,pooling层即可,唯一不同的是卷积层 filter_size = 1就可以了,不再需要更大 filter_size 获得更大视野,这里词的表示也可以只用双向RNN输出。
3. 一点经验
理论和实践之间的Gap往往差异巨大,学术paper更关注的是模型架构设计的新颖性等,更重要的是新的思路;而实践最重要的是在落地场景的效果,关注的点和方法都不一样。这部分简单梳理实际做项目过程中的一点经验教训。
模型显然并不是最重要的:不能否认,好的模型设计对拿到好结果的至关重要,也更是学术关注热点。但实际使用中,模型的工作量占的时间其实相对比较少。虽然再第二部分介绍了5种CNN/RNN及其变体的模型,实际中文本分类任务单纯用CNN已经足以取得很不错的结果了,我们的实验测试RCNN对准确率提升大约1%,并不是十分的显著。最佳实践是先用TextCNN模型把整体任务效果调试到最好,再尝试改进模型。
理解你的数据:虽然应用深度学习有一个很大的优势是不再需要繁琐低效的人工特征工程,然而如果你只是把他当做一个黑盒,难免会经常怀疑人生。一定要理解你的数据,记住无论传统方法还是深度学习方法,数据 sense 始终非常重要。要重视 badcase 分析,明白你的数据是否适合,为什么对为什么错。
关注迭代质量 - 记录和分析你的每次实验:迭代速度是决定算法项目成败的关键,学过概率的同学都很容易认同。而算法项目重要的不只是迭代速度,一定要关注迭代质量。如果你没有搭建一个快速实验分析的套路,迭代速度再快也只会替你公司心疼宝贵的计算资源。建议记录每次实验,实验分析至少回答这三个问题:为什么要实验?结论是什么?下一步怎么实验?
超参调节:超参调节是各位调参工程师的日常了,推荐一篇文本分类实践的论文 A Sensitivity Analysis of (and Practitioners’ Guide to) Convolutional Neural Networks for Sentence Classification(https://arxiv.org/pdf/.pdf),里面贴了一些超参的对比实验,如果你刚开始启动文本分析任务,不妨按文章的结果设置超参,怎么最快的得到超参调节其实是一个非常重要的问题,可以读读萧瑟的这篇文章 《深度学习网络调参技巧 - 知乎专栏》(/p/?utm_source=zhihu&utm_medium=social)。
一定要用 dropout:有两种情况可以不用:数据量特别小,或者你用了更好的正则方法,比如bn。实际中我们尝试了不同参数的dropout,最好的还是0.5,所以如果你的计算资源很有限,默认0.5是一个很好的选择。
fine-tuning 是必选的:上文聊到了,如果只是使用word2vec训练的词向量作为特征表示,我赌你一定会损失很大的效果。
未必一定要 softmax loss: 这取决与你的数据,如果你的任务是多个类别间非互斥,可以试试着训练多个二分类器,我们调整后准确率还是增加了&1%。
类目不均衡问题:基本是一个在很多场景都验证过的结论:如果你的loss被一部分类别dominate,对总体而言大多是负向的。建议可以尝试类似 booststrap 方法调整 loss 中样本权重方式解决。
避免训练震荡:默认一定要增加随机采样因素尽可能使得数据分布iid,默认shuffle机制能使得训练结果更稳定。如果训练模型仍然很震荡,可以考虑调整学习率或 mini_batch_size。
没有收敛前不要过早的下结论:玩到最后的才是玩的最好的,特别是一些新的角度的测试,不要轻易否定,至少要等到收敛吧。
4. 写在最后
几年前校招面阿里时,一面二面聊的都是一个文本分类的项目(一个新浪微博主题分类的学校课题项目),用的还是文中介绍的传统的做法。面试时对特征项处理和各个分类器可谓如数家珍,被要求在白板上写了好几个特征选择公式,短短几年传统做法已经被远远超越,不得不感慨深度学习的发展。
值得感慨的一方面是今天技术的发展非常快,故步自封自然是万万万万不可取,深知还有很多理论尚且不懂还要继续深读paper;另一方面,理解理论原理和做好项目间实际非常有巨大的gap,特别是身处工业界的同仁们,学术圈值得钻但要把握分寸,如果仅仅追逐技术深度,不免容易陷入空中阁楼。
最后老规矩再次安利下我们team的招聘,对淘宝搜索排序和自然语言处理方向感兴趣的同学欢迎邮件我 qingsong.,来淘宝,一起成长!
责任编辑:
声明:本文由入驻搜狐号的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
今日搜狐热点温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(1642)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'【转】斯坦福大学自然语言处理第六课“文本分类(Text Classification)”',
blogAbstract:'一、课程介绍斯坦福大学于2012年3月在Coursera启动了在线自然语言处理课程,由NLP领域大牛Dan Jurafsky 和 Chirs Manning教授授课:'
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}学员分享 | 一篇文章带你看懂 Keras 文本分类实现
本文作者为 Udacity深度学习纳米学位毕业学员,他毕业后,一直想自己动手做点什么来着,之前一直没怎么观看Youtube网红Siraj老师的课程视频,他每个视频最后都会有一个编程挑战。于是,想着先从自己熟悉的内容着手吧,Siraj老师第三周的编程挑战是做一个多类别的文本分类器,那就来试试吧。
除了想自己练练手外,也顺便把模型都好好梳理一遍。为了给自己增加些难度,是否有可能把过去几年内那些大牛们论文中的模型复现出来呢?阅读这篇文章,需要你对自然语言处理和深度学习的模型有一个基础的了解哦!
另外,需要声明的是,本文在写作过程中或多或少参考了如下大牛们的博客:
用深度学习(CNN RNN Attention)解决大规模文本分类问题 - 综述和实践
卷积神经网络(CNN)在句子建模上的应用
深度学习在文本分类中的应用
深度学习与文本分类总结第一篇--常用模型总结
优达学城深度学习基石纳米学位课程
文本多分类
首先我们来看下数据集长什么样子吧 :P Let‘s get started!
我们使用pandas来加载数据,数据集来自http://,收集了过去20年各大游戏厂商发布的游戏数据,如发布日期,发布平台,游戏评价等变量,这里有一篇关于这个数据集很不错的分析教程 Kaggle。而我们现在想分析下游戏名与用户评价之间的关系,看上去并不合理,我们姑且按照Siraj老师的任务来试试。于是,游戏名作为文本变量将作为模型的输入X,而用户评价词作为文本类别Y。然后来看看各个类别的数量,为了避免类别样本数的不平衡,我们这里把关于评价为Disaster的游戏去除。
首先我们先来试试传统机器学习模型对文本分类任务常见的做法吧
传统文本分类方法
由于计算机只能处理数字型的变量,并不能直接把文本丢给计算机然后让它告诉我们这段文字的类别。于是,我们需要对词进行one-hot编码。假设我们总共有N个词,然后对词进行索引编码并构造一个N维零向量,如果这个文本中的某些词出现,就在该词索引值位置标记为1,表示这个文本包含这个词。于是,我们会得到如下类似的向量
(0,0,1,0,....,1,...0,0,1,0)
但是,一般来说词库量至少都是百万级别,因此词袋模型有个两个最大的问题:高维度、高稀疏性。这种表示方法还存在一个重要的问题就是”词汇鸿沟”现象:任意两个词之间都是孤立的。光从这两个向量中看不出两个词是否有关系。
为了使用上下文来表示单词间的关系,也有人提出使用基于窗口大小的共现矩阵,但仍然存在数据维度大稀疏的问题。
TF-IDF 用以评估一字词对于一个文档集或一个语料库中的其中一份文档的重要程度,是一种计算特征权重的方法。核心思想即,字词的重要性随着它在文档中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。有效地规避了那些高频却包含很少信息量的词。我们这里也是用TF-IDF 对文本变量进行特征提取。
分类器就是常见的机器学习分类模型了,常用的有以下两种,这里我不再赘述这两个模型的原理了。
朴素贝叶斯:从垃圾邮件识别应用开始被广泛使用
支持向量机:这篇文章很通俗地解释了SVM的工作原理
使用Scikit-Learn库能够傻瓜似的来实现你的机器学习模型,我们这里使用TfidfVectorizer函数对文本进行特征处理,并去除停用词,模型有多类别朴素贝叶斯和线性SVM分类器。结果很不令人满意,NB模型结果稍好,准确率为28%,领先SVM 1%。下面我们来看看深度学习模型强大的性能。
vect=TfidfVectorizer(stop_words='english',token_pattern=r'bw{2,}b',min_df=1,max_df=0.1,ngram_range=(1,2))
mnb=MultinomialNB(alpha=2)
svm=SGDClassifier(loss='hinge',penalty='l2',alpha=1e-3,max_iter=5,random_state=42)
mnb_pipeline=make_pipeline(vect,mnb)
svm_pipeline=make_pipeline(vect,svm)
mnb_cv=cross_val_score(mnb_pipeline,title,label,scoring='accuracy',cv=10,n_jobs=-1)
svm_cv=cross_val_score(svm_pipeline,title,label,scoring='accuracy',cv=10,n_jobs=-1)
print('nMultinomialNB Classifier's Accuracy: %0.5fn'%mnb_cv.mean())
print('nSVM Classifier's Accuracy: %0.5fn'%svm_cv.mean())走进NLP和DL
传统方法对于文本的特征表达能力很弱,神经网络同样不擅长处理这样高维度高稀疏性的数据,因此我们需要对文本做进一步的特征处理,这里就要讲到词嵌入的概念了。深度学习模型中,一个单词常常用一个低维且稠密的向量来表示,如下所示:
(0.286,0.792,-0.177,-0.107,....,0.109,...0.349,0.271,-0.642)
主流的词嵌入实现方法有Mikolov的Word2Vec和斯坦福大学的Glove,也有人做过实验来比较这两种方法的优劣,并没有多大的差异。Word2Vec是基于预测的词向量模型,简单来说,就是给定一个词,去预测这个词周围可能出现的词,或者给定一些词来确定位于中心位置的词。而Glove是基于统计方法的,通过对词-词共现矩阵里的非零元素进行训练。总体来说,Word2Vec使用的是局部信息,而Glove使用的是全局信息,因此前者训练起来更慢但不占用内存,而Glove通过更多的计算资源换取训练速度上的提升。具体的实现细节可以参考这两篇论文。本文中将使用预训练的Glove300维词向量和由自己文本生成的词向量。
为了快速实现模型,这篇文章中将使用Keras(TensorFlow的高级API)来完成。要使用Keras前,你必须安装TensorFlow作为其后端,Keras目前支持Tensorflow、Theano和CNTK作为后端,不过我还是推荐大家使用TensorFlow。Keras的中文文档能够帮助大家无坑完成安装过程。
我们先来了解一些基础的深度学习模型吧!
深度学习入门必学的两大模型之一卷积神经网络。首先我们来理解下什么是卷积操作?卷积,你可以把它想象成一个应用在矩阵上的滑动窗口函数。下图中左边的矩阵表示的是一张黑白图像。每个方格代表了一个像素,0表示黑色,1表示白色。这个滑动窗口称作kernel或者filter。这里我们使用的是一个3*3的filter,将它的值和与其对应的原图像矩阵进行相乘,然后再将它们相加。这样我们在整个原图矩阵上滑动filter来遍历所有像素后得到一个完整的卷积特征。
卷积网络也就是对输入样本进行多次卷积操作,提取数据中的局部位置的特征,然后再拼接池化层(图中的Pooling层)做进一步的降维操作,最后与全连接层拼接完成对输入样本的全新的特征构造,将新的特征向量输送给分类器(以图片分类为例)进行预测分类。我们可以把CNN类比N-gram模型,N-gram也是基于词窗范围这种局部的方式对文本进行特征提取,与CNN的做法很类似,在下文中,我们再来看看如何运用CNN对文本数据进行建模。
卷积网络开始崭露头角是在CV领域,2012年的ImageNet竞赛中,大大降低了图片分类的错误率。为什么CNN在计算机视觉领域这么厉害呢?直观的感受就是:
它能够学习识别基本的直线,曲线,然后是形状,点块,然后是图片中更复杂的物体。最终CNN分类器把这些大的,复杂的物体综合起来识别图片
在下图中的例子中,可以看作这样的层级关系:
简单的形状,如椭圆,暗色圆圈
复杂的物体(简单形状的组合),例如眼睛,鼻子,毛发
狗的整体(复杂物体的组合)
而循环网络与CNN不同的是,CNN学习空间位置上局部位置的特征表示,而RNN学习的是时间顺序上的特征,用来处理序列数据,如股价,文本等。RNN之所以称为循环神经网路,即一个序列当前的输出与前面的输出也有关。具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点是相互连接的,并且隐藏层的输入不仅包括输入层的输出还包括上一时刻隐藏层的输出。
就像我们说话一样,我们不能把说的话倒过来表示,这样会变得毫无意义,并不会明白你在说什么,也就是说文本中的每个词是包含顺序信息的,由此可以使用RNN对文本数据进行建模。
但是,随着时间的不断增加,你的隐藏层一次又一次地乘以权重W。假如某个权重w是一个接近于0或者大于1的数,随着乘法次数的增加,这个权重值会变得很小或者很大,造成反向传播时梯度计算变得很困难,造成梯度爆炸或者梯度消失的情况,模型难以训练。也就是说一般的RNN模型对于长时间距离的信息记忆很差,比如人老了会忘记某件很久发生的事情一样,于是,LSTM和GRU 应运而生。LSTM与GRU很相似,以LSTM为例。
LSTM又称为长短期记忆网络,LSTM 单元乍看起来很复杂。关键的新增部分就在于标记为 C 的单元状态。在这个单元中,有四个显示为黄色框的网络层,每个层都有自己的权重,如以 σ 标记的层是 sigmoid 层。这些红圈表示逐点或逐元素操作。单元状态在通过 LSTM 单元时几乎没有交互,使得大部分信息得以保留,单元状态仅通过这些控制门(gate)进行修改。第一个控制门是遗忘门,用来决定我们会从单元状态中丢弃什么信息。第二个门是更新们,用以确定什么样的新信息被存放到单元状态中。最后一个门是输出门,我们需要确定输出什么样的值。总结来说 LSTM 单元由单元状态和一堆用于更新信息的控制门组成,让信息部分传递到隐藏层状态。更直观的来讲,把LSTM看作是一部电影,可以把单元状态看作是剧情主线,而随着剧情的发展,有些不必要的事件会被遗忘,而一些更加影响主线的剧情会被加入到单元状态中来,不断更新剧情然后输出新的剧情发展。
Attention机制
基于Attention的模型在NLP领域首先被应用于自然语言生成问题中,用于改进机器翻译任务的性能。我们这里也以机器翻译为例来解释下注意力机制的原理。我们可以把翻译任务是一个序列向另一个序列转换的过程。
上图就是Seq2Seq模型的基本结构,由编码器(Encoder)和解码器(Decoder)组成。编码器负责将输入的单词按顺序进行信息提取,在最后一步生成的隐藏状态即固定长度的句子的特征向量。然后解码器从这个句子向量中获取信息对文本进行翻译。由于解码器的主要信息来源就是最后一步的隐藏状态,这个h3向量必须尽可能地包含句子的所有必要的信息。这个向量说白了就是句子嵌入(类比词嵌入)。假如我们需要翻译的文本不是很长,这个模型已经能达到很不错的性能。假如我们现在要翻译一句超过50个单词的句子,似乎这个模型很难再hold住,即使你在训练的时候使用了LSTM去提取句子特征,去尽可能保留过去的记忆,但还是达不到想要的结果。
而注意力机制恰恰是为了解决长距离依赖的问题,我们不再需要固定长度的句子向量,而是让解码器自己去输入文本中寻找想要关注的被翻译文本。比如把”I am learning deep learning model“成中文时,我们让解码器去与输入文本中的词对齐,翻译deep的时候去关注deep这个词,而不是平等对待每个有可能的词,找到与输入文本相对应的相同语义的词,而不再是对句子进行特征提取。
上图我们可以看到,解码器在翻译下一个词时,需要依赖之前已经翻译好的文本和与输入文本相对齐的那个词。简单描述的话,用解码器t时刻的隐藏状态去和输入文本中的每个单词对应的隐藏状态去比对,通过某个函数f去计算带翻译的单词yi与每个输入单词对齐的可能性。而编码器由Bi-LSTM模型组成。不同的语言的f函数可能会有差别,就像中文和英文,语法结构差异很大,很难按顺序单词一一对齐。由此可以得出结论,注意力机制的核心思想是在翻译每个目标词(或对文本进行分类时)所用的上下文是不同的,这样的考虑显然是更合理的。具体实现请见这篇论文。而如何将注意力机制运用到文本分类中来,下文会介绍。
深度学习文本分类模型
这是CNN首次被应用于文本分类任务的开山之作,可以说,之后很多论文都是基于此进行拓展的。它是由Yoon Kim于2014年发表的,你可以在github上找到各种不同深度学习框架对于这个模型的实现。下面我们来细细品读这篇论文吧。
上图很好地诠释了模型的框架。假设我们有一句句子需要对其进行分类。句子中每个词是由n维词向量组成的,也就是说输入矩阵大小为m*n,其中m为句子长度。CNN需要对输入样本进行卷积操作,对于文本数据,filter不再横向滑动,仅仅是向下移动,有点类似于N-gram在提取词与词间的局部相关性。图中共有三种步长策略,分别是2,3,4,每个步长都有两个filter(实际训练时filter数量会很多)。在不同词窗上应用不同filter,最终得到6个卷积后的向量。然后对每一个向量进行最大化池化操作并拼接各个池化值,最终得到这个句子的特征表示,将这个句子向量丢给分类器进行分类,至此完成整个流程。
文中作者还提出了动态的词向量,即将词向量也作为权重变量进行训练,而我们平时常用的产生词向量的方法有从当前数据集中自己产生的词向量和使用预训练好的word2vec或glove词向量,都属于静态词向量范畴,即它们不再网络训练时发生变化。文中实验表明,动态的词向量表现更好。有时间的话之后来尝使用Tensorflow来实现这种动态词向量。另外,这篇论文 A Sensitivity Analysis of (and Practitioners' Guide to) Convolutional Neural Networks for Sentence Classification详细地阐述了关于TextCNN模型的调参心得。
这篇论文的亮点在于采用的动态的K-max Pooling,而不是我们常见的Max Pooling层。模型细节主要分为以下几个部分:
宽卷积:卷积分为两种,窄卷积和宽卷积。窄卷积即从第一个元素开始卷积操作,这样第一个元素和最后一个元素只能被filter扫过一次。而宽卷积为了弥补这一点,就在第一个元素前和最后一个元素后增加0作为补充,因此宽卷积又叫做补零法。当filter长度相对输入向量的长度较大时,你会发现宽卷积很有用,或者说很有必要。
动态的K-Max Pooling:下图中可以看到两个个池化层的K是不确定的,即动态的,具体的取值依赖于输入和网络的其他参数。文中提到,K的取值与输入文本的长度,网络中总共的卷积数,上一层卷积的个数有关,具体可以查看论文(始终没有解决数学公式的显示问题,所以不展开了)。因此文中的pooling的结果不是返回一个最大值,而是返回k组最大值,这些最大值是原输入的一个子序列
Folding层:图中很清楚地看到,Folding层将词向量的维度缩减一半,即将两行的向量相加,可能考虑相邻两行之前某种未知的联系吧。不确定是否真的有效,第一次看到卷积网络中出现这样缩减维度的层。
本篇论文由复旦大学的邱锡鹏教授的团队于2015年发表,文中详细地阐述了RNN模型用于文本分类任务的各种变体模型。最简单的RNN用于文本分类如下图所示,这是LSTM用于网络结构原理示意图,示例中的是利用最后一个词的结果直接接全连接层softmax输出就完成了。详情可见这里的阅读笔记链接
论文A C-LSTM Neural Network for Text Classification中将CNN和RNN混合使用作为文本的分类器。其实就是将CNN训练得到的新的特征作为LSTM的输入,模型的简单描述如下:
Feature maps指不同词窗经过不同过滤层即卷积操作后得到的特征集合
Window feature sequence是指CNN不再经过Max-pooling操作,而是将特征集合重新排列,得到同一词窗在经过不同卷积操作后的综合特征向量,即把相同颜色的放在一个序列里面,然后依次排列下来
在window feature sequence层的每个序列,其实和原始句子中的序列是对应的,保持了原有的相对顺序,只不过是中间进行了卷积的操作,将这些新的向量作为LSTM的输入变量。
这篇Recurrent Convolutional Neural Networks for Text Classification是由中科院与2015年发表在AAAI上的一篇文章。文中将RNN和CNN以另外一种方式呈现。
我们可以发现,这个模型是把CNN模型中的卷积的部分使用RNN代替了,最后加上池化层。而这个RNN层做的事情是,将每一个词分别和左边的词以及右边的词进行融合。每以文本先经过1层双向LSTM,该词的左侧的词正向输入进去得到一个词向量,该词的右侧反向输入进去得到一个词向量。再结合该词的词向量,生成一个 3k维的组合词向量。然后再将这些新的词向量传入全连接层,紧接着是最大化池化层进行特征降维。最后接上全连接层,便完成多分类任务。
FastText是Facebook于2016年发表的论文中提出的一种简单快速实现的 文本分类模型。可能你已经被前面那些复杂的模型搞得七荤八素了,那么这个模型你很快地理解,令人意外的是,它的性能并不差。输入变量是经过embedding的词向量,这里的隐藏层只是一个简单的平均池化层,然后把这个池化过的向量丢给softmax分类器就完成了。另外,这里的X并不仅仅是单个单词,也可以加入N-gram组合的词作为输入的一部分,文中将2-元和3-元的特征也加入到了模型中。本文的思想在于通过简单的特征线性组合就可以达到不错的分类性能,我们可以把fasttext当作是工业界一种快速实现模型的产物。
Hierarchical Attention Networks(HAN)
本文最大的特点是结合了注意力机制,并成功运用到文本分类任务中。模型如下图所示,分为两大部分,分别是对句子建模和对文档建模。之前提到的模型基本上都是在对句子进行建模,通过对句子中的词进行特征组合,形成句子向量。本文更进一步的是,对句子的上一级篇章进行建模。我们假设评论中有好几句话,那么我们首先要切分句子然后再切分词,对于长评论的分类是一个不错的选择。
首先,词向量会经过双向LSTM网络完成编码,将隐藏层的输出和注意力机制相结合,形成对句子的特征表示。然后每一个句子相当于一个词,再重复一次前一步词到句子的建模过程,完成句子到文档的建模过程。而注意力机制在这里发挥的作用相当于去寻找这句句子中的核心词或者这篇文档中的核心句子。具体实现的过程可参照我接下来的代码。这里有关于在Keras中完成Attention层的构建的详细讨论。游戏标题只涉及单句,因此构不成文档,只需要 word-level 这一层的注意力即可。加入Attention之后最大的好处自然是能够直观的解释各个句子和词对分类类别的重要性。
Aspect Level Sentiment
首先来介绍先aspect的概念,给定一个句子和句子中出现的某个aspect,aspect-level 情感分析的目标是分析出这个句子在给定aspect上的情感倾向。例如:"Great food but the service was dreadful!" 在“food”这个aspect上,情感倾向为正,而在 “service”这个aspect上情感倾向为负。Aspect level的情感分析相对于文档级别来说粒度更细。
Aspect Level Sentiment Classification with Deep Memory Network
Attention-based LSTM for Aspect-level Sentiment Classification
首先我们先要对文本数据进行编码,因为模型只能接受数值型的数据。常见的编码之前有提到过有One-Hot和词嵌入。第一步,来划分训练样本和测试样本。如果需要将你的模型部署到产品中去,则需要更加复杂的划分,详情请见吴恩达最新的AI课程中提及的机器学习项目中必须注意的一些问题。这里,我们不需要考虑太多的细节,就简单划分训练集和测试集即可。
# 导入使用到的库
fromkeras.preprocessing.sequenceimportpad_sequences
fromkeras.preprocessing.textimportTokenizer
fromkeras.layers.mergeimportconcatenate
fromkeras.modelsimportSequential,Model
fromkeras.layersimportDense,Embedding,Activation,merge,Input,Lambda,Reshape
fromkeras.layersimportConvolution1D,Flatten,Dropout,MaxPool1D,GlobalAveragePooling1D
fromkeras.layersimportLSTM,GRU,TimeDistributed,Bidirectional
fromkeras.utils.np_utilsimportto_categorical
fromkerasimportinitializers
fromkerasimportbackendasK
fromkeras.engine.topologyimportLayer
fromsklearn.naive_bayesimportMultinomialNB
fromsklearn.linear_modelimportSGDClassifier
fromsklearn.feature_extraction.text
importTfidfVectorizer
importpandasaspd
importnumpyasnp
# 划分训练/测试集
X_train,X_test,y_train,y_test=train_test_split(title,label,test_size=0.1,random_state=42)# 对类别变量进行编码,共10类y_labels=list(y_train.value_counts().index)le=preprocessing.LabelEncoder()le.fit(y_labels)num_labels=len(y_labels)y_train=to_categorical(y_train.map(lambdax:le.transform([x])[0]),num_labels)y_test=to_categorical(y_test.map(lambdax:le.transform([x])[0]),num_labels)# 分词,构建单词-id词典 tokenizer=Tokenizer(filters='!"#$%&()*+,-./:;&=&?@[]^_`{|}~tn',lower=True,split=" ")tokenizer.fit_on_texts(title)vocab=tokenizer.word_index# 将每个词用词典中的数值代替X_train_word_ids=tokenizer.texts_to_sequences(X_train)X_test_word_ids=tokenizer.texts_to_sequences(X_test)# One-hotx_train=tokenizer.sequences_to_matrix(X_train_word_ids,mode='binary')x_test=tokenizer.sequences_to_matrix(X_test_word_ids,mode='binary')# 序列模式x_train=pad_sequences(X_train_word_ids,maxlen=20)x_test=pad_sequences(X_test_word_ids,maxlen=20)
Keras提供两大类模型框架。第一种是Sequential模式,就像搭积木一样,将你想要的网络层拼接起来,可以理解为串联。而另外一种是Model模式,需要你指定模型的输入和输出格式,更加灵活地组合你的网络层,可以理解为串联加并联。搭建完模型结构后,你需要对模型进行编译,这一步你需要指定模型的损失函数,本文是文本多分类任务,所以损失函数是多类别的交叉熵函数。另外, 需要确定损失函数的优化算法和模型评估指标。Adam优化器是目前公认的各项任务中性能最优的,所以本文将全部使用Adam作为优化器。这里有一篇实战教程对不同优化器做了性能评估。接着就是模型的训练,使用fit函数,这里需要指定的参数有输入数据,批量大小,迭代轮数,验证数据集等。然后,你就能看到你的模型开始愉快地运行起来了。Keras作为Tensforflow的高级API,对很多细节进行了封装,可以让深度学习小白快速上手,如果你需要实现更加复杂的模型的话,就需要去好好研究下Tensorflow了。下一篇博文目标是用Tensorflow来实现简单的机器翻译任务,也为接下来准备参加的AI Challenger比赛做准备!
One-Hot + MLP
MLP翻译过来叫多层感知机,其实就是多隐藏层的网络。如此简单的模型,结果居然出奇的好!卖个关子,最后看看各个模型的最终准确率排名 = =
模仿LeNet-5
LeNet-5是卷积神经网络的作者Yann LeCun用于MNIST识别任务提出的模型。模型很简单,就是卷积池化层的堆叠,最后加上几层全连接层。我们依样画葫芦,将它运用在文本分类任务中,只是模型的输入不同。
TextCNN(这里需要使用Model模式)
# 模型结构:词嵌入-卷积池化*3-拼接-全连接-dropout-全连接
main_input=Input(shape=(20,),dtype='float64')
# 词嵌入(使用预训练的词向量)
embedder=Embedding(len(vocab)+1,300,input_length=20,weights=[embedding_matrix],trainable=False)
embed=embedder(main_input)
# 词窗大小分别为3,4,5
cnn1=Convolution1D(256,3,padding='same',strides=1,activation='relu')(embed)
cnn1=MaxPool1D(pool_size=4)
(cnn1)cnn2=Convolution1D(256,4,padding='same',strides=1,activation='relu')(embed)
cnn2=MaxPool1D(pool_size=4)(cnn2)
cnn3=Convolution1D(256,5,padding='same',strides=1,activation='relu')(embed)
cnn3=MaxPool1D(pool_size=4)(cnn3)
# 合并三个模型的输出向量
cnn=concatenate([cnn1,cnn2,cnn3],axis=-1)
flat=Flatten()(cnn)
drop=Dropout(0.2)(flat)
main_output=Dense(num_labels,activation='softmax')(drop)
model=Model(inputs=main_input,outputs=main_output)
DCNN(占坑)
LSTM(你也可以换成GRU,经过多次试验GRU的性能较LSTM稍好)
GRU采用与LSTM相似的单元结构用于控制信息的更新与保存,它将遗忘门和输入门合成了一个单一的更新门,最终的模型比标准的 LSTM 模型要简单,也是非常流行的变体。
需要注意的是,你如果需要堆叠多层RNN,需要在前一层返回序列,设置return_sequences参数为True即可。Bi即双向RNN结构,模型会从正向读取文本,也会逆向读取文本,从两个角度去获取文本的顺序信息。
C-LSTM串联(将CNN的输出直接拼接上RNN)
并联(将CNN的输出和RNN的输出合并成一个输出)(论文)
由于Keras目前还没有现成的Attention层可以直接使用,我们需要自己来构建一个新的层函数。Keras自定义的函数主要分为四个部分,分别是:
init:初始化一些需要的参数
bulid:具体来定义权重是怎么样的
call:核心部分,定义向量是如何进行运算的
compute_output_shape:定义该层输出的大小
这里我只列出核心的call部分,传送门:官方示例
定义好Attention层,直接调用即可,我们来看下:
Aspect-Level Sentiment(占坑)
FastText(模型很简单,比较复杂的是构造输入数据)
Char-Level
我分别测试了TextCNN和RNN模型采用字符作为输入时的模型性能,发现不尽如人意,究其原因,可能是字级别粒度太细,而且文本是短文本,并不能反映出什么有效的信息。前者能达到0.4勉强及格的准确率,而后者只能达到0.28的准确率。因此,不再尝试对短文本进行字粒度的考证。这里想简单应用字符级别的输入,只需对原始文本稍作改变即可。
To-do list
还有一些论文还没有实现,接下来我会继续更新,敬请期待。。。
Aspect Level Sentiment
Dynamic K-max Pooling
模型结果比较
每个模型我都尝试了使用预训练的Glove词向量,效果都不如直接从原文本训练来的好,可能的原因是,文本内容比较简单,而300维的Glove词向量是根据海量语料训练的,看来并不能简单使用Word2Vec和Glove的训练好的向量。需要注意的是,我将最后一个epoch(总共12个epoch)的结果最为模型最终的准确率而且并没有做交叉验证,这样的做法不太合理,可能存在有的模型过拟合了,有的还是欠拟合状态的,简单粗暴吧。每个模型的训练时间和准确率如下图:
我们可以看到CNN模型的训练一般都比较快,性能也不算太差。可能是由于语料相对简单,简单的模型如FastText和MLP在准确率上名列前茅,精心设计的模型反而不如简单的模型,有点小题大作的意思。接下来,我们看看更加复杂的推特语料,这些复杂的模型会不会给我们带来一些惊喜呢?
推文情感分析
之前我提到其实,这个游戏标题分类任务并没有什么实际的意义,只是为了熟悉模型,小试牛刀,接下来我们来试试更大的数据集,比如推文的情感分析任务。标注好的情感分析任务可以当做文本分任务来处理。数据集来自密歇根大学的课程作业SI650 - Sentiment Classification和由Niek Sanders收集的推文数据集,总共有大约157W条推文,目标变量为0或1,表示消极和积极的情感,是一个大数据集的二分类任务。文中提到使用朴素贝叶斯分类器可以达到75%的准确率,为了验证,我分别使用NB和SVM模型对全部数据集做了测试,NB的准确率在77.5%,SVM为73%。我们来看看深度学习模型是否会有大幅度的提升呢?
fromkeras.preprocessing.sequenceimportpad_sequences
fromkeras.preprocessing.textimportTokenizer
fromkeras.utils.np_utilsimportto_categorical
fromkeras.modelsimportSequential,Model
fromkeras.layersimportDense,Embedding,Activation,merge,Input,Lambda,Reshape
fromkeras.layersimportConvolution1D,Flatten,Dropout,MaxPool1D,GlobalAveragePooling1D
fromkeras.layersimportBatchNormalization
输入文本处理
# 刚开始想直接应用之前的处理方法,发现渣本由于显存太小,根本跑不起来
# 于是减少一些词汇量和输入文本的大小
# 随机抽取10W条推文
df=df.sample(100000)
# 先处理目标变量
Y=df.Sentiment.values
Y=to_categorical(Y)
# 另外,nltk包还有一个内置的专门处理推特文本的分词器
tokenizer=Tokenizer(filters='!"#$%&()*+,-./:;&=&?@[]^_`{|}~tn',lower=True,split=" ")
tokenizer.fit_on_texts(df.SentimentText)vocab=tokenizer.word_index
# 划分train/test set
x_train,x_test,y_train,y_test=train_test_split(df.SentimentText,Y,test_size=0.2,random_state=2017)
# 对文本进行编码(40是所有文本的90%左右的长度,超过的部分直接截去,不足的以0补足)
x_train_word_ids=tokenizer.texts_to_sequences(x_train)
x_test_word_ids=tokenizer.texts_to_sequences(x_test)
x_train_padded_seqs=pad_sequences(x_train_word_ids,maxlen=64)
x_test_padded_seqs=pad_sequences(x_test_word_ids,maxlen=64)
跑模型(以TextCNN为例)
这里我参照的是知乎看山杯比赛第一名的模型,是TextCNN的扩展版本。他在原先模型的基础上
使用两层卷积
使用更多的卷积核,更多尺度的卷积核
使用了BatchNorm
分类的时候使用了两层的全连接
总之就是更深更复杂,所以我也来试试,依样画葫芦。
但是结果却不尽如人意,出现了严重的过拟合,最终取第二个batch结束后的准确率为76.75%,训练时间为520秒。由于这个模型比之前的模型都要复杂,即使使用了BN技术加速训练,仍旧需要10分钟左右的训练时间。本文使用的GPU为GTX1060(3GB)。什么时候能够拥有一台跑模型的服务器啊? T T
我们使用了复杂的模型和Adam优化器使得模型在训练集上表现出色,准确率不断提升。但是却在测试集上出现了过拟合。过拟合的解决思路一般有以下三点:
加入正则化技术,如L2正则项,dropout,BatchNormalization等
更多的训练数据,这里我们只使用了10%不到的数据,就已经超越了朴素贝叶斯使用全部数据集的准确率
调整超参数,这个是玄学,凭经验吧 - -
之前由于对几乎没有语义的游戏标题短文本,预训练的Glove词向量,并没有发挥作用。这次,我们再来看看是否有效?
读入Glove词向量
# 模型中需要修改的仅仅是这里
embedder=Embedding(len(vocab)+1,200,input_length=64,weights=[embedding_matrix],trainable=False)
神奇的词向量,模型不再严重过拟合了,准确率进一步提升到了77.63%,训练时间缩短了一半!
为了证明之前的防过拟合策略是正确的,我们增加一倍的训练集,来看看效果。不出意外,果然提升了!至此,模型基本达到了我们想要的状态,准确进一步提升来到了79%,估计进行完整的调参的话,可以上到80%以上。
我们再来试试中文的文本分类。中文天生有个坑需要去跨越,那就是分词,对于一般的文本,现有的分词工具已经能够出色地完成任务了。而面对网络文本,目前还没有看到有效的解决方案,这篇论文尝试使用Bi-LSTM+CRF的方法来实现深度学习模型分词器,有空可以来研究下。所以,本文目前还是使用的主流的分词工具结巴分词。
根据用户给的评分,5分视作好评,2,3,4分视作中评,1分视作差评。于是,我们便得到了目标类别,共三类。其实,中评的定义很模糊,用户自身也很难去判断,中评的文本中会有一定的好评或者差评的倾向性,对于文本分类造成一定的困难。
传统机器学习方法(TF-IDF + 朴素贝叶斯/SVM)
结果如下图:
深度学习模型
为了照顾类别的平衡,在爬取数据的时候尽可能保持各个类别数量的相等,每个类别大约5200条评论左右。之后的步骤就很类似了,由于目前没有很好的中文预训练好的词向量文件,我们这里直接从原文本训练词向量。
这里我们依旧仿照知乎看山杯的冠军作者来实现一个新的模型架构Inception,Inception的结构源于2015年ImageNet竞赛中的冠军模型的缩小版。模型和之前的TextCNNBN版本很相似,如下图所示:
大家也可以自己动手来试试搭建这样一个Inception模型,代码我就不贴出来了:P
始终没有解决过拟合的问题,可能是数据问题,模型之间的差距并不明显,最终结果如下:
我们来回顾下,我们至此学到了哪些内容。
文本分类任务的处理流程(文本清理编码-数据集的划分-模型搭建-模型运行评估)
传统机器学习模型的处理方法(Baseline:TF-IDF + 分类器)
常见的深度学习模型(CNN,RNN,Attention)
历年经典论文中的模型复现(TextCNN,RCNN,HAN等)
实战(多分类的小数据集,推文情感分析,京东评论好中差评)
最后给大家推荐一些高质量的学习资源:
NLP大牛 Chris Manning 和 Richard Socher 在 Stanford 合开的课程CS224d(一直没有静下心来认真学习这门课程 T T)
Google Brain成员Christopher Olah大神的理论博客
另一位Google Brain成员Denny Britz大神关于NLP的博客 WILDML
MOOC课程资源:优达学城深度学习基石纳米学位和吴恩达三大项目之一deeplearning.ai
方得智能大神brightmart的Github Repo
最近亚马逊的DL大牛李沐老师于近期也推出了基于MXNet的Gluon框架的系列课程
希望大家能够有所收获,第一次自己动手码字,有很多论文和模型的理解还不够深刻!大家向我提出宝贵的意见!最后祝大家玩的开心!:P
客官,觉得文章不错的话,帮忙转发点个赞再走呗。
@所有人,,免费体验Google 与DiDi 联合制作的机器学习课程,成为世界领先的机器学习工程师!
责任编辑:
声明:本文由入驻搜狐号的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
今日搜狐热点

我要回帖

更多关于 任务管理器 内存 的文章

 

随机推荐