ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PyTorch训练可视化进阶:WandB实验管理与超参记录全攻略

PyTorch训练可视化进阶:WandB实验管理与超参记录全攻略 训练跑起来只是第一步跑完什么都看不懂才是最折磨人的。我真正被 WB 这个工具打动是在一个周一下午手头 12 组不同超参的实验同时跑我一边盯着终端翻日志一边手动往 Excel 里抄 loss 值抄到第 7 组的时候忽然发现有一组实验的 batch_size 我忘记记了。那一刻我意识到训练过程可视化真正要解决的不是“画一条曲线”而是“让每次实验都有一条完整、可追溯、可对比的生命周期记录”。这篇是“Pytorch 可视化”系列的第五篇。前面几篇聊过怎么用 matplotlib 画 Loss 曲线、怎么把中间特征图可视化这一篇我决定集中写一个工具——WandBWeights Biases它是我目前最推荐的 Pytorch 训练过程可视化方案没有之一。它能把训练中的 loss、准确率、学习率、梯度分布、显存占用、验证集指标全部统一记录到一个可视化管理页面里自动按超参数分组对比还能做超参搜索、模型文件版本管理、团队共享报告。这篇文章我会从安装登录、四个核心 API、改造完整训练循环一路写到 Sweeps 自动调参、Artifacts 版本管理、离线同步以及我在实际使用中踩过的那些报错坑。不管你是刚搭好 Pytorch 环境、正准备认真调模型的初学者还是已经用 TensorBoard 很久、觉得实验对比和团队分享不方便的进阶玩家这篇都适用。下面所有内容都是我自己用下来的经验你可以直接当作一份能抄作业的攻略。1. 为什么训练可视化我最后选了 WandB1.1 TensorBoard 够用但不够好用TensorBoard 我前后用了大概两年。作为 Pytorch 官方出品它确实轻量、免安装用 SummaryWriter 写几个 scalars 就能看曲线单机训练完全没有问题。但当我开始同时跑一组对比实验时它的短板就特别明显了第一是实验对比太割裂。TensorBoard 确实支持同时勾选多个 run 查看但日志文件一多页面加载变慢run 的名字一长就分不清谁是谁。而且它把所有本地事件文件都压在你自己电脑上换一台机器训练就看不到历史除非你再把日志拷过去。第二是超参数没法跟指标自动绑定。TensorBoard 的 hparams 插件虽然存在但我使用下来的体验是配置麻烦而且每次都要手动指定哪些超参要记录、要展示一段时间不维护新实验就忘了加。可我记得最重要的恰恰是当时用了什么优化器、什么 batch_size、多少步衰减的学习率。第三是团队协作几乎为零。同事想看你某个实验的曲线要么你把截图发过去要么给他开端口要么把 events 文件打包发给他。在团队里做模型实验这效率实在太低了。说白了TensorBoard 是一个“单机版画线工具”不是实验管理平台。当你只有一两个实验、自己调试用它完全够但当你把训练当成一场持续进行的“实验管理”时工具就会变成瓶颈。1.2 WandB 到底解决了什么WandB 的定位和 TensorBoard 不同。它把“记录训练指标”这件事直接做成了服务你在训练脚本里调用 log数据会传到 wandb 项目页面打开浏览器你能在一个页面里看到这个项目下所有 run 的曲线支持按超参数值给曲线着色点开任意一个 run 就能看到完整配置、输出日志、训练指标、梯度直方图、甚至模型权重分布。对我来说最实用的功能有三个实验自动归档每次 wandb.init 都是一个新 run训练时用了什么参数、什么环境、什么代码版本都会自动归档到页面不用自己再维护一份实验记录表。超参与指标联动曲线图旁边可以直接看 config 表某个 run 用的 lr、batch_size、优化器参数一目了然对比 0.001 和 0.0001 两组实验时直接勾选两个 run颜色和名称都区分好了。链路完整训练日志、指标曲线、模型权重文件、数据集版本、生成报告全在同一个工作区里复现实验时不用在微信里翻聊天记录找模型文件放在哪。还有一个很现实的原因WandB 有免费额度个人和初创团队用起来完全够。数据默认存云端你在任何一台能开浏览器的机器上都能看。它也支持离线模式后面我会单独讲。1.3 选型对比TensorBoard、Mlflow、WandB 与手写日志我最初自建过一套“轮子”——直接在训练脚本里把 loss 打印到日志再写个 matplotlib 把日志解析画图。听起来可控但过了一周连自己都不想看因为要写大量解析代码而且不同的实验脚本日志格式还经常不统一。选 WB 前我也大致对比了一圈方案指标可视化超参记录实验对比协作分享上手成本备注TensorBoard好一般一般几乎为零低单机调试首选Mlflow一般好好一般中更偏向模型注册与工程化WandB很好很好很好很好低一体化实验管理本系列第五篇主角手写日志matplotlib自控自己写自己写自己写高适合完全内网隔离的极端场景结论是单机调试、小团队做算法验证、教学演示、入门 PytorchWandB 的综合体验最均衡。而且它和 Pytorch 的集成非常自然训练循环里每 step 调一次 log 就行原来的代码结构基本不用动。这也是为什么我在这个系列里把训练过程可视化这一篇给了 WandB 而不是继续写 matplotlib。2. 三分钟跑通 WandB 基础配置2.1 安装与登录先让第一个 run 跑起来安装很简单直接用 pippip install wandb装完之后在终端执行wandb login首次登录会让你去官网注册账号拿到一个 API key粘贴回来就完成授权。key 会写入用户目录下的~/.netrc之后在当前机器上运行时不需要重复登录。如果你是在脚本里自动化跑更推荐用环境变量避免交互式粘贴import os os.environ[WANDB_API_KEY] 你的-api-key os.environ[WANDB_PROJECT] pytorch-visualization-demo os.environ[WANDB_ENTITY] 你的用户名或团队名把 key 写环境变量还有个好处多人共用的训练服务器上每位同事可以有自己的 key不会因为.netrc被其他人覆盖而互相干扰。注意绝对不要把 API key 提交到公开代码仓库这是最容易踩的安全坑。提示如果运行环境没有外网或者你暂时不想把数据传到云端可以先执行wandb offline切换成本地离线模式记录的数据会写在本机缓存目录之后再统一同步。这个用法在后面第 4.3 节详细讲。2.2 记住这四个 API 就够入门WandB 的接口很多但 90% 的日常使用只需要下面四个wandb.init()每次训练开始前调用创建一条 run 记录。project 参数指定项目名config 参数把超参打包传进去后续所有指标都会挂在这个 run 名下。wandb.configinit 时传入的超参集合。它既是一个可读的对象也可以当作字典操作。训练脚本里直接读wandb.config.lr整个实验的超参数就能自动归档到页面上。wandb.log()最核心的接口。每次调用传入一个字典比如wandb.log({loss: 0.32, acc: 0.91})页面就会把这条记录追加到对应 run 的曲线里。支持一次传多个 key间隔一定 step 调用一次即可不用每个 batch 都调。wandb.watch()用来监控模型参数和梯度。传入 model 之后它会自动在设定的频率下记录权重直方图、梯度直方图方便你观察有没有梯度消失、爆炸或者某些层长时间不更新。最小示例大概长这样import wandb wandb.init(projectmy-demo, config{lr: 1e-3, batch_size: 64}) # 训练循环里调用 for step in range(100): loss compute_loss(step) wandb.log({loss: loss}) wandb.watch(model, logall, log_freq100) wandb.finish()2.3 理解 run 的生命周期id、tags、notes 与断点续跑每次wandb.init()都会生成一个唯一的 run即使脚本崩溃或者手动退出这个 run 依然会保留在项目页面里。很多新手困惑“我重新跑了一下怎么又多了一个 run”——这是 WandB 的默认设计每次启动都是一次新的训练记录。如果想在同一个 run 上续跑需要手动指定 idrun wandb.init( projectmy-demo, idyour-previous-run-id, resumemust, # 或 allow )resumemust表示必须续跑旧 run找不到就直接报错适合训练中断后恢复的场景。resumeallow则表示能找到就续找不到就新建。除了 id我强烈建议用tags、notes、group三个字段维护实验组织wandb.init( projectresnet-cifar, nameresnet18-bs128-lr1e-3, groupresnet18-batchsize-compare, job_typetrain, tags[resnet18, cifar10, baseline], notes第一次正式跑resnet18作为后续实验基线, )group特别适合把同维度对比实验归到一组tags方便筛选notes可以写备注比在团队群里发一句“这个实验是 xxx 跑的好模型”靠谱多了。2.4 用 config 管理超参数别再把参数写在变量名里我见过很多项目超参数散落在脚本各处跑完后根本分不清“这个 run 用的 lr 是 1e-3 还是 1e-4”。WandB 的 config 就是来解决这个问题的config wandb.config config.lr 1e-3 config.batch_size 64 config.epochs 30之后在训练代码里直接读取config.lr页面会自动把这一组配置归档到 run 详情页。你回看任何一个 run点开就知道当时用了什么配置完全不用靠记忆。注意不要在训练过程中随意修改 config 的值。尤其不要把动态学习率写进 config比如config.lr scheduler.get_last_lr()。学习率这类逐 step 变化的值应该用wandb.log({lr: current_lr})当作普通指标记录config 里只保留初始静态超参。3. 实战改造一个 Pytorch 训练循环3.1 完整示例给 MNIST 的 CNN 训练接上 WandB这里我给出一个可以直接复制的完整示例。任务很简单MNIST 手写数字分类用一个两层卷积的 CNN训练 5 个 epoch。重点是展示 WandB 在真实训练循环里应该插在哪些位置。import torch from torch import nn, optim from torch.utils.data import DataLoader from torchvision import datasets, transforms import wandb device cuda if torch.cuda.is_available() else cpu # 1. 初始化 run传入超参 run wandb.init( projectpytorch-visualization-demo, namecnn-mnist-baseline, config{ lr: 1e-3, batch_size: 64, epochs: 5, optimizer: adam, }, tags[mnist, baseline], notes用于验证wandb接入流程的第一个run, ) config wandb.config # 2. 数据准备 transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)), ]) train_set datasets.MNIST(root./data, trainTrue, downloadTrue, transformtransform) val_set datasets.MNIST(root./data, trainFalse, downloadTrue, transformtransform) train_loader DataLoader(train_set, batch_sizeconfig.batch_size, shuffleTrue, num_workers2) val_loader DataLoader(val_set, batch_size256, shuffleFalse, num_workers2) # 3. 模型与优化器 class CNN(nn.Module): def __init__(self): super().__init__() self.features nn.Sequential( nn.Conv2d(1, 32, 3, padding1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(32, 64, 3, padding1), nn.ReLU(), nn.MaxPool2d(2), ) self.classifier nn.Sequential( nn.Flatten(), nn.Linear(64 * 7 * 7, 256), nn.ReLU(), nn.Linear(256, 10), ) def forward(self, x): return self.classifier(self.features(x)) model CNN().to(device) criterion nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lrconfig.lr) # 4. 监控模型参数与梯度 wandb.watch(model, criterioncriterion, logall, log_freq50) # 5. 验证函数 def evaluate(model, loader): model.eval() correct, total 0, 0 with torch.no_grad(): for x, y in loader: x, y x.to(device), y.to(device) out model(x) pred out.argmax(dim1) total y.size(0) correct (pred y).sum().item() return correct / total # 6. 训练循环 for epoch in range(config.epochs): model.train() train_loss, train_correct, train_total 0.0, 0, 0 for step, (x, y) in enumerate(train_loader): x, y x.to(device), y.to(device) optimizer.zero_grad() out model(x) loss criterion(out, y) loss.backward() optimizer.step() train_loss loss.item() * x.size(0) pred out.argmax(dim1) train_correct (pred y).sum().item() train_total y.size(0) # 每 100 个 batch 记录一次训练侧指标 if step % 100 0: wandb.log({ batch_loss: loss.item(), batch_acc: (pred y).float().mean().item(), epoch: epoch, }) # epoch 结束后跑一次验证集并记录验证准确率 val_acc evaluate(model, val_loader) avg_train_loss train_loss / train_total train_acc train_correct / train_total wandb.log({ epoch: epoch, train_loss: avg_train_loss, train_acc: train_acc, val_acc: val_acc, }) print(fepoch {epoch} | train_loss {avg_train_loss:.4f} | ftrain_acc {train_acc:.4f} | val_acc {val_acc:.4f}) # 7. 保存模型并记录为 artifact torch.save(model.state_dict(), cnn_mnist_baseline.pt) artifact wandb.Artifact(cnn-mnist, typemodel) artifact.add_file(cnn_mnist_baseline.pt) run.log_artifact(artifact) run.finish()这段代码结构很常规你只需要把模型结构换成自己的网络数据加载换成自己的数据WandB 部分完全不需要动。3.2 拆解每个记录点的意义我把刚才示例里的记录点逐个说明一下避免你照抄完不知道为什么要写这些。第一个记录点是训练循环里的wandb.log({ batch_loss: loss.item(), batch_acc: (pred y).float().mean().item(), epoch: epoch, })它记录的是当前 batch 的 loss 和准确率。为什么取名 batch_loss 而不是 loss因为一个 epoch 结束后我还会记录一个 train_loss两者语义不同一个是实时噪声大的 batch 值一个是经过全量平均的 epoch 值。如果你只用一个 key后面再记录另一个值曲线会被覆盖或混杂区分开更清晰。第二个记录点在 epoch 结束之后wandb.log({ epoch: epoch, train_loss: avg_train_loss, train_acc: train_acc, val_acc: val_acc, })这里三个指标之间的横轴必须统一。我的习惯是显式传epoch作为时间轴的一部分。如果不传stepWandB 默认按照 log 的调用次数递增 x 轴。问题在于训练循环里每 100 个 batch 调一次 logepoch 结束又调一次这两类曲线的横轴语义会不一致batch_loss 是 0, 100, 200... 的步数val_acc 是 0, 1, 2... 的轮数。统一在 log 里带上epoch这个 key页面会自动把 val 相关曲线放到 epoch 维度上方便和 train 指标对看。第三个是wandb.watch(model, criterioncriterion, logall, log_freq50)。watch 会把模型参数的权重分布、梯度分布记录成直方图。训练跑到一半如果你发现 loss 不掉去看直方图通常能直接发现问题比如某一层梯度全变零或者权重数值异常大。但注意不要logall的同时把log_freq设太密否则序列化开销会拖慢训练后面第 3.4 节会展开。3.3 记录 Loss、准确率之外的指标真实项目很少只看 loss 和 acc。下面三个自定义指标是最常见也最容易被问到的学习率曲线尤其是使用 StepLR、CosineAnnealingLR 这类动态调度器时学习率变化直接决定 loss 走势。每次 scheduler 更新后顺手记录wandb.log({lr: scheduler.get_last_lr()[0]})梯度范数判断梯度是否消失或爆炸。PyTorch 里可以先对梯度做 clip再把 clip 前的总范数记录total_norm 0.0 for p in model.parameters(): if p.grad is not None: param_norm p.grad.data.norm(2) total_norm param_norm.item() ** 2 total_norm total_norm ** 0.5 wandb.log({grad_norm: total_norm})F1、IoU 这类验证集指标在完成一个 epoch 的验证后计算。比如分割任务可以这样val_iou compute_iou(pred_masks, target_masks) wandb.log({val_iou: val_iou})还有一个实用技巧WandB 不只支持数值曲线还支持把本地的图片、音频、表格直接记录到页面。例如wandb.log({val_examples: [wandb.Image(img), wandb.Image(mask)]})训练中随手存一批验证样本的预测结果比截图传群再写“这是第 20 个 epoch 的效果”高效得多。3.4 日志频率与性能别让记录拖慢训练WandB 默认是边训练边把数据异步上传到服务端不会因为网络问题阻塞训练但高频调用wandb.log和wandb.watch依然会产生 CPU 序列化和 IO 开销。我实测下来的经验是记录内容推荐频率原因batch 级 loss / acc每 50~200 个 batch画曲线密度足够开销很小epoch 级指标每个 epoch 一次天然低频无压力学习率每次 scheduler 更新后本来就是要看变化趋势梯度直方图 / 权重直方图每 100~500 个 batch高频直方图序列化开销大验证集图片每个 epoch 存 8~16 张每 epoch 一次即可避免占空间另一个性能大坑是不要在验证循环内部调wandb.log。如果你写for x, y in val_loader: wandb.log({loss_per_batch: ...})验证集几百个 batch 就会产生几百条记录页面曲线又乱又卡还白白拖慢验证速度。验证集指标应该等整个验证循环跑完汇总成单个数值再记录。4. 进阶能力Sweeps、Artifacts 与协作4.1 Sweeps一键自动搜索超参数当你不再手动一组组跑实验而是想让 WandB 自动帮你搜索超参数时用 Sweeps。它内置了随机搜索、网格搜索和贝叶斯搜索三种算法。我目前使用最多的是贝叶斯搜索因为它会根据历史试点的结果来指导下一组参数同样的试点数下效果往往更好。用法分两步。第一步写一个 sweep 配置文件比如sweep.yamlprogram: train.py method: bayes metric: name: val_acc goal: maximize parameters: lr: distribution: log_uniform min: 0.0001 max: 0.01 batch_size: values: [32, 64, 128] hidden_dim: distribution: int_uniform min: 128 max: 512第二步在终端启动wandb sweep sweep.yaml启动后终端会输出一个 sweep_id然后启动一个或多个 agentwandb agent sweep_id每个 agent 会不断从参数空间里采样生成新的 run自动调用train.py。你可以在同一台机器上起多个 agent 并行也可以在多台机器上各起一个最终搜索结果都会汇总到同一个 sweep 页面里。这里有一个细节学习率这类跨度极大、影响非线性的超参我建议用log_uniform而不是uniform。因为 0.0001 和 0.001 之间的差距与 0.1 和 0.2 之间的差距对训练的影响完全不同在 log 空间采样更合理。这也是我在实际搜索中踩过坑后换过来的经验。4.2 Artifacts模型和数据集进入版本管理Artifacts 是 WandB 给我惊喜最多的一块。它把“模型文件”和“数据集”也纳入版本管理。训练完一个模型不再只是存一个.pt文件还会自动记录是哪个 run 产生的、当时的超参是什么、父 artifact 是哪个数据版本。记录模型 artifact 的代码其实就在刚才第 3.1 节里artifact wandb.Artifact(cnn-mnist, typemodel) artifact.add_file(cnn_mnist_baseline.pt) run.log_artifact(artifact)重新运行训练时可以读取某个历史版本artifact run.use_artifact(cnn-mnist:latest) model_path artifact.file()数据集同样可以管理。比如一份经过预处理的训练数据第一次处理完写入数据集 artifact之后每次实验都从同一个数据版本读取。这样如果团队里有人改过数据处理逻辑你能明确知道某个 run 用的到底是哪一版数据避免“这个结果怎么复现不出来”的争论。注意不要在训练循环里把 checkpoints 每轮都 log 一次。只保存最优模型或最后几个 epoch 的模型就够了否则 artifact 体积会迅速膨胀页面也会变得难以维护。4.3 离线环境下的 WandB先本地记录再同步很多训练环境并没有外网或者你对数据上传有顾虑。这时候 WandB 的本地模式就很重要。在终端或脚本里设置wandb offline或者用环境变量os.environ[WANDB_MODE] offline离线模式下wandb.log、wandb.watch照常工作所有记录会写入本地的.wandb缓存目录不会做网络上传。等这台机器恢复网络之后再执行wandb sync同步命令会把缓存里所有 run 的记录上传到云端项目。我自己的习惯是在实验室几台没有公网的机器上全部开启离线模式跑完实验后用一台有网络的机器统一wandb sync这样既保留了 WandB 的完整功能又不影响训练环境的网络限制。如果你是公司内网环境不想把数据传到外部服务WandB 也有私有化部署方案但门槛相对高我建议小团队先在云端免费额度上跑通再评估是否需要私有化。4.4 用 Report 把实验结果变成共享页面训练跑完了曲线都在 WandB 里了但总不能把网页链接甩给同事让他自己一个个 run 点开看。WandB 的 Report 功能就是把一堆曲线、表格、文字说明组合成一份可分享的试验报告。操作上很简单在项目页面的 Runs 列表里勾选几组要展示的 run然后点击“Create report”把损失曲线、验证集准确率、准确率对比表这些面板拖进报告里再补两段文字说明结论生成一个固定链接。之后每次训练完把新 run 加进报告链接不用变团队里所有人都能看到最新的对比结果。这个功能在我写周报、和算法组同步进展时帮了很大忙。以前要把截图一张张贴上去现在直接丢一个链接同事自己点开看曲线还能交互式缩放。5. 常见问题与排查技巧实录5.1 高频报错速查表我整理了一张速查表都是我在训练中实际遇到并排查过的问题现象最常见原因解决办法初始化时卡在网络请求当前环境无法访问 WandB 公网服务切换 offline 模式或设置 WANDB_MODEoffline提示 API key 未找到没有执行 wandb login或环境变量未设置执行wandb login或设置 WANDB_API_KEY曲线画了一部分就停住训练崩溃run 被标记为 failed修复脚本后使用 resumeallow 续跑曲线横轴乱了train 和 val 对不上log 中 step 语义不统一显式在 log 里带上 epoch 或 global_step多卡训练出现重复 run每个进程都调用了 wandb.init只在 rank 0 进程 init 和 logwatch 之后显存明显变大logall 且频率过高改为 loggradientslog_freq 调大页面数据不更新本地控制台也无输出网络上传线程异常检查缓存目录必要时重启脚本并 resume5.2 初始化卡住与登录失效最让新手头疼的就是wandb.init()卡住不动。通常是当前环境访问不了 WandB 云端服务。排查思路很简单先看终端有没有出现Network error之类的字样如果没有再尝试临时切到 offline 模式wandb offline python train.py如果能正常跑且生成了本地缓存说明确实卡在网络同步。你可以在有外网的机器上用wandb sync同步结果不影响训练数据本身。登录失效也比较常见尤其多人共用一台服务器时。.netrc被覆盖之后再次运行就会出现 key 找不到的报错。我习惯直接用环境变量export WANDB_API_KEY你的key写入~/.bashrc或者项目启动脚本里比依赖.netrc要稳定得多。5.3 曲线没显示或数据丢失如果你调用了wandb.log但页面上看不到曲线大概率是横轴步数语义出了问题。比如你在验证循环里也调用了 log和训练循环的 step 混在一起曲线刷新时前后点顺序错乱页面会把数据覆盖或者画出很奇怪的多段折线。解决办法是统一所有 log 的步数语义。我通常在脚本里维护一个全局的global_stepglobal_step 1 wandb.log({train_loss: loss}, stepglobal_step)这样无论训练循环、验证循环还是学习率更新都基于同一个全局计数器曲线一定整齐。另一个常见问题是数据量太大导致图表加载慢。几十万条 batch 日志点会让浏览器渲染很吃力。这时候解决思路不是删数据而是只保留关键频率的记录点或者用页面上自带的平滑系数看图。5.4 分布式训练与多进程避坑现在不少项目用 DDP 多卡训练。WandB 在这块的坑非常经典如果你在每个进程里都执行wandb.init()项目页面就会出现 N 个一模一样的 run曲线全被淹没还很难清理。正确做法是只在主进程里记录。代码里加一个判断import torch.distributed as dist if dist.is_initialized(): is_main dist.get_rank() 0 else: is_main True run None if is_main: run wandb.init(project...) # 训练循环里 if is_main: wandb.log({loss: loss.item()})对于DataParallel这种单进程多卡模式不需要做这个处理整个进程只有一个 run。数据加载方面DDP 场景记得用DistributedSampler保证每个进程拿到不同子集WandB 记录的是主进程负责的那部分数据指标。如果采样器写错导致多个进程看到的数据完全相同最后汇总出的指标可能重复放大某种异常排查起来特别费劲。6. 最后说点个人经验我从 TensorBoard 切成 WandB 之后最直观的感受不是“曲线更好看了”而是“实验记录这件事终于自动了”。我现在写任何 Pytorch 脚本不管是个小消融实验还是完整训练都会顺手把 WandB 接上init 一下、config 传参数、log 几个指标、watch 一下模型五分钟的事。但省下来的时间远超五分钟——我再也不用翻聊天记录确认“那个 0.993 的模型到底是哪次跑出来的”也不用在周报里一个个贴损失图。个人建议的接入顺序是先把第 3 节的最小改造跑通确认基础流程没问题再用 config 和 tags 规范项目组织接着上 Sweeps 做超参搜索最后才是 Artifacts 和 Report 这类团队协作功能。一步到位反而容易因为细节不熟而气馁。这个系列如果在“Pytorch 可视化”上继续往深走下一步我会想写训练完模型转换部署方向的内容有读者之前在后台问过 Pytorch 转 ONNX 的细节。不管你是做图像、NLP 还是强化学习——强化学习里每个 episode 的 reward 曲线用 WandB 看同样很合适——先把 WandB 接进训练流程后面所有实验效率都会上一个台阶。
返回列表