大多数"夺旗"风格的ML谜题给你一个黑盒神经网络,你的工作是弄清楚它在做什么。当Jane Street考虑创建自己的ML谜题时,他们想做点不一样的事情。
他们认为,给用户一个神经网络的完整规格——包括所有权重——会很有趣。然后用户将被迫使用机械可解释性的工具来逆向工程这个网络。这正是我们在自己的研究中有时面临的情况,当试图解释复杂模型的特征时。
谜题:来自新石器时代墓葬堆的神经网络
谜题描述如下:
今天我去徒步旅行,在新石器时代的墓葬堆下发现了一堆张量!我把它送到了当地的神经网络管道工那里,他们设法拼凑出了这个。
总之,我还不知道它是做什么的,但它对这个过去的文明一定很重要。也许先从最后两层开始看。
模型输入:vegetable dog
模型输出:0
如果你弄清楚了,请告诉我们。
那个model.pt文件基本上只是一个pickle化的PyTorch模型。
一个真实的解决过程
第一步:异常的网络结构
一位名叫Alex的大学生开始研究这个谜题。他下载了模型并四处查看,特别关注最后一层:
import torch
import plotly.express as px
model = torch.load('./model.pt')
linears = [x for x in model if isinstance(x, torch.nn.Linear)]
px.imshow(linears[-1].weight.detach())
立即清楚这不是一个普通的神经网络。它显然没有被训练过:所有权重都是整数值。相反,它是手工设计的,可能用于执行一些非常特定的计算。
最后一层是一个48x1矩阵,但显然分为三个部分。确实,如果你查看前一层的激活,它们总是三个相同事物的重复。倒数第二层似乎是三个相同的权重重复,而其偏置包含相同的16个字节,但每次递增1,就像编码一个向量v,然后v+1,然后v+2。
第二步:理解比较机制
经过思考,Alex意识到这个倒数第二层的ReLU层必须是在计算两个16字节整数是否彼此相等(每个神经元一个字节)。它的工作方式似乎是制作输入向量v的三个副本(一个16字节的数字)。它试图将其与一个参考数字x进行比较(由倒数第二层的偏置决定)。所以这三个副本实际上代表v-x-1、v-x和v-x+1。最后一层对这些情况分别应用权重1、-2和1。
最后一层的偏置是-15,所以只有当所有16个字节的v=x时,最终的神经元才会激活。
第三步:线性规划的失败尝试
Alex想:如果网络在最后检查某个数字,那么网络的其余部分必须是某种大方程。网络确实有很多结构。
所以Alex开始将这个东西视为线性规划问题并解决它。当然,由于这么多ReLU层,这是不可能的——ReLU不是线性的——但可以通过添加一个额外的整数值来建模,对应于"这个激活是负的"的陈述。你可以将其视为整数线性规划,并使用能够处理整数规划的约束求解器。
但经过多次尝试,这似乎毫无进展。
第四步:网络简化
Alex现在尝试减少程序中的变量数量。也许有一些简化可以做?Alex发现,如果你看一堆层,它们大多看起来像单位矩阵。事实上,在1500层左右,80%的节点只是执行恒等操作。
Alex将网络中的每个神经元视为DAG中的一个节点,每个节点以某些权重进入下一层的节点;但如果你有一个入度为1且权重恰好为1的节点,你可以合并这两个节点。(你知道这样做是安全的,因为网络中的所有值都是整数:所有输入都是整数,所有权重也是整数。)
还有更复杂的简化。例如,如果一个节点的每个传入边都有正权重,那么你正在做ReLU这一事实并不重要,因为它永远不会达到负钳位——所以你可以将其传入边转发给其子节点,直接将其传递到下一层。
Alex现在已经投入了数小时进行分析。他发现似乎在许多层中重复出现的电路。他会打印出不同等价类的节点,查看每个节点作为输入的权重序列,发现只有几种节点。
第五步:转向SAT求解器
一个新想法:如果你通过网络传播边界呢?仅仅通过逐层推理,你可以找出任何给定节点可以达到的最大值;你只需查看其输入的边界。事实证明,在相当保守的假设下,许多节点最终具有非常严格的边界,例如0-1。
此时,Alex从线性规划转向SAT求解器,因为值的总数已经变得小得多。在SAT版本中,每个节点等于其范围内的每个值都有一个布尔变量。经过所有简化后,这总共导致20万个变量。运行一天后,SAT求解器将程序减少到2万个变量。从那里似乎不再进一步减少。
第六步:关键的洞察
他思考元问题:这必须是一个可解的谜题,对吧?有人会如何构建一个像这样有趣的谜题?如果你生成随机权重,SAT求解器可能能够通过暴力破解它。这个网络是由人类创建的。在其核心似乎有一个函数,你不能仅仅使用搜索或优化来恢复。它是一个不可逆函数。有哪些不可逆函数的典型例子?
Alex向ChatGPT询问了一些常见的哈希函数,并将其与层宽度的基本图进行比较,这些图看起来是周期性的。事实上,有32个长度为48的周期,每次完全重复。也许网络在做32个相同的计算块?再次问ChatGPT:有没有常见的哈希函数使用32个计算块?宾果。事实证明,它们几乎都这样做。
为了确定是哪一个,他手动探索:他会将某个字符串输入网络,用单独的程序计算各种哈希风格,然后查看倒数第二层。结果发现md5匹配,而其他常见的哈希函数不匹配。
第七步:意外的错误
Alex注意到网络中有些奇怪。它似乎有一个错误:如果你的输入长度大于32,它就不再产生正确的md5哈希。也许在那个错误中有关键可以反转构建在网络中的哈希值?
他花了接下来的两天时间逆向工程这个错误。首先,他让Gemini编写md5哈希函数的实现。然后他将网络中的每个神经元与md5算法中的相应变量匹配。他编写了一些代码来存储给定中间变量的值序列,然后在网络的32个块中搜索该值;这将挑选出哪些神经元范围对应于每个变量的位。结果发现,某些位范围完全对应于变量,而其他范围是中间计算值。
然后,对于长度>32的输入,他可以费力地跟踪块,找到网络与正确算法分道扬镳的确切位置。
关键在前7层——有一个电路会计算输入的长度,并尝试将其存储在4个字节中,按小端顺序。但当长度大于等于256位时,你会有一个包含值256的长度变量,而不是正确的编码。
第八步:最终的解决方案
事实证明,一旦你知道编码在倒数第二层偏置中的哈希,你就完成了。弄清楚这一点是谜题的核心。谜题创建者有意使哈希易于暴力破解,在谜题描述和Python代码中留下了各种小提示,表明解决方案由两个英文单词组成,小写,由空格连接。
Alex实际上早些时候尝试过暴力破解哈希,但他下载了前10,000个最流行的单词列表来做,结果发现不够大,找不到它。一旦他有了足够大的单词列表,他就得到了答案。
更深层的意义
1. AI解释性的现实挑战
这个谜题展示了机械可解释性的实际困难。即使有了完整的网络权重,理解它在计算什么也可能非常困难。这反映了现实世界中解释复杂AI模型的挑战。
2. 神经网络作为计算设备
这个网络不是通过训练学习的,而是手工设计的来计算md5哈希。这表明神经网络可以作为通用计算设备,而不仅仅是模式识别器。
3. 密码学与AI的交集
将md5实现为神经网络提出了有趣的问题:神经网络能否成为密码分析的新工具?或者,神经网络能否被设计来执行传统上需要专门硬件的加密操作?
4. 教育价值
这样的谜题是教授AI解释性的绝佳方式。它们迫使解决者深入思考神经网络实际上在计算什么,而不是仅仅将其视为黑盒。
5. 招聘工具
Jane Street使用这样的谜题作为招聘工具并非偶然。解决它需要结合机器学习知识、密码学技能、算法思维和顽强的毅力——这些都是量化金融中宝贵的特质。
结语:理解我们创造的机器
这个谜题最终不仅仅是关于逆向工程神经网络。它是关于我们与创造的技术的关系。
当我们构建越来越复杂的AI系统时,我们面临一个根本问题:我们真的理解它们在做什么吗?或者它们对我们来说就像新石器时代的文物一样神秘?
Jane Street的谜题提醒我们,真正的理解需要深入探究,而不仅仅是表面观察。它需要耐心、创造力和愿意尝试多种方法。
在AI快速发展的时代,这样的练习变得越来越重要。随着系统变得更加复杂,确保我们能够解释和理解它们变得至关重要——不仅是为了调试和安全,也是为了信任和责任。
毕竟,如果我们不能理解我们创造的机器,我们怎么能相信它们呢?