你能把 Maven 烤进神经网络里吗?
我们试过了,它确实能构建。我们将一个Maven风格构建工具的决策部分编译成一个固定权重矩阵,并用它构建了一个真实的Java库。输出与Apache Maven逐字节完全一致。
在包含测试的干净构建中,耗时为同等逻辑Python实现的1.49倍(95%置信区间为1.4至1.54倍,30次配对运行)。
每位Java开发者都曾目睹过Maven的“思考”过程:解析依赖、编译、测试并打包。其中大部分时间花在javac和JUnit上,但贯穿其间的是一小段精细而复杂的逻辑,用于决定下一步该做什么——当两个模块对某个库的版本产生分歧时,哪个版本胜出;哪些文件应送入编译器,以及使用何种编译选项;某个测试失败时是否终止构建。
我们想验证这部分逻辑能否嵌入神经网络之中。我们并非要训练一个模型来猜测Maven通常会采取的下一步动作:那样的模型虽然多数情况下正确,但一个大多数时候正确的构建工具本质上仍是不完善的。
我们追求的是将决策逻辑本身编译进权重,使网络要么给出完全正确的答案,要么干脆拒绝回答。
本文顶部的视频展示的就是这个网络。其26,626个柱状条分别对应权重表中的一行(模型nmvn-exact-v2,详见“降低成本”一节),柱高表示该行在一次ZXing构建过程中被调用的频率,而亮点则按步骤回放了该构建的真实片段。
决定构建流程的一切都在其中。
从程序到权重表
诀窍源自手工接线:你可以编写一段程序,然后通过设置网络的权重,使网络等同于这段程序。我们用Python的一个受限子集编写了一个小型的Maven兼容构建控制器,并将其编译成一张包含29,625×7个数值的表格,外加7,382个常量单元(这是第一版v1;后续章节会将表格缩减至你所见的26,626行)。
无需训练,也无需梯度下降:零优化步数。
运行过程是一个循环。每一步,网络通过两次矩阵乘法查表,利用一个小规模寄存器文件执行该行编码的算术运算,并将结果写回内存。
网络无法打开文件或启动javac。当需要这些操作时,它会在内存的固定位置写下请求,由一层轻量级桥接机制将请求传递出去,并将原始响应写回。
桥接机制本身不作任何决策,所有选择均由权重决定。
测试对象是ZXing 3.5.3——一个条码库:其父项目及core和javase模块,采用clean package命令构建,同时运行测试。
它真的能构建吗?
能。它生成的JAR文件与Apache Maven逐字节完全一致,且是在一个Maven无法运行、网络处于关闭状态、既无法读取Python版本逻辑也无法读取Maven输出的沙盒环境中构建的。
全部549个上游测试均顺利通过,新构建的JAR文件在27项检查中均能正确编码和解码QR码。
519个手写构建案例通过验证,每个均与真实Maven结果比对;10,000个自动生成的项目案例通过验证;33个其他小型项目使用相同权重成功构建;一次完整的ZXing构建共经历4,796,191个网络步骤。
两项验证让我们确信,真正起作用的是权重。CPU和GPU版本的网络在完整构建过程中发出了完全相同的1,731个请求,顺序亦无二致。而当我们删除或损坏权重文件时,构建便完全无法进行。

观看构建过程
左侧:普通Python实现的控制器;右侧:同一控制器的神经网络版本。两者均实际构建ZXing,先后在同一台Mac上运行,以真实速度回放。
性能表现
在我们测量的所有场景下,它的速度都更慢。Python直接执行控制器逻辑,而网络则为每一条微小指令都要走完一轮矩阵运算,一次ZXing构建需经历4,796,191步。
仅就决策而言,网络的差距更为显著。但在整个构建过程中,这一差距缩小至约1.5倍,因为大部分时间仍消耗在javac和JUnit上,而两者的实现并无差异。
在GPU上运行网络并未带来改善,反而更糟。对于一台按顺序执行指令的程序来说,GPU几乎无处施展并行计算的优势。
在不改动网络的情况下降低成本
总耗时大致为步骤数×每步成本,因此我们统计了各步骤的来源。我们在一个指令级模拟器中重演了一次完整的ZXing构建,并记录了所有执行的指令。
在v1的4,796,191步中,有652,773步(14%)只是将值从一个寄存器复制到另一个寄存器,另有553,333步(12%)用于加载常量或跳回循环头部。
这些都是编译器的“胶水”,而非构建逻辑。
于是我们不动网络,只改进了编译器。结果直接写入所需寄存器,常量内嵌于使用它们的指令中,条件判断直接编译为分支,循环则改为在末尾检测,而非跳回开头。
机器、其步骤图以及GPU内核均保持不变,只有数值表格发生了变化,且体积更小。
23%的网络步骤得以减少,一次完整的ZXing构建从4,796,191步降至3,676,728步;10%的权重表行数减少,从29,625行降至26,626行;完全相同的决策:输入v1记录的序列,v2在CPU和GPU上均发出相同的1,731个请求,顺序一致;2/2的正确性关卡经v2再次通过(相同测试套件、沙盒构建、JAR文件逐字节一致)。
GPU的收益更为明显,因为它几乎完全按步骤计费:决策阶段耗时从v1的27.97秒缩短至v2的21.61秒(减少了23%),与步骤数的降幅基本一致。
不过,GPU依然是最慢的执行引擎。
我们用新权重重新运行了整条正确性链条:所有测试套件、必须生成逐字节一致JAR文件的沙盒构建、阴性对照,以及CPU/GPU上的回放。
在关键环节,效果虽真实但并不显著。由于Java工具仍主导着整个构建过程,因此即使削减了网络的占比,端到端的整体耗时降幅也小于步骤数的缩减幅度。
这不仅仅是Maven
为确认编译器未针对特定程序做特殊优化,我们为其赋予了一个毫不相关的任务:求解迷宫(广度优先搜索,programs/maze/maze_nml.py)。
它被编译成279行权重。一个小程序同时启动经典实现和神经网络版本,作为独立进程,并在各自报告时立即绘制相应单元格。
在三个不同的171×121迷宫上,纯Python、Python调试封装层、神经网络CPU版本和GPU版本均产生了完全相同的事件序列:访问过的每个单元格,顺序一致,距离相同。
第一个迷宫耗时2,572,288步。神经网络在CPU上运行的时间是纯Python的161至168倍,在GPU上则是791至812倍(各程序自有计时器,每个迷宫仅运行一次,因此这些数据仅供参考)。
既然速度较慢,那还有意义吗?
这个问题很合理,我们也曾问过自己。如果你追求更快的构建,答案是否定的:继续使用Maven吧。更大的GPU也无法拯救它,因为网络一次只能执行一条指令,而构建控制器中的任何操作都无法分散到数千个核心上。
然而,速度从来不是重点。我们最终得到的是一个每个权重都有明确含义的神经网络,而这相当罕见。以下是我们认为它最有价值的几个应用场景,其中前两个最为有力。
供拆解网络的研究者使用的“答案钥匙”
可解释性研究试图仅凭权重推断网络的功能。难点在于评估结果,因为对于经过训练的模型,真相往往无人知晓。而我们的网络自带“真相”。
除了一段七行的启动代码外,其26,626行权重每一行都对应控制器中249个已知函数之一,且我们清楚每个函数的具体作用。因此,我们可以指出do_surefire那一列——负责运行测试并决定失败是否终止构建的部分。
如果某工具声称发现了“依赖解析电路”,你就可以加以检验。手工构建的测试网络往往是小型玩具,而我们的网络却能在真实的代码库上完成实际工作,我们认为这才是它的最大价值。
嵌入预测模型中的精确子程序
一个在99%情况下都能选对库版本的模型,每百次构建中仍会出错一次。编译后的权重提供了一种将精确子程序以与学习模型相同的形式嵌入的方法:相同的张量、相同的运行时、相同的硬件。
需要说明的是,我们尚未将此类权重与训练好的模型结合。那是下一个实验,而非当前成果。尽管如此,这仍是我们最感兴趣的方向。
可哈希的决策逻辑
整套策略仅由一份数值文件构成。将其从CPU迁移到GPU,它仍会以相同顺序作出相同的1,731个决策;输入一段记录的构建过程,它也能原样回放。
这就是我们在“降低成本”一节中逐条比较v1和v2决策的方式。你可以对这份文件进行差异比对、签名,并证明某次构建的确出自它。公平地说,带有锁文件的普通代码也能达到类似目的。
而张量形式的优势在于,无论你将何种程序编译进去,执行策略的始终是同一套固定的查找与算术循环,且运行时越小,就越值得信赖。
还有一点值得一提:当决策只是重型工具之上的一层“胶水”时,成本也会随之降低。在完整的ZXing构建中,javac和JUnit承担了绝大部分工作,这也是为什么网络的耗时约为Python的1.5倍,而不是20多倍。
围绕昂贵步骤的“胶水”逻辑只需付出同样适度的代价。
不适合的应用场景:
- 追求更快的构建,或任何对毫秒级时间敏感的场景
- 单纯加大GPU投入
- 取代Maven
值得关注的场景:
- 用具有已知答案的网络测试可解释性工具
- 在学习模型旁部署精确子程序
- 拥有可哈希、可回放、可比对的决策逻辑
我们并未宣称的内容
- 这并非完整的Maven功能。它仅处理一个真实项目的单次构建(
clean package),省略了Enforcer、Checkstyle、Javadoc和源码JAR的生成。签名、部署以及仅在verify阶段运行的环节均不在其覆盖范围内。插件并非神经网络实现:javac、JUnit、bnd和zip仍以常规程序方式运行。 - 这不是机器学习。权重系从程序编译而来,而非通过学习获得。我们并未尝试训练版本,且预计这样的模型在未见过的项目上会失效。
欢迎验证我们的工作
权重、运行时环境及完整结果均已发布在Hugging Face的希尔曼/神经专家页面:方法论、全部十一项场景、内存占用、运行环境与证据哈希,以及原始测量数据、两种协议、分析代码和校验码。
凭借这些资料,你可以复现本文中的每一项数值。