第二个挑战是关于模型大小以及模型训练难度的问题,前面提到了深度神经网络有很多层,而且一般参数都很大,几十亿的参数是家常便饭。面对这样的网络,至少有两个困难,一个是我们经常提到的梯度消减和梯度爆炸的问题,当深层网络有非常多层次的时候,输出层和标签之间运算出来的残差或者是损失函数,是很难有效地传递到底层去的。所以在用这种反向传播训练的时候,底层的网络参数通常不太容易被很有效的训练,表现不好。人们发明了各种各样的手段来解决它,比如加一些skip-level connection,像我们微软亚洲研究院发明的ResNet技术就是做这件事情的,还有很多各种各样的技巧。但这些其实都只是去解决问题的技巧,回过头来,原来的这个问题本身是不是必要的,是需要我们反思的。 再有就是模型爆炸。前面说了几十亿的参数是家常便饭,几十亿甚至上百亿个参数意味着什么,意味着模型本身的存储量是非常大的。举一个简单的例子,如果我们用神经网络来做语言模型,给出的训练数据集是Clueweb整个网络上的网页,大概有十亿个网页的量级。 这样的一个数据,如果要去用循环神经网络去训练一个语言模型,简单计算一下就会知道,它需要用到的模型的大小大概是80G到100G的大小,听起来好像不太大,但是现在主流的GPU板上的存储24G已经算是高配,换句话说,80G到100G的大小已经远远超过一个GPU卡的容量,那么就一定要做分布式的运算,atv直播,还要做模型并行,有很多技术难度在里面。即便有一个GPU卡,能够放下这80G或100G的模型,如此大的训练数据过一遍也可能要用上百年的时间,这听起来也相当不靠谱。到底需不需要这么大的模型,有没有必要我们非要把自己放在一个内存也不够用,计算时间也非常长,也不能忍受的境地呢,这个是值得思考的问题。 说到大模型,标注数据很大,那必然要提到分布式运算,分布式运算听起来是一个相对成熟的领域,因为系统领域已经对分布式计算研究了很多年。但是回到我们分布式机器学习这件事情上是有所不同的:这里我们做分布式运算的目的是为了让我们能够用更多的资源来容纳更大的模型,使得运算的时间缩短到能接受的程度,但是我们不想丢掉运算的精度。 举个例子,原来用上百年的时间可以得到一个非常精准的语言模型,现在有100台机器,虽然算的很快,但出来的语言模型不能用了,这件得不偿失。 说到分布式运算有两个主流的方式,一个是同步的并行方式,一个是异步的并行方式。同步的并行方式是什么,就是很多机器都分了一个子任务,大家每计算一步之后要互相等待,交换一下计算的结果,然后再往前走。这个过程能够保证对整个分布式运算的流程是可控的,可以知道发生了什么,在数学上可以做建模,能够在理论上有所保证。但它的问题就是所谓的木桶原理,这个集群里面只要有一台机器很慢,分布式运算就会被这台机器拖垮,就不会得到好的加速比。 所以人们开始做异步的并行方式,异步的意思就是每台机器各自做自己的事情,互相不等待,把当前按照各自的数据训练出来的模型更新推到某一个服务器上,再更新整体模型。但这时候又出现了一个新的问题,就是乱序更新的问题,这个过程是不能被我们原来的数学模型所描述的,违背了优化技术的一些基本假设。比如当我们使用随机梯度下降法的时候,可以证明当时用一个不断减小的学习率时,优化过程是有收敛性的。这是因为我们每一次增加的那个梯度是在上一次计算的模型基础上算出来的梯度。一旦加上去的梯度可能是旧的,不是依据前一个模型算出来的,到底优化过还能不能收敛,就不那么清楚了,所以虽然速度快,精度却可能没有保证。 (责任编辑:本港台直播) |