☰
wandb入门指南:从TensorBoard迁移到实验跟踪看板的完整实践
2026/10/1 21:49:12 网站建设 项目流程

1. wandb是什么,以及为什么我建议你从TensorBoard换过来

先说一个我自己的经历。去年年中我在调一个图像分割模型,每天要同时跑五六组对比实验,超参数、Loss曲线、验证集指标散落在不同的本地日志文件里。TensorBoard虽然也能看曲线,但每开一组实验就要手动指定一次logdir,时间一长连我自己都记不清哪个曲线对应哪组参数。后来一个同事把wandb(Weights & Biases)丢给我,说"你试试这个",我用了一个下午把项目接进去,当天晚上就决定彻底换掉TensorBoard。

wandb本质上是一个实验跟踪与可视化工具,它在你的训练脚本里加上几行代码,就能把每次运行的超参数、指标曲线、模型结构、预测结果、甚至系统资源占用全部自动上传到一个统一的看板里。你不需要自己维护日志文件,不需要手动记录哪组实验用了什么配置,只要打开浏览器就能看到每一次run的完整生命周期。

对比TensorBoard,最打动我的三个点是:

  • 多实验对比不用翻目录:TensorBoard一次只能看一个logdir,wandb可以在一个页面里勾选任意多次run,曲线直接叠在一起。
  • 实验配置和指标放在同一处:每个run自带的config区记录超参数,summary区记录最终指标,不用再对着命令行历史猜参数。
  • 团队协作天然支持:只要大家都登录同一个账号(或同一个团队),谁跑的实验全组都能看到,省掉了"把你跑的实验结果打包发我一下"这种沟通成本。

当然,TensorBoard并不是没有优势,它在纯本地、低带宽环境下的渲染速度更快,插件生态也成熟。但如果你像我一样需要频繁对比实验、追溯历史结果,wandb带来的体验提升是断层级的。

1.1 一个简单的对比:TensorBoard vs wandb

我没有要引战的意思,只是从实际体验出发做一个横向对比。下面这个表格是我自己总结的,适合纠结选哪个工具的人参考:

维度TensorBoardwandb
安装与启动随TensorFlow/PyTorch附带,本地起服务pip安装,登录后云端看板,也可自建私有化
多实验对比需要指定多个logdir,操作略繁琐网页端勾选run即可,代码零改动
超参数与指标关联弱,主要靠命名规范强,config和metric天然绑定在run上
团队共享需自行搭建并处理端口访问同一workspace内所有人可见
数据存储位置本地磁盘云端或自托管,本地有缓存
崩溃恢复日志文件留档,但需要自行解析run状态可恢复,支持离线重传
调参辅助无Sweeps自动超参搜索
模型/数据集版本管理无Artifacts

我不是说TensorBoard一无是处,如果你的实验都在单机且完全不需要协作,用TensorBoard完全没问题。可一旦进入"实验数量多、需要频繁回溯、团队要共享结果"这个节奏,wandb的组织方式明显更省心。

1.2 wandb的核心概念:run、config、log

刚开始用wandb的时候,我绕了很久才想明白三个词:run、config、log。

一个run就是一次代码运行,对应你在训练脚本里调用wandb.init()创建的一条实验记录。每次run会有一个唯一的ID和名字,你的所有指标、配置、文件都挂在它下面。你可以把run理解成一次训练从开始到结束的"档案袋"。

config是挂在run上的超参数字典,一般放learning rate、batch size、模型层数这类不会频繁变化的值。它最大的价值不是存储,而是让每次run自带"配方",日后对比时一眼就能看出两组实验差异在哪。config的使用方式比较灵活,可以在初始化时直接传字典,也可以初始化后再像字典一样赋值。

log是核心中的核心。wandb.log({})接收一个字典,里面放你想记录的指标名和值,比如{"loss": loss.item(), "acc": acc}。每调用一次,就会在曲线上增加一个点。如果训练了100个epoch,每个epoch调用一次,你就能得到一条100个点的曲线。wandb在底层会自动按step排列,不需要你手动传step,除非你有特殊需求。

搞清楚这三个概念,wandb的基本使用其实已经掌握一半了。

2. 从安装到跑通第一条实验记录:环境准备与登录

这部分我按实际操作顺序来讲,方便你直接照着做。

2.1 安装与登录:API Key是新手第一个拦路虎

安装非常简单,用pip或者conda都行:

pip install wandb

如果你的环境里有多个Python环境,记得先激活目标环境再装,避免装错地方。装完之后在终端执行:

wandb login

这里会出现一个登录流程,它会给你一个授权链接,让你在浏览器里打开并授权。麻烦的点在于,首次使用需要注册一个wandb账号,然后拿到一个API Key(一串40位左右的字符),粘贴到终端回车确认。

很多人在这一步卡住,是因为没搞清楚API Key在哪找。正确路径是:登录wandb官网后,点击右上角头像,选择Settings,在页面里找到API Keys区域,点New Key生成一个,然后复制。这个Key相当于你访问wandb服务的凭证,一定要保管好,不要提交到Git仓库里。

如果终端不方便交互,也可以直接把Key写进环境变量:

export WANDB_API_KEY=你的key

或者在代码里指定:

import wandb wandb.login(key="你的key")

不过我不建议在代码里硬编码Key,万一代码分享出去,你的账号就被别人接管了。最稳妥的方式是wandb login登录一次,Key会缓存在本机~/.netrc文件中,后续运行代码会自动读取。

2.2 最小示例:三分钟跑通第一个run

登录成功之后,我们来写一个最小示例,验证整条链路是否通。新建一个Python文件,比如test_wandb.py,内容如下:

import wandb import random # 初始化一个run,project名称可以随意起 wandb.init(project="demo-project", name="first-run") # 记录超参数 wandb.config.update({ "learning_rate": 0.01, "epochs": 10, "batch_size": 32 }) # 模拟训练循环 for epoch in range(10): loss = 1.0 / (epoch + 1) + random.uniform(0, 0.01) acc = epoch * 0.1 + random.uniform(0, 0.05) # 记录指标 wandb.log({"loss": loss, "acc": acc}) # 结束run wandb.finish()

运行这个脚本:

python test_wandb.py

只要看到终端输出里有Syncing run和View run at之类的信息,说明数据已经开始上传。用浏览器打开输出的网址,就能看到这个run的页面,里面有config、loss曲线、acc曲线和系统日志。

这里我提醒一下:wandb.finish()一定要加。不加的话,run在程序正常退出时也会自动结束,但如果你用的是交互式环境(比如Jupyter Notebook),不显式调用finish可能导致run一直处于"running"状态,看起来像卡住了。

2.3 离线模式:网络不稳定时的保命手段

云服务固然方便,但你在内网环境或者网络不稳定的情况下训练,一断网就上传失败会很崩溃。wandb支持离线运行模式,先本地存着,等网络恢复再上传。

使用方法是在初始化时指定:

wandb.init(project="demo-project", mode="offline")

或者通过环境变量:

export WANDB_MODE=offline

离线模式下,run的数据会先写入本地wandb/目录下的文件,等你想同步时,执行:

wandb sync wandb/offline-run-xxx

把对应的离线目录同步到云端。我个人的习惯是:在服务器上跑训练时默认开离线模式,训练结束看结果满意了再统一sync,这样既不受网络波动影响,也不会产生大量实时上传的带宽压力。

3. 训练循环中必须掌握的API与数据记录规范

很多人用wandb只学会了log loss和acc,然后觉得"就这?"。实际上,把记录能力用满,对你的实验效率提升非常明显。这一节我把最核心的几个API和它们的正确用法过一遍。

3.1 init/config/log/finish:四个API的细节边界

**wandb.init()**的参数虽然多,但最常用的只有几个:

  • project:项目名,同一项目下的run会聚合在一起对比,建议按研究课题划分。
  • name:当前run的显示名,不加的话系统会自动生成一个随机名字,写代码时显式命名会好追溯。
  • entity:团队用户名,单人使用可以忽略。
  • notes:一段文本备注,记录实验想法之类的,团队协作时很有用。
  • tags:给run打标签,比如"baseline"、"with-aug"、"debug",方便筛选。
  • config:可以直接把超参数字典传进去,省去后面再update一步。

wandb.config我会把它当做一个只增不减的配置存储区。训练开始后就不要再修改config里的值,因为对比实验时config是判断两组实验差异的依据,中途改掉会造成"挂着羊头卖狗肉"的混乱。如果需要记录动态变化的超参数,比如带衰减的学习率,应该用wandb.log记录,而不是改config。

**wandb.log()**接收字典,值的类型可以是标量、matplotlib图片、PIL图片、音频、视频、表格等。有几个细节容易被忽略:

  • 同一个run里,log传的字典key要尽量保持一致。你今天传{"loss": ...},明天改成{"train_loss": ...},曲线图里就会出现两条断开的线,看起来很难受。
  • 如果你在同一个step里想记录多个指标,一次性传一个字典即可,不要分开多次调用,因为多次调用会占据多个step。
  • 默认情况下,wandb会把每次log当成一个新step。如果想手动控制step(比如每个epoch记录一次但内部跑了多个batch),可以这样写:
wandb.log({"loss": loss}, step=epoch)

**wandb.finish()**用于显式结束run。建议把整个训练逻辑放在try...finally里,确保异常时也能结束run:

wandb.init(project="my-project") try: # 训练逻辑 pass finally: wandb.finish()

这样做的原因在于:如果训练途中抛出异常导致进程直接退出,wandb会判定run为crashed。这不是不能看,但有些可视化统计会把crashed的run单独区分开,偶尔会造成误判。

3.2 watch()自动记录梯度与模型结构

wandb.watch()是我很喜欢的一个API,它能自动记录模型的计算图、梯度、参数分布,用法如下:

wandb.watch(model, log_freq=100, log="gradients", log_graph=True)

log_freq表示每多少步记录一次梯度信息,log支持"gradients"和"parameters"两种模式,log_graph=True会把模型结构图也传上去。

这个功能在排查训练问题时特别有用。比如模型loss不下降,你可以去run页面看梯度的分布图,如果某层梯度已经变成0或者爆炸性增大,马上就能锁定问题层,省去自己写一堆梯度打印代码的时间。

但要注意,watch会显著降低训练速度,尤其是在batch比较小、模型比较大的情况下。我一般只在调试阶段开启,正常大规模训练时会选择只记录参数不经梯度,或者干脆关闭。

3.3 多指标、多曲线、图像与音频的记录姿势

除了标量曲线,wandb还能直接在浏览器里渲染图像、音频和表格。以图像分割任务为例,我经常在验证集上取几个样本,把原图、预测mask、标注mask横向拼接成一张图记录下来:

import matplotlib.pyplot as plt fig, axes = plt.subplots(1, 3, figsize=(12, 4)) axes[0].imshow(image) axes[1].imshow(pred_mask) axes[2].imshow(gt_mask) wandb.log({"validation_samples": wandb.Image(fig)})

这里的wandb.Image()支持传入numpy数组、PIL对象或matplotlib figure,非常方便。图像在网页端能按step滑动查看,一张图对应一个step,训练过程中随时可以回到某个step观察预测效果的变化。

音频任务可以用wandb.Audio(),点开就能在线播放,不用下载文件。表格用wandb.Table(),可以构建带列名的数据表,在run页面直接筛选排序。文本类数据可以用wandb.Html()渲染HTML内容,也可以用它做简单的富文本记录。

这些能力看起来简单,实际用起来会非常顺手。因为你不用再把样本文件一个个下载下来肉眼对比,浏览器里直接看,效率提升不是一点半点。

4. 典型报错排查:我在实际项目中遇到的几个坑

作为工具,wandb用着舒服,但该踩的坑一个也躲不掉。我整理了自己和同事在项目中遇到频率最高的几类报错,按排查链路拆解一遍。

4.1 报错一:Not logged in / 提示需要API Key

这种现象常见于新环境或CI机器上:代码运行到wandb.init()时,直接报缺少凭证,或者陷入交互式登录停滞。

排查链路我是这样走的:

  1. 先在终端执行wandb login --verify,如果提示Valid API key,说明本机凭证没问题,问题大概率出在代码里手动指定了别的key。
  2. 如果提示无效或没有凭证,重新执行wandb login。
  3. 检查环境变量WANDB_API_KEY是否被错误地设置成一个空字符串或旧key,因为在部分环境下,环境变量优先级高于~/.netrc文件,一个失效的key会覆盖掉正常凭证。
  4. 如果是在容器里跑,注意基础镜像是否包含~/.netrc。我踩过一次:本地登录完成,但打进Docker镜像后凭证没拷进去,导致容器内一直报Not logged in。解决方式是用环境变量传入key,或者在镜像构建时把.netrc复制进去。

另外,国内网络访问wandb服务的延迟较高,有时登录时网页授权成功,但终端迟迟等不到响应。这种情况下,可以检查网络连通性后重试,必要时切换一个更稳定的网络环境。

4.2 报错二:网络连接超时与上传失败

这类报错的表现形式很多:ConnectionError、TimeoutError、Failed to upload等。发生在数据同步阶段居多。

排查思路:

  1. 确认当前网络访问外网是否正常。wandb的云端服务部署在海外,公司内网或某些网络环境下可能访问受限。最简单的验证方式是在浏览器打开wandb官网,看能否正常访问。
  2. 检查代理设置。如果你的机器配置了HTTP代理但没有正确设置HTTP_PROXY和HTTPS_PROXY环境变量,wandb的请求就会直连导致超时。反过来,如果配置了代理但代理本身不稳定,也会出现上传失败。
  3. 查看离线缓存。看./wandb/目录下是否有大量*.wandb文件堆积,如果有,说明历史数据一直在排队没传上去。等一下重试,或者手动执行wandb sync。

对于内网环境,我会建议直接用WANDB_MODE=offline跑训练,最后统一同步,时间上更可控。如果连最后同步都做不了,那就考虑自建wandb私有化服务,或者在公司内部选用其他替代工具。

4.3 报错三:训练进程卡死或重复输出同一run

这个坑是我自己踩得最深的。现象是:在Jupyter Notebook里反复运行同一个训练单元格,每次都会创建一个新run,但旧run并没有结束,导致同一指标在多个run里重复出现。或者用PyTorch DataLoader的num_workers开启多进程时,wandb在每个子进程里都被初始化一次,日志混乱,卡死。

根因是wandb.init()被调用了多次,且没有正确关闭。解决方式:

  1. 在Notebook环境里,每次重新训练前先调用wandb.finish(),确保旧run结束。
  2. 使用wandb.init(reinit=True),它允许在同一个Python进程里多次init,而不是报错或复用旧run。
  3. 多进程训练时,把wandb初始化逻辑放到if __name__ == "__main__"保护块内,或者设num_workers=0测试一次。如果多进程场景下确实需要在子进程记录日志,要给每个进程独立的run name,避免混淆。

4.4 报错四:磁盘占用暴涨,本地缓存失控

wandb会在本地缓存所有log数据,包括图像和音频。训练时间长了,wandb/目录可能膨胀到几十GB,小磁盘的机器直接被写满。

我的处理方式是分两类:

  • 临时清理:跑完实验后把不需要的wandb/offline-run-*目录删除,或者用wandb artifact ls查看大文件。
  • 配置限制:在wandb.init时设置sync_tensorboard=False防止重复记录,通过环境变量WANDB_DIR把缓存目录迁移到大磁盘。

另外,如果你确定某个run的数据已经在网页端看过了,并且本地不再需要,可以直接删除本地目录,不影响网页端数据。数据同步完成后,本地目录只是副本,删掉不影响云端记录。

5. 进阶玩法:Sweeps超参搜索与Artifacts模型管理

基本使用跑通之后,你会发现wandb真正的威力在进阶功能上。这里我只挑两个我认为对日常实验最有效的:Sweeps和Artifacts。

5.1 Sweeps:让机器替你调参

Sweeps是wandb自带的超参数搜索模块。你不用像之前那样一个个手写for循环试learning rate,只需要定义一个搜索配置,wandb就会自动启动多个agent,每个agent用不同的参数组合跑训练,然后把结果汇总到同一个项目里。

一个简单的sweep配置(YAML格式)长这样:

program: train.py method: bayes metric: name: val_acc goal: maximize parameters: learning_rate: min: 0.0001 max: 0.01 distribution: log_uniform batch_size: values: [16, 32, 64]

保存为sweep.yaml,然后执行:

wandb sweep sweep.yaml

它会输出一个sweep ID,然后你需要在多个终端或机器上执行:

wandb agent 你的sweep_id

每个agent会从参数空间里取一组参数,自动注入到环境变量里,然后运行train.py。train.py里不再显式写死超参数,而是从wandb.config中读取。这样跑完几十组实验后,直接在Sweeps页面看平行坐标图和重要性分析,哪些参数对结果影响大一目了然。

我个人使用Sweeps的经验是:先小规模跑十几组,看参数重要性排序,再根据结果收窄参数范围做第二轮搜索。直接上来就跑几百组,既浪费算力,也没太大意义。

5.2 Artifacts:把数据集和模型版本管起来

Artifacts是wandb的版本控制模块,可以管数据集、模型权重、任何文件。以前我把模型保存到本地,命名规则是model_v1_0.87.pth、model_v2_0.89.pth,时间一长根本分不清哪个对应哪个。用Artifacts之后,每个run产出什么模型、基于什么数据集、效果如何,全部串在一个链条上。

保存一个模型:

artifact = wandb.Artifact("resnet50-finetune", type="model") artifact.add_file("model.pth") wandb.log_artifact(artifact)

如果还想记录这个模型对应的数据集版本,可以在定义Artifact时用add_reference()指向数据集目录,或者在一个run里同时记录数据和模型,让它们形成关联。之后需要复现时,可以直接从某个run的Artifacts里下载对应文件,不用再翻聊天记录找"上一次用的那个模型"。

我这里有一条很实际的经验:Artifacts的命名最好包含有意义的版本语义,比如model-resnet50-aug-v1.0.0.pth。不要只写model.pth然后靠系统时间戳区分,后期你会疯掉的。

5.3 团队协作的体会与工作流建议

最后聊点软的。真正把wandb用好,不只是一个工具问题,还是一个团队习惯问题。

我们团队现在的日常流程是:

  1. 每个人开始新实验时,wandb.init的project固定为当前课题名,name用"姓名缩写+实验简述",比如zc/lr-0.01-aug。
  2. 所有对比实验都挂在同一个project下,看板按run对比,谁调的参、效果如何,一目了然。
  3. 每个run必须写notes,哪怕只有一句话,比如"换了ResNet50当backbone",这是为了一个月后回溯还能想起来当时为什么这么做。
  4. 模型以Artifacts形式存储,报告中附上run链接,而不是粘贴一张截图。

这套流程跑顺之后,实验回溯成本大大降低。我经常上午来了先打开wandb页面看昨晚跑完的实验结果,数据已经整整齐齐躺在那里,比起翻log文件、写Excel记录,不知道省了多少时间。

不过我也得说句公道话:如果你只是偶尔跑一两个模型、不需要对比、更不需要协作,wandb对你来说确实有点重。它的学习曲线虽然不算陡,但也是需要花时间适应的。项目真正进入规模化实验阶段,你才会感受到"埋点记录数据"这件事带来的巨大回报。

我个人目前最满意的用法,是结合离线模式和Sweeps:白天在本地机器把参数搜索范围定义好,挂上agent让它自己跑,晚上回家打开手机看结果,第二天到公司直接根据分析图选定下一轮方向。这套流程帮我节省的时间,保守估计每周能省出一个完整工作日。

从最开始抵触"多一个平台多一件事",到现在把wandb当成实验流程的标配,我这个转变还是很快的。工具的价值不在于功能列表有多长,而在于它是否真的能让你把精力从"记录"转移到"思考"上。在这一点上,wandb做到了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询