巴音郭楞蒙古自治州网站建设_网站建设公司_原型设计_seo优化
2026/1/21 11:12:51 网站建设 项目流程

📖 本日学习目标

  • 知识点回顾
    1. 深入理解 TensorBoard 的发展历史和核心原理。
    2. 掌握 TensorBoard 的四大核心可视化操作:add_scalar,add_graph,add_image,add_histogram
    3. 通过 MLP 和 CNN 在 CIFAR-10 上的实战,对比 TensorBoard 在不同模型监控中的应用。
  • 今日作业
    • 对 ResNet18 在 CIFAR-10 上采用微调策略时,使用 TensorBoard 全程监控训练过程。

💡 心得体会:从“事后复盘”到“实时驾驶”

如果说之前的matplotlibprint语句是我们训练结束后的“战报分析”,那么TensorBoard 就是我们驾驶飞船(训练模型)时的实时飞行仪表盘

  • print就像通过舷窗瞥一眼外面,信息零散且转瞬即逝。
  • matplotlib是降落后才能绘制的航线图,只能用于总结,无法在飞行中调整。
  • TensorBoard则是集成了**速度表(准确率)、油耗表(损失)、引擎状态(权重分布)、航线图(训练曲线)、甚至外部摄像头(图像可视化)**于一体的综合驾驶舱。

它最大的价值在于实时性交互性。我们可以随时打开浏览器,像舰长一样审视各项指标:

  • SCALARS:损失曲线有没有“塌陷”?准确率是否“停滞”?学习率调整是否生效?
  • HISTOGRAMS:权重分布是否健康?梯度有没有出现“消失”或“爆炸”的迹象?
  • GRAPHS:我的模型结构搭对了吗?数据流向是否符合预期?
  • IMAGES:模型到底把什么图片认错了?是“猫”和“狗”分不清,还是“飞机”和“鸟”搞混了?

正如老师所说,深度学习的代码很多时候是“八股文”。我们不必死记硬背writer.add_xxx的所有细节,但必须深刻理解TensorBoard 能为我们提供哪些维度的信息。这样,我们就能精准地向 AI 提出需求:“请为我的训练循环加入 TensorBoard,并记录训练/验证的准确率、损失、学习率以及每500步的权重直方图。” AI 负责实现,我们负责分析和决策


📝 知识点回顾

1. TensorBoard 是什么?

一个官方的、交互式的、网页端的可视化工具,用于实时监控和分析机器学习训练过程。它是炼丹师的“照妖镜”和“监控室”。

2. 核心原理:两步走

TensorBoard 的工作方式非常优雅:

  1. ✍️ 写入日志 (Write):在你的 Python 训练代码中,实例化一个SummaryWriter对象。在训练的各个阶段,调用它的方法(如add_scalar)将你想监控的数据(损失、准确率、图片等)和当前的“步数”(global_step)一起写入一个本地日志文件(.tfevents文件)。

  2. 👀 读取与展示 (Read & Display):在终端启动 TensorBoard 服务,并指向日志文件所在的目录。TensorBoard 会自动解析这些日志文件,并启动一个本地 Web 服务器。你只需在浏览器中打开给定的 URL (如http://localhost:6006),就能看到所有数据被渲染成的交互式图表。

3. 四大金刚:核心操作一览

操作函数作用TensorBoard 界面应用场景
writer.add_scalar()记录标量数据SCALARS监控损失、准确率、学习率等随时间变化的单值指标。
writer.add_graph()可视化模型结构GRAPHS检查模型搭建是否正确,理清数据流。
writer.add_image()可视化图像数据IMAGES查看原始数据、数据增强效果、模型预测错误的样本。
writer.add_histogram()记录张量的分布直方图HISTOGRAMS诊断权重和梯度的分布,判断梯度消失/爆炸等问题。

🚀 今日作业:使用 TensorBoard 监控 ResNet18 微调过程

结合 Day 44 的两阶段微调策略和今天学习的TensorBoard,我们将完成一个更具工业级水准的训练任务。

1. 我的代码实现

下面的代码整合了 Day 44 的train_with_freeze_schedule函数,并在其中加入了 TensorBoard 的所有核心监控功能。

# 【Day 45 作业】# 目标:在ResNet18微调CIFAR-10的过程中,使用TensorBoard进行全程监控。importtorchimporttorch.nnasnnimporttorch.optimasoptimfromtorchvisionimportdatasets,transforms,modelsfromtorch.utils.dataimportDataLoaderfromtorch.utils.tensorboardimportSummaryWriter# 导入核心工具importosimporttimefromtqdmimporttqdm# --- 1. 全局配置与数据加载 ---plt.rcParams["font.family"]=["SimHei"]plt.rcParams['axes.unicode_minus']=Falsedevice=torch.device("cuda"iftorch.cuda.is_available()else"cpu")print(f"==================== 使用设备:{device}====================")# 数据增强与加载 (与Day 44相同)train_transform=transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize(mean=[0.485,0.456,0.406],std=[0.229,0.224,0.225])])test_transform=transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize(mean=[0.485,0.456,0.406],std=[0.229,0.224,0.225])])train_dataset=datasets.CIFAR10(root='./data',train=True,download=True,transform=train_transform)test_dataset=datasets.CIFAR10(root='./data',train=False,download=True,transform=test_transform)train_loader=DataLoader(train_dataset,batch_size=64,shuffle=True,num_workers=4,pin_memory=True)test_loader=DataLoader(test_dataset,batch_size=64,shuffle=False,num_workers=4,pin_memory=True)classes=('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')print("数据加载完成...")# --- 2. 模型定义、冻结/解冻函数 (与Day 44相同) ---defcreate_resnet18(pretrained=True,num_classes=10):model=models.resnet18(pretrained=pretrained)in_features=model.fc.in_features model.fc=nn.Linear(in_features,num_classes)returnmodel.to(device)deffreeze_model(model,freeze=True):forname,paraminmodel.named_parameters():if'fc'notinname:param.requires_grad=notfreeze status="冻结"iffreezeelse"解冻"print(f">> 已{status}模型卷积层参数 <<")returnmodel# --- 3. 集成了TensorBoard的“两阶段”训练函数 ---deftrain_with_tb_monitoring(model,train_loader,test_loader,criterion,optimizer,scheduler,device,epochs,freeze_epochs,writer):global_step=0# 记录模型结构sample_inputs,_=next(iter(train_loader))writer.add_graph(model,sample_inputs.to(device))print("模型结构已写入TensorBoard.")iffreeze_epochs>0:model=freeze_model(model,freeze=True)forepochinrange(epochs):# ... [与Day44相同的训练和验证逻辑] ...# (为保持简洁,此处省略内部循环,只展示TensorBoard记录点)# 训练阶段model.train()train_loss,train_correct=0.0,0train_pbar=tqdm(train_loader,desc=f"Epoch{epoch+1}/{epochs}[训练]")forinputs,labelsintrain_pbar:inputs,labels=inputs.to(device),labels.to(device)optimizer.zero_grad()outputs=model(inputs)loss=criterion(outputs,labels)loss.backward()optimizer.step()# 记录 batch-level 指标writer.add_scalar('Train/Batch_Loss',loss.item(),global_step)# 统计train_loss+=loss.item()*inputs.size(0)_,preds=torch.max(outputs,1)train_correct+=torch.sum(preds==labels.data)global_step+=1# 验证阶段model.eval()val_loss,val_correct=0.0,0wrong_images,wrong_labels,wrong_preds=[],[],[]withtorch.no_grad():forinputs,labelsintest_loader:inputs,labels=inputs.to(device),labels.to(device)outputs=model(inputs)loss=criterion(outputs,labels)val_loss+=loss.item()*inputs.size(0)_,preds=torch.max(outputs,1)val_correct+=torch.sum(preds==labels.data)# 收集错误样本mask=preds!=labelsifmask.any()andlen(wrong_images)<8:wrong_images.extend(inputs[mask][:8-len(wrong_images)].cpu())# --- TensorBoard 核心记录点 (Epoch-level) ---avg_train_loss=train_loss/len(train_dataset)avg_train_acc=train_correct.double()/len(train_dataset)avg_val_loss=val_loss/len(test_dataset)avg_val_acc=val_correct.double()/len(test_dataset)writer.add_scalar('Loss/Train',avg_train_loss,epoch)writer.add_scalar('Accuracy/Train',avg_train_acc,epoch)writer.add_scalar('Loss/Validation',avg_val_loss,epoch)writer.add_scalar('Accuracy/Validation',avg_val_acc,epoch)writer.add_scalar('Learning_Rate',optimizer.param_groups[0]['lr'],epoch)# 记录权重直方图forname,paraminmodel.named_parameters():writer.add_histogram(f'Weights/{name.replace(".","/")}',param,epoch)# 记录错误预测图像ifwrong_images:img_grid=torchvision.utils.make_grid(wrong_images)writer.add_image('Validation/Wrong_Predictions',img_grid,epoch)# 打印并更新学习率print(f"Epoch{epoch+1}/{epochs}- Acc:{avg_val_acc:.4f}, Loss:{avg_val_loss:.4f}")scheduler.step(avg_val_loss)writer.close()print("训练完成,TensorBoard日志已保存。")# --- 4. 主函数 ---defmain():epochs=15freeze_epochs=3# 初始化 TensorBoard SummaryWriterlog_dir="runs/day45_resnet18_finetune"ifos.path.exists(log_dir):version=1whileos.path.exists(f"{log_dir}_v{version}"):version+=1log_dir=f"{log_dir}_v{version}"writer=SummaryWriter(log_dir)print(f"TensorBoard 日志目录:{log_dir}")print("启动命令: tensorboard --logdir=runs")model=create_resnet18(pretrained=True,num_classes=10)optimizer=optim.Adam(model.fc.parameters(),lr=1e-3)criterion=nn.CrossEntropyLoss()scheduler=optim.lr_scheduler.ReduceLROnPlateau(optimizer,'min',patience=3,factor=0.1,verbose=True)train_with_tb_monitoring(model,train_loader,test_loader,criterion,optimizer,scheduler,device,epochs=epochs,freeze_epochs=freeze_epochs,writer=writer)if__name__=="__main__":main()

2. 如何运行与查看结果

  1. 运行代码:将上述代码保存为day45_homework.py并运行。
  2. 启动TensorBoard:在代码运行的同时或运行结束后,打开一个新的终端,确保处于你的conda环境中,然后进入项目根目录,输入以下命令:
    tensorboard --logdir=runs
  3. 打开浏览器:在浏览器中访问终端提示的地址(通常是http://localhost:6006/)。

3. 预期可视化结果

你将在 TensorBoard 的网页中看到一个名为day45_resnet18_finetune(或更高版本)的实验记录,其中包含:

  • SCALARS
    • AccuracyLoss栏下各有TrainValidation两条曲线,你可以清晰地对比训练集和验证集的表现,判断是否过拟合。
    • Learning_Rate曲线,可以看到学习率在何时被ReduceLROnPlateau调度器降低了。
  • GRAPHS: ResNet18 庞大而清晰的网络结构图。
  • HISTOGRAMS:Weights目录下,包含模型每一层(如layer1/0/conv1,fc)的权重分布随 epoch 变化的动态图。你可以观察到在解冻后,底层网络的权重也开始发生变化。
  • IMAGES:Validation/Wrong_Predictions中展示了模型在每个 epoch 预测错误的一些样本,帮助我们直观理解模型的“盲点”。

再次感谢 @浙大疏锦行 老师,将我们从只会print的“代码小子”带成了能驾驭 TensorBoard 的“炼丹工程师”!

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

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

立即咨询