Save you from anything

0%

实验:预分类对于seq2seq模型的影响

seq2seq模型的decoder的起始输入总是<START>标记,这个标记仅用于启动decoder的循环输入输出,而没有提供任何其他的有效信息,理论上,如果能通过<START>向decoder提供某些信息,那么理论上应该可以改善seq2seq的性能,这个实验基于这个假设展开。

(本实验进行于2020年4月。顺便这个实验也被否了)

思路介绍

多标签推荐的一个难点在于,它的输出空间规模是指数增长的。

而文本标签推荐是有大致的分类倾向的,例如:如果一篇文档有tensorflow的tag,那它很可能也有python的标签,而spring显然不大可能和python同时出现,如果能向decoder提供文档的大致的分类,则可以极大的减小输出的空间的规模。

这个想法是在做GCN时冒出来的,根据GCN的描述,如果构建图的方式合适,在图被创建出来的时候就已经有了大致的分类:

主要思路已经在上面的摘要里写了,对于seq2seq模型,如果通过<START>标记向第一个RNN单元提供一些关于文档的大致分类的数据,理论上应该对模型有所帮助。

假设一个极端情况:对于一个有100个tag的多tag推荐任务,创建100个不同的<START>标记,对第一个RNN单元,总是直接输入其正确输出对应的<START>标记,这实际上是等于直接告诉模型第一个tag是什么,这种情况下第一个标签的准确率和召回很容易接近100%,从而使得后续的其他标签的预测效果也获得提升。

模型介绍

模型使用原版的itag,不对其进行修改,但是使用别的模型/方法将数据集预先分类为N个类别,然后设定N个不同<START>标记,用于提示decoder。

预分类实现

前文提到了GCN可以用于生成文档的大致分类,但是实际上我并没有用GCN做这个预分类,因为GCN是有监督或半监督的,等于我需要预先知道文章的大致分类,但是我并不知道(我知道了我还要GCN干啥?)。

因为我所使用的数据集根本就没有预分类类别这项属性,所以我无法使用监督/半监督类的算法,这时候我有两个选择:

  • 给数据集加上预分类类别
    • 换数据集
    • 人工标注
  • 无监督学习

由于当时是在快速验证想法,所以只使用了ask ubuntu论坛的提问数据集。

换数据集

换数据集是一个正常的思路,因为我的目的不是业务(一定要拿这个数据集做),而是研究,所以我可以去找合适的数据集,当时我的想法是,使用reddit、quora等本身就带有“预分类”属性的数据集,例如reddit本身就分为各种不同的板块,我可以将不同的板块作为预分类标签。

但是众所周知,找数据集是个挺麻烦的事,我当时打算先检验一下这个想法可不可行,所以用了后面的两种方法。

人工标注

这个选项的问题在于,多tag文档压根没法人工标记大类别数据,于是我使用了粗糙的人工分类来对这个想法进行定性。

针对ask ubuntu论坛的数据集,我按出现频率挑选了约前60个tag,并根据个人知识对其进行了分类,大概80%的文档都至少有一个这些tag。

预分类时检测到一篇文本有一个tag属于这60个时,即将这篇文档指定为该tag所属的类别,并且不再进行判定,即,暂不考虑文档属于多类别时的分类问题。

如果没有任何一个tag属于这60个,则将这篇文档指定为other类,

使用的预分类方案:

  • 硬件 ‘networking’, ‘drivers’, ‘wireless’, ‘usb’, ‘sound’, ‘keyboard’, ‘hard-drive’,’uefi’, ‘boot’, ‘dual-boot’, ‘mouse’, ‘printing’, ‘display’, ‘touchpad’, ‘bluetooth’, ‘dell’, ‘ati’, ‘graphics’ ‘video’,
  • 软件 ‘virtualbox’, ‘shortcut-keys’, ‘nautilus’, ‘xorg’, ‘firefox’, ‘wine’, ‘google-chrome’, ‘software-center’, ‘pulseaudio’, ‘software-installation’, ‘upgrade’, ‘installation’, ‘updates’,’kde’
  • 系统 ‘server’, ‘grub2’, ‘system-installation’, ‘kernel’, ‘permissions’, ‘login’, ‘network-manager’, ‘suspend’, ‘launcher’, ‘password’, ‘filesystem’, ‘files’, ‘icons’
  • 操作 ‘command-line’, ‘apt’, ‘bash, ‘package-management’ ‘mount’, ‘scripts’, ‘ssh’, ‘dpkg’, ‘software-recommendation’, ‘sudo’,
  • 其他系统: ‘xubuntu’, ‘windows’, ‘lubuntu’, ‘kubuntu’, ‘ubuntu-touch’, ‘windows-7’, ‘live-usb’, ‘samba’
  • 代码:’python’, ‘apache2’, ‘java’, ‘mysql’, ‘php’

另外还有一个other类别,共7类

这种粗糙的人工预分类,既影响模型的迁移能力(模型依赖于人工预分类的效果),也无法捕捉到真实的tag聚类,例如中间的其他系统类别,这几个tag可能完全不会同时出现,但是我却将其分为一类,这种情况下预分类反而是有害的。

无监督学习

说到无监督分类,那就是聚类,我查找了容易实现的图无监督方法,最后使用了谱聚类方法(这是一个非常老的方法,而且按我导师的说法,用谱聚类做tag推荐没有任何文献支撑)

然后我仿照了Text-GCN的方法构建了图,没有使用文档节点,仅使用了tag节点,因为tag推荐任务本质上是推荐tag,对于tag进行大类别分类更加贴近任务。

我使用了两种图构建方法,分别是相似度法和词对法。

  • 相似度法:利用预训练的word2vec将tag转换为词向量,根据词向量的相似度构建tag互动图
  • 词对法:检测所有文章的tag,如果两个tag同时属于一篇文章,则将这两个tag间的权重+1

词对法会导致高频tag的权重极大,因而还进行了权重对数化和归一化。

谱聚类使用了7个和10个类别。

实验结果

获得每个tag的分类结果后,再读取每篇文档的第一个tag的分类作为文本的分类,然后使用预分类结果运行itag。结果如下:

精确 召回 F1 全命中
Itag 0.326030 0.391759 0.355885 0.004979
人工设计/7类别 0.327306 0.392381 0.356902 0.005477
词对/谱聚类,7类别 0.340205 0.409898 0.371814 0.008713
相似度/谱聚类,7类别 0.326591 0.391953 0.356299 0.007002
词对/谱聚类,10类别 0.345573 0.416317 0.377661 0.006691
相似度/谱聚类,10类别 0.340439 0.410417 0.372167 0.007780

(全命中指模型预测出所有tag且没有多预测)

结果分析:

  • 通过<START>标记为decoder提供信息是有效的,无论是粗糙的人工分类还是无监督分类,相比itag都有所提升,尤其是谱聚类方法,提升更加明显。
  • 粗糙的人工分类效果远不如无监督分类,因为人工分类过于依赖于人类的经验。
  • 相比使用词向量相似度,使用词对共现次数建图的效果更好,因为预训练的词向量并不能很好反应tag的语义(一个词出现在文本中和tag中的语义是不一样的),而基于文档的共现次数则效果更好。
  • 提升预分类的类比数量可以提升预分类的效果,理论上预分类数量越多,向decoder提示的数据就越多,考虑前文假设的极端情况,如果使用的预分类数量和tag数一致,等于是向decoder直接告知了第一个tag是什么,显然效果会很好,但是这样就失去了这个算法的意义。

结论

对文本进行预分类,然后通过<START>标记向decoder提示信息是有效的,如果继续做下去的话,就是寻找更高效的聚类方法,或者是用有预分类属性的数据集,再研究有监督的预分类。

但这个方向最后没有做下去,我的导师认为我使用的聚类方法没有文献支撑,并且这个方法创新性也有限,只是改了一下<START>标记,所以让我不要继续做这个方向了。