最早接触启发法是在初中时学校半强制推销的一本书,名字大概是启发法解数学题之类的,通读下来最大感受就是那些题都是稀奇古怪的,解法也是类似灵光乍现的那种。到今天我是一道题都记不起来了,但当时确实没搞懂书名里那个“启发法”是什么鬼,其英文 heuristic 也是字如其名,搞不清词根哪来的。启发法的较正式的解释是非最优非理性快速解决问题或作决策的方法,包括试错、经验法还有拟设(类似假设检验),类似直觉经验判断的混合体。我相信你看这个估计脑子里也犯嘀咕,能不能说人话?
我理解启发法大概就是瞎猜的艺术。说瞎猜是因为启发法通常用在资源不够的情况下,例如求解一些解析解非常复杂的函数方程,说艺术是因为瞎猜给出的解决方法很多情况下不是最优的,也不是唯一的。换句话说,启发法是用来完美解决问题的既不必要也不充分条件,属于没办法的办法,想到这一点我才突然发现已经在启发法的坑里玩了很久泥巴了,这不就是科研过程吗。科研外人看是有章可循的但到了前沿领域是没有完全可靠的排列组合路线的,例如当前疫苗开发,虽然各国都在搞但实话说没个几年是拿不到安全性评价的,副作用大家都是猜,甚至新冠病毒的最致命靶点究竟是不是只有肺都没搞清楚,有没有引发慢性病可能也是一头雾水。面对这种未知情况,其实初期用的都是类比与启发法,类比相似病毒,尝试各种可能方案。
如果把启发法当算法来理解,一般包括两步,随机寻找与爬坡,随机寻找进行尝试,根据结果向着期望方向寻找直到达成目标或时间用尽。此时,使用者知道如何检测结果但不知道如何生成出现结果的机制。与启发式相对的是解析式问题(例如梯度优化),此时我们知道问题原因,可以根据原因来求解,例如有函数我们可以求导来算极值,而启发式则是只知道要求极值但函数未知,常用来解决黑箱难题。
启发法里也存在一组制衡:探索(exploration)与利用(exploitation)权衡。探索侧重复杂空间例如完全随机搜索,利用强调快速求解例如爬坡。启发法中一个关键步骤就是探索完一次得到继续探索信号后如何生成新参数,微小的参数改变有利于寻找方向而较大的改变有利于摆脱局部最优。也就是说在资源有限条件下,想更多探索解决方案空间就没法获取很高的求解精度,反之,在局部解决方法上反复优化就没法探索更大的解决方法空间。
不过,启发法本身的设计却可以很艺术的去探索两者的平衡。模拟退火算法的核心思想是在随机寻优结果是负面的时候也会以一定概率接纳,负面越高越不接纳,也就是尽可能引入改变来防止局部最优。禁忌搜索(tabu search)算法会预先设定一个列表,最优的结果都存到里面,存入后就不再考虑对应的参数修改方式,这个过程反复进行填满列表后最早的就可以踢出去重新考虑了。这也是防止局部最优的策略。迭代式局部搜索则从时间上做文章,先进行一段时间爬坡找到局部最优,然后进行较大的随机行走,在新位置上爬坡找最优,跟之前对比留下好的,然后继续迭代。
上面这些策略都可以用,也可以组合使用。除了这类单一状态优化外,另一类启发法则是从种群角度进行计算的,同时进行多组扰动,根据结果探索变化方向。这个思路来自生物学里的进化算法,包括遗传算法与进化策略。基本思路是设置初始种群,计算适应度,然后选一部分个体进行一代遗传,遗传过程伴随突变,之后重新计算适应度,最后留下适应度高的继续遗传。
种群初始化时要尽量多保持多样性,可以用哈希表来存储独立个体。在进化策略上,计算完个体适应度后只保留部分高适应度个体进行遗传,下一代数目与初始种群一致,例如每代10个个体,但只选2个最高适应度的遗传突变,下一代数量还是10个。当然,也可以在下一代里把第一代也都考虑进去进行筛选,如果一代不如一代,至少还保留了上一代的优良基因。突变率依赖正态分布的方差,经验法则就是如果多于五分之一子代表现更好,需要增加方差防止局部最优,如果少于则减少方差,等于则不变。
在遗传算法中,子代生成是有父母贡献一半进行杂交然后加上突变的,这里面多一个随机翻硬币来决定子代那一部分交换的步骤,此时遗传部分的可能性空间是确定的,另外杂交过程也可以对连续变量进行线性插值。在进行适应度选择上,可以根据概率去选,也可以用非参方法排序来进行选择。
在启发法特别是基于种群的启发法中,并行计算特别重要,你可以并行多组启发算法,或者在同一台机器多线程计算适应度,或者用分布式计算来分散汇总结果。如果需要多目标优化,就设计一个由多目标加权组合的新适应度指标。启发法也可以用在组合优化问题例如背包问题或邮差送信问题。此时可以先构建出一个组合,然后在有限时间内进行组分调整计算适应度,最后留下好的。蚁群优化则是先构建一组备选方案,然后计算适应度,记录各个组分的表现(信息素),重复这个过程,然后根据各组分信息素多少来选择最终组合。这个过程信息素可以挥发,备选方案也可以进行一定的爬坡,也可以用禁忌搜索来禁用掉一部分组分。同时随机数生成对于启发法也很重要。
了解启发法的相关算法对科研是有帮助的,因为科学问题的求解通常面临资源有限的情景,此时预实验或探索性数据分析就要借鉴启发式算法的思想,不仅仅优化自己熟悉成熟的解决策略,还有留足够的随机行走空间。时至今日,很多科学问题可以通过仿真手段来验证与求解,怎么设计一个探索性仿真策略也需要对启发式算法有一定的理解。
但最重要的是,启发法其实与认知偏误有时是伴生的,很多直觉性尝试都埋伏了认知偏误而容易导致陷入局部最优而不自知,而完全随机尝试的启发法其实是反直觉的。如果所有人都在用一套解题策略来攻克一个科学问题,那么尝试下从所有思路里随机选择可能会发现更好的解题策略,也就是要试错。不知道从什么时候开始,流行文化里对正确与成功的故事给予了很高的认可,很多人不能也不敢犯错,按部就班走流程排列组合在科研论文中形成了新八股的趋势。我们只能看到漂亮且显著的结果而不知道论文背后的试错过程,很多研究事实上脱离实际且不易重复,这种趋势会把科研人员的思路锁在那些四平八稳不犯错的研究而不是真正解决问题,把科学沦为了技术。
现在我们很少在算法之外的课程里看到关于启发法的介绍,一方面是因为很多学科已经有了比较固化的研究模版,不愿意尝试高风险的启发法;另一方面则在于启发法里瞎猜与艺术性很难通过课程来学习,更多是一线人员自己摸索。不过,如果各学科可以更多介绍启发式思维,在有限资源下权衡好探索与利用,相信对于学科自身的发展也是有帮助的。