news 2026/9/17 8:58:47

用 Rerun 在 Jupyter Notebook 中实时训练并可视化 2D 神经场:notebook_neural_field_2d 实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 Rerun 在 Jupyter Notebook 中实时训练并可视化 2D 神经场:notebook_neural_field_2d 实战指南

用 Rerun 在 Jupyter Notebook 中实时训练并可视化 2D 神经场:notebook_neural_field_2d 实战指南

【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun

本篇指南以 Rerun 仓库中的 notebook_neural_field_2d 示例为核心,讲解如何在 Jupyter 环境中用rerun-sdk[notebook]直接嵌入 Rerun 查看器,并驱动一个多层感知机(MLP)神经场去拟合一张 2D 图片,同时把训练损失与网络解码出的图像实时流式可视化。读完本文,你将掌握 Rerun 的 Notebook 集成安装、蓝图(Blueprint)布局编排、按迭代时间轴记录标量与图像、以及神经场训练监控的完整实战链路。

概述:Rerun 与 Notebook 生态的无缝集成

Rerun 可以直接运行在 Jupyter Notebook 内部,且不止于 Jupyter——Google Colab、VSCode Notebook 等多种交互式环境均受支持。这意味着你可以把"训练循环"和"可视化调试"放进同一个文档流里:每跑一个 cell,训练进度就实时推送到内嵌的 Rerun 查看器中。

要使用这一能力,需要单独的支撑包rerun-notebook。通常通过 Rerun SDK 的notebookextra 一条命令完成安装:

pip install "rerun-sdk[notebook]"

关于依赖关系,仓库中的 rerun_notebook/README.md 给出了更详细的解释:rerun-notebookrerun-sdkNotebook 集成的实现包,内部封装了 Rerun Viewer 编译为 Wasm 的产物(约 31MiB)以及将其绑定为 Jupyter widget 的胶水代码(re_viewer_bg.wasmwidget.js)。单独拆分这个包,是为了避免让主 SDK 的体积翻倍,同时让rerun-sdk使用 Maturin、rerun-notebook使用 hatch 各自保持简单的构建后端。

示例背景:用神经场拟合一张 2D 图片

本 Notebook 演示的是一个经典且直观的神经场(Neural Field)问题:用一个简单的神经网络去拟合一张 2D 图片。

  • 神经场本质上是一个多层感知机(MLP),可选地搭配位置编码(positional input encoding)
  • 图片被均匀采样,网络的任务是根据给定的像素坐标 (u, v) 预测该位置的 RGB 颜色;
  • 训练过程中,我们记录 loss,并周期性密集查询网络,把编码在网络权重中的"图像"重新解码出来,实时可视化训练效果。

利用 Notebook 的交互性,你可以就地尝试不同的学习率、不同的损失函数、不同的网络架构,直观地观察这些超参数对训练过程的影响——这正是本示例最有价值的实验场景。

快速开始:在 Jupyter 中运行

第一步:安装依赖

进入示例目录,安装 requirements 即可(其中已包含 Jupyter、Rerun SDK 与 Notebook 支撑包):

pip install -r requirements.txt

对应的 requirements.txt 内容如下:

ipython<=8.12 # ipython 8.13 or greater doesn't work with python 3.8 jupyter rerun-sdk[notebook] torch # Lots of reported incompatibilities across recent versions for these 3 deps. # The following seems to be the most recent recommendations for a stable experience. # See e.g. https://github.com/jupyter/notebook/issues/6721 jupyter_client<8 pyzmq<25 tornado<=6.5.5

其中有三条值得注意的版本约束:jupyter_client<8pyzmq<25tornado<=6.5.5。这是社区针对近期 Jupyter 生态依赖不兼容问题总结出的稳定组合(详见 requirements 中的注释),在复现本示例时建议保持这些上限约束,以免遇到 Jupyter 通信层(pyzmq/tornado)的已知问题。

第二步:启动 Notebook

jupyter notebook neural_field_2d.ipynb

随后在浏览器中打开生成的 Notebook 页面,从上到下依次执行 cell 即可。整个 Notebook 只有 6 个 cell,流程分为四段:导入与初始化 → 定义神经场类 → 初始化并可视化神经场 → 训练神经场。

核心实现拆解

1. 神经场网络定义

Notebook 用 PyTorch 实现了一个极简的神经场类 NeuralField,它由"位置编码(可选)+ MLP + 激活函数"三部分构成:

class NeuralField(torch.nn.Module): """Simple neural field composed of positional encoding, MLP, and activation function.""" def __init__( self, num_layers: int, dim_hidden: int, dim_in: int = 2, dim_out: int = 3, activation: str = "sigmoid", pe_sigma: float | None = None, ) -> None: super().__init__() ... sizes = [dim_in] + [dim_hidden for _ in range(num_layers - 1)] + [dim_out] self.linears = torch.nn.ModuleList() for in_size, out_size in itertools.pairwise(sizes): self.linears.append(torch.nn.Linear(in_size, out_size)) if self.pe_sigma is not None: torch.nn.init.normal_(self.linears[0].weight, 0.0, self.pe_sigma)

关键点在于pe_sigma(位置编码强度):

  • pe_sigma=None时,第一层使用relu激活;
  • pe_sigma不为None时,第一层使用sin作为激活,并以pe_sigma为标准差做正态初始化——这实际上把第一层线性层变成了一个随机傅里叶特征映射(random Fourier features)。

pe_sigma直接决定了神经场"开箱即用"的空间变化频率:值越大,场能轻松表示的细节越丰富,但场在训练区域之外的 extrapolation(外推)行为也会越剧烈。这在可视化实验里会非常直观地体现出来。

2. 初始化与蓝图布局

Notebook 创建了 4 个参数各异(pe_sigma分别为 5 / 15 / 30 / 100,其余相同:num_layers=5, dim_hidden=128)的神经场,用于对比位置编码强度的影响。

随后通过rr.init("rerun_example_cube")初始化 Rerun 记录,并使用rerun.blueprint声明式地搭建查看器布局:

blueprint = rrb.Blueprint( rrb.Vertical( rrb.Grid( rrb.Spatial2DView(name="Target", origin="target"), *[rrb.Spatial2DView(name=str(field), origin=f"field_{i}") for i, field in enumerate(fields)], ), rrb.TimeSeriesView( name="Losses", origin="/", plot_legend=rrb.Corner2D.LeftTop, ), row_shares=[0.7, 0.3], ), collapse_panels=True, )

这段布局对应仓库中 blueprint 模块的两个核心容器 containers.py(Vertical纵向容器、Grid网格容器)与两个核心视图 spatial2d_view.py、time_series_view.py:

  • 上方Grid(占 70% 高度)并排显示 1 个Target目标图 + 4 个神经场解码图;
  • 下方TimeSeriesView(占 30% 高度)显示所有 loss 曲线,图例置于左上角(Corner2D.LeftTop);
  • collapse_panels=True折叠左右面板,把屏幕空间全部留给可视化内容。

接着用rr.notebook_show(blueprint=blueprint, width=1050, height=600)把查看器内嵌到 Notebook 输出中。从 SDK 源码 recording_stream.py 可以看到,notebook_show阻塞直到内嵌 Viewer 初始化完成并准备好接收数据,此后的所有rr.log调用都会把数据实时推送到查看器,因此把它放在数据开始流动之前非常关键。

3. 把神经场解码为图像

log_field_as_image是可视化的核心辅助函数:它在 (u, v) 坐标的[min_uv, max_uv]范围内生成稠密网格点,逐点查询网络输出,重整为 RGB 图像后通过rr.log(entity_path, rr.Image(...))记录:

@torch.no_grad() def log_field_as_image(entity_path, field, min_uv, max_uv, uv_resolution) -> None: u_values = torch.linspace(min_uv[0], max_uv[0], uv_resolution[0]) v_values = torch.linspace(min_uv[1], max_uv[1], uv_resolution[1]) uv_points = torch.cartesian_prod(u_values, v_values) + 0.5 / torch.tensor(uv_resolution) predictions = field(uv_points) image_prediction = torch.clamp(predictions.reshape(uv_resolution[0], uv_resolution[1], 3), 0, 1) image_prediction = image_prediction.permute(1, 0, 2) rr.log(entity_path, rr.Image(image_prediction.numpy(force=True)))

注意两点细节:

  • 采样范围是(-0.1, -0.1)(1.1, 1.1),即在 [0,1] 单位正方形之外留了 10% 的余量,用来观察神经场在训练区域之外的外推行为;
  • 坐标点加0.5 / resolution的偏移,对应"像素中心"的语义,保证解码图像与真实采样一致。

初始时刻(rr.set_time("iteration", sequence=0))就记录一次各字段的初始图像,此时网络权重未训练,图像完全由位置编码决定。

4. 训练循环与实时日志

训练 cell 使用 Adam 优化器,默认参数为num_iterations=3000(README 与代码注释建议跑到10000以获得更好拟合)、batch_size=1000learning_rate=1e-3、每 10 次迭代记录一次图像。目标图片通过requests从 Rerun 示例数据集下载(tiger.jpg,可切换为注释中的bird.jpg),归一化到 [0,1] 后作为target实体记录。

每个 iteration 的核心逻辑:

target_uvs = torch.rand(batch_size, 2) # 均匀采样像素坐标 target_jis = (target_uvs * torch.tensor([target_image.shape[1], target_image.shape[0]])).int() target_rgbs = target_image[target_jis[:, 1], target_jis[:, 0]] # 采样目标颜色 for field_id in field_ids: field = fields[field_id] total_iterations[field_id] += 1 predicted_rgbs = field(target_uvs) loss = torch.nn.functional.mse_loss(target_rgbs, predicted_rgbs) rr.set_time("iteration", sequence=total_iterations[field_id]) rr.log(f"loss/field_{field_id}", rr.Scalars(loss.item())) loss.backward() optimizer.step() if iteration % log_image_period == 0: for field_id in field_ids: log_field_as_image(f"field_{field_id}", fields[field_id], (-0.1, -0.1), (1.1, 1.1), (100, 100))

这里体现了 Rerun 时序数据模型的正确用法:

  • rr.set_time("iteration", sequence=...)设置自定义时间轴(timeline),后续 log 都挂在该时间戳上;
  • loss 用rr.Scalars记录到loss/field_i实体,配合初始化时rr.log(..., rr.SeriesLines(names=..., aggregation_policy=...), static=True)注册的序列样式(使用Average 聚合策略),多条 loss 曲线在同一张时序图中可读性极佳;
  • 图像按log_image_period=10的周期更新,形成"每 10 步刷新一帧解码图"的训练动画;
  • 整个循环包裹在try/except KeyboardInterrupt中,中途中断也能保留已记录的数据;重复运行该 cell 会从上次状态继续训练total_iterations累加),想要重置则重新运行上一个 cell。

深入原理:Notebook 集成在底层是如何工作的

rr.notebook_show并不是简单地把图片贴进 Notebook。从 SDK 的 notebook 实现(如 recording_stream.py 与 _legacy_notebook.py)可以看到两条技术路径:

  1. 现代路径(默认):基于anywidget机制的 Jupyter widget。查看器(Wasm 编译产物)作为 widget 资源注入单元格,Rerun SDK 通过 Jupyter comms 通道把日志数据持续推送给内嵌 viewer。notebook_show会阻塞到 viewer 就绪,之后所有 log 调用即时送达。

  2. Legacy 路径legacy_notebook_show/as_html将当前录制数据整体编码为 base64 的.rrd,嵌入一个 HTML 模板,再放进 iframe 加载https://app.rerun.io(默认地址,可用app_url覆盖;若调用过rr.start_web_viewer_server()则指向 localhost)。该方式对 anywidget 支持不完善的环境更友好,但每次展示都会做一次阻塞式 flush。

对于资产(Wasm/JS)的加载方式,rerun-notebook支持通过环境变量RERUN_NOTEBOOK_ASSET控制,需在import rerun_notebook之前设置:

  • RERUN_NOTEBOOK_ASSET=inline:将资产内联后通过 comms 直接传输,最可移植,但已知在 Google Colab 等环境存在内存泄漏与性能问题;
  • RERUN_NOTEBOOK_ASSET=serve-local:在内核生命周期内于本地启动线程提供资产,Wasm 可流式编译,启动更快且可被浏览器缓存,适合本地 Jupyter;
  • RERUN_NOTEBOOK_ASSET=https://your-hosted-asset-url.com/widget.js:从自托管 URL 加载,需同时提供相邻路径的re_viewer_bg.wasm,并配置好 CORS。

实验建议:把 Notebook 当作训练调参台

README 明确指出本示例的核心价值在于交互式实验。建议你按以下思路改造训练 cell,观察不同超参数对收敛行为的影响:

  • 位置编码强度:对比pe_sigma在 5、15、30、100 下的表现——过小则网络难以表达高频细节(图像模糊),过大则训练初期抖动剧烈、外推区域出现强烈的纹波;
  • 学习率:把learning_rate1e-3调大或调小一两个数量级,观察 loss 曲线的收敛速度与震荡;
  • 网络容量:修改num_layersdim_hidden,感受表达能力与拟合速度的权衡;
  • 训练轮数num_iterations从 3000 提到 10000,让图像细节持续逼近原图;
  • 损失函数:将mse_loss换成其他损失,观察视觉质量差异。

得益于rr.Scalars+TimeSeriesView的实时联动,你无需等待训练结束即可判断当前配置是否有效;KeyboardInterrupt随时可以中断并保留已记录的所有中间帧。

小结

notebook_neural_field_2d 是一个把"训练 + 可视化 + 交互调参"压缩进单个 Notebook 的典型范例:它同时演示了 Rerun Notebook 集成的安装与运行、Blueprint 声明式布局、自定义时间轴上的标量/图像日志,以及神经场的原理与超参数影响。掌握这一模式后,你可以把它推广到任何"循环内可视化"的深度学习工作流——实时监控 loss、权重、梯度乃至任意中间表征,让调试回归直觉。

相关文件索引:

  • 示例说明:README.md
  • Notebook 本体:neural_field_2d.ipynb
  • 依赖清单:requirements.txt
  • Notebook 集成实现包说明:rerun_notebook/README.md
  • notebook_show源码:recording_stream.py
  • Legacy HTML 渲染实现:_legacy_notebook.py
  • 蓝图容器与视图:containers.py、spatial2d_view.py、time_series_view.py

【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 8:55:31

C#实现ChatGPT集成:MCP应用开发实战

1. 项目概述&#xff1a;构建基于C#的MCP/ChatGPT应用最近在技术社区看到不少开发者讨论如何将ChatGPT这类大语言模型整合到自己的应用中。作为一个长期使用C#进行企业级开发的工程师&#xff0c;我花了三周时间完整走通了从接口对接、功能封装到应用集成的全流程。本文将分享如…

作者头像 李华
网站建设 2026/9/17 8:53:59

CAN协议族演进:从经典CAN到CAN XL的技术演进与选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 8:53:29

NETX90通信SoC如何用一颗芯片解决工业IO模块多协议难题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 8:49:36

OpenMontage:命令行视频批处理与自动化拼接实战指南

很多人第一次听说OpenMontage这个名字的时候&#xff0c;第一反应都是问&#xff1a;这到底是个什么工具&#xff1f;你要是去翻它官方的技术文档&#xff0c;里面全是API、节点、渲染队列这些词&#xff0c;容易把人劝退。但如果你真的花半小时把它跑起来&#xff0c;你会发现…

作者头像 李华