09 / 12 · Connect a learned model连接训练模型
Trace one learned number all the way to a pixel追踪一个学到的参数,直到最终像素
Connect capture, optimization, export and runtime without confusing a viewer with a trainer.连接采集、优化、导出与运行时,分清 viewer 和训练器的职责。
The viewer is the last half of an inverse-rendering loop. To build it correctly, follow one number—such as opacity logit—from an optimizer update into a file, through activation, and finally into blending.Viewer 位于逆渲染闭环的后半段。要正确构建它,可以追踪一个数字,例如不透明度 logit:从优化器更新,到文件、激活,再到混合。
1. Observations define the problem1. 观测定义了训练问题
Capture supplies images, camera intrinsics, camera poses and timestamps. Split training observations from held-out evaluation views/times. Check units and camera conventions before optimizing: wrong poses can look like a model that refuses to learn. Resizing an image also requires scaling focal lengths and principal point coordinates.采集提供图像、相机内参、相机姿态与时间戳。将训练观测与留出的评估视角、时间分开。优化前检查单位及相机约定;错误姿态可能看起来像模型学不动。缩放图像时,也要缩放焦距和主点坐标。
2. Differentiate a predicted image2. 对预测图像求导
Initialize model parameters. Render the sampled camera/time, compare predicted pixels with target pixels, differentiate the chosen loss and update parameters. Repeat with a defined sampling schedule. A differentiable training rasterizer needs gradients through projection, appearance and composition; this real-time Rust viewer implements forward rendering only.初始化模型参数,渲染采样的相机与时间,比较预测像素和目标像素,对选定损失求导并更新参数,按明确的采样方式重复。可微训练光栅器需要投影、外观及合成的梯度;当前 Rust 实时 viewer 只实现前向渲染。
The existing training laboratory actually updates three parameters of one Gaussian against fixed targets. Use it to watch loss, gradient and candidate update separately. It is a small synthetic learning problem, not full-scene training; the included Python toy trainer provides a separate PyTorch/Adam path.已有训练实验会针对固定目标,真实更新一个 Gaussian 的三个参数。用它分别观察损失、梯度和候选更新。这是小型合成训练问题,不是完整场景训练;附带 Python 教学训练器另有 PyTorch/Adam 路径。
3. Export the meaning of the learned values3. 导出学到的数值及其含义
For one opacity logit β, the trainer updates β, the exporter writes β, the decoder reads β, and the shader computes sigmoid(β). Exporting sigmoid(β) into a field the viewer activates again changes the model. Apply the same audit to log-scales, quaternion order, motion time units and SH coefficient ordering.对不透明度 logit β,训练器更新 β,导出器写 β,解码器读 β,shader 再求 sigmoid(β)。若导出时已经写成 sigmoid(β),viewer 又激活一次,就改变了模型。对对数尺度、四元数顺序、运动时间单位和 SH 系数顺序,也要做同样核对。
A training checkpoint may contain optimizer moments and neural network weights. A runtime package contains whatever its forward path needs. A deformation-based 4DGS model can require a deformation network; a native 4D Gaussian requires conditioning its joint spacetime distribution. Renaming either file to STG-Lite cannot make our polynomial decoder correct.训练 checkpoint 可能带优化器动量及神经网络权重,运行包则包含前向路径需要的东西。基于形变的 4DGS 可能需要形变网络,原生 4D Gaussian 需要对联合时空分布做条件化。把文件改名为 STG-Lite,不能让多项式解码器正确处理它们。
4. Validate the bridge at three levels4. 分三个层级验证连接
First compare decoded scalar values with the trainer’s export. Next compare a few projected centers and covariance matrices under a known camera. Finally compare the rendered image at that camera and timestamp. A beautiful orbiting preview can hide an activation or coordinate mismatch that a small numeric check immediately reveals.先把解码后的标量与训练器导出值比较,再在已知相机下比较几个投影中心与协方差,最后比较该相机、该时间的图像。漂亮的绕转预览可能掩盖激活或坐标错误,而一个很小的数值检查就能发现。
RUN → OBSERVE运行 → 观察
Make this step concrete把这一步运行起来
You can point to the exact same raw opacity value in the training record, exported bytes and runtime decode, then explain its effect on a pixel.能在训练记录、导出字节及运行时解码里指出同一个原始不透明度值,并解释它如何影响像素。
Open GPU milestone 7 →打开 GPU 里程碑 7 →npm run qa:math
# Open /math/#training-lab for the step-by-step optimizer.
# Open /learn/12-build-and-explain/ for the Python training/export capstone.Commands use the reference repository. Rust/WGSL changes need a native rebuild or npm run build:wasm, followed by a browser reload.命令以参考仓库为基础。修改 Rust/WGSL 后需重新编译桌面程序,或运行 npm run build:wasm 后刷新浏览器。
IDEA → IMPLEMENTATION想法 → 实现
Follow the running code沿着真实代码看
Excerpts are extracted from the repository at site build time. Expand only the part you are studying; full files include context and line numbers.片段在网站构建时直接从仓库提取。只展开正在研究的部分,完整文件包含上下文与行号。
src/workshop.wgsl · L72–79
The runtime end of the bridge: activated opacity becomes a pixel contribution.连接的运行时末端:激活后的不透明度成为像素贡献。
@fragment fn fs_main(input: Out) -> @location(0) vec4<f32> {
let stage = u32(globals.viewport_stage.z);
if stage <= 2u { return vec4(input.rgba.rgb, 1.0); }
let weight = exp(-0.5 * dot(input.local, input.local));
let alpha = min(0.99, input.rgba.a * weight);
if alpha < 1.0 / 255.0 { discard; }
return vec4(input.rgba.rgb * alpha, alpha);
}Open full source with line numbers ↗打开带行号的完整源码 ↗Real-model render pass ↗真实模型渲染 pass ↗ · Real-model shader ↗真实模型 shader ↗
Predict it, change it, explain it先预测,再修改,再解释
A raw opacity logit is 0. What runtime opacity should the viewer use? What if an exporter writes 0.5 into that raw field?原始不透明度 logit 为 0 时,运行时应使用多少不透明度?如果导出器把 0.5 写进原始字段会怎样?
Check your reasoning核对推理
sigmoid(0) = 0.5. If the raw field instead contains 0.5, the viewer computes sigmoid(0.5) ≈ 0.6225. This is a contract error, not a blending bug.sigmoid(0) = 0.5;若原始字段写成 0.5,viewer 会算出 sigmoid(0.5) ≈ 0.6225。这是数据约定错误,不是混合错误。
Keep the theory beside the code把原理放在代码旁边
Open the related derivation or lab ↗打开对应推导或实验 ↗
3D Gaussian Splatting · original research ↗