经过初步(是初步,这个是隐藏的)训练后得到全部权重模型后,我们就开始考试它,比如注入神经网络几万张含有猫的图片(每张图片都需要在猫的地方标注猫,这个过程一般是手工标注,也有自动标注,但准确度肯定不如手工),然后拿一张图片让神经网络识别图片里的是不是猫。如果答对了,这个正确会反向传播到该权重层,给予奖励就是保留,如果答错了,这个错误会回传到网络各层,让网络再猜一下,给出一个不同的论断,这个错误会反向地传播通过该网络的层,该网络也必须做出其它猜测,网络并不知道自己错在哪里,也无需知道。在每一次尝试中,它都必须考虑其它属性——在我们的例子中是「猫」的属性——并为每一层所检查的属性赋予更高或更低的权重。然后它再次做出猜测,一次又一次,无数次尝试……直到其得到正确的权重配置,从而在几乎所有的考试中都能得到正确的答案。 得到正确的权重配置,这是一个巨大的数据库,显然无法实际应用,特别是嵌入式应用,于是我们要对其修剪,让其瘦身。首先去掉神经网络中训练之后就不再激活的部分。这些部分已不再被需要,可以被「修剪」掉。其次是压缩,这和我们常用的图像和视频压缩类似,保留最重要的部分,如今模拟视频几乎不存在,都是压缩视频的天下,但我们并未感觉到压缩视频与原始视频有区别。压缩的理论基础是信息论(它与算法信息论密切相关)以及率失真理论,这个领域的研究工作主要是由上世纪40年代的 Claude Shannon 奠定的,实际机器学习所有的理论基础在上世纪50年代就已经全部具备,绝大部分理论基础也来自Claude Shannon 的信息论,唯一差的就是算力,是英伟达的GPU造就了深度学习时代的到来,目前的深度学习没有理论上的突破,只是应用上的扩展。经过压缩后,多个神经网络层被合为一个单一的计算。最后得到的这个就是推理Inference用模型或者说算法模型,实际我觉得叫Prediction猜测更准确。
图片来源:互联网
深度学习的关键理论是线性代数和概率论,因为深度学习的根本思想就是把任何事物转化成高维空间的向量,强大无比的神经网络,说来归齐就是无数的矩阵运算和简单的非线性变换的结合。在19世纪中期,矩阵理论就已经成熟。概率论在18世纪中期就有托马斯贝叶斯,在1900年俄罗斯的马尔科夫发表概率演算,概率论完全成熟。优化理论主要来自微积分,包括拉格朗日乘子法及其延伸的KKT,而拉格朗日是18世纪中叶的法国数学家。RNN则和非线性动力学关联甚密,其基础在20世纪初已经完备。至于GAN网络,则离不开19世纪末伟大的奥地利物理学家波尔兹曼。强化学习的理论基础是1906年俄罗斯数学家马尔科夫发表的弱大数定律(weak law of large numbers)和中心极限定理(central limit theorem),也就是马尔科夫链。 深度学习的理论基础已经不可能出现大的突破,因为目前人类的数学特别是非确定性数学已经走火入魔了。 实际深度学习就是靠蛮力计算(当然也有1X1卷积、池化等操作降低参数量和维度)代替了精妙的科学。深度学习没有数学算法那般有智慧,它知其然,不知其所以然,它只是概率预测(深度学习里最重要的置信度)。所以在目前的深度学习方法中,参数的调节方法依然是一门“艺术”,而非“科学”。深度学习方法深刻地转变了人类几乎所有学科的研究方法。以前学者们所采用的观察现象,提炼规律,数学建模,模拟解析,实验检验,修正模型的研究套路被彻底颠覆,被数据科学的方法所取代:收集数据,训练网络,实验检验,加强训练。这也使得算力需求越来越高。机械定理证明验证了命题的真伪,但是无法明确地提出新的概念和方法,实质上背离了数学的真正目的。这是一种“相关性”而非“因果性”的科学。历史上,人类积累科学知识,在初期总是得到“经验公式”,但是最终还是寻求更为深刻本质的理解。例如从炼丹术到化学、量子力学的发展历程。人类智能独特之处也在于数学推理,特别是机械定理证明,对于这一点,机器学习永远无能为力的。 对于深度学习推理阶段来说,分解到最底层,其运算核心就是数据矩阵与权重模型之间的乘积累加,乘积累加运算(英语:Multiply Accumulate, MAC)。这种运算的操作,是将乘法的乘积结果和累加器A的值相加,再存入累加器:若没有使用MAC指令,上述的程序需要二个指令,但MAC指令可以使用一个指令完成。而许多运算(例如卷积运算、点积运算、矩阵运算、数字滤波器运算、乃至多项式的求值运算,基本上全部的深度学习类型都可以对应)都可以分解为数个MAC指令,因此可以提高上述运算的效率。推理阶段要求精度不高,一般是整数8位,即INT8。 对于训练阶段,要求比较高,常见的是FP64和FP32两种精度,近来又出现Bfloat16,Bfloat16就是截断浮点数(truncated 16-bit floating point),它是由一个float32截断前16位而成。它和IEEE定义的float16不同,主要用于取代float32来加速训练网络,同时降低梯度消失(vanishing gradient)的风险,也可以防止出现NaN这样的异常值。深层神经网络每次梯度相乘的系数如果小于1,那就是浮点数,如果层数越来越多,那这个系数会越来越大,传播到最底层可以学习到的参数就很小了,所以需要截断来防止(或降低)梯度消失。在float32和bfloat16之间进行转换时非常容易,事实上 Tensorflow也只提供了bfloat16和float32之间的转换,不过毕竟还是需要转换的。 英特尔的内嵌汇编格式GNU Gas添加了BFloat16支持,英特尔在2019年4月发布补丁,支持GNU编译器集合(GCC)中的BFloat16支持。和IEEE float16相比,动态范围更大(和float32一样大),但是尾数位更少(精度更低)。更大的动态范围意味着不容易下溢(上溢在实践中几乎不会发生,这里不考虑)。另一个优势是Bfloat16既可以用于训练又可以用于推断。Amazon也证明Deep Speech模型使用BFloat16的训练和推断的效果都足够好。Uint8在大部分情况下不能用于训练,只能用于推断,大多数的Uint8模型都从FP32转换而来。所以,Bfloat16可能是未来包括移动端的主流格式,尤其是需要语言相关的模型时候。当然英伟达认为Bfloat16牺牲了部分精度,对于某些场合如HPC,精度比运算效率和成本更重要。 一个MAC单元通常包括三部分:乘法器、加法器和累加器。
图片来源:互联网
上图为一个典型的MAC单元。计算机体系中的乘法和加法都历经了长时间的研究改进,纯粹的乘法器和加法器肯定是不会有人用。乘法器最常用的Wallace树,这是1963年C.S.Wallace提出的一种高效快速的加法树结构,被后人称为Wallace树。人工智能95%的理论工作都是在1970年前完成的,只是没有高性能计算系统,才没有在那个时代铺展开。加法器多是CSA,即进位保存加法器(Carry Save Adder,CSA)。使用进位保存加法器在执行多个数加法时具有极小的进位传播延迟,它的基本思想是将3个加数的和减少为2个加数的和,将进位c和s分别计算保存,并且每比特可以独立计算c和s,所以速度极快。这些都已经非常成熟,刚出校门的学生都可以做到。 除了降低精度以外,还可以结合一些数据结构转换来减少运算量,比如通过快速傅里叶变换(FFT)来减少矩阵运算中的乘法;还可以通过查表的方法来简化MAC的实现等。