损失曲线记录训练误差随迭代的变化。损失地形(loss landscape)进一步展示参数位置与损失之间的关系,让我们观察优化轨迹如何穿过平坦区域、沿谷地移动。
本文使用一个只有 31 个参数的小型神经网络拟合一维函数。你可以调整目标函数、学习率和随机种子,观察训练曲线与轨迹的变化,再通过二维和三维视图探索轨迹周围的损失结构。地形可视化采用局部平面融合方法,参考 Ziming Liu 的 Seeing sticky plateau。
训练与地形计算均在浏览器中运行,由 quarto-marimo 和 Pyodide 提供 Python 环境。首次打开需要联网加载运行时和依赖,请等待加载完成再提交参数。如果出现 Failed to load marimo runtime 或 RPC request timed out,可稍后刷新。初始图表是构建时生成的静态结果;提交参数后结果更新,表示运行时已就绪。
1. 训练一个小型神经网络
网络结构为 [1, 10, 1],隐藏层使用 SiLU 激活函数,包含 31 个可训练参数。输入为从 \([-1, 1]\) 均匀采样的 1,000 个点,标签由所选目标函数生成。Adam 优化器最小化这些样本上的均方误差(MSE):
\[ L(\theta) = \frac{1}{N}\sum_{i=1}^{N}\left(f_\theta(x_i)-y_i\right)^2. \]
改变目标函数或学习率,点击 训练 / Train 应用参数。表单只在提交时触发重新训练;首次加载使用默认配置。
2. 从参数轨迹构建损失地形
先将 31 维参数轨迹投影到前两个 PCA 方向,再沿训练轨迹取局部平面,计算真实网络损失并做高斯加权融合。修改下面的参数并点击 计算地形,只重算地形,复用上面的训练结果。
默认采用 24 × 24 网格、每 20 步取一个局部平面。网格精度增加时计算量显著增长,建议从默认值开始。k 必须满足 2k ≤ 训练步数。
3. 观察训练轨迹
桌面上左图是真实训练 MSE,右图是局部平面融合后的 loss 地形;手机窄屏下改为上下排列。使用 Play / Pause / Reset 或时间条查看训练轨迹,切换 3D surface 后可以拖动旋转。播放和切换视图仅更新 JavaScript 图表,不重新运行 Python。
可以先保持随机种子不变,对比不同学习率下的损失下降速度和轨迹形状;再改变随机种子,观察初始化与采样变化带来的影响。单独调整地形网格精度或高斯宽度,可以比较可视化的细节与平滑程度,训练轨迹本身保持不变。
3D 视图需要浏览器支持 WebGL。较高的网格精度会增加计算量,移动设备建议从默认配置开始。
4. 如何理解这张地形图
网络参数空间有 31 维,图中的两个水平坐标对应训练轨迹的前两个 PCA 方向。页面报告的解释方差表示这两个方向保留了多少轨迹变化信息;它无法衡量损失地形的还原精度。
地形由沿轨迹采样的局部平面融合而成。高斯宽度控制各局部平面的影响范围,网格精度控制采样密度,loss 截断值限制局部损失的显示幅度。这些设置会改变地形外观,比较不同训练配置时应一并留意。
损失曲线下降缓慢时,可以结合时间条观察对应的轨迹区段,查看它在投影视图中的移动情况。平坦区域与训练停滞之间的关系仍需结合真实 MSE 判断。
解释边界
右图的高度是经过截断和融合的局部 loss,与真实轨迹的 MSE 通常不同。3D 小球的高度使用融合网格插值并增加显示偏移。PCA 投影、局部平面和平滑都可能隐藏结构,因此这张图不能证明优化器的稳定性或收敛性,也不保证所有配置都出现 sticky plateau。