在 B 站观看:神经网络动画演示 | Dive into deeplearning
我做了一部 11 分钟的神经网络动画,叫 Neural Choreography。内容跟着《动手学深度学习》走,从线性回归、卷积、循环网络,一直做到注意力机制、优化器和词向量,一共挑了 49 个片段。
我想做的是一部可以从头看到尾的片子。哪怕完全不懂模型,光看屏幕上的点怎么聚在一起、连线怎么抽拉展开、几何体怎么形变,也能看下去。

观看或下载完整配乐版(正片 11 分 21 秒,上传版另加了 12 秒署名)
项目刚建的时候名字叫 points-still-moving,也就是“点还在动”。后面改叫 Neural Choreography,因为我觉得“编舞”更接近我后来想干的事:用同一批点和线,放进不同的网络结构,让它们换个方式动起来。
但前面的版本离这个目标差得很远。每节确实都把数据老老实实算出来了,单看也行,连着看就特别催眠。换个标题、换个颜色,小球走来走去还是那几条路线。文字占了大半个屏幕,画面本身其实没说明白什么。
代码大部分是扔给 Codex 写的,我主要负责看预览、提要求、反复打回去重做。反馈记录里出现最多的就是“丑”、“无聊”、“看不出来”。有一次看完 RNN 的预览,我直接跟它说:你这就是把算出来的数值戳在坐标轴上。隐藏状态有了坐标,也画出了轨迹,但我还是看不出它怎么把前面的信息接过来,又怎么被后面的输入改掉。
我一直在照着 3Blue1Brown 的画面找感觉。除了黑底、细线和克制的颜色,最关键的是对象变换的过程——眼睛能一直盯住一个东西,看着它去哪儿、变成什么。后来哪怕给图加了立体投影,只要这个变换关系看不清,就还是得推倒继续改。
后面我学乖了,要求提得越来越具体。
比如 ResNet,必须能明显看出一根线绕过中间的变换、直接插回主路;DenseNet 则要把前面每一层的输出都留着,后面的层要一根根接过去。这两段看完,得让人记住它们在拓扑上的区别。

GRU 和 LSTM 返工的次数也多。早期版本就是几股流线乱飘,不看标题根本分不出谁是谁。改了好几轮,才把保留、更新、门控拆到不同的路径上,LSTM 那条长长的记忆通道才算露出来。深度 RNN 要看出层跟层往上递,双向 RNN 要看出两头对着走。屏幕上既然打了这些名字,画面里就必须有对应的结构。

文字也是在这几轮里越删越少。最后只留了中文主题、章节号,加一句短提示。看预览的时候,我习惯先盯着动画看,最后才看那行字。如果动画没看懂,必须靠读那行字才能反应过来,那画面就还得改。
怎么把这 49 段顺畅地接起来,也卡了我很久。
一段一段拆开看还过得去,拼在一起就很别扭。比如 ResNet 接 DenseNet 那里,之前的版本是上一段刚停,下一段就换了全套场景,像在翻 PPT。后来的办法是尽量留住上一段的一点东西——可能是一个残存的形状、一种颜色,或者一点运动的惯性,让下一段顺着这个由头继续长出来。片子结尾也是这样,又收回到了开头的粒子环上。
这么一来,改动成本就很高。一个局部动画做得再好看,只要接不上前后,就得调速度、挪位置,甚至整段删了重做。
底层动画是用 Zanim 写的。中间有一阵子我也怀疑过,是不是这工具限制了发挥,想过要不要换方案。最后还是忍住了,已经攒了这么多片段,无论如何先把这一版剪成一个完整的视频,别陷进工具折腾里。
配乐也折腾了一圈。先试了一段原创配乐,觉得不好听;又换成夜曲风的钢琴独奏,强行拉长到 11 分钟,中间还特意改了调性和编排,听下来还是不对劲。
最后索性用了现成的三首古典钢琴录音:
- 贝多芬《悲怆奏鸣曲》第二乐章
- 柴可夫斯基《感伤圆舞曲》(剪掉了重复的一段)
- 萨蒂《裸体舞曲》第 1 首
曲子没做变速,中间留了一点气口,最后用萨蒂收尾。录音演奏者是 Paul Pitman、Luis Kolodin 和 Kevin MacLeod,来源跟许可我放在仓库的制作记录里了,视频片尾也有署名。
现在导出的版本是 1080p、60 帧。片子肯定还有很多能挑刺的地方,里面有严谨的计算,也有不少为了方便看而硬凑的投影、粒子动效和转场。哪些是真算出来的,哪些是人为编排的,源码和记录里都写了。
先放出来这一版。成片和代码都在下面,感兴趣的可以直接去翻:
作品仓库:Neural Choreography
动画引擎:Zanim



Reader notes · archived
公开留言存档 · 截至 2026-10-19。当前站点不接收新留言。
siddhartha-yz ·
测试。