SERVICE PHONE

400-023-4588
  • 诚信为本,市场在变,诚信永远不变...

行业资讯

新闻上的文本分类:机器学习大乱斗竞博体育

发布时间:2023-05-06 点击量:751

  竞博体育第 1-3 组属于深度学习方法,第 4-6 组属于传统机器学习方法,第 7 组算是种深度与传统合作的方法,画风清奇,拿来试试看看效果

  引入预训练的 word2vec 模型会给训练带来好处,具体来说:(1)间接引入外部训练数据,防止过拟合;(2)减少需要训练的参数个数,提高训练效率

  LSTM 需要训练的参数个数远小于 CNN,但训练时间大于 CNN竞博体育。CNN 在分类问题的表现上一直很好,无论是图像还是文本;而想让 LSTM 优势得到发挥,首先让训练数据量得到保证

  将单词在 word2vec 中的词向量加和求平均获得整个句子的语义向量的方法看似 naive 有时真挺奏效,当然仅限于短句子,长度 100 以内应该问题不大

  机器学习方法万千,具体选择用什么样的方法还是要取决于数据集的规模以及问题本身的复杂度,对于复杂程度一般的问题,看似简单的方法有可能是坠吼地

  将下载的原始数据进行转码,然后给文本标类别的标签,然后制作训练与测试数据,然后控制文本长度,分词,去标点符号

  首先,搜狗实验室提供的数据下载下来是 xml 格式,并且是 GBK (万恶之源)编码,需要转成 UTF8,并整理成 json 方便处理。原始数据长这个样:

  这么大的数据量,怎么转码呢?先尝试利用 python 先读入数据然后转码再保存,可傲娇 python 并不喜欢执行这种语句。。。再尝试利用 vim 的 :set fileencoding=utf-8,乱码从███变成锟斤拷。。。

  经过几次尝试,菜鸡的我只能通过文本编辑器打开,然后利用文本编辑器转换编码。这样问题来了,文件大小1.6G,记事本就不提了,Notepad 和 Editplus 也都纷纷阵亡。。。

  还好最后发现了UltraEdit,不但可以打开,速度简直飞起来,转码后再整理成的 json 长这个样子:

  搜狗新闻的数据没有直接提供分类,而是得通过新闻来源网址的 url 来查其对应得分类,比如gongyi.sohu.com的 url 前缀对应的新闻类型就是“公益类”。对着他提供的对照表查,1410000+的总数据,成功标出来的有510000+,标不出来的新闻基本都来自roll.sohu.com,这是搜狐的滚动新闻,乱七八糟大杂烩,难以确定是什么类

  分布比较不均,第 14 类和第 15 类的新闻很少,另外第 8 类和第 11 类一个新闻也没有

  所以最后选了剩下的11个类,每个类抽2000个新闻,按4:1分成训练与测试,如图

  横轴是新闻的长度,纵轴是拥有此长度的新闻数量。在长度为500字和1600字时突然两个峰,猜测是搜狐新闻的一些长度限制???

  长度0-100的放大观察,分布还可以,说明如果基于这套数据做短文本分类,需要对原始文本进行固定长度的截取,长度 100 可能是个不错的选择

  上一步选出来的训练新闻长这样,因为考虑到新闻标题的意义重大,这里就将新闻标题和新闻内容接到一起,用空格隔开,然后截取每条新闻的前100个字

  一行是一条新闻,训练数据17600行,测试数据4324行。然后用jieba分词,分词后利用词性标注结果,把词性为‘x’(字符串)的去掉,就完成了去标点符号

  最后得到以下结果文件:(1)新闻文本数据,每行 1 条新闻,每条新闻由若干个词组成,词之间以空格隔开,训练文本 17600 行,测试文本 4324 行;(2)新闻标签数据,每行 1 个数字,对应这条新闻所属的类别编号,训练标签 17600行,测试标签 4324 行

  深度学习用的 keras 工具,操作简单易懂,模型上手飞快,居家旅行必备。keras 后端用的 Tensorflow,虽然用什么都一样

  然后就是搭建模型,首先是一个将文本处理成向量的 embedding 层,这样每个新闻文档被处理成一个 100 x 200 的二维向量,100 是每条新闻的固定长度,每一行的长度为 200 的行向量代表这个单词在空间中的词向量。下面通过 1 层卷积层与池化层来缩小向量长度,再加一层 Flatten 层将 2 维向量压缩到 1 维,最后通过两层 Dense(全连接层)将向量长度收缩到 12 上,对应新闻分类的 12 个类(其实只有 11 个类,标签 0 没有用到)。搭完收工,最后,训练模型竞博体育,测试模型,一鼓作气,攻下高地。

  答:新闻长度只有100个单词,即特征只有100维,1 层卷积加池化后特征已经缩减为 32 维,再加卷积可能就卷没了。 2 层 3 层也做过,效果都不好

  答:问题比较简单,1 轮训练已经收敛,实验表明第 2 轮训练基本没什么提升

  拥有11个分类的问题达到这个准确度竞博体育,应该也不错(易满足)。并且搜狗给的数据本来也不是很好(甩锅)。可以看到在训练集上的准确度达到了 0.88,但是测试集上的准确度只有 0.81,说明还是有些过拟合。另外,整个模型需要训练的参数接近 1500 万,其中 1300 万都是 embedding 层的参数,说明如果利用 word2vec 模型替换 embedding 层,解放这 1300 万参数,肯定会让训练效率得到提高

  既然提到了 word2vec 可能会提高训练效率,那就用实验验证一下。(重点)(重点)(重点)正常的深度学习训练,比如上面的 CNN 模型,第一层(除去 Input 层)是一个将文本处理成向量的 embedding 层。这里为了使用预训练的 word2vec 来代替这个 embedding 层,就需要将 embedding 层的 1312 万个参数用 word2vec 模型中的词向量替换。替换后的 embedding 矩阵形状为 65604 x 200,65604 行代表 65604 个单词,每一行的这长度 200 的行向量对应这个词在 word2vec 空间中的 200 维向量。最后竞博体育,设定 embedding 层的参数固定,不参加训练,这样就把预训练的 word2vec 嵌入到了深度学习的模型之中

  相比不使用 word2vec 的 cnn,过拟合的现象明显减轻,使准确度得到了提高。并且需要训练的参数大大减少了,使训练时间平均每轮减少 20s 左右

  特征提取以及 embedding 的过程跟 CNN 的实验一致。接下来的 LSTM 层的功能在最终效果上(或许)可以理解成将一个序列的词向量压缩成一个句向量。每个新闻经过 embedding 层后得到一个 100 x 200 的 2 维向量,通过将这 100 个词向量按前后顺序逐个输入 LSTM 层中,最后输出一个 1 维的长度 200 的向量,最后一个全连接层将长度收缩到 12

  并没有期待中那么美好。。。原因是这点小数据量,并没有让 LSTM 发挥出它的优势。并不能给大哥一个奔驰的草原。。。并不能让大哥飞起来。。。另外使用 LSTM 需要训练的参数要比使用 CNN 少很多,但是训练时间是 CNN 的 2 倍。大哥表示不但飞不动,还飞的很累。。。

  效果好了不少,依然存在过拟合现象,再一次说明了数据量对 LSTM 的重要性,使用预训练的 word2vec 模型等于间接增加了训练语料,所以在这次实验中崩坏的不是很严重

  MLP 是一个结构上很简单很 naive 的神经网络。数据的处理流程也跟上面两个实验差不多,不过不再将每条新闻处理成 100 x 200 的 2 维向量,而是成为长度 65604 的 1 维向量。65604 代表数据集中所有出现的 65604 个单词,数据的值用 tf-idf 值填充,整个文档集成为一个用 17600 x 65604 个 tf-idf 值填充的矩阵,第 i 行 j 列的值表征了第 j 个单词在第 i 个文档中的的 tf-idf值(当然这里也可以不用 tf-idf 值,而只是使用 0/1 值填充, 0/1 代表第 j 个单词在第 i 个文档中是否出现,但是实验显示用 tf-idf 的效果更好)

  模型很简单,仅有两个全连接层组成,将长度 65604 的 1 维向量经过 2 次压缩成为长度 12 的 1 维向量

  只是不能像 CNN 与 LSTM 那样借助预训练 word2vec 的帮助,加上数据量不大,所以稍微有些过拟合,不过结果依旧很不错。没有复杂的 embedding,清新脱俗的传统感知机模型在这种小数据集的简单问题上表现非常好(虽然训练参数已经达到了 3300 万个,单轮耗时也将近 200s 了)

  这里有一个需要注意的地方,由于训练集和测试集分开提取特征会导致两者的特征空间不同,比如训练集里 “苟” 这个单词的序号是 1024,但是在测试集里序号就不同了,或者根本就不存在在测试集里。所以这里先用所有文档共同提取特征(counts_v0),然后利用得到的词典(counts_v0.vocabulary_)再分别给训练集和测试集提取特征。然后开始训练与测试

  这只是一个简单的朴素贝叶斯方法,准确度高到惊人,果然最简单的有时候就是最有效的

  K=11时,准确度0.31961147,非常低,说明 KNN 方法不太适合做此类问题

  这里 svm 的 kernel 选用了线性核,其他的比如多项式核和高斯核也都试过,效果极差,直接上结果

  这两个实验是后期新加入的,画风比较清奇,是骡是马溜一圈,就决定拿过来做个实验一起比较一下

  这个实验的主要思想是这样:原本每条新闻由若干个词组成,每个词在 word2vec 中都有由一个长度 200 的词向量表示,且这个词向量的位置是与词的语义相关联的。那么对于每一条新闻,将这条新闻中所有的词的词向量加和取平均,既能保留句子中所有单词的语义,又能生成一个蕴含着这句话的综合语义的“句向量”,再基于这个长度 200 的句向量使用 svm 分类。这个思想看起来很 naive,但是又说不出什么不合理的地方。尝试一下,代码与结果如下:

  准确度0.85175763,惊了,这种看似很 naive 的方法竟然取得了非常好的效果。相比于之前所有包括 CNN竞博体育、LSTM、MLP、SVM 等方法,这种方法有很强的优势。它不需要特征提取的过程,也不需固定新闻的长度,一个模型训练好,跨着数据集都能跑。但是也有其缺陷一面,比如忽略词语的前后关系,并且当句子长度较长时,求和取平均已经无法准确保留语义信息了。但是在短文本分类上的表现还是很亮

  上面 svm + word2vec 的实验提到当句子很长时,简单求和取平均已经不能保证原来的语义信息了。偶然发现了 gensim 提供了一个 doc2vec 的模型,直接为文档量身训练“句向量”,神奇。具体原理不讲了(也不是很懂),直接给出使用方法

  all_contents.txt 里是包括训练文档与测试文档在内的所有数据,同样每行 1 条新闻,由若干个词组成,词之间用空格隔开,先使用 gensim 的 TaggedLineDocument 函数预处理下,然后直接使用 Doc2Vec 函数开始训练,训练过程很快(可能因为数据少)。然后这所有 21924 篇新闻就变成了 21924 个长度 200 的向量,取出前 17600 个给 SVM 做分类训练,后 4324 个测试,代码和结果如下:

  准确度0.48126734,惨不忍睹。原因可能就是文档太短,每个文档只有不超过 100 个词,导致对“句向量”的学习不准确,word2vec 模型训练需要 1G 以上的数据量,这里训练 doc2vec 模型20000个文档却只有 5M 的大小,所以崩坏

  另外!这里对 doc2vec 的应用场景有一些疑问,如果我新加入一条新闻想要分类,那么我必须先要把这个新闻加到文档集里,然后重新对文档集进行 doc2vec 的训练,得到这个新新闻的文档向量,然后由于文档向量模型变了, svm 分类模型应该也需要重新训练了。所以需要自底向上把所有模型打破重建才能让为新文档分类?那实用性很差啊。也可能我理解有误,希望是这样