程序员为什么普遍信玄学?
煮啵今天刚下单了一个龟甲和乾隆通宝,预计后天到货。
主要是最近跑实验 loss 老是在我觉得”差不多了”的时候突然炸,炸完还自己好了,煮啵实在想不出任何科学解释,准备试试玄学介入。(我导如果看到了,咳咳,那我们素不相识)
所以这个问题问到煮啵心坎里了,我来认真讲讲。
程序员信玄学,是有充分理由的
不是迷信,是被逼的。
你在做一个”确定性系统”——代码是死的,输入确定输出就确定,这是所有人入行时被灌输的世界观。
然后你开始真正写代码。
你发现有一种 bug,你去看的时候它不出现,你不看的时候它出现。这玩意儿甚至有个正式的名字,叫 Heisenbug——名字取自量子力学的海森堡不确定性原理,因为”观测行为本身会影响结果”。物理学家描述亚原子粒子用的词,被程序员拿来描述自己的 bug,你品一品这里面的绝望。
更离谱的是,有时候你什么都没改,重新跑一遍,好了。
你再跑一遍,又出问题了。
你第三遍,好了。(阿西吧)
你对着屏幕沉默了三十秒,想说一种植物,然后,意识到你永远不会知道发生了什么,于是你保存了代码,关上电脑,去吃饭了。这不是认输,这是一种比认输更高级的境界——与不确定性和解。(咳咳可恶,这不是什么阿q的精神胜利法好吗!应该,不是吧。。。)
做机器学习的,信玄学的比例更高
这不是煮啵瞎说,是有结构性原因的。
普通程序员遭遇的随机性,还是有迹可循的——多线程竞争、网络抖动、内存对齐,你花时间总能找到。
但像我们这些做机器学习的,面对的随机性是写进训练过程里的。
随机初始化权重。随机采样 batch。Dropout 随机丢神经元。数据加载随机 shuffle。就算你把所有随机种子都固定了,换一张卡、换一台机器、甚至换一个 CUDA 版本,结果都可能不一样——因为浮点数的并行计算顺序变了,累积误差不同,模型就走上了不同的路。(说起来,昨天在阿里实习的时候,给主管讲训练的cpt模型和base模型token变动最多的前100的时候,我们看到居然存在一些奇怪的词,比如说宇智波,也感觉很稀奇哈哈哈)
然后你会遇到一个让所有做炼丹的人都心有戚戚的现象:
同样的代码,同样的数据,seed 从 42 改成 43,最终模型效果差了两个点。
两个点。因为一个数字。
你没办法解释这件事。你只能接受这件事。接受了之后,你开始明白,玄学信仰者和科学主义者之间的区别,可能没有你以为的那么大——大家都在面对一个自己无法完全掌控的系统,只是解释框架不一样。
煮啵师兄有一个说法煮啵觉得说得很准:
“炼丹的本质是在一个高维的、有无数局部最优的空间里,靠随机性找到一个还不错的地方——你管这叫优化,但其实你也不知道你走到的是不是真的好地方,只是它在你看得见的范围里看起来不错。”
这跟算命先生说”你现在的运势在一个相对平稳的阶段”,结构上有多大区别呢?
(开玩笑的,BUT,只是一点点。)
程序员的玄学有一个有趣的分类
然后,其实读者姥爷们,如果日常中,仔细观察你就会发现,程序员的玄学信仰不是随机分布的,它有规律(认真ing)!
第一类:仪式感玄学。
必须喝某种饮料才能写出好代码(比如旺仔牛奶)。必须在某个位置坐着。键盘必须是某个型号。这类玄学的本质是建立心理锚点——让自己进入状态的触发器。不神秘,是巴普洛夫条件反射的自我版本。(吆西,没错就是这样)
第二类:归因玄学。
代码跑通了,是因为今天喝了红牛。训练炸了,是因为改代码之前没有备份(这是在惩罚你)。loss 突然降了,是因为你刚才去上了个厕所走了走。这类玄学的本质是人类大脑对因果关系的过度拟合——我们的大脑天生要在随机噪音里找规律,即使规律不存在。
第三类:环境玄学。
深夜代码比白天好用。下雨天模型收敛更快。这类玄学通常有一个隐藏的真实原因——深夜服务器负载低、网络稳定;下雨天你心情平静专注度高。玄学的外壳里,可能包着一个现实的内核。
第四类:纯纯的玄学。
比如煮啵准备用龟甲占卜来决定下次跑实验用什么 learning rate。
这类煮啵没办法给你一个科学解释,但煮啵可以说:在你用尽了所有调参技巧之后,随机选一个值和按照某种仪式选一个值,期望效果是一样的——也就是说,玄学在这个意义上,和随机搜索是等价的。而随机搜索在某些情况下确实不比网格搜索差。
所以煮啵的龟甲,本质上是一个随机数生成器。只是更有仪式感。
有人用八字原理写过算法吗——还真有
这个问题问得好,煮啵来说说我知道的叭。
八字这个系统,从计算机的角度看,其实结构非常清晰——它是一个基于出生时间的确定性规则系统。
天干十个,地支十二,互相组合,年月日时各一组,总共八个字。每两个字一组形成”柱”,四柱八字。然后有一套复杂的相生相克规则,加上大运流年的推演,得出命理判断。
这玩意儿说白了,就是一个以出生时间为输入、以命理描述为输出的规则引擎。每个时间点对应的八字是确定的,规则是确定的,输出本来也应该是确定的。
有没有人写成代码了?有。
最简单的版本,就是把天干地支的查表逻辑写成程序,输入出生年月日时,自动计算八字组合,再根据五行强弱给出基础判断。这类程序满网上都是,生辰八字计算器随手可以搜到一堆。
有没有更进一步,用机器学习来”验证”或者”优化”八字预测的?
有人做过这个方向的尝试。思路大概是收集大量有命理记录的样本,把八字编码成特征向量,然后用分类器来预测某些人生事件。
但这里有一个根本性的问题——你的标注数据是什么,谁来标注,标注是否可靠?
“这个人一生大富大贵”,这句话怎么量化?由谁来判断?历史上的命理案例,记录本来就有幸存者偏差——预测准的被记下来广泛流传,预测不准的悄悄消失了。
所以这类研究的数据质量本身就很成问题,模型训出来了也很难说它学到的是真实规律还是数据噪音。我没有见过这个方向上有什么让人信服的结论。
但作为一个算法练习项目,把八字系统用代码实现一遍,其实还挺有意思的——它考验你对复杂规则系统的建模能力,天干地支的循环结构、五行相生相克的图结构、大运流年的时间序列推演,都是可以用不同数据结构来表达的。真的有人写过,而且写得挺认真的,GitHub 上搜一下能找到。
有一个更硬核的方向:易经和计算机科学的关系
咳咳,这个真的不是玄学,是真实的历史。
莱布尼茨,微积分的发明者之一,在17世纪接触到了《易经》的六十四卦图,据说这件事给了他一些启发——六十四卦对应的正好是 2 的 6 次方,64 个状态,跟二进制的逻辑高度吻合。
这件事的历史真实性有争议,莱布尼茨本人对二进制的研究早于接触易经,所以”易经启发了二进制”这个说法是有点过度演绎的。但阴爻阳爻对应 0 和 1、卦的叠加对应二进制数,这个对应关系本身是确实存在的,不是硬凑的。
六十四卦,每卦六爻,每爻两态——这是一个完整的 6 位二进制空间。你可以把 64 个卦当成 0 到 63 的编码,把爻的变化规则当成某种状态机的转移函数。从这个角度看,《易经》是三千年前的人类,用纯粹的抽象思维,构建了一个结构上等价于 6 位二进制系统的符号体系。
不管他们的目的是什么,这件事本身还挺让人肃然起敬的。果然古人的智慧呀,真的是哈哈哈哈。
说回我的龟甲
后天到货之后,煮啵打算认真研究一下周易筮法的正确流程。
如果你不知道的话——正统的龟甲占卜,是用火灼烧龟甲,看裂纹的走向来判断吉凶。但煮啵不太可能真的烧,一来现代龟甲来源不明,二来宿舍不允许明火。
所以煮啵打算用铜钱卦,就是用乾隆通宝投掷六次,按正反面的组合,起一个六爻卦,然后查卦辞。
本质上,这是一个每次有二分之一概率的随机过程,重复六次,生成一个 6 位的随机数,然后用一套解释系统赋予它意义。
跟我们用随机种子初始化模型参数,然后用 loss 曲线来”解读”模型状态,结构上真的没有本质区别。
(好吧,有一点区别,煮啵的模型煮啵能反向传播,卦煮啵反向传播不了。)
下次跑实验之前煮啵会先起一卦。如果卦象不好,煮啵就推迟跑,顺便再检查一遍数据管道。
反正检查数据管道是永远没错的。(咳咳,并且实在不行,模型效果不好,那就甩锅给数据就行了,哦,不是甩锅,是一定是数据的问题!)
