针对垂直问题的高性能机器学习算法设计

Posted 3A是个坏同志

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了针对垂直问题的高性能机器学习算法设计相关的知识,希望对你有一定的参考价值。

这是我前几天在CCF青年大会学生论坛的报告内容。因为台上每个人就给十分钟,所以算法细节和一些我自己的想法都没讲,这是15分钟的完整讲稿。

现在深度学习非常火,像计算机视觉、自然语言处理这些面向很多问题的泛领域都有很强大的预训练模型。这些预训练模型能解决很多问题,所以现在面对一个特定问题,很多人的基本操作就是基于预训练模型套上数据调一下,看看效果怎么样。
这么做能解决很多问题,但因为预训练模型体量一般都很大,这么搞不管是训练还是推断都有很大的计算开销。而且本身调这个过程也充满了不确定性,所以大家说深度学习是炼丹。
这种复杂性真的有必要吗?这种微调要解决的特定问题一般是相对预训练模型的表达能力窄的,预训练模型里很多东西用不上。另外纯用数据微调,没办法显式的引入领域知识。纯用数据拟合它方向可能会偏掉,这带来了模型安全性上的问题。

另外,现在深度学习这么火,很多传统的算法相对来说就不受重视了。其实我觉得很多传统机器学习算法的威力还是挺大的,而且很多算法更容易显式引入领域知识。然后可以比如和深度学习结合实现更好的效果
今天我想讲的内容就是,针对某些问题,我们不用预训练模型,不用复杂的深度学习结构,可以用一些来自于传统算法的思想、或者是简单的数学上的分析,算是另辟蹊径啊,用一种更优美、更高效的方法解决问题。

我要讲的是我的两篇文章里的内容,第一个是关于文本生成问题——用户给出一些要求,怎么生成一篇文章?另一个是在有一些已知信息的情况下,怎么对自相关序列实现一个快速的预测。先来讲第一个。

文本生成,和语言模型有很大的关系,语言模型,就是对语言中元素的这个序列、概率关系建模。那文本生成,就是有了这个语言模型之后,要算出在某个条件下出现概率最大的文本。这个条件就是我们要让它写一个啥样的文章,然后最后它生成出一个最合理的文章。那什么样的语言模型更适合这种任务呢?

从神经网络这条线来说,我们有RNN,有word2vec,对序列建模,预测一个词之后将会出现啥词这种问题,这个可以做。大家认为,word2vec给每个词弄出的这个编码可以一定程度上表达上词语的语义。但是考虑文本生成这个任务,用编码这种方式表达语义,有时候它的开销或者说给模型拟合造成的这个困惑可能大于它表达能力强的好处。
那既然说给语言元素序列关系建模,一个直观的想法就是:比如一个词,我直接给它当成一个节点。一个词后面可以出现另一个词,他俩之间连一条边,这个边的权值就是这个词后面出现那个词的频率。然后现在我想要,比如生成有某个词的句子,我把这个词对应的节点激活,赋予它一个信度,然后这个信度沿着边传播出去,把很多节点都激活,最后得到一个句子。这个是不用编解码了,给训练语料程序可以很快给处理成这种数据结构。
但这个给人感觉有问题:就这一个词一个词连,这个表达的层次太低了,一点也不抽象。很多时候我们要生成的是某种主题的文章,给模型的是一个主题,我们不知道这句子里的词是啥。而且这么简单的结构表达能力属实令人怀疑。

这个怎么办呢?我们知道神经网络可以堆叠函数,复合起来,表达更复杂的函数。那文本其实也有这种语义上,词、句子、段落的层次关系,也可以堆叠,那其实可以根据这个把之前的那个简单的连接模式搞成一个深度模型——我用不同大小的窗口采样出子文本,然后对这个子文本摘要,作为上层节点。
这个真实的实现挺绕的。这里就简单理解,就是第一层表达词之间的序列关系,第二层表达比如抽象的句子之间的序列关系,第三层表达段落之间的序列关系。越来越抽象,然后用户就可以指定一个或多个抽象的主题让它生成了。
不过这有个问题是对于一个词它会在不同情况下后面接很多不同的词。但是句子和段落这些每一个都是不同的,所以后面接的是唯一的。直接连的话就相当于把文本复述一遍,没实现抽象。对于这个的解决方法就是把相似度大于某个阈值的句子或者段落视为同一个,这样就能用和第一层词一样的方法处理了。

现在知道这个模型结构是怎么建起来的。然后看看它怎么生成文本。生成这个过程简单来说是这样的:用户激活一个或者多个顶层的摘要块,赋予这些摘要块一个初始信度。这个信度会先进行同层的传递,同层传递完了,生成序列,然后按序列顺序向下层传递。下层还是进行这么个过程,直到最底层生成出序列为止。这个的实际意义是这样的:比如顶层节点代表的是抽象句子,同层传递得到的就是这些抽象句子之间的顺序。然后每个抽象句子的信度向下层传递,下层是词,词再同层传递构成序列,就相当于把一个句子写出来了。因为这个每一层行为都是一样的,所以我举一个摘要块被激活的例子,更复杂的情况可以类推。
首先,我激活一个摘要块,上面的那个蓝色×
它会沿着跨层连接的橙色边向下传递它的信度,每条边都有权值,权值是和这个信度相乘的。这样激活下层的一些节点
下层有一些蓝色节点被激活了,然后它们把信度往周围的节点传,传的时候也要乘边的权值,因为同层边的权值是频率,所以信度随着传播会衰减,小于阈值,传播停止
传播停止之后,我们知道哪些节点被激活了,现在要从这里面找出一个概率最大的序列。
所有的节点在建图的时候都统计了它在序列首部的概率,我们找首部概率最大的节点作为生成的这个序列的首部,从它开始,搞个图遍历,把邻接的节点串起来,同时计算目前串出来这个序列的联合概率。这里是每次扩展都生成一些新序列,也就是说生成的序列里可能有一个词的、两个词的、三个词的。所以这个序列出现的概率不能直接乘边的权值算,否则越长的序列乘完越小了。用的是一个类似贝叶斯定理更新后验概率的形式,相当于乘一个跟平均情况比完的概率。所以加上一个词之后这个序列概率可能增大也可能减小
这部也设一个停止条件,序列概率小于阈值,或者没有节点可扩展时停止扩展。最后得到一堆序列,近似选择里概率最大的那个,就是我们生成出来的文本了

说到这还缺一步。层内边的权值是频率,层间边的权值应该怎么求呢?我的想法是这样的:既然每个摘要块都是对于某个子文本的抽象,那我单独就激活这个摘要块,生成的文本应该和子文本越像越好
为了简化计算,我们满足它的充分条件:就是只激活这个摘要块,最后传完了,在子文本里的词节点应该都被激活(就是橙色的),不在的应该都不被激活(就是灰色的)

如果把这个跨层连接权值先拿一系列未知量代替,那传播之后每个词的信度是固定可以表示的,对于每个节点都有一个式子。
因为我们有阈值,信度大于多少的选(变成橙色),信度小于多少的不选(变成灰色)。那我们就让在和不在这个子文本里的词分别满足这个大于小于关系。就是右边这个约束条件,v就是阈值。
PPT里这说的是一个摘要块的约束条件,实际应该让所有摘要块的这个条件同时满足。因为这个图是基于很多语料文章建立的,这么多条件很难同时满足。因此对每个约束条件都引入一个独立松弛量s,把它的边界拓展一下。当然拓展不能太多,所以目标函数是让这些s的和最小化,也就是让边界改变最小。
因为这些传递其实都是对于信度乘和加,所以每个约束条件这个式子就是个线性的,那这整个就是个线性规划,可以很快的求解。

这篇文章是17年的,实验我是和我自己训练的word2vec+seq2seq基线对比。基线是跑在CPU并行的keras上,我这模型实现是单线程的,速度还是比它快几十倍。因为这个结构和训练都简单,快是可以预料的。效果也好了一个量级,基线只能保证临近的几个词之间比较通顺,长了就不知道要表达啥了。我这个可以从上到下进行一个整体的规划。因为这个模型从结构上已经包含了很多文本生成任务需要的先验知识,这是它又快又好的原因
现在深度学习NLP又发展了一大步了,有transformer。基于transformer的那个语言模型GPT2我调调实验了一下,确实是比我这效果好一些,感觉更通顺。当然训练那个一般人都玩不起,这个还是有一定性能优势。在当时我是实验做的不全没好意思说,不过我觉得这模型是当年文本生成的SOTA也不是没有可能。

然后说说下一篇文章。这里针对的是这样一个问题:我们的数据有一些函数,这些函数大体上受同样的规律作用产生,但是因为一些外生参数的不同形状有所不同。然后现在有个不完整的函数,应该怎么利用这些数据来预测这函数后面的值呢?
这个问题来源于一个比赛,当时不少人的想法就是把这一大堆函数数据点和外生参数都扔LSTM里,然后用训练完这LSTM预测未知函数。这样的模型是复杂而且不透明的,我们想的是这样一个办法

因为这一堆函数都是受同样因素作用,大体上形态都是肉眼可见的相似。所以我们分三步,第一步:找到理论上和未知函数最像的那个完整函数,作为基准函数。然后对基准函数进行一些变换,让它实现对未知那个函数最大程度的贴合。变换完之后他俩看起来合在一起了,那变换后基准函数后面那些值就可以作为预测值。看起来是很直白的一个方案,那怎么实现呢?

首先选基准函数。从理论上讲,作用参数越像,作用得到的函数越像,所以我们选这组外生变量最接近的那个函数作为基准函数。这个不是重点,重点是变换

怎么变换呢?因为形态都是肉眼可见的相似了,所以就可以看出,这个横轴捏一捏,挪一挪,纵轴也捏一捏,让他俩贴上,这就是我们要的变换。
那写成公式就是先变x,捏一捏横轴,然后把变完的x代入基准函数,这步相当于实现了坐标变换,把基准函数的x映射到待预测函数x’的那个量纲。然后外面再套一个h函数,捏一捏纵轴,得到我们变换完的函数。变换完的函数应该满足啥样的性质呢?就是这个目标,取每个值的时候都让他俩尽可能像,那写写出来一看发现这不就MSE吗。所以就自然而然想到整体结构是这样的

这样的,这么一看,好像神经网络啊。g和h我们未知,就相当于是两个待训练的网络,或者说一个网络里的两部分。然后通过使变换后函数和变换前函数差的最小这个目标反向传播求参数值。而且根据之前的分析,我们知道g和h应该是啥样的:捏一捏挪一挪,这不就是仿射变换吗?Ax+b,所以这用线形层理论上就行。不过可能线性层这个参数组合比较难找,我们实际用relu让它收敛更快。
然后f是我们的基准函数,固定的,因为要反向传播,它得可导,不能是数据点的形式了。所以插值求出解析式,弄个自定义层放在这里

其实这结构一看可能发现,这个很像迁移学习,few shot学习。现在这类文章不少都是度量分析,从流形的角度看源领域模型和迁移到的这个领域的分布差距。其实这个思想是类似的,只是我们这个简单,不是流形了,就一个函数,既然这样,我这么做的原因其实就是借助那个思想反向推导,我知道它的几何特征,就知道在他俩之间实现迁移的网络结构。

这个模型虽然是神经网络,但不是深度学习,因为它就几十个节点,浅度学习。虽然这样,但它很有效,比乱七八糟的LSTM好,而且可以看出速度会非常快。我们是再3000多队里精度排70名,而且这个成绩是不用炼丹,一把成的。排名前几的那几个队看它们的介绍都是kaggle那种经典结构,决策树集成,有的不同情况下换用LSTM,那它们那复杂程度肯定远远高于这个了,虽然说这个表达能力有限,但其实可以解决很多问题。我觉得这就是分析问题的威力。

引用文章/PPT下载

Liu, Tingzhen (2021): Design of High Performance Machine Learning Algorithm for Vertical Domain Problem. CCF YEF2021. Presentation. https://doi.org/10.6084/m9.figshare.17054918.v1 

以上是关于针对垂直问题的高性能机器学习算法设计的主要内容,如果未能解决你的问题,请参考以下文章

针对垂直问题的高性能机器学习算法设计

深度学习框架只为GPU? 答案在这里

机器学习系统设计 ---- Machine Learning System Design

Python深度学习之路-2.1 机器学习的流程

Python深度学习之路-2.1 机器学习的流程

Python深度学习之路-2.1 机器学习的流程