硕大的汤姆

硕大的汤姆

The official website of Minhua Chen

23 Jun 2019

机器学习视角下的软件工程过拟合问题

软件工程中充斥着过拟合,它不但刻画了我们在构建系统时常常掉入的思维陷阱,也刻画了我们日常生活中思考与行动的方方面面。

什么是过拟合

在机器学习中,当训练集的数据量比较少,而模型又较为复杂的时候,模型可能会出现在训练集上 fit 的非常好,但是当遇到训练集外的数据时就完全懵逼的情况,这就被称为过拟合(over fitting)。在机器学习领域,过拟合是一个非常关键的问题,甚至可以说是 No.1 的核心问题。过拟合的本质其实是训练数据量与模型复杂度之间的矛盾,由于训练数据集的大小不足以满足模型复杂度的需求,导致模型在训练集和测试集上的表现之间存在较大的差距,训练误差中的方差(variance)太高。

我喜欢将过拟合的模型比喻成一个没见过世面的年轻人,看见什么都想往自己曾经见过的、被训练和教育过的东西上套,嘴里总是在说着:”A 不就是 B 吗?”。而可能它看到的仅仅是世界的一个点、一个边、一个局部而已,当现实世界的其他测试数据向它扑来时,它就崩溃了。

软件工程中的过拟合

在软件设计的初期,我们往往并不知道完整的市场以及完整的需求,因此对软件的架构设计很可能也是有问题的。当你看着手里的这些需求分析时,你很容易开始确信自己要做的”不就是那个什么什么嘛”。这时候,过拟合很容易发生。你开始想:”我们现在有 a,b,c,d,e,f 这几种用户,看起来他们大概有这十几种需求,所以我们只要做一个软件把这十几个需求都满足了,那应该就可以满足我们所有的用户了”。在系统构建的初期,这种方式往往看起来挺美好的,你确实成功满足了当前的所有用户的所有需求。

可以过了一段时间,又来了 100 个用户,他们又提出了 300 个需求,其中有 100 个可以用现有的软件设计来满足,100 个可以通过一些扩展来搞定,而剩下的 100 个可能完全与你当初的设计背道而驰。更糟糕的是,机器学习算法可以把所有数据拿来重新训练一遍,但你的软件一旦交付了,可就不能说变就变了。在用户较少且需求分析不够完整的时候,简单地去满足所有用户的所有需求,over fitting 几乎必然发生,而这往往是致命的。

如何减轻过拟合

正则化

在机器学习算法中,正则化起到了很好的减轻过拟合的作用。事实上,我们可以将正则化看成是奥卡姆剃刀原则在机器学习中的应用。奥卡姆剃刀原理(Occam’s Razor)又称”简单有效原理”,其揭示了一个非常重要的理念:”如无必要,勿增实体”。奥卡姆剃刀原理在很多学科中都有着非常重要的应用,是一个非常底层的逻辑。而正则化其实就是利用数学方式人为的引入惩罚,惩罚过于复杂的模型,在维持模型在训练集上准确性的前提下降低模型的复杂度。当然,正则化也是有一些代价的,可能会提高一些训练误差。所以从另一个角度看可以认为正则化是训练误差换测试误差。

我们同样可以用奥卡姆剃刀原理指导我们的生活实践以及软件工程的构建,在生活中或者软件工程中应用”正则化”。无论是近年来生活方式领域流行的极简主义,或是在软件工程中保持系统的简单与可扩展性,这些都是奥卡姆剃刀原理的良好实践。

更多的数据

另一种对抗过拟合的方式是增加数据,正如前文所述,过拟合本质上揭示了训练数据量与模型复杂度之间的矛盾。理论上来说,如果你能够得到足够的的数据,就能训练出很好的模型。换一种说法,数据量决定了对模型复杂度的容忍度,数据越多,我们就越能构建一个复杂的模型。

在产品设计与软件构建中,更多的数据其实就是说,你收集的需求越多越准确,你就越能构建一个复杂而准确的系统。由此可见,大量的需求分析是多么的必不可少。那么,到底多少才算够呢?在读读上面那段话你就明白了,多少才算够取决于你要构建一个多么复杂的系统,或者说需求分析的完整性决定了对软件系统复杂度的容忍度,需求分析越完整,我们就越能构建一个复杂的系统。

预训练

有些时候,数据并不那么容易获得。幸好我们还有一种对抗过拟合的方式–预训练。预训练就是找到一个已经在某个巨大的数据集上训练过的模型,然后基于这个模型扩展出一个新的模型来。由于那个在其他大型数据集上训练好的模型已经学到了大量的相关知识,这些信息都可以为新模型所利用,因此这个新的模型就可以”站在巨人的肩膀上”。

在软件工程中,对行业已有产品或是相似产品进行准确分析定位,研究其他产品的架构设计以及方法论进行深入研究,也能够帮助我们对抗过拟合风险。