文本分类 订阅
文本分类用电脑对文本集(或其他实体或物件)按照一定的分类体系或标准进行自动分类标记。 它根据一个已经被标注的训练文档集合, 找到文档特征和文档类别之间的关系模型, 然后利用这种学习得到的关系模型对 新的文档进行类别判断 。文本分类从基于知识的方法逐渐转变为基于统计 和机器学习的方法。 展开全文
文本分类用电脑对文本集(或其他实体或物件)按照一定的分类体系或标准进行自动分类标记。 它根据一个已经被标注的训练文档集合, 找到文档特征和文档类别之间的关系模型, 然后利用这种学习得到的关系模型对 新的文档进行类别判断 。文本分类从基于知识的方法逐渐转变为基于统计 和机器学习的方法。
信息
定    义
基于分类体系的自动分类
方    法
朴素贝叶斯、支持向量机、K邻近法、决策树
中文名
文本分类
类    别
处理方式
文本分类定义
基于分类体系的自动分类基于资讯过滤和用户兴趣(Profiles)的自动分类所谓分类体系就是针对词的统计来分类关键字分类,全文检索词的正确切分不易分辨(白痴造句法)学习人类对文本分类的知识和策略从人对文本和类别之间相关性判断来学习文件用字和标记类别之间的关联
收起全文
精华内容
参与话题
问答
  • 文本分类

    千次阅读 2018-09-07 16:56:06
    一、传统文本分类方法  文本分类问题算是自然语言处理领域中一个非常经典的问题了,相关研究最早可以追溯到上世纪50年代,当时是通过专家规则(Pattern)进行分类,甚至在80年代初一度发展到利用知识工程建立专家...

    一、传统文本分类方法 
    文本分类问题算是自然语言处理领域中一个非常经典的问题了,相关研究最早可以追溯到上世纪50年代,当时是通过专家规则(Pattern)进行分类,甚至在80年代初一度发展到利用知识工程建立专家系统,这样做的好处是短平快的解决top问题,但显然天花板非常低,不仅费时费力,覆盖的范围和准确率都非常有限。

    后来伴随着统计学习方法的发展,特别是90年代后互联网在线文本数量增长和机器学习学科的兴起,逐渐形成了一套解决大规模文本分类问题的经典玩法,这个阶段的主要套路是人工特征工程+浅层分类模型。训练文本分类器过程见下图: 
    这里写图片描述 
    整个文本分类问题就拆分成了特征工程和分类器两部分,玩机器学习的同学对此自然再熟悉不过了

    1.1 特征工程

    特征工程在机器学习中往往是最耗时耗力的,但却极其的重要。抽象来讲,机器学习问题是把数据转换成信息再提炼到知识的过程,特征是“数据–>信息”的过程,决定了结果的上限,而分类器是“信息–>知识”的过程,则是去逼近这个上限。然而特征工程不同于分类器模型,不具备很强的通用性,往往需要结合对特征任务的理解。

    文本分类问题所在的自然语言领域自然也有其特有的特征处理逻辑,传统分本分类任务大部分工作也在此处。文本特征工程分位文本预处理、特征提取、文本表示三个部分,最终目的是把文本转换成计算机可理解的格式,并封装足够用于分类的信息,即很强的特征表达能力。 
    1)文本预处理

    文本预处理过程是在文本中提取关键词表示文本的过程,中文文本处理中主要包括文本分词和去停用词两个阶段。之所以进行分词,是因为很多研究表明特征粒度为词粒度远好于字粒度,其实很好理解,因为大部分分类算法不考虑词序信息,基于字粒度显然损失了过多“n-gram”信息。

    具体到中文分词,不同于英文有天然的空格间隔,需要设计复杂的分词算法。传统算法主要有基于字符串匹配的正向/逆向/双向最大匹配;基于理解的句法和语义分析消歧;基于统计的互信息/CRF方法。近年来随着深度学习的应用,WordEmbedding + Bi-LSTM+CRF方法逐渐成为主流,本文重点在文本分类,就不展开了。而停止词是文本中一些高频的代词连词介词等对文本分类无意义的词,通常维护一个停用词表,特征提取过程中删除停用表中出现的词,本质上属于特征选择的一部分。

    经过文本分词和去停止词之后淘宝商品示例标题变成了下图“ / ”分割的一个个关键词的形式:

    夏装 / 雪纺 / 条纹 / 短袖 / t恤 / 女 / 春 / 半袖 / 衣服 / 夏天 / 中长款 / 大码 / 胖mm / 显瘦 / 上衣 / 夏 
    2)文本表示和特征提取

    文本表示:

    文本表示的目的是把文本预处理后的转换成计算机可理解的方式,是决定文本分类质量最重要的部分。传统做法常用词袋模型(BOW, Bag Of Words)或向量空间模型(Vector Space Model),最大的不足是忽略文本上下文关系,每个词之间彼此独立,并且无法表征语义信息。词袋模型的示例如下:

     ( 0, 0, 0, 0, .... , 1, ... 0, 0, 0, 0)
    
    • 1
    • 2

    一般来说词库量至少都是百万级别,因此词袋模型有个两个最大的问题:高纬度、高稀疏性。词袋模型是向量空间模型的基础,因此向量空间模型通过特征项选择降低维度,通过特征权重计算增加稠密性。 
    特征提取: 
    向量空间模型的文本表示方法的特征提取对应特征项的选择和特征权重计算两部分。特征选择的基本思路是根据某个评价指标独立的对原始特征项(词项)进行评分排序,从中选择得分最高的一些特征项,过滤掉其余的特征项。常用的评价有文档频率、互信息、信息增益、χ²统计量等。 
    特征权重主要是经典的TF-IDF方法及其扩展方法,主要思路是一个词的重要度与在类别内的词频成正比,与所有类别出现的次数成反比。 
    3)基于语义的文本表示 
    传统做法在文本表示方面除了向量空间模型,还有基于语义的文本表示方法,比如LDA主题模型、LSI/PLSI概率潜在语义索引等方法,一般认为这些方法得到的文本表示可以认为文档的深层表示,而word embedding文本分布式表示方法则是深度学习方法的重要基础,下文会展现。 
    1.2 分类器 
    分类器基本都是统计分类方法了,基本上大部分机器学习方法都在文本分类领域有所应用,比如朴素贝叶斯分类算法(Naïve Bayes)、KNN、SVM、最大熵和神经网络等等,传统分类模型不是本文重点,在这里就不展开了。 
    二、深度学习文本分类方法 
    上文介绍了传统的文本分类做法,传统做法主要问题的文本表示是高纬度高稀疏的,特征表达能力很弱,而且神经网络很不擅长对此类数据的处理;此外需要人工进行特征工程,成本很高。而深度学习最初在之所以图像和语音取得巨大成功,一个很重要的原因是图像和语音原始数据是连续和稠密的,有局部相关性。应用深度学习解决大规模文本分类问题最重要的是解决文本表示,再利用CNN/RNN等网络结构自动获取特征表达能力,去掉繁杂的人工特征工程,端到端的解决问题。接下来会分别介绍: 
    2.1 文本的分布式表示:词向量(word embedding) 
    分布式表示(Distributed Representation)其实Hinton 最早在1986年就提出了,基本思想是将每个词表达成 n 维稠密、连续的实数向量,与之相对的one-hot encoding向量空间只有一个维度是1,其余都是0。分布式表示最大的优点是具备非常powerful的特征表达能力,比如 n 维向量每维 k 个值,可以表征 n^k个概念。事实上,不管是神经网络的隐层,还是多个潜在变量的概率主题模型,都是应用分布式表示。下图是03年Bengio在 A Neural Probabilistic Language Model 的网络结构 
    这里写图片描述 
    这篇文章提出的神经网络语言模型(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 和 Distributed Representations of Words and Phrases and their Compositionality,更重要的是发布了简单好用的word2vec工具包,在语义维度上得到了很好的验证,极大的推进了文本分析的进程。下图是文中提出的CBOW 和 Skip-Gram两个模型的结构,基本类似于NNLM,不同的是模型去掉了非线性隐层,预测目标不同,CBOW是上下文词预测当前词,Skip-Gram则相反。 
    这里写图片描述 
    除此之外,提出了Hierarchical Softmax 和 Negative Sample两个方法,很好的解决了计算有效性,事实上这两个方法都没有严格的理论证明,有些trick之处,非常的实用主义。详细的过程不再阐述了,有兴趣深入理解word2vec的,推荐读读这篇很不错的paper:word2vec Parameter Learning Explained。额外多提一点,实际上word2vec学习的向量和真正语义还有差距,更多学到的是具备相似上下文的词,比如“good”“bad”相似度也很高,反而是文本分类任务输入有监督的语义能够学到更好的语义表示,有机会后续系统分享下。

    至此,文本的表示通过词向量的表示方式,把文本数据从高纬度高稀疏的神经网络难处理的方式,变成了类似图像、语音的的连续稠密数据。深度学习算法本身有很强的数据迁移性,很多之前在图像领域很适用的深度学习算法比如CNN等也可以很好的迁移到文本领域了,下一小节具体阐述下文本分类领域深度学习的方法。 
    2.2 深度学习文本分类模型

    词向量解决了文本表示的问题,该部分介绍的文本分类模型则是利用CNN/RNN等深度学习网络及其变体解决自动特征提取(即特征表达)的问题。

    1)fastText

    fastText 是上文提到的 word2vec 作者 Mikolov 转战 Facebook 后16年7月刚发表的一篇论文 Bag of Tricks for Efficient Text Classification。把 fastText 放在此处并非因为它是文本分类的主流做法,而是它极致简单,模型图见下:

    这里写图片描述 
    原理是把句子中所有的词向量进行平均(某种意义上可以理解为只有一个avg pooling特殊CNN),然后直接接 softmax 层。其实文章也加入了一些 n-gram 特征的 trick 来捕获局部序列信息。文章倒没太多信息量,算是“水文”吧,带来的思考是文本分类问题是有一些“线性”问题的部分,也就是说不必做过多的非线性转换、特征组合即可捕获很多分类信息,因此有些任务即便简单的模型便可以搞定了。 
    2)TextCNN 
    本篇文章的题图选用的就是14年这篇文章提出的TextCNN的结构(见下图)。fastText 中的网络结果是完全没有考虑词序信息的,而它用的 n-gram 特征 trick 恰恰说明了局部序列信息的重要意义。卷积神经网络(CNN Convolutional Neural Network)最初在图像领域取得了巨大成功,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 最有意思的输入是在 pooling 改成 (dynamic) k-max pooling ,pooling阶段保留 k 个最大的信息,保留了全局的序列信息。比如在情感分析场景,举个例子:

    “ 我觉得这个地方景色还不错,但是人也实在太多了 ” 
    虽然前半部分体现情感是正向的,全局文本表达的是偏负面的情感,利用 k-max pooling能够很好捕捉这类信息。 
    3)TextRNN

    尽管TextCNN能够在很多任务里面能有不错的表现,但CNN有个最大问题是固定 filter_size 的视野,一方面无法建模更长的序列信息,另一方面 filter_size 的超参调节也很繁琐。CNN本质是做文本的特征表达工作,而自然语言处理中更常用的是递归神经网络(RNN, Recurrent Neural Network),能够更好的表达上下文信息。具体在文本分类任务中,Bi-directional RNN(实际使用的是双向LSTM)从某种意义上可以理解为可以捕获变长且双向的的 “n-gram” 信息。

    RNN算是在自然语言处理领域非常一个标配网络了,在序列标注/命名体识别/seq2seq模型等很多场景都有应用,Recurrent Neural Network for Text Classification with Multi-Task Learning文中介绍了RNN用于分类问题的设计,下图LSTM用于网络结构原理示意图,示例中的是利用最后一个词的结果直接接全连接层softmax输出了 
    这里写图片描述 
    4)TextRNN + Attention

    CNN和RNN用在文本分类任务中尽管效果显著,但都有一个不足的地方就是不够直观,可解释性不好,特别是在分析badcase时候感受尤其深刻。而注意力(Attention)机制是自然语言处理领域一个常用的建模长时间记忆机制,能够很直观的给出每个词对结果的贡献,基本成了Seq2Seq模型的标配了。实际上文本分类从某种意义上也可以理解为一种特殊的Seq2Seq,所以考虑把Attention机制引入近来,研究了下学术界果然有类似做法。

    Attention机制介绍: 
    这里写图片描述
    这里写图片描述 
    Attention的核心point是在翻译每个目标词(或 预测商品标题文本所属类别)所用的上下文是不同的,这样的考虑显然是更合理的。 
    TextRNN + Attention 模型:

    我们参考了这篇文章 Hierarchical Attention Networks for Document Classification,下图是模型的网络结构图,它一方面用层次化的结构保留了文档的结构,另一方面在word-level和sentence-level。淘宝标题场景只需要 word-level 这一层的 Attention 即可。 
    这里写图片描述 
    加入Attention之后最大的好处自然是能够直观的解释各个句子和词对分类类别的重要性。

    5)TextRCNN(TextRNN + CNN) 
    我们参考的是中科院15年发表在AAAI上的这篇文章 Recurrent Convolutional Neural Networks for Text Classification 的结构: 
    这里写图片描述 
    利用前向和后向RNN得到每个词的前向和后向上下文的表示: 
    这里写图片描述 
    这样词的表示就变成词向量和前向后向上下文向量concat起来的形式了,即: 
    这里写图片描述 
    最后再接跟TextCNN相同卷积层,pooling层即可,唯一不同的是卷积层 filter_size = 1就可以了,不再需要更大 filter_size 获得更大视野,这里词的表示也可以只用双向RNN输出。 
    三、一点经验 
    理论和实践之间的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,里面贴了一些超参的对比实验,如果你刚开始启动文本分析任务,不妨按文章的结果设置超参,怎么最快的得到超参调节其实是一个非常重要的问题.

    一定要用 dropout:有两种情况可以不用:数据量特别小,或者你用了更好的正则方法,比如bn。实际中我们尝试了不同参数的dropout,最好的还是0.5,所以如果你的计算资源很有限,默认0.5是一个很好的选择。

    Fine-tuning 是必选的:上文聊到了,如果只是使用word2vec训练的词向量作为特征表示,我赌你一定会损失很大的效果。

    未必一定要 softmax loss: 这取决与你的数据,如果你的任务是多个类别间非互斥,可以试试着训练多个二分类器,也就是把问题定义为multi lable 而非 multi class,我们调整后准确率还是增加了>1%。

    类目不均衡问题:基本是一个在很多场景都验证过的结论:如果你的loss被一部分类别dominate,对总体而言大多是负向的。建议可以尝试类似 booststrap 方法调整 loss 中样本权重方式解决。

    避免训练震荡:默认一定要增加随机采样因素尽可能使得数据分布iid,默认shuffle机制能使得训练结果更稳定。如果训练模型仍然很震荡,可以考虑调整学习率或 mini_batch_size。

    转自https://blog.csdn.net/ch1209498273/article/details/78452452

    展开全文
  • BERT模型实战之多文本分类(附源码)

    万次阅读 多人点赞 2019-03-21 11:00:36
    写在前面 BERT模型也出来很久了,之前看了论文学习...这篇文章的内容还是以比较简单文本分类任务入手,数据集选取的是新浪新闻cnews,包括了[‘体育’, ‘财经’, ‘房产’, ‘家居’, ‘教育’, ‘科技’, ‘时尚’...

    欢迎关注微信公众号:NewBeeNLP,获取更多干货资源。

    PS!!评论区很多同学想要发cnews的数据集,我实在没有那么多时间单发,所以就上传到了百度云,大家自取吧。微信公众号后台回复cnews即可获取。

    BERT模型也出来很久了,之前看了论文学习过它的大致模型(可以参考前些日子写的笔记NLP大杀器BERT模型解读),但是一直有杂七杂八的事拖着没有具体去实现过真实效果如何。今天就趁机来动手写一写实战,顺便复现一下之前的内容。这篇文章的内容还是以比较简单文本分类任务入手,数据集选取的是新浪新闻cnews,包括了[‘体育’, ‘财经’, ‘房产’, ‘家居’, ‘教育’, ‘科技’, ‘时尚’, ‘时政’, ‘游戏’, ‘娱乐’]总共十个主题的新闻数据。那么我们就开始吧!

    Transformer模型

    BERT模型就是以Transformer基础上训练出来的嘛,所以在开始之前我们首先复习一下目前NLP领域可以说是最高效的‘变形金刚’Transformer。由于网上Transformer介绍解读文章满天飞了都,这里就不浪费太多时间了。

    本质上来说,Transformer就是一个只由attention机制形成的encoder-decoder结构。关于attention的具体介绍可以参考之前这篇理解Attention机制原理及模型。理解Transformer模型可以将其进行解剖,分成几个组成部分:

    1. Embedding (word + position)
    2. Attention mechanism (scaled dot-product + multi-head)
    3. Feed-Forward network
    4. ADD(类似于Resnet里的残差操作)
    5. Norm(加快收敛)
    6. Softmax
    7. Fine-tuning

    前期准备

    1.下载BERT

    我们要使用BERT模型的话,首先要去github上下载相关源码:

    git clone  https://github.com/google-research/bert.git
    

    下载成功以后我们现在的文件大概就是这样的
    在这里插入图片描述

    2.下载bert预训练模型

    Google提供了多种预训练好的bert模型,有针对不同语言的和不同模型大小的。Uncased参数指的是将数据全都转成小写的(大多数任务使用Uncased模型效果会比较好,当然对于一些大小写影响严重的任务比如NER等就可以选择Cased)
    在这里插入图片描述
    对于中文模型,我们使用Bert-Base, Chinese。下载后的文件包括五个文件:

    bert_model.ckpt:有三个,包含预训练的参数
    vocab.txt:词表
    bert_config.json:保存模型超参数的文件

    3. 数据集准备

    前面有提到过数据使用的是新浪新闻分类数据集,每一行组成是 【标签+ TAB + 文本内容】
    在这里插入图片描述

    Start Working

    BERT非常友好的一点就是对于NLP任务,我们只需要对最后一层进行微调便可以用于我们的项目需求。我们只需要将我们的数据输入处理成标准的结构进行输入就可以了。

    DataProcessor基类

    首先在run_classifier.py文件中有一个基类DataProcessor类:

    class DataProcessor(object):
      """Base class for data converters for sequence classification data sets."""
    
      def get_train_examples(self, data_dir):
        """Gets a collection of `InputExample`s for the train set."""
        raise NotImplementedError()
    
      def get_dev_examples(self, data_dir):
        """Gets a collection of `InputExample`s for the dev set."""
        raise NotImplementedError()
    
      def get_test_examples(self, data_dir):
        """Gets a collection of `InputExample`s for prediction."""
        raise NotImplementedError()
    
      def get_labels(self):
        """Gets the list of labels for this data set."""
        raise NotImplementedError()
    
      @classmethod
      def _read_tsv(cls, input_file, quotechar=None):
        """Reads a tab separated value file."""
        with tf.gfile.Open(input_file, "r") as f:
          reader = csv.reader(f, delimiter="\t", quotechar=quotechar)
          lines = []
          for line in reader:
            lines.append(line)
          return lines
    

    在这个基类中定义了一个读取文件的静态方法_read_tsv,四个分别获取训练集,验证集,测试集和标签的方法。接下来我们要定义自己的数据处理的类,我们将我们的类命名为MyTaskProcessor

    编写MyTaskProcessor

    MyTaskProcessor继承DataProcessor,用于定义我们自己的任务

    class MyTaskProcessor(DataProcessor):
      """Processor for my task-news classification """
      def __init__(self):
        self.labels = ['体育', '财经', '房产', '家居', '教育', '科技', '时尚', '时政', '游戏', '娱乐']
    
      def get_train_examples(self, data_dir):
        return self._create_examples(
          self._read_tsv(os.path.join(data_dir, 'cnews.train.txt')), 'train')
    
      def get_dev_examples(self, data_dir):
        return self._create_examples(
          self._read_tsv(os.path.join(data_dir, 'cnews.val.txt')), 'val')
    
      def get_test_examples(self, data_dir):
        return self._create_examples(
          self._read_tsv(os.path.join(data_dir, 'cnews.test.txt')), 'test')
    
      def get_labels(self):
        return self.labels
    
      def _create_examples(self, lines, set_type):
        """create examples for the training and val sets"""
        examples = []
        for (i, line) in enumerate(lines):
          guid = '%s-%s' %(set_type, i)
          text_a = tokenization.convert_to_unicode(line[1])
          label = tokenization.convert_to_unicode(line[0])
          examples.append(InputExample(guid=guid, text_a=text_a, label=label))
        return examples
    

    注意这里有一个self._read_tsv()方法,规定读取的数据是使用TAB分割的,如果你的数据集不是这种形式组织的,需要重写一个读取数据的方法,更改“_create_examples()”的实现。

    编写main以及训练

    至此我们就完成了对我们的数据加工成BERT所需要的格式,就可以进行模型训练了。

    def main(_):
      tf.logging.set_verbosity(tf.logging.INFO)
    
      processors = {
          "cola": ColaProcessor,
          "mnli": MnliProcessor,
          "mrpc": MrpcProcessor,
          "xnli": XnliProcessor,
          "mytask": MyTaskProcessor,
      }
    
    python run_classifier.py \
    
     --task_name=mytask \
    
     --do_train=true \
    
     --do_eval=true \
    
     --data_dir=$DATA_DIR/ \
    
     --vocab_file=$BERT_BASE_DIR/vocab.txt \
    
     --bert_config_file=$BERT_BASE_DIR/bert_config.json \
    
     --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
    
     --max_seq_length=128 \
    
     --train_batch_size=32 \
    
     --learning_rate=2e-5 \
    
     --num_train_epochs=3.0 \
    
     --output_dir=mytask_output
    

    其中DATA_DIR是你的要训练的文本的数据所在的文件夹,BERT_BASE_DIR是你的bert预训练模型存放的地址。task_name要求和你的DataProcessor类中的名称一致。下面的几个参数,do_train代表是否进行fine tune,do_eval代表是否进行evaluation,还有未出现的参数do_predict代表是否进行预测。如果不需要进行fine tune,或者显卡配置太低的话,可以将do_trian去掉。max_seq_length代表了句子的最长长度,当显存不足时,可以适当降低max_seq_length。
    在这里插入图片描述

    BERT prediction

    上面一节主要就是介绍了怎么去根据我们实际的任务(多文本分类)去fine-tune bert模型,那么训练好适用于我们特定的任务的模型后,接下来就是使用这个模型去做相应地预测任务。预测阶段唯一需要做的就是修改 – do_predict=true。你需要将测试样本命名为test.csv,输出会保存在输出文件夹的test_result.csv,其中每一行代表一个测试样本对应的预测输出,每一列代表对应于不同类别的概率。

    export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12
    export GLUE_DIR=/path/to/glue
    export TRAINED_CLASSIFIER=/path/to/fine/tuned/classifier
    
    python run_classifier.py \
      --task_name=MRPC \
      --do_predict=true \
      --data_dir=$GLUE_DIR/MRPC \
      --vocab_file=$BERT_BASE_DIR/vocab.txt \
      --bert_config_file=$BERT_BASE_DIR/bert_config.json \
      --init_checkpoint=$TRAINED_CLASSIFIER \
      --max_seq_length=128 \
      --output_dir=/tmp/mrpc_output/
    

    有趣的优化

    指定训练时输出loss

    bert自带代码中是这样的,在run_classifier.py文件中,训练模型,验证模型都是用的tensorflow中的estimator接口,因此我们无法实现在训练迭代100步就用验证集验证一次,在run_classifier.py文件中提供的方法是先运行完所有的epochs之后,再加载模型进行验证。训练模型时的代码:

    train_input_fn = file_based_input_fn_builder(
            input_file=train_file,
            seq_length=FLAGS.max_seq_length,
            is_training=True,
            drop_remainder=True)
        estimator.train(input_fn=train_input_fn, max_steps=num_train_steps)
    

    想要实现在训练过程中输出loss日志,我们可以使用hooks参数:

    train_input_fn = file_based_input_fn_builder(
            input_file=train_file,
            seq_length=FLAGS.max_seq_length,
            is_training=True,
            drop_remainder=True)
        tensors_to_log = {'train loss': 'loss/Mean:0'}
        logging_hook = tf.train.LoggingTensorHook(tensors=tensors_to_log, every_n_iter=100)
        estimator.train(input_fn=train_input_fn, hooks=[logging_hook], max_steps=num_train_steps)
    
    增加验证集输出的指标值

    原生BERT代码中验证集的输出指标值只有loss和accuracy,

    def metric_fn(per_example_loss, label_ids, logits, is_real_example):
            predictions = tf.argmax(logits, axis=-1, output_type=tf.int32)
            accuracy = tf.metrics.accuracy(
                labels=label_ids, predictions=predictions, weights=is_real_example)
            loss = tf.metrics.mean(values=per_example_loss, weights=is_real_example)
            return {
                "eval_accuracy": accuracy,
                "eval_loss": loss,
            }
    

    但是在分类时,我们可能还需要分析auc,recall,precision等的值。

    def metric_fn(per_example_loss, label_ids, logits, is_real_example):
            predictions = tf.argmax(logits, axis=-1, output_type=tf.int32)
            accuracy = tf.metrics.accuracy(
                labels=label_ids, predictions=predictions, weights=is_real_example)
            loss = tf.metrics.mean(values=per_example_loss, weights=is_real_example)
            auc = tf.metrics.auc(labels=label_ids, predictions=predictions, weights=is_real_example)
            precision = tf.metrics.precision(labels=label_ids, predictions=predictions, weights=is_real_example)
            recall = tf.metrics.recall(labels=label_ids, predictions=predictions, weights=is_real_example)
    
            return {
                "eval_accuracy": accuracy,
                "eval_loss": loss,
                'eval_auc': auc,
                'eval_precision': precision,
                'eval_recall': recall,
            }
    


    以上~
    2019.03.21

    展开全文
  • 用深度学习(CNN RNN Attention)解决大规模文本分类问题 - 综述和实践 近来在同时做一个应用深度学习解决淘宝商品的类目预测问题的项目,恰好硕士毕业时论文题目便是文本分类问题,趁此机会总结下文本分类领域特别...

    用深度学习(CNN RNN Attention)解决大规模文本分类问题 - 综述和实践

    近来在同时做一个应用深度学习解决淘宝商品的类目预测问题的项目,恰好硕士毕业时论文题目便是文本分类问题,趁此机会总结下文本分类领域特别是应用深度学习解决文本分类的相关的思路、做法和部分实践的经验。

    业务问题描述:

    淘宝商品的一个典型的例子见下图,图中商品的标题是“夏装雪纺条纹短袖t恤女春半袖衣服夏天中长款大码胖mm显瘦上衣夏”。淘宝网后台是通过树形的多层的类目体系管理商品的,覆盖叶子类目数量达上万个,商品量也是10亿量级,我们是任务是根据商品标题预测其所在叶子类目,示例中商品归属的类目为“女装/女士精品>>蕾丝衫/雪纺衫”。很显然,这是一个非常典型的短文本多分类问题。接下来分别会介绍下文本分类传统和深度学习的做法,最后简单梳理下实践的经验。

    一、传统文本分类方法

    文本分类问题算是自然语言处理领域中一个非常经典的问题了,相关研究最早可以追溯到上世纪50年代,当时是通过专家规则(Pattern)进行分类,甚至在80年代初一度发展到利用知识工程建立专家系统,这样做的好处是短平快的解决top问题,但显然天花板非常低,不仅费时费力,覆盖的范围和准确率都非常有限。

    后来伴随着统计学习方法的发展,特别是90年代后互联网在线文本数量增长和机器学习学科的兴起,逐渐形成了一套解决大规模文本分类问题的经典玩法,这个阶段的主要套路是人工特征工程+浅层分类模型。训练文本分类器过程见下图:

    整个文本分类问题就拆分成了特征工程和分类器两部分,玩机器学习的同学对此自然再熟悉不过了。

    1.1 特征工程

    特征工程在机器学习中往往是最耗时耗力的,但却极其的重要。抽象来讲,机器学习问题是把数据转换成信息再提炼到知识的过程,特征是“数据–>信息”的过程,决定了结果的上限,而分类器是“信息–>知识”的过程,则是去逼近这个上限。然而特征工程不同于分类器模型,不具备很强的通用性,往往需要结合对特征任务的理解。

    文本分类问题所在的自然语言领域自然也有其特有的特征处理逻辑,传统分本分类任务大部分工作也在此处。文本特征工程分位文本预处理、特征提取、文本表示三个部分,最终目的是把文本转换成计算机可理解的格式,并封装足够用于分类的信息,即很强的特征表达能力。

    文本预处理

    文本预处理过程是在文本中提取关键词表示文本的过程,中文文本处理中主要包括文本分词和去停用词两个阶段。之所以进行分词,是因为很多研究表明特征粒度为词粒度远好于字粒度,其实很好理解,因为大部分分类算法不考虑词序信息,基于字粒度显然损失了过多“n-gram”信息。

    具体到中文分词,不同于英文有天然的空格间隔,需要设计复杂的分词算法。传统算法主要有基于字符串匹配的正向/逆向/双向最大匹配;基于理解的句法和语义分析消歧;基于统计的互信息/CRF方法。近年来随着深度学习的应用,WordEmbedding + Bi-LSTM+CRF方法逐渐成为主流,本文重点在文本分类,就不展开了。而停止词是文本中一些高频的代词连词介词等对文本分类无意义的词,通常维护一个停用词表,特征提取过程中删除停用表中出现的词,本质上属于特征选择的一部分。

    经过文本分词和去停止词之后淘宝商品示例标题变成了下图“ / ”分割的一个个关键词的形式:

    夏装 / 雪纺 / 条纹 / 短袖 / t恤 / 女 / 春 / 半袖 / 衣服 / 夏天 / 中长款 / 大码 / 胖mm / 显瘦 / 上衣 / 夏

    文本表示和特征提取

    • 文本表示:

    文本表示的目的是把文本预处理后的转换成计算机可理解的方式,是决定文本分类质量最重要的部分。传统做法常用词袋模型(BOW, Bag Of Words)或向量空间模型(Vector Space Model),最大的不足是忽略文本上下文关系,每个词之间彼此独立,并且无法表征语义信息。词袋模型的示例如下:

                   ( 0, 0, 0, 0, .... , 1, ... 0, 0, 0, 0)

    一般来说词库量至少都是百万级别,因此词袋模型有个两个最大的问题:高维度、高稀疏性。词袋模型是向量空间模型的基础,因此向量空间模型通过特征项选择降低维度,通过特征权重计算增加稠密性。

    • 特征提取:

    向量空间模型的文本表示方法的特征提取对应特征项的选择和特征权重计算两部分。特征选择的基本思路是根据某个评价指标独立的对原始特征项(词项)进行评分排序,从中选择得分最高的一些特征项,过滤掉其余的特征项。常用的评价有文档频率、互信息、信息增益、χ²统计量等。

    特征权重主要是经典的TF-IDF方法及其扩展方法,主要思路是一个词的重要度与在类别内的词频成正比,与所有类别出现的次数成反比。

    基于语义的文本表示

    传统做法在文本表示方面除了向量空间模型,还有基于语义的文本表示方法,比如LDA主题模型、LSI/PLSI概率潜在语义索引等方法,一般认为这些方法得到的文本表示可以认为文档的深层表示,而word embedding文本分布式表示方法则是深度学习方法的重要基础,下文会展现。

    1.2 分类器

    分类器基本都是统计分类方法了,基本上大部分机器学习方法都在文本分类领域有所应用,比如朴素贝叶斯分类算法(Naïve Bayes)、KNN、SVM、最大熵和神经网络等等,传统分类模型不是本文重点,在这里就不展开了。

    二、深度学习文本分类方法

    上文介绍了传统的文本分类做法,传统做法主要问题的文本表示是高维度高稀疏的,特征表达能力很弱,而且神经网络很不擅长对此类数据的处理;此外需要人工进行特征工程,成本很高。而深度学习最初在之所以图像和语音取得巨大成功,一个很重要的原因是图像和语音原始数据是连续和稠密的,有局部相关性。应用深度学习解决大规模文本分类问题最重要的是解决文本表示,再利用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 的网络结构:

    这篇文章提出的神经网络语言模型(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 和 Distributed Representations of Words and Phrases and their Compositionality,更重要的是发布了简单好用的word2vec工具包,在语义维度上得到了很好的验证,极大的推进了文本分析的进程。下图是文中提出的CBOW 和 Skip-Gram两个模型的结构,基本类似于NNLM,不同的是模型去掉了非线性隐层,预测目标不同,CBOW是上下文词预测当前词,Skip-Gram则相反。

    除此之外,提出了Hierarchical Softmax 和 Negative Sample两个方法,很好的解决了计算有效性,事实上这两个方法都没有严格的理论证明,有些trick之处,非常的实用主义。详细的过程不再阐述了,有兴趣深入理解word2vec的,推荐读读这篇很不错的paper:word2vec Parameter Learning Explained。额外多提一点,实际上word2vec学习的向量和真正语义还有差距,更多学到的是具备相似上下文的词,比如“good”“bad”相似度也很高,反而是文本分类任务输入有监督的语义能够学到更好的语义表示,有机会后续系统分享下。

    至此,文本的表示通过词向量的表示方式,把文本数据从高纬度高稀疏的神经网络难处理的方式,变成了类似图像、语音的的连续稠密数据。深度学习算法本身有很强的数据迁移性,很多之前在图像领域很适用的深度学习算法比如CNN等也可以很好的迁移到文本领域了,下一小节具体阐述下文本分类领域深度学习的方法。

    2.2 深度学习文本分类模型

    词向量解决了文本表示的问题,该部分介绍的文本分类模型则是利用CNN/RNN等深度学习网络及其变体解决自动特征提取(即特征表达)的问题。

    fastText

    fastText 是上文提到的 word2vec 作者 Mikolov 转战 Facebook 后16年7月刚发表的一篇论文 Bag of Tricks for Efficient Text Classification。把 fastText 放在此处并非因为它是文本分类的主流做法,而是它极致简单,模型图见下:

    原理是把句子中所有的词向量进行平均(某种意义上可以理解为只有一个avg pooling特殊CNN),然后直接接 softmax 层。其实文章也加入了一些 n-gram 特征的 trick 来捕获局部序列信息。文章倒没太多信息量,算是“水文”吧,带来的思考是文本分类问题是有一些“线性”问题的部分[from项亮],也就是说不必做过多的非线性转换、特征组合即可捕获很多分类信息,因此有些任务即便简单的模型便可以搞定了。

    TextCNN

    本篇文章的题图选用的就是14年这篇文章提出的TextCNN的结构(见下图)。fastText 中的网络结果是完全没有考虑词序信息的,而它用的 n-gram 特征 trick 恰恰说明了局部序列信息的重要意义。卷积神经网络(CNN Convolutional Neural Network)最初在图像领域取得了巨大成功,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 最有意思的输入是在 pooling 改成 (dynamic) k-max pooling ,pooling阶段保留 k 个最大的信息,保留了全局的序列信息。比如在情感分析场景,举个例子:

                “ 我觉得这个地方景色还不错,但是人也实在太多了 ”

    虽然前半部分体现情感是正向的,全局文本表达的是偏负面的情感,利用 k-max pooling能够很好捕捉这类信息。

    TextRNN

    尽管TextCNN能够在很多任务里面能有不错的表现,但CNN有个最大问题是固定 filter_size 的视野,一方面无法建模更长的序列信息,另一方面 filter_size 的超参调节也很繁琐。CNN本质是做文本的特征表达工作,而自然语言处理中更常用的是递归神经网络(RNN, Recurrent Neural Network),能够更好的表达上下文信息。具体在文本分类任务中,Bi-directional RNN(实际使用的是双向LSTM)从某种意义上可以理解为可以捕获变长且双向的的 “n-gram” 信息。

    双向LSTM算是在自然语言处理领域非常一个标配网络了,在序列标注/命名体识别/seq2seq模型等很多场景都有应用,下图是Bi-LSTM用于分类问题的网络结构原理示意图,黄色的节点分别是前向和后向RNN的输出,示例中的是利用最后一个词的结果直接接全连接层softmax输出了。

    TextRNN + Attention

    CNN和RNN用在文本分类任务中尽管效果显著,但都有一个不足的地方就是不够直观,可解释性不好,特别是在分析badcase时候感受尤其深刻。而注意力(Attention)机制是自然语言处理领域一个常用的建模长时间记忆机制,能够很直观的给出每个词对结果的贡献,基本成了Seq2Seq模型的标配了。实际上文本分类从某种意义上也可以理解为一种特殊的Seq2Seq,所以考虑把Attention机制引入近来,研究了下学术界果然有类似做法。

    • Attention机制介绍:

    详细介绍Attention恐怕需要一小篇文章的篇幅,感兴趣的可参考14年这篇paper NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE。

    以机器翻译为例简单介绍下,下图中 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,下图是模型的网络结构图,它一方面用层次化的结构保留了文档的结构,另一方面在word-level和sentence-level。淘宝标题场景只需要 word-level 这一层的 Attention 即可。

    加入Attention之后最大的好处自然是能够直观的解释各个句子和词对分类类别的重要性。

    TextRCNN(TextRNN + CNN)

    我们参考的是中科院15年发表在AAAI上的这篇文章 Recurrent Convolutional Neural Networks for Text Classification 的结构:

    利用前向和后向RNN得到每个词的前向和后向上下文的表示:

    这样词的表示就变成词向量和前向后向上下文向量concat起来的形式了,即:

    最后再接跟TextCNN相同卷积层,pooling层即可,唯一不同的是卷积层 filter_size = 1就可以了,不再需要更大 filter_size 获得更大视野,这里词的表示也可以只用双向RNN输出。

    三、一点经验

    理论和实践之间的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,里面贴了一些超参的对比实验,如果你刚开始启动文本分析任务,不妨按文章的结果设置超参,怎么最快的得到超参调节其实是一个非常重要的问题,可以读读 萧瑟的这篇文章 深度学习网络调参技巧 - 知乎专栏。

    一定要用 dropout

    有两种情况可以不用:数据量特别小,或者你用了更好的正则方法,比如bn。实际中我们尝试了不同参数的dropout,最好的还是0.5,所以如果你的计算资源很有限,默认0.5是一个很好的选择。

    fine-tuning 是必选的

    上文聊到了,如果只是使用word2vec训练的词向量作为特征表示,我赌你一定会损失很大的效果。

    未必一定要 softmax loss

    这取决与你的数据,如果你的任务是多个类别间非互斥,可以试试着训练多个二分类器,我们调整后准确率还是增加了>1%。

    类目不均衡问题

    基本是一个在很多场景都验证过的结论:如果你的loss被一部分类别dominate,对总体而言大多是负向的。建议可以尝试类似 booststrap 方法调整 loss 中样本权重方式解决。

    避免训练震荡

    默认一定要增加随机采样因素尽可能使得数据分布iid,默认shuffle机制能使得训练结果更稳定。如果训练模型仍然很震荡,可以考虑调整学习率或 mini_batch_size。

    没有收敛前不要过早的下结论

    玩到最后的才是玩的最好的,特别是一些新的角度的测试,不要轻易否定,至少要等到收敛吧。

    四、写在最后

    几年前校招面阿里时,一面二面聊的都是一个文本分类的项目(一个新浪微博主题分类的学校课题项目),用的还是文中介绍的传统的做法。面试时对特征项处理和各个分类器可谓如数家珍,被要求在白板上写了好几个特征选择公式,短短几年传统做法已经被远远超越,不得不感慨深度学习的发展。

    值得感慨的一方面是今天技术的发展非常快,故步自封自然是万万万万不可取,深知还有很多理论尚且不懂还要继续深读paper;另一方面,理解理论原理和做好项目间实际非常有巨大的gap,特别是身处工业界的同仁们,学术圈值得钻但要把握分寸,如果仅仅追逐技术深度,不免容易陷入空中阁楼。

    最后老规矩再次安利下我们team的招聘,对淘宝搜索排序和自然语言处理方向感兴趣的同学欢迎邮件我 qingsong.huaqs@taobao.com,来淘宝,一起成长!

    ---------------------

    作者:csdn_csdn__AI

    来源:CSDN

    原文:https://blog.csdn.net/heyc861221/article/details/80128748

    版权声明:本文为博主原创文章,转载请附上博文链接!

    展开全文
  • python 实现中文文本分类

    万次阅读 多人点赞 2019-02-01 16:20:14
    python 实现中文文本分类 本文基于 Python 采用 scikit-learn 模块实现中文文本分类文本分类 一、预处理 1. 获取语料库 语料库数据选用搜狗语料库的搜狐新闻数据精简版:...

    python 实现中文文本分类

    本文基于 Python 采用 scikit-learn 模块实现中文文本分类。

    文本分类

    一、预处理

    1. 获取语料库

    语料库数据选用搜狗语料库的搜狐新闻数据精简版:http://www.sogou.com/labs/resource/cs.php

    数据集介绍:
    来自搜狐新闻2012年6月—7月期间国内,国际,体育,社会,娱乐等18个频道的新闻数据,提供URL和正文信息

    格式说明:
    数据格式为

    <doc>
    
    <url>页面URL</url>
    
    <docno>页面ID</docno>
    
    <contenttitle>页面标题</contenttitle>
    
    <content>页面内容</content>
    
    </doc>
    

    注意:content字段去除了HTML标签,保存的是新闻正文文本

    下载后解压到 SogouCS.reduced 文件夹。下载的文本是 xml 格式,需要解析为纯文本。参考这篇博文进行解析:http://www.sohu.com/a/147504203_609569 。需要注意的是,下载的原文本数据中 缺少跟节点,并且有些特殊符号需要去掉,因此进行了一些格式处理步骤。代码如下所示,保存为 sougou_text.py:

    #!/usr/bin/python
    # -*- encoding:utf-8 -*-
     
     
    import os
    from xml.dom import minidom
    from urllib.parse import urlparse
    import glob
    from queue import Queue
    from threading import Thread, Lock
    import time
    
    THREADLOCK = Lock()
    # 解析的文本保存路径
    corpus_dir = './SogouCS.corpus/'
    
    
    def file_format(from_file, to_file):
        """对下载的文本进行格式处理"""
        try:
            # 原文本需要用 gb18030 打开
            with open(from_file, 'r', encoding='gb18030') as rf:
                lines = rf.readlines()
            # xml 格式有问题,需添加根节点
            lines.insert(0, '<data>\n')
            lines.append('</data>')
            with open(to_file, 'w', encoding='utf-8') as wf:
                for l in lines:
                    l = l.replace('&', '')
                    wf.write(l)
        except UnicodeDecodeError:
            print("转码出错",from_file)
    
    
    def praser_handler(q: Queue):
        # 建立url和类别的映射词典
        dicurl = {'auto.sohu.com': 'qiche', 'it.sohu.com': 'hulianwang', 'health.sohu.com': 'jiankang',
                  'sports.sohu.com': 'tiyu', 'travel.sohu.com': 'lvyou', 'learning.sohu.com': 'jiaoyu',
                  'cul.sohu.com': 'wenhua', 'mil.news.sohu.com': 'junshi', 'business.sohu.com': 'shangye',
                  'house.sohu.com': 'fangchan', 'yule.sohu.com': 'yule', 'women.sohu.com': 'shishang',
                  'media.sohu.com': 'chuanmei', 'gongyi.sohu.com': 'gongyi', '2008.sohu.com': 'aoyun'}
        while not q.empty():
            file = q.get()
            with THREADLOCK:
                print("文件" + file)
            file_code = file.split('.')[-2]
            file_format(file, file) # 进行格式处理
            doc = minidom.parse(file)
            root = doc.documentElement
            claimtext = root.getElementsByTagName("content")
            claimurl = root.getElementsByTagName("url")
            textnum = len(claimurl)
            for index in range(textnum):
                if claimtext[index].firstChild is None:
                    continue
                url = urlparse(claimurl[index].firstChild.data)
                if url.hostname in dicurl:
                    if not os.path.exists(corpus_dir + dicurl[url.hostname]):
                        os.makedirs(corpus_dir + dicurl[url.hostname])
                    fp_in = open(
                        corpus_dir + dicurl[url.hostname] + "/%s_%d.txt" % (file_code, index),"wb")
                    fp_in.write((claimtext[index].firstChild.data).encode('utf8'))
                    fp_in.close()
    
    
    def sougou_text_praser(org_dir):
        # 用8个线程处理文本
        q = Queue()
        for file in glob.glob(org_dir + '*.txt'):
            q.put(file)
        for i in range(8):
            Thread(target=praser_handler, args=(q,)).start()
        while not q.empty():
            time.sleep(10)
    
    
    def files_count(corpus_dir):
        # 统计各类别下的文本数
        folders = os.listdir(corpus_dir)
        total = 0
        for folder in folders:
            if folder.startswith('.DS'):
                continue
            fpath = os.path.join(corpus_dir, folder)
            files = os.listdir(fpath)
            num = len(files)
            total += num
            print(folder, num, sep=':')
        print('Total article:', total)
    
    
    if __name__=="__main__":
    
        org_dir = './SogouCS.reduced/'
        sougou_text_praser(org_dir)
        files_count(corpus_dir)
    

    直接运行脚本,解析后得到 13类 336960 篇文章。

    shangye		60790
    hulianwang	10736
    fangchan	69661
    jiaoyu		10045
    qiche		6539
    wenhua		3225
    jiankang	5442
    tiyu		83689
    shishang	16412
    aoyun		26437
    lvyou		8760
    yule		32335
    junshi		2889
    

    2. 数据集切分

    将文本库切分为训练集和测试集,切分比例为 0.2,数据集切分后存储在SogouCS目录下train和test两个文件夹下。代码如下:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """
    将文本分类数据集分为训练集和测试集
    @author: CSD
    """
    import glob
    import os
    import random
    import shutil
    from threading import Thread, Lock
    from queue import Queue
    
    
    THREADLOCK = Lock()
    
    
    def check_dir_exist(dir):
        # 坚持目录是否存在,不存在则创建
        if not os.path.exists(dir):
            os.mkdir(dir)
    
    
    def copyfile(q):
        while not q.empty():
            full_folder, train, test, divodd = q.get()
            files = glob.glob(full_folder)
            filenum = len(files)
            testnum = int(filenum * divodd)
            testls = random.sample(list(range(filenum)), testnum)
            for i in range(filenum):
                if i in testls:
                    shutil.copy(files[i], os.path.join(test, os.path.basename(files[i])))
                else:
                    shutil.copy(files[i], os.path.join(train, os.path.basename(files[i])))
            with THREADLOCK:
                print(full_folder)
    
    
    def data_divi(from_dir, to_dir, divodd=0.2):
        train_folder = os.path.join(to_dir, "train")
        test_folder = os.path.join(to_dir, "test")
        check_dir_exist(train_folder)
        check_dir_exist(test_folder)
    
        q = Queue()
    
        for basefolder in os.listdir(from_dir):
            if basefolder.startswith('.DS'):
                continue
            full_folder = os.path.join(from_dir, basefolder)
            print(basefolder)
            train = os.path.join(train_folder, basefolder)
            check_dir_exist(train)
            test = os.path.join(test_folder,basefolder)
            check_dir_exist(test)
            full_folder += "/*.txt"
            q.put((full_folder, train, test, divodd))
    
        for i in range(8):
            Thread(target=copyfile, args=(q,)).start()
    
    
    if __name__ == "__main__":
        corpus_dir = './SogouCS.corpus'
        exp_path = './SogouCS/'
        divodd = 0.2
        data_divi(corpus_dir, exp_path, divodd)
    

    3. 中文分词

    中文分词使用结巴分词器(详情请参考:jieba),分析器加载自定义词典:

    jieba.load_userdict(userdict)
    

    为了体现分词的过程,现将分词后的语料存储为train_seg和test_seg。

    import jieba
    import os
    from threading import Thread, Lock
    from queue import Queue
    
    userdict = './userdict.txt'
    jieba.load_userdict(userdict)
    LOCK = Lock()
    
    def readfile(filepath, encoding='utf-8'):
        # 读取文本
        with open(filepath, "rt", encoding=encoding) as fp:
            content = fp.read()
        return content
    
    
    def savefile(savepath, content):
        # 保存文本
        with open(savepath, "wt") as fp:
            fp.write(content)
            
    def check_dir_exist(dir):
        # 坚持目录是否存在,不存在则创建
        if not os.path.exists(dir):
            os.mkdir(dir)
    
    def text_segment(q):
        """
        对一个类别目录下进行分词
        """
        while not q.empty():
            from_dir, to_dir = q.get()
            with LOCK:
                print(from_dir)
            files = os.listdir(from_dir)
            for name in files:
                if name.startswith('.DS'):
                    continue
                from_file = os.path.join(from_dir, name)
                to_file = os.path.join(to_dir, name)
    
                content = readfile(from_file)
                seg_content = jieba.cut(content)
                savefile(to_file, ' '.join(seg_content))
    
    
    def corpus_seg(curpus_path, seg_path):
        """对文本库分词,保存分词后的文本库,目录下以文件归类 curpus_path/category/1.txt, 保存为 seg_path/category/1.txt"""
        check_dir_exist(seg_path)
        q = Queue()
        cat_folders = os.listdir(curpus_path)
        for folder in cat_folders:
            from_dir = os.path.join(curpus_path, folder)
            to_dir = os.path.join(seg_path, folder)
            check_dir_exist(to_dir)
    
            q.put((from_dir, to_dir))
    
        for i in range(len(cat_folders)):
            Thread(target=text_segment, args=(q,)).start()
    if __name__ == '__main__':
        # 分词
        data_dir = './SogouCS/'
        corpus_seg(data_dir + 'train/', data_dir + 'train_seg')
        corpus_seg(data_dir + 'test/', data_dir + 'test_seg')
    

    4. TFIDF 特征提取

    用 tfidf 权重计算方法构建文档向量空间,用到 sklearn 特征提取模块的 TfidfVectorizer 类。构建词带对象,将特征矩阵保存为 sklearn 的 Bunch 数据结构 Bunch(filenames=[], label=[], tdm=[], vocabulary={})。其中 filenames 是文本绝对路径列表,label 是对应的标签,tdm 是特征矩阵,vocabulary 是语料库词典,为了统一向量空间,使用训练集的语料库词典。
    代码如下,保存为 tfidf_feature.py:

    """
    文章分词
    提供两种方案:
    """
    
    import jieba
    import os
    from sklearn.feature_extraction.text import TfidfVectorizer
    from sklearn.datasets.base import Bunch
    from concurrent import futures
    import sys
    import pickle
    
    userdict = '/Users/ivzbv/WorkLocal/programing/datasets/sogoudataset/userdict.txt'
    jieba.load_userdict(userdict)
    
    
    def tokenizer():
        return jieba
        
    def readfile(filepath, encoding='utf-8'):
        # 读取文本
        with open(filepath, "rt", encoding=encoding) as fp:
            content = fp.read()
        return content
    
    
    def savefile(savepath, content):
        # 保存文本
        with open(savepath, "wt") as fp:
            fp.write(content)
    
    
    def writeobj(path, obj):
        # 持久化python对象
        with open(path, "wb") as file_obj:
            pickle.dump(obj, file_obj)
    
    
    def readobj(path):
        # 载入python对象
        with open(path, "rb") as file_obj:
            obj = pickle.load(file_obj)
        return obj
    
    
    def check_dir_exist(dir):
        # 坚持目录是否存在,不存在则创建
        if not os.path.exists(dir):
            os.mkdir(dir)
    
    
    def folder_handler(args):
        """遍历一个文件夹下的文本"""
        folder, encoding, seg = args
        print('遍历:', folder)
        try:
            assert os.path.isdir(folder)
        except AssertionError:
            return None
        files = os.listdir(folder)
        content = []
        filenames = []
        for name in files:
            if name.startswith('.DS'):
                continue
            filepath = os.path.join(folder, name)
            text = readfile(filepath, encoding)
            # 在此可直接分词
            if seg:
                text = ' '.join(jieba.cut(text))
            content.append(text)
            filenames.append(filepath)
        return (filenames, content)
    
    
    def corpus_bunch(data_dir, encoding='utf-8', seg=True, tier=2):
        """
        得到文本库,返回一个 Bunch 对象
        :param data_dir:    文本库目录,目录下以文件归类 data_dir/category/1.txt
        :param encoding:    文本库编码
        :param seg:         是否需要分词
        :param tier:        data_dir 目录下的层级 2: data_dir/category/1.txt, 1: data_dir/1.txt
        :return:
        """
        try:
            assert os.path.isdir(data_dir)
        except AssertionError:
            print('{} is not a folder!')
            sys.exit(0)
        try:
            assert tier in [1, 2]
        except AssertionError:
            print('目录层级 tier 只能是 1 或 2!')
            sys.exit(0)
        corpus = Bunch(filenames=[], label=[], contents=[])
        if tier == 2:
            folders = [os.path.join(data_dir, d) for d in os.listdir(data_dir) if not d.startswith('.DS')]
        else:
            folders = [data_dir]
        # 创建线程池遍历二级目录
        with futures.ThreadPoolExecutor(max_workers=len(folders)) as executor:
            folders_executor = {executor.submit(folder_handler, (folder, encoding, seg)): folder for folder in folders}
            for fol_exe in futures.as_completed(folders_executor):
                folder = folders_executor[fol_exe]
                filenames, content = fol_exe.result()
                if content:
                    cat_name = folder.split('/')[-1]
                    content_num = len(content)
                    print(cat_name, content_num, sep=': ')
                    label = [cat_name] * content_num
                    corpus.filenames.extend(filenames)
                    corpus.label.extend(label)
                    corpus.contents.extend(content)
        return corpus
    
    
    def vector_space(corpus_dir, stop_words=None, vocabulary=None, encoding='utf-8', seg=True, tier=2):
        """将一个语料库向量化"""
        vectorizer = TfidfVectorizer(stop_words=stop_words, vocabulary=vocabulary)
        corpus = corpus_bunch(corpus_dir, encoding=encoding, seg=seg, tier=tier)
        tfidf_bunch = Bunch(filenames=corpus.filenames, label=corpus.label, tdm=[], vocabulary={})
        tfidf_bunch.tdm = vectorizer.fit_transform(corpus.contents)
        tfidf_bunch.vocabulary = vectorizer.vocabulary_
        return tfidf_bunch
    
    
    def tfidf_space(data_dir, save_path, stopword_path=None, encoding='utf-8', seg=True):
        stpwd = None
        if stopword_path:
            stpwd = [wd.strip() for wd in readfile(stopword_path).splitlines()]
        check_dir_exist(save_path)
        train = data_dir + 'train'
        train_tfidf = vector_space(train, stop_words=stpwd, encoding=encoding, seg=seg)
        test = data_dir + 'test'
        test_tfidf = vector_space(test, stop_words=stpwd, vocabulary=train_tfidf.vocabulary, encoding=encoding, seg=seg)
        writeobj(os.path.join(save_path, 'train_tfidf.data'), train_tfidf)
        writeobj(os.path.join(save_path, 'test_tfidf.data'), test_tfidf)
        writeobj(os.path.join(save_path, 'vocabulary.data'), train_tfidf.vocabulary)
    
    
    if __name__ == '__main__':
        data_dir = './SogouCS/'
    
        # 构建词袋
        tfidf_space(data_dir, data_dir + 'fearture_space', stopword_path=data_dir + 'stop_words.txt', seg=True)
    

    二、分类算法

    1. 重构代码

    将一些工具函数转移到一个函数模块,func_tools.py :

    """
    工具函数
    """
    import os
    import pickle
    
    
    def readfile(filepath, encoding='utf-8'):
        # 读取文本
        with open(filepath, "rt", encoding=encoding) as fp:
            content = fp.read()
        return content
    
    
    def savefile(savepath, content):
        # 保存文本
        with open(savepath, "wt") as fp:
            fp.write(content)
    
    
    def writeobj(path, obj):
        # 持久化python对象
        with open(path, "wb") as file_obj:
            pickle.dump(obj, file_obj)
    
    
    def readobj(path):
        # 载入python对象
        with open(path, "rb") as file_obj:
            obj = pickle.load(file_obj)
        return obj
    
    
    def check_dir_exist(dir):
        # 坚持目录是否存在,不存在则创建
        if not os.path.exists(dir):
            os.mkdir(dir)
    

    2. 分类器

    编写一个分类器类,可以根据需要选择不同的分类算法,初始化特征数据目录和模型保存文件名。若模型存在,则直接加载模型得到分类器,否则用训练集训练模型并保存。validation() 函数使用测试集验证模型,predict() 函数应用模型进行预测,可以传入文本所在目录给text_dir 参数,返回文件名与预测类别对应的列表。当预测一个目录下的文本时,enconding 参数可以设置文本的编码格式。也可以传入文本内容字符串给text_string参数,直接预测

    分类器代码如下:

    """
    文本分类
    实现读取文本,实现分词,构建词袋,保存分词后的词袋。
    提取 tfidf 特征,保存提取的特征
    """
    import os
    from sklearn.externals import joblib
    from sklearn import metrics
    import func_tools as ft
    from tfidf_feature import vector_space
    from sklearn.feature_extraction.text import TfidfVectorizer
    
    
    class TextClassifier:
    
        def __init__(self, clf_model, data_dir, model_path):
            """
            分类器
            :param clf_model:   分类器算法模型
            :param data_dir:    特征数据存放位置
            :param model_path:  模型保存路径
            """
            self.data_dir = data_dir
            self.model_path = model_path
            self.train_data = os.path.join(data_dir, 'train_tfidf.data')
            self.test_data = os.path.join(data_dir, 'test_tfidf.data')
            self.vocabulary_data = os.path.join(data_dir, 'vocabulary.data')
            self.clf = self._load_clf_model(clf_model)
    
        def _load_clf_model(self, clf_model):
            if os.path.exists(self.model_path):
                print('loading exists model...')
                return joblib.load(self.model_path)
            else:
                print('training model...')
                train_set = ft.readobj(self.train_data)
                clf = clf_model.fit(train_set.tdm, train_set.label)
                joblib.dump(clf, self.model_path)
                return clf
    
        def _predict(self, tdm):
            """
            :param tdm:     # 特征矩阵
            :return:
            """
            return self.clf.predict(tdm)
    
        def validation(self):
            """使用测试集进行模型验证"""
            print('starting validation...')
            test_set = ft.readobj(self.test_data)
            predicted = self._predict(test_set.tdm)
            actual = test_set.label
            for flabel, file_name, expct_cate in zip(actual, test_set.filenames, predicted):
                if flabel != expct_cate:
                    print(file_name, ": 实际类别:", flabel, " --> 预测类别:", expct_cate)
            print('准确率: {0:.3f}'.format(metrics.precision_score(actual, predicted, average='weighted')))
            print('召回率: {0:0.3f}'.format(metrics.recall_score(actual, predicted, average='weighted')))
            print('f1-score: {0:.3f}'.format(metrics.f1_score(actual, predicted, average='weighted')))
    
        def predict(self, text_dir=None, text_string=None, encoding='utf-8'):
            """应用模型预测"""
            vocabulary = ft.readobj(self.vocabulary_data)
            if text_dir:
                tfidf_bunch = vector_space(corpus_dir=text_dir, stop_words=None, vocabulary=vocabulary, encoding=encoding, seg=True, tier=1)
                return list(zip(tfidf_bunch.filenames, self._predict(tfidf_bunch.tdm)))
            elif text_string:
                from tfidf_feature import tokenizer
                corpus = [' '.join(tokenizer().cut(text_string))]
                vectorizer = TfidfVectorizer(vocabulary=vocabulary)
                tdm = vectorizer.fit_transform(corpus)
                return self._predict(tdm)
            else:
                return None
    

    3. 不同分类算法的比较

    先用多项式贝叶斯算法训练模型:

    from sklearn.naive_bayes import MultinomialNB
    
    data_dir = './SogouCS/'
    
    clf = MultinomialNB(alpha=0.001)
    model_path = data_dir + 'models/NBclassifier.pkl'
    
    classifier = TextClassifier(clf, data_dir + '/fearture_space', model_path)
    classifier.validation()
    

    贝叶斯算法训练耗时很短,用测试集验证可以得到 0.921 的正确率:

    准确率: 0.921
    召回率: 0.918
    f1-score: 0.918
    

    随机森林算法在测试集上有 0.924 的正确率:

    from sklearn.naive_bayes import MultinomialNB
    
    data_dir = './SogouCS/'
    
    clf = RandomForestClassifier(bootstrap=True, oob_score=True, criterion='gini')
    model_path = data_dir + 'models/Radfclassifier.pkl'
    
    classifier = TextClassifier(clf, data_dir + '/fearture_space', model_path)
    classifier.validation()
    

    用测试集验证可以得到 0.921 的正确率:

    准确率: 0.924
    召回率: 0.925
    f1-score: 0.924
    

    Logistic 回归算法在测试集上能达到 0.972 的正确率:

    from sklearn.naive_bayes import MultinomialNB
    
    data_dir = './SogouCS/'
    
    clf = LogisticRegression(C=1000.0)
    model_path = data_dir + 'models/LRclassifier.pkl'
    
    classifier = TextClassifier(clf, data_dir + '/fearture_space', model_path)
    classifier.validation()
    

    用测试集验证可以得到 0.921 的正确率:

    准确率: 0.972
    召回率: 0.972
    f1-score: 0.972
    

    4. 模型应用

    # # 模型应用
    # 预测一个目录下的文本
    ret = classifier.predict(text_dir=data_dir + 'tmp')
    for item in ret:
        print(item)
    # 预测一个文本字符串
    text_string = '互联网一直在不经意中改变人们的生活和娱乐方式。当电视娱乐和纸介娱乐越来越同质化的时候,人们开始渴望一种新鲜的、更刺激的娱乐方式。于是,来自民间的智慧开始显现,网络恶搞应运而生,并迅速风靡中美这两个互联网最发达的国家。恶搞短片在带给人们无限快感的时候,也招来众多的批评。最新的消息称,国家广电总局将把视频纳入统一监管,引导视频带领中国互联网迈入一个新的时代。'
    ret = classifier.predict(text_string=text_string)
    print(ret)
    
    展开全文
  • pytorch-bert文本分类

    2020-02-23 19:05:30
    基于bert预训练模型和pytorch深度学习框架实现文本分类
  • 文本分类概述(nlp)

    万次阅读 多人点赞 2018-06-22 23:28:27
    文本分类问题:给定文档p(可能含有标题t),将文档分类为n个类别中的一个或多个 文本分类应用:常见的有垃圾邮件识别,情感分析 文本分类方向:主要有二分类,多分类,多标签分类 文本分类方法:传统机器学习...
  • 如果要使用聚类分析算法对一堆文本分类,关键要解决这几个问题: 如何衡量两个对象是否相似 算法的性能怎么度量 如何确定分类的个数或聚类结束的条件 选择哪种分类算法 下面就带着这几个问题,以我工作中的一个...
  • 文本分类方法总结

    千次阅读 2020-01-17 15:01:42
    1 机器学习的文本分类方法 1.1 特征工程 1.1.1 文本预处理 1.1.2 文本表示和特征提取 1.1.3 基于语义的文本表示 1.2 分类器 朴素贝叶斯分类(Naïve Bayes) 用朴素贝叶斯分类算法做中文文本分类 KNN SVM ...
  • 文本挖掘之文本分类

    2017-12-18 09:37:43
    文本分类介绍 文本分类问题是根据文本的特征将其分到预先设定好的类别中,类别可以是两类,也可以是更多的类别。文本分类是机器学习领域里监督学习的一种重要应用问题。不过需要指出的是,第一,文本分类问题中用于...
  • 文本分类论文

    2019-03-18 12:29:42
    文本分类论文 后面有时间会更新比较完整的整理版,感兴趣的可以关注。
  • 如何使用BERT实现中文的文本分类(附代码)

    万次阅读 多人点赞 2018-12-11 11:07:53
    如何使用BERT模型实现文本分类前言Pytorchreadme参数表Tensorflowreadme 前言 Pytorch readme 参数表 data_dir Tensorflow readme 涂壁抗体纽
  • 文本分类

    千次阅读 2019-07-30 09:29:05
    采用文本分类技术对海量数据进行科学地组织和管理显得尤为重要。 文本作为分布最广、数据量最大的信息载体,如何对这些数据进行有效地组织和管理是亟待解决的难题。 文本分类是自然语言处理任务中的一项基础性工作,...
  • Fasttext文本分类

    千次阅读 热门讨论 2018-08-31 14:05:36
    Fasttext文本分类 一、简介 1、简介 fasttext是facebook开源的一个词向量与文本分类工具,在2016年开源,典型应用场景是“带监督的文本分类问题”。提供简单而高效的文本分类和表征学习的方法,...
  • 中文文本分类

    2019-08-13 23:54:07
    文本挖掘与文本分类的概念 文本挖掘(Text Mining)是从一个非机构化文本信息中获取用户感兴趣或者有用的模式过程。文本挖掘的 7 个主要领域如下: 搜索和信息检索:存储和文本文档的检索,包括搜索引擎和文档的...
  • CNN文本分类

    千次阅读 2018-09-20 08:33:46
    文本分类是NLP领域的一个重要的子任务,文本分类的目标是自动的将文本打上已经定义好的标签,常见的文本分类任务有:垃圾邮件过滤、情感分析、新闻分类等等。 代码是来自 ... 大家可以自行下载阅读,下面仅仅是自己对...
  • flair文本分类

    千次阅读 2018-12-25 22:24:20
    Flair是一个基于PyTorch构建的NLP开发包,它在解决命名实体识别(NER)、语句标注(POS)、文本分类等NLP问题时达到了当前的顶尖水准。本文将介绍如何使用Flair构建定制的文本分类器。 简介 文本分类是一种用来将...
  • 大话文本分类

    千次阅读 2018-02-14 09:49:26
    概述文本分类是自然语言处理的重要应用,也可以说是最基础的应用。常见的文本分类应用有:新闻文本分类、信息检索、情感分析、意图判断等。本文主要针对文本分类的方法进行简单总结。传统机器学习方法分类问题一般的...
  • fastText原理和文本分类实战,看这一篇就够了

    万次阅读 多人点赞 2019-03-19 11:19:48
    fastText是一个快速文本分类算法,与基于神经网络的分类算法相比有两大优点: 1、fastText在保持高精度的情况下加快了训练速度和测试速度 2、fastText不需要预训练好的词向量,fastText会自己训练词向量 3、fastText...
  • TextCNN文本分类(keras实现)

    万次阅读 多人点赞 2019-03-26 19:23:46
    二、Keras文本预处理 1、读取数据集 2、将文字转换成数字特征 3、将每条文本转换为数字列表 4、将每条文本设置为相同长度 5、将每个词编码转换为词向量 6、Keras文本预处理代码实现 三、基于keras的TextCNN...

空空如也

1 2 3 4 5 ... 20
收藏数 25,727
精华内容 10,290
关键字:

文本分类