模块化和结构:AI 时代的一些个人思考碎片
在很长一段时间里面,我对自己的思考和定位并不是特别的明细.不论是作为一个科研工作者、一个开发者还是一个学生,我觉得自己很难在各种身份中找到属于自己的平衡。本人不善言辞,满篇暴论,大家全当一乐就好。祝大家不论什么时候,都不放弃自己的梦想。
引:那些纯粹的和不纯粹的
长久以来,我对所谓「纯粹」有一种近乎偏执的执念。对这个世界,我长久以来都怀有最虔诚的好奇和热爱。这里我列举几个有意思的小问题,这些问题可能在诸位眼里稀疏平常,但可能并不能很好的解释:
- 颜料的混合是物理反应还是化学反应,为什么混合之后有颜色会发生变化?
- 为什么纸张折叠之后会有痕迹,即使我们还原了纸张,也不能让痕迹消除?
- 自行车轮胎的轨迹是双S线,这和自行车的平衡方式有什么关系吗?
很多事情可能在大家眼里是没有意义的,但是对我来说,这是我内心深处的纯粹和热爱。在我有限人生的 23 年的挣扎中,我自认为我已经具备了在生存的能力。我接受的教育已经让我有能力找到维持生计的工作(当然主要是因为自己没有对象,一个人的生活开销也确实很低,哈哈)。《阿波罗吉亚》中,苏格拉底提出的:「The unexamined life is not worth living for man.」在本科的最后一年和我研究生的生活过程中,我几乎也不依赖来自家庭的经济支持了。所以,也是时候开始审视自己的生活,并且思考我的下一个人生阶段,应该要什么模样的生活。
我自己对这个问题的最终答案是「研究」和「思考」。亚里士多德在《尼各马可伦理学》提出,人应该追求自己的本性,发展本性趋向的活动。诚然这世间万物都有各自的优秀,鸟善飞,鱼善游。人不能违背本性追求超越自己能力的行为,比如「不借助外力飞行」。即便是你带了开着飞行模式的手机,那也是不能原地起飞的。顺应自己的本性可以借助自然的势能,最大程度发挥自己带活动效力。而人类能做到超越世间其他万物的显著本性,就是思考。而我确实有几分幸运,思考的过程能给我带来极大的愉悦。而我也足够幸运的找到了适合自己的博士岗位,可以给我足够多的时间,去纯粹的思考。
优化和解构
「我思,故我在。」那么我应该思考什么呢?
论思考,我并不是擅长。如果提及思考的方法论,我心中并没有一定的定数。我迄今为止的所有工作某种意义上都只是停留在「优化」的层面上。但是经历了数十个不同的优化项目之后,我认为应该重新审视「优化」这件事情本身。而我在博士期间也希望得到这些问题的终极答案:我们要为什么样的系统优化,以及我们需要如何优化,什么样的系统有优化空间,需要优化到什么程度。
优化的意义
在探讨着一系列问题之前,我们需要定义清楚,「优化」这件事情本身。现如今大部分的科研工作,这里特指计算机领域的科研,几乎将所有的工作力量投入到了「计算时间」或者说「计算速度」上的优化。这种观点无可厚非,确实是我们追求「更快计算」的本质,某种意义上这也是计算机科学的立足基石。当然,算法效果的优化、计算开销的优化,也是系统优化的一部分。但是「优化」的理念可以不仅仅限制在这些层面上。《纯粹理性批判》中,康德探索了我们如何理解和组织经验的问题。我们能够更好的复用经验和技能,某种意义上也是优化的一个重要组成部分。随着 GPT 系列的工作诞生和大语言模型的快速发展,我的观点也随之刷新。我们现在已经有了一个很好的辅助工具,GPT。这个工具可以让每一个人都拥有「人类知识的最大似然估计」,可以用更快的速度接触到人类知识的边界。这种效应我认为理应最大程度的推动我们的怀疑精神去发挥。正如波普尔在《猜想与反驳》中提出,科学知识的发展是通过猜想和批判的循环过程进行的;赫伯特西蒙的《科学发现的逻辑》也提及,科学的发现的建立也是在「有限理性」的基础上。为此我首当其冲地对优化的意义进行了质疑,有没有可能,我们刻意但合理让性能变差,其实也是一种「优化」?
因此,我觉得我认为的「优化」可能需要从广度上拓展一下本身的定义和合理性。首先,优化本身不是一个理论和范畴。为了让一个数值指标朝向一个指定的目标方向发展,我们需要借助的是「原理」或者其他领域的「经验」。而这就是我在这篇文章中希望阐述的观念「解构主义和模块化」。而优化,其实应该是:基于「第一性基础原理」和「迁移经验」共同作用,让「既定指标」朝向「目标方向发展」的完整流程。最常见的例子是:我们基于对体系结构的认知,了解到计算机对内存访问有空间局部性,从而我们可以对数组访存进行充分优化,从而达到计算效率的提升。而这个例子可以概括大部分在体系结构上对访存性能提升的工作的中心思想。但是科学的发展过程,我们离不开「传承」和「怀疑」,而我觉得随着 GPT 的诞生,另一个可能有价值的发展方向是:我们基于对人类理解能力的认知,了解到程序的可读性可以被评估和量化,从而我们可以对原有代码进行语义化的变性,从而让程序的可读性增强。这个方向某种意义上是站立在性能优化的反方向,但是我们可以将过去已有的经验反向迁移。具体的作用和应用也非常多,例如推动跨学科的合作,辅助负责不同阶段优化人员对程序的理解等等。
在阅读文学作品的时候,作品往往会进行分类,一个重要的分类标准是,这部作品探讨的是「宏大叙事」亦或是「内在精神」。这两个话题并非独立,而计算机优化领域的「内在精神」无疑是追求效率和效果,去刷几个百分点的指标。但我认为计算机的发展也应该有自己的「宏大叙事」去指引我自己的思考。我当初选择计算机作为自己的发展方向,一方面也是受到了图灵和费曼的传记的影响,从而希望通过一个新的视角去思考和理解这个世界。实施上,大部分作品中的「宏大叙事」和「内在精神」也并非独立关系。借助计算机研究其他领域的研究者也一定是注重计算性能的,并不会因为计算科学的视角从而忽视优化程序性能的本身。
而我对优化深度的认识,也在 2023 年这一年得到了质变。「量变引起质变」的观念其实已经成为大众的共识,可是真的出现了 GPT-3 之后,我们才真的深刻认识到了 GPT-3 的强大,也是第一次认识到,如果训练参数足够大和训练数据足够多,确实可以制造出这种「弗兰克斯坦」。一定程度上,对系统承载力的优化,也可以提升模型的效果。我在这一年之前,对 AI 发展一直保持悲观态度和抵触情绪。相反的,我认为计算科学的底层基础,例如体系结构和线性代数算法才是计算机应该认真思考的领域。但是认真接触到大模型的能力和 AI for Science 的一些成果之后,我觉得也是时候抛弃自己故步自封的想法了。
高性能计算的一个重要应用领域就是计算模拟。计算模拟的最重要的作用就是在进行实际的物理生产之前,经过合理的模型进行预估,从而大大降低实验成本,规避失败实验造成资源浪费。但是随着异构计算设备的发展,很多传统模拟的速度已经来到了一个重要的分水岭面前——实时模拟。如果模拟的速度超过了真实反应的速度,那么模拟的意义也可以超越「预先实验」这个层面。其实在这个分水岭面前,我自己也有非常多的疑惑和不确定性。目前很多的科学领域的数据和知识积累并不足以训练模型,很多时候仅仅通过数据是不能表达我们的物理模型的。个人看来,GPT 可能是一个机会,可以将一些已有的实验知识放在现有的模型中共同作用。这个领域我自己也有非常多的不确定和纠结,在这里也不做过多的讨论。回归之前的话题,当模拟的速度已经超越实时,我们会有更多的机会去实现前所未有的预测和模拟,不论是 Google 的气象模型,还是 Deepmind 的 Gnome 材料模型,都为我们展示了更多的可能性。
优化的方法
我个人对优化的方法理论,很大程度上受到了 LLVM 项目的影响。很多人对计算机科学有一个调侃:「明明手动的工作只需要一小会,但是为了实现自动化付出了数倍甚至数百倍的时间成本」。LLVM 项目为我带来最重要的思考,其实并不是编译的自动化,而是模块化和解构的思想。可以说 LLVM 是我所有学习过的项目中,模块化和工程化的巅峰。
LLVM 中,有一个重要的概念叫 LLVM IR,是一种公用的中间表示。简单来说,我们需要使用的编程语言是复杂的,有 Rust,C++,C,甚至是 Fortran;我们的目标机器也是多样的,可能是 x86 平台,ARM 芯片,甚至是更新的特定加速器。如果我们要实现每一种语言和一种硬件设备之间的编译操作,工程量无疑是非常惊人的。但是规定了一种「中间格式」,我们把所有的语言翻译到这种中间格式上,再分别开发这种中间格式到每一种硬件平台上的编译工作,那么工程量会大大降低。从而,我们的优化和后续流程是基于相同的公共起点,人类的创造力就可以最大程度的避免重复劳动。「Golden Age For Compilers」的演讲中的很多观点对我来说非常有启发。如果说 ARM 的工程师、AMD 的工程师和 Intel 的工程师都出于自己的目的设计了自己的编译器去开发,其中不可避免的会有很多重复的优化流程,例如常数传播,循环展开等等。但是 LLVM IR 通过规定公共的表达形式,统一了优化的流程。
规定了公共的表达方法,在工程意义上确实也是合理的,但是在追求极致性能的路线上,可能不是一个真的可取的方案。现代的处理器有不同规格的向量处理指令,在异构设备上甚至还有对应的张量处理单元。对于不同的优化需求,如果生成到 LLVM IR 之后,可能已经产生了极大的性能损失,从而无法发挥硬件的真实性能。
在 2023 年,体系结构发展变得更加抽象和复杂的今天,我个人认为,解构主义思想可能是破局的最好办法。不论是 Pytorch,还是 MLIR 项目,都在做一些尝试。而找到「最小可估计上界计算模块」,「最大可估计下界计算模块」可能最容易突破的方向。通过建立足够多的可以评估计算时间上界的计算模块,我们很容易搭建一个可以评估性能的神经网络。而通过找到代码中最大的可以估计下界的计算模块,我们就很容易找到对应的模块进行极致的性能优化。而这两点在 MSRA 的 Rammer, Roller, Welder 系列工作中,通过建立不同的 cost model 分别对这些问题找到了合适的答案。通过先建立合适的中间表达进行优化,再将部分过度错误优化的模块重新击碎。解构主义的出现是在 20 世纪后半叶,雅克·德里达等人提出了解构主义思想,它质疑了固定意义的可能性,并强调了文本的多义性和开放性。解构主义者认为,意义不是由作者的意图或文本的内容所决定的,而是在读者解读的过程中不断地产生和变化的。这和我们当下优化困境其实是一致的,我们基于已有的硬件架构写了很多优秀的代码,但是随着时代发展,我们需要对已有代码进行新的解读和变化,让他们适应新的硬件。而这个复杂的过程不可能通过人力完成,通过翻译和编译的工作可能是最轻松的尝试方法。
至于如何找到程序代码的「最小可估计上界计算模块」,「最大可估计下界计算模块」,也是我近期来思考的一个重要问题,近期可能会在个人 blog 上更新一个系列文章。
优化的目标
对一个问题的优化可能是永远没有尽头的。因为我们其实也不知道我们到底可以优化到什么程度,对一个问题真正的时间代价,我们也很难有一个确切的估计。真实的世界具有非常强的复杂性,但是系统的设计应该保持精简和易用。不可避免的,通用和专用之间的冲突,对优化问题也产生了巨大的冲击。在这个背景之下,最近 30 年高性能的发展中,也出现了 DSL(Domain-Specific Language) 和 DSP(Domain-Specific Processor),这类将专用性发挥到极致。在专用问题上,这类工作也确实将专用性能发挥到了一定程度上的极致。
可是用我们刚刚说的解构主义思考一下,这个问题可能已经将自己的发展道路堵死了。高性能领域的算法发展速度虽然没有 AI 领域这么日新月异,但是每过三四年,都会有不同的高性能编程框架和并行范式出现。OpenMP、MPI、OpenACC、OpenTBB、OneAPI、OpenCL、Numba、Cuda 等等,如何更加充分的利用计算资源这个问题上的软件发展从未停止过。而为了支持一种特定的 API 发展无疑是容易走向极端的。除非,DSL 的生成并不是人工手写的,而是编译器自动生成的,可以降低重复劳动的成本,也让 DSL 的易用性得到最大程度的提升。
基于上述的思考,我认为 AI-System 发展的必要性和合理性应该呼之欲出。AI for Science 的发展趋势已经几乎不可阻挡,虽然目前为止,合理性还有一些存疑。但是我个人的观点认为,目前的 AI 做的是对已有物理系统的最大似然估计,有潜力的是对位置的物理体系做合理的推理。这两种发展趋势在很大程度上都具有合理性。设计 Domain-Specific System 的设计理念和 System 需要拥有的通用型是相互冲突的。为了设计尽可能让更多的应用适用的高效系统,我目前看到的发展方向就是设计适合通用 DNN 的系统。这里可能要再挖一个坑,后面打算整理一下之前的论文阅读笔记,整理出从「内存」、「算力」、「数据存储」、「通信」等不同角度思考系统设计的一些文章。具体的设计框架最近还要和导师讨论一下。
新的优化思路和趋势
2023 年我看到另外一个值得尝试的思想是设计领域的 Bento 风格。这个设计源自便当设计,其实是一种极简主义的美学设计的拓展。而近期 AI Chip 的设计理念也变得非常有趣。2D 的芯片阵列设计逐渐成为设计领域的主流。不论是 Cerebras 还是 TPUv5 中,都用到了类似的设计结构。但是我们在其中有很多问题都没有解决:
- 如何将芯片的利用率达到最高,单片性能最高和整片性能最高存在一定的冲突
- 2D 阵列芯片可以同时计算多少矩阵,如果这些矩阵计算有后续依赖,我们应该如何安排调度
- 传统的矩阵分块算法是否适用于新硬件
- 稀疏计算的计算范式能不能在 2D mesh 上取得更好的效果
- 有没有什么算法是非 2D mesh 非常适合但是在 2D mesh 上无法做到的
这一系列问题都牵扯到了软硬件的协同设计。Bento 的理念是极简风格,我认为我们也应该找到在 2D mesh 上最基础的模块。这些工作我也还在探索的初期。不过希望在这个月得到一些初步的答案。
破局
生命不息,思考不止。这篇文章献给 23 岁的自己。首先祝贺我自己,和自己和解,放下了自己的执念,找回了自己对知识最纯粹的追求。也希望我自己能顺利的把上面提到的工作完成。2024 是人类的破局之年。2023 一整年的积累,让科技走到了爆发的瓶颈口。对我来说,在机遇冲击我自己的时候,尽力追求「为学日益,为道日损」。多学点,多想点。让自己体验思考和生活的快乐。