【深入浅出PyTorch】--7.2.PyTorch可视化2

目录

3.TensorBoard--可视化训练过程

3.1.TensorBoard--基本逻辑

3.2.TensorBoard-配置与启动

3.3.TensorBoard--模型结构可视化

3.4.TensorBoard--图像可视化

3.5.TensorBoard--连续变量可视化

3.6.TensorBoard--参数分布可视化

3.7.服务器端使用TensorBoard

3.8.总结

4.wandb--可视化训练过程

4.1.wandb的安装

4.2.wandb的使用

4.3.wandb的demo演示


3.TensorBoard--可视化训练过程

训练过程的可视化在深度学习模型训练中扮演着重要的角色。学习的过程是一个优化的过程,我们需要找到最优的点作为训练过程的输出产物 。一般来说,我们会结合训练集的损失函数和验证集的损失函数,绘制两条损失函数的曲线来确定训练的终点,找到对应的模型用于测试。那么除了记录训练中每个epoch的loss值,能否实时观察损失函数曲线的变化,及时捕捉模型的变化呢?

此外,我们也希望可视化其他内容,如输入数据(尤其是图片)、模型结构、参数分布等,这些对于我们在debug中查找问题来源非常重要(比如输入数据和我们想象的是否一致)。

TensorBoard作为一款可视化工具能够满足上面提到的各种需求。TensorBoard由TensorFlow团队开发,最早和TensorFlow配合使用,后来广泛应用于各种深度学习框架的可视化中来。本节我们探索TensorBoard的强大功能,希望帮助读者"从入门到精通"。

经过本节的学习,你将收获:

  • 安装TensorBoard工具

  • 了解TensorBoard可视化的基本逻辑

  • 掌握利用TensorBoard实现训练过程可视化

  • 掌握利用TensorBoard完成其他内容的可视化

3.1.TensorBoard--基本逻辑

我们可以将TensorBoard看做一个记录员,它可以记录我们指定的数据,包括模型每一层的feature map,权重,以及训练loss等等。TensorBoard将记录下来的内容保存在一个用户指定的文件夹里,程序不断运行中TensorBoard会不断记录。记录下的内容可以通过网页的形式加以可视化。

3.2.TensorBoard-配置与启动

在使用TensorBoard前,我们需要先指定一个文件夹供TensorBoard保存记录下来的数据。然后调用tensorboard中的SummaryWriter作为上述"记录员"

python 复制代码
from tensorboardX import SummaryWriter

writer = SummaryWriter('./runs')

上面的操作实例化SummaryWritter为变量writer,并指定writer的输出目录为当前目录下的"runs"目录。也就是说,之后tensorboard记录下来的内容都会保存在runs。

如果使用PyTorch自带的tensorboard,则采用如下方式import:

python 复制代码
from torch.utils.tensorboard import SummaryWriter

启动tensorboard也很简单,在命令行中输入

bash 复制代码
tensorboard --logdir=/path/to/logs/ --port=xxxx
  • "path/to/logs/"是指定的保存tensorboard记录结果的文件路径(等价于上面的"./runs",
  • port是外部访问TensorBoard的端口号,可以通过访问ip:port访问tensorboard,这一操作和jupyter notebook的使用类似。如果不是在服务器远程使用的话则不需要配置port。

有时,为了tensorboard能够不断地在后台运行,也可以使用nohup命令或者tmux工具来运行tensorboard。大家可以自行搜索,这里不展开讨论了。

下面,我们将模拟深度学习模型训练过程,来介绍如何利用TensorBoard可视化其中的各个部分。

3.3.TensorBoard--模型结构可视化

首先定义模型:

bash 复制代码
import torch.nn as nn

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3,out_channels=32,kernel_size = 3)
        self.pool = nn.MaxPool2d(kernel_size = 2,stride = 2)
        self.conv2 = nn.Conv2d(in_channels=32,out_channels=64,kernel_size = 5)
        self.adaptive_pool = nn.AdaptiveMaxPool2d((1,1))
        self.flatten = nn.Flatten()
        self.linear1 = nn.Linear(64,32)
        self.relu = nn.ReLU()
        self.linear2 = nn.Linear(32,1)
        self.sigmoid = nn.Sigmoid()

    def forward(self,x):
        x = self.conv1(x)
        x = self.pool(x)
        x = self.conv2(x)
        x = self.pool(x)
        x = self.adaptive_pool(x)
        x = self.flatten(x)
        x = self.linear1(x)
        x = self.relu(x)
        x = self.linear2(x)
        y = self.sigmoid(x)
        return y

model = Net()
print(model)

可视化模型的思路和7.1中介绍的方法一样,都是给定一个输入数据,前向传播后得到模型的结构,再通过TensorBoard进行可视化,使用add_graph:

python 复制代码
import torch

writer.add_graph(model, input_to_model = torch.rand(1, 3, 224, 224))
writer.close()

把生成的文件拖到英文路径下:改名为11,

路径不要带中文字符否者报错,加载的是绝对路径

bash 复制代码
python -m tensorboard.main --logdir=./test --host=0.0.0.0 --port=6006

http://0.0.0.0:6006/

3.4.TensorBoard--图像可视化

当我们做图像相关的任务时,可以方便地将所处理的图片在tensorboard中进行可视化展示。

  • 对于单张图片的显示使用add_image

  • 对于多张图片的显示使用add_images

  • 有时需要使用torchvision.utils.make_grid将多张图片拼成一张图片后,用writer.add_image显示

这里我们使用torchvision的CIFAR10数据集为例:

bash 复制代码
import torchvision
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
from tensorboardX import SummaryWriter

transform_train = transforms.Compose(
    [transforms.ToTensor()])
transform_test = transforms.Compose(
    [transforms.ToTensor()])

train_data = datasets.CIFAR10(".", train=True, download=True, transform=transform_train)
test_data = datasets.CIFAR10(".", train=False, download=True, transform=transform_test)
train_loader = DataLoader(train_data, batch_size=64, shuffle=True)
test_loader = DataLoader(test_data, batch_size=64)

images, labels = next(iter(train_loader))

# 仅查看一张图片
writer = SummaryWriter('./pytorch_tb')
writer.add_image('images[0]', images[0])
writer.close()

# 将多张图片拼接成一张图片,中间用黑色网格分割
# create grid of images
# writer = SummaryWriter('./pytorch_tb')
# img_grid = torchvision.utils.make_grid(images)
# writer.add_image('image_grid', img_grid)
# writer.close()
#
# # 将多张图片直接写入
# writer = SummaryWriter('./pytorch_tb')
# writer.add_images("images",images,global_step = 0)
# writer.close()
bash 复制代码
 python -m tensorboard.main --logdir=./pytorch_tb --host=0.0.0.0 --port=6006 

另外注意上方menu部分,刚刚只有"GRAPHS"栏对应模型的可视化,现在则多出了"IMAGES"栏对应图像的可视化。左侧的滑动按钮可以调整图像的亮度和对比度。

此外,除了可视化原始图像,TensorBoard提供的可视化方案自然也适用于我们在Python中用matplotlib等工具绘制的其他图像,用于展示分析结果等内容。

3.5.TensorBoard--连续变量可视化

TensorBoard可以用来可视化连续变量(或时序变量)的变化过程,通过add_scalar实现:

bash 复制代码
writer = SummaryWriter('./pytorch_tb')
for i in range(500):
    x = i
    y = x**2
    writer.add_scalar("x", x, i) #日志中记录x在第step i 的值
    writer.add_scalar("y", y, i) #日志中记录y在第step i 的值
writer.close()

可视化结果如下:

如果想在同一张图中显示多个曲线,则需要分别建立存放子路径(使用SummaryWriter指定路径即可自动创建,但需要在tensorboard运行目录下),同时在add_scalar中修改曲线的标签使其一致即可:

bash 复制代码
writer1 = SummaryWriter('./pytorch_tb/x')
writer2 = SummaryWriter('./pytorch_tb/y')
for i in range(500):
    x = i
    y = x*2
    writer1.add_scalar("same", x, i) #日志中记录x在第step i 的值
    writer2.add_scalar("same", y, i) #日志中记录y在第step i 的值
writer1.close()
writer2.close()

这里也可以用一个writer,但for循环中不断创建SummaryWriter不是一个好选项。此时左下角的Runs部分出现了勾选项,我们可以选择我们想要可视化的曲线。曲线名称对应存放子路径的名称(这里是x和y)。

这部分功能非常适合损失函数的可视化,可以帮助我们更加直观地了解模型的训练情况,从而确定最佳的checkpoint。左侧的Smoothing滑动按钮可以调整曲线的平滑度,当损失函数震荡较大时,将Smoothing调大有助于观察loss的整体变化趋势。

3.6.TensorBoard--参数分布可视化

当我们需要对参数(或向量)的变化,或者对其分布进行研究时,可以方便地用TensorBoard来进行可视化,通过add_histogram实现。下面给出一个例子:

bash 复制代码
import torch
import numpy as np
from torch.utils.tensorboard import SummaryWriter  # 导入 TensorBoard 可视化工具

# 定义一个函数,用于生成服从正态分布的张量(模拟神经网络参数)
def norm(mean, std):
    """
    生成一个形状为 (100, 20) 的张量,其元素服从均值为 mean、标准差为 std 的正态分布。
    这可以用来模拟某一层神经网络的参数(如权重)。
    
    参数:
        mean (float): 正态分布的均值
        std (float): 正态分布的标准差
    
    返回:
        torch.Tensor: 形状为 (100, 20) 的张量
    """
    t = std * torch.randn((100, 20)) + mean  # torch.randn 生成标准正态分布(均值0,标准差1)
    return t

# 创建一个 SummaryWriter 实例,将日志写入 './pytorch_tb/' 目录
# 后续可通过 `tensorboard --logdir=./pytorch_tb/` 在浏览器中查看可视化结果
writer = SummaryWriter('./pytorch_tb/')

# 遍历均值从 -10 到 9(步长为 1),共 20 个 step
for step, mean in enumerate(range(-10, 10, 1)):
    # 生成当前均值下的参数张量(标准差固定为 1)
    w = norm(mean, 1)

    writer.add_histogram("w", w, step)
    
    # 立即将数据写入磁盘(确保日志及时保存,便于实时查看)
    writer.flush()

# 关闭 SummaryWriter,释放资源并确保所有数据写入完成
writer.close()

3.7.服务器端使用TensorBoard

一般情况下,我们会连接远程的服务器来对模型进行训练,但由于服务器端是没有浏览器的(纯命令模式),因此,我们需要进行相应的配置,才可以在本地浏览器,使用tensorboard查看服务器运行的训练过程。 本文提供以下几种方式进行,其中前两种方法都是建立SSH隧道,实现远程端口到本机端口的转发,最后一种方法适用于没有下载Xshell等SSH连接工具的用户

  • MobaXterm

    1. 在MobaXterm点击Tunneling

    2. 选择New SSH tunnel,我们会出现以下界面。

    1. 对新建的SSH通道做以下设置,第一栏我们选择Local port forwarding< Remote Server>我们填写localhost< Remote port>填写6006,tensorboard默认会在6006端口进行显示,我们也可以根据 tensorboard --logdir=/path/to/logs/ --port=xxxx 的命令中的port进行修改,< SSH server> 填写我们连接服务器的ip地址,<SSH login>填写我们连接的服务器的用户名,<SSH port>填写端口号(通常为22),< forwarded port>填写的是本地的一个端口号,以便我们后面可以对其进行访问。

    2. 设定好之后,点击Save,然后Start。在启动tensorboard,这样我们就可以在本地的浏览器输入http://localhost:6006/对其进行访问了

  • Xshell

    1. Xshell的连接方法与MobaXterm的连接方式本质上是一样的,具体操作如下:

    2. 连接上服务器后,打开当前会话属性,会出现下图,我们选择隧道,点击添加

    3. 按照下方图进行选择,其中目标主机代表的是服务器,源主机代表的是本地,端口的选择根据实际情况而定。

    4. 启动tensorboard,在本地127.0.0.1:6006 或者 localhost:6006进行访问。

  • SSH

    1. 该方法是将服务器的6006端口重定向到自己机器上来,我们可以在本地的终端里输入以下代码:其中16006代表映射到本地的端口,6006代表的是服务器上的端口。
    复制代码
      ssh -L 16006:127.0.0.1:6006 username@remote_server_ip
    1. 在服务上使用默认的6006端口正常启动tensorboard
    复制代码
    tensorboard --logdir=xxx --port=6006
    1. 在本地的浏览器输入地址
    复制代码
    127.0.0.1:16006 或者 localhost:16006

3.8.总结

对于TensorBoard来说,它的功能是很强大的,可以记录的东西不只限于本节所介绍的范围。

主要的实现方案是构建一个SummaryWriter,然后通过add_XXX()函数来实现。

其实TensorBoard的逻辑还是很简单的,它的基本逻辑就是文件的读写逻辑,写入想要可视化的数据,然后TensorBoard自己会读出来。

4.wandb--可视化训练过程

我们使用了Tensorboard可视化训练过程,但是Tensorboard对数据的保存仅限于本地 ,也很难分析超参数不同对实验的影响。

wandb的出现很好的解决了这些问题,因此在本章节中,我们将对wandb进行简要介绍。 wandb是Weights & Biases( 权重和偏差**)** 的缩写,它能够自动记录模型训练过程中**的超参数和输出指标,然后可视化和比较结果,**并快速与其他人共享结果。目前它能够和Jupyter、TensorFlow、Pytorch、Keras、Scikit、fast.ai、LightGBM、XGBoost一起结合使用。

经过本节的学习,你将收获:

  • wandb的安装

  • wandb的使用

  • demo演示

4.1.wandb的安装

wandb的安装非常简单,我们只需要使用pip安装即可。

bash 复制代码
pip install wandb

安装完成后,我们需要在官网注册一个账号并复制下自己的API keys,然后在本地使用下面的命令登录。https://wandb.ai/site

需要连接外网。call me

bash 复制代码
wandb login

这时,我们会看到下面的界面,只需要粘贴你的API keys即可。

4.2.wandb的使用

wandb的使用也非常简单,只需要在代码中添加几行代码即可。

bash 复制代码
import wandb
wandb.init(project='my-project', entity='my-name')

这里的project和entity是你在wandb上创建的项目名称和用户名 ,如果你还没有创建项目,可以参考官方文档

bash 复制代码
#api:#api接口:5db56bbfd6a1c2feb98f219ffb789d9660afa761


import wandb
wandb.init(project='my-project', entity='2898694631-gyp')

4.3.wandb的demo演示

下面我们使用一个CIFAR10的图像分类demo来演示wandb的使用。

python 复制代码
import random  # to set the python random seed
import numpy  # to set the numpy random seed
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
from torchvision.models import resnet18
import warnings
warnings.filterwarnings('ignore')#忽略警告warning

使用wandb的第一步是初始化wandb,这里我们使用wandb.init()函数来初始化wandb,其中project是你在wandb上创建的项目名称,name是你的实验名称。

python 复制代码
# 初始化wandb
import wandb
wandb.init(project="my-project",
           name="wandb_demo",)

使用wandb的第二步是设置超参数,这里我们使用wandb.config来设置超参数,这样我们就可以在wandb的界面上看到超参数的变化。wandb.config的使用方法和字典类似,我们可以使用config.key的方式来设置超参数。

python 复制代码
# 超参数设置
config = wandb.config  # config的初始化
config.batch_size = 64  
config.test_batch_size = 10 
config.epochs = 5  
config.lr = 0.01 
config.momentum = 0.1  
config.use_cuda = True  
config.seed = 2043  
config.log_interval = 10 

# 设置随机数
def set_seed(seed):
    random.seed(config.seed)      
    torch.manual_seed(config.seed) 
    numpy.random.seed(config.seed) 

第三步是构建训练和测试的pipeline,这里我们使用pytorch的CIFAR10数据集和resnet18来构建训练和测试的pipeline。

python 复制代码
# 定义训练函数:对模型进行一个 epoch 的训练
def train(model, device, train_loader, optimizer):
    model.train()  # 将模型设为训练模式(启用梯度、BatchNorm 等)

    for batch_id, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)  # 数据迁移到指定设备(CPU/GPU)
        optimizer.zero_grad()                              # 清空优化器中的梯度
        output = model(data)                               # 前向传播,得到模型输出
        criterion = nn.CrossEntropyLoss()                  # 定义交叉熵损失函数
        loss = criterion(output, target)                   # 计算损失
        loss.backward()                                    # 反向传播,计算梯度
        optimizer.step()                                   # 更新模型参数


# 定义测试函数:评估模型性能,并通过 wandb 记录指标和示例图像
def test(model, device, test_loader, classes):
    model.eval()  # 将模型设为评估模式(关闭 Dropout、冻结 BatchNorm)
    test_loss = 0
    correct = 0
    example_images = []  # 用于保存预测示例图像

    with torch.no_grad():  # 禁用梯度计算,加速推理并节省显存
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            criterion = nn.CrossEntropyLoss()
            test_loss += criterion(output, target).item()  # 累加损失值
            pred = output.max(1, keepdim=True)[1]          # 获取预测类别(最大 logit 的索引)
            correct += pred.eq(target.view_as(pred)).sum().item()  # 统计正确预测数量

            # 将第一个样本的图像及预测/真实标签保存为 wandb.Image 对象
            example_images.append(wandb.Image(
                data[0], caption="Pred:{} Truth:{}".format(classes[pred[0].item()], classes[target[0]])))

    # 使用 wandb.log 记录测试阶段的关键指标和可视化示例
    wandb.log({
        "Examples": example_images,                        # 可视化预测样例
        "Test Accuracy": 100. * correct / len(test_loader.dataset),  # 测试准确率(%)
        "Test Loss": test_loss                         # 测试总损失(未平均)
    })


# 防止 wandb.watch 被重复调用(兼容性处理)
wandb.watch_called = False


# 主函数:配置环境、加载数据、初始化模型并开始训练
def main():
    use_cuda = config.use_cuda and torch.cuda.is_available()
    device = torch.device("cuda:0" if use_cuda else "cpu")
    kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}

    # 设置随机种子,保证实验可复现
    set_seed(config.seed)
    torch.backends.cudnn.deterministic = True

    # 定义数据预处理流程:转为 Tensor 并标准化(CIFAR-10 常用均值/标准差)
    transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ])

    # 加载 CIFAR-10 训练数据集
    train_loader = DataLoader(datasets.CIFAR10(
        root='dataset',
        train=True,
        download=True,
        transform=transform
    ), batch_size=config.batch_size, shuffle=True, **kwargs)

    # 加载 CIFAR-10 测试数据集
    test_loader = DataLoader(datasets.CIFAR10(
        root='dataset',
        train=False,
        download=True,
        transform=transform
    ), batch_size=config.batch_size, shuffle=False, **kwargs)

    # CIFAR-10 数据集的 10 个类别名称
    classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

    # 加载预训练的 ResNet18 模型,并移动到指定设备
    model = resnet18(pretrained=True).to(device)
    # 注意:此处未修改最后的分类层,若用于 CIFAR-10 可能存在类别数不匹配问题(但代码未改)

    # 定义优化器:使用 SGD,传入学习率和动量参数
    optimizer = optim.SGD(model.parameters(), lr=config.lr, momentum=config.momentum)

    # 使用 wandb 监控模型(记录参数、梯度、计算图等)
    wandb.watch(model, log="all")

    # 开始训练循环:逐 epoch 训练并测试
    for epoch in range(1, config.epochs + 1):
        train(model, device, train_loader, optimizer)
        test(model, device, test_loader, classes)

    # 保存训练好的模型到本地文件
    torch.save(model.state_dict(), 'model.pth')
    # 同时将模型文件同步到 wandb 云端
    wandb.save('model.pth')


# 程序入口
if __name__ == '__main__':
    main()

哎,中国大陆要断开,真麻烦,用一下别人的实验结果

我们可以发现,使用wandb可以很方便的记录我们的训练结果,除此之外,wandb还为我们提供了很多的功能,比如:模型的超参数搜索,模型的版本控制,模型的部署等等。这些功能都可以帮助我们更好的管理我们的模型,更好的进行模型的迭代和优化。这些功能我们在后面的更新中会进行介绍。

相关推荐
青瓷程序设计4 小时前
动物识别系统【最新版】Python+TensorFlow+Vue3+Django+人工智能+深度学习+卷积神经网络算法
人工智能·python·深度学习
tobebetter95274 小时前
How to manage python versions on windows
开发语言·windows·python
F_D_Z5 小时前
数据集相关类代码回顾理解 | sns.distplot\%matplotlib inline\sns.scatterplot
python·深度学习·matplotlib
daidaidaiyu5 小时前
一文入门 LangGraph 开发
python·ai
金智维科技官方5 小时前
RPA财务机器人为企业高质量发展注入动能
人工智能·机器人·rpa·财务
沫儿笙5 小时前
安川机器人tag焊接怎么节省保护气
人工智能·物联网·机器人
2501_941147425 小时前
人工智能赋能智慧教育互联网应用:智能学习与教育管理优化实践探索》
人工智能
阿龙AI日记6 小时前
详解Transformer04:Decoder的结构
人工智能·深度学习·自然语言处理
爱写代码的小朋友6 小时前
“数字镜像”与认知负能者:生成式AI个性化学习支持者的协同构建与伦理规制研究
人工智能
找方案6 小时前
新型智慧城市城市大数据应用解决方案
人工智能·智慧城市