PyTorch 入门指南
学习 PyTorch
图像和视频
音频
后端
强化学习
在生产环境中部署 PyTorch 模型
Profiling PyTorch
代码变换与FX
前端API
扩展 PyTorch
模型优化
并行和分布式训练
边缘端的 ExecuTorch
推荐系统
多模态

使用 TensorBoard 可视化模型、数据和训练

60 分钟快速入门 中,我们向您展示了如何加载数据,将其输入到我们定义为 nn.Module 子类的模型中,在训练数据上训练该模型,并在测试数据上进行测试。为了了解训练过程,我们打印了一些统计信息,以便感知训练是否在进展。然而,我们可以做得更好:PyTorch 集成了 TensorBoard,这是一个专为可视化神经网络训练结果而设计的工具。本教程使用 Fashion-MNIST 数据集 展示了 TensorBoard 的一些功能,该数据集可以通过 torchvision.datasets 读取到 PyTorch 中。

在本教程中,我们将学习如何:

  1. 读取数据并应用适当的转换(与之前的教程几乎相同)。

  2. 设置 TensorBoard。

  3. 写入 TensorBoard。

  4. 使用 TensorBoard 检查模型架构。

  5. 使用 TensorBoard 以更少的代码创建我们在上一个教程中创建的可视化的交互版本。

具体来说,在第5点中,我们将看到:

  • 几种检查训练数据的方法

  • 如何在训练过程中跟踪模型的性能

  • 如何在模型训练完成后评估其性能。

我们将从与 CIFAR-10 教程 中相似的样板代码开始:

# imports
importmatplotlib.pyplotasplt
importnumpyasnp

importtorch
importtorchvision
importtorchvision.transformsastransforms

importtorch.nnasnn
importtorch.nn.functionalasF
importtorch.optimasoptim

# transforms
transform = transforms.Compose(
    [transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))])

# datasets
trainset = torchvision.datasets.FashionMNIST('./data',
    download=True,
    train=True,
    transform=transform)
testset = torchvision.datasets.FashionMNIST('./data',
    download=True,
    train=False,
    transform=transform)

# dataloaders
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                        shuffle=True, num_workers=2)


testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                        shuffle=False, num_workers=2)

# constant for classes
classes = ('T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
        'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle Boot')

# helper function to show an image
# (used in the `plot_classes_preds` function below)
defmatplotlib_imshow(img, one_channel=False):
    if one_channel:
        img = img.mean(dim=0)
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    if one_channel:
        plt.imshow(npimg, cmap="Greys")
    else:
        plt.imshow(np.transpose(npimg, (1, 2, 0)))

我们将根据该教程定义一个类似的模型架构,仅进行少量修改,以适应图像现在为单通道而非三通道,且大小为28x28而非32x32的情况:

classNet(nn.Module):
    def__init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 4 * 4, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    defforward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 4 * 4)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x


net = Net()

我们将定义与之前相同的 optimizercriterion

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

1. TensorBoard 配置

现在我们将设置 TensorBoard,从 torch.utils 中导入 tensorboard 并定义一个 SummaryWriter,这是我们向 TensorBoard 写入信息的关键对象。

fromtorch.utils.tensorboardimport SummaryWriter

# default `log_dir` is "runs" - we'll be more specific here
writer = SummaryWriter('runs/fashion_mnist_experiment_1')

请注意,仅这一行代码就会创建一个 runs/fashion_mnist_experiment_1 文件夹。

2. 写入 TensorBoard

现在让我们使用 make_grid 将一张图像写入到 TensorBoard 中 — 具体来说,是一个网格。

# get some random training images
dataiter = iter(trainloader)
images, labels = next(dataiter)

# create grid of images
img_grid = torchvision.utils.make_grid(images)

# show images
matplotlib_imshow(img_grid, one_channel=True)

# write to tensorboard
writer.add_image('four_fashion_mnist_images', img_grid)

正在运行

tensorboard --logdir=runs

在命令行中执行以下操作后,导航到 http://localhost:6006 应显示如下内容。

../_static/img/tensorboard_first_view.png

现在您已经知道如何使用 TensorBoard 了!不过,这个示例也可以在 Jupyter Notebook 中完成——TensorBoard 真正擅长的是创建交互式可视化。接下来我们将介绍其中之一,并在教程结束时介绍更多内容。

3. 使用 TensorBoard 检查模型

TensorBoard 的一大优势在于其能够可视化复杂的模型结构。让我们来可视化我们构建的模型。

writer.add_graph(net, images)
writer.close()

现在,刷新 TensorBoard 后,您应该会看到一个如下所示的“Graphs”(图表)标签:

../_static/img/tensorboard_model_viz.png

接下来,双击“Net”以展开它,查看构成模型的各个操作的详细视图。

TensorBoard 提供了一个非常方便的功能,用于将高维数据(如图像数据)可视化在低维空间中;我们接下来会介绍这一点。

4. 向 TensorBoard 添加“Projector”

我们可以通过 add_embedding 方法可视化高维数据的低维表示

# helper function
defselect_n_random(data, labels, n=100):
'''
    Selects n random datapoints and their corresponding labels from a dataset
    '''
    assert len(data) == len(labels)

    perm = torch.randperm(len(data))
    return data[perm][:n], labels[perm][:n]

# select random images and their target indices
images, labels = select_n_random(trainset.data, trainset.targets)

# get the class labels for each image
class_labels = [classes[lab] for lab in labels]

# log embeddings
features = images.view(-1, 28 * 28)
writer.add_embedding(features,
                    metadata=class_labels,
                    label_img=images.unsqueeze(1))
writer.close()

现在,在 TensorBoard 的“Projector”选项卡中,您可以看到这些 100 张图片——每张都是 784 维的——被投影到三维空间中。此外,这是交互式的:您可以点击并拖动来旋转三维投影。最后,提供几个使可视化更容易查看的技巧:在左上角选择“color: label”,并启用“night mode”,这将使图片更易于查看,因为它们的背景是白色的:

../_static/img/tensorboard_projector.png

现在我们已经彻底检查了数据,接下来让我们展示 TensorBoard 如何使模型训练和评估的跟踪更加清晰,从训练开始。

5. 使用 TensorBoard 跟踪模型训练

在前面的示例中,我们只是每2000次迭代简单地打印模型的运行损失。现在,我们将改为将运行损失记录到TensorBoard中,同时通过plot_classes_preds函数查看模型的预测结果。

# helper functions

defimages_to_probs(net, images):
'''
    Generates predictions and corresponding probabilities from a trained
    network and a list of images
    '''
    output = net(images)
    # convert output probabilities to predicted class
    _, preds_tensor = torch.max(output, 1)
    preds = np.squeeze(preds_tensor.numpy())
    return preds, [F.softmax(el, dim=0)[i].item() for i, el in zip(preds, output)]


defplot_classes_preds(net, images, labels):
'''
    Generates matplotlib Figure using a trained network, along with images
    and labels from a batch, that shows the network's top prediction along
    with its probability, alongside the actual label, coloring this
    information based on whether the prediction was correct or not.
    Uses the "images_to_probs" function.
    '''
    preds, probs = images_to_probs(net, images)
    # plot the images in the batch, along with predicted and true labels
    fig = plt.figure(figsize=(12, 48))
    for idx in np.arange(4):
        ax = fig.add_subplot(1, 4, idx+1, xticks=[], yticks=[])
        matplotlib_imshow(images[idx], one_channel=True)
        ax.set_title("{0}, {1:.1f}%\n(label: {2})".format(
            classes[preds[idx]],
            probs[idx] * 100.0,
            classes[labels[idx]]),
                    color=("green" if preds[idx]==labels[idx].item() else "red"))
    return fig

最后,让我们使用之前教程中的相同模型训练代码来训练模型,但每1000个批次将结果写入TensorBoard,而不是打印到控制台;这是通过使用add_scalar函数完成的。

此外,在训练过程中,我们将生成一张图像,显示模型预测结果与该批次中包含的四张图像的实际结果的对比。

running_loss = 0.0
for epoch in range(1):  # loop over the dataset multiple times

    for i, data in enumerate(trainloader, 0):

        # get the inputs; data is a list of [inputs, labels]
        inputs, labels = data

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if i % 1000 == 999:    # every 1000 mini-batches...

            # ...log the running loss
            writer.add_scalar('training loss',
                            running_loss / 1000,
                            epoch * len(trainloader) + i)

            # ...log a Matplotlib Figure showing the model's predictions on a
            # random mini-batch
            writer.add_figure('predictions vs. actuals',
                            plot_classes_preds(net, inputs, labels),
                            global_step=epoch * len(trainloader) + i)
            running_loss = 0.0
print('Finished Training')

您现在可以查看 scalars 标签,查看在 15,000 次训练迭代中绘制的运行损失:

../_static/img/tensorboard_scalar_runs.png

此外,我们还可以查看模型在整个学习过程中对任意批次所做的预测。请查看“Images”标签,并在“predictions vs. actuals”可视化下方滚动查看;这向我们展示了,例如,仅经过 3000 次训练迭代后,模型已经能够区分视觉上不同的类别,如衬衫、运动鞋和外套,尽管它此时还没有像训练后期那样自信:

../_static/img/tensorboard_images.png

在之前的教程中,我们查看了模型训练后的每类准确率;在这里,我们将使用 TensorBoard 为每个类绘制精度-召回曲线(这里有很好的解释)。

6. 使用 TensorBoard 评估训练好的模型

# 1. gets the probability predictions in a test_size x num_classes Tensor
# 2. gets the preds in a test_size Tensor
# takes ~10 seconds to run
class_probs = []
class_label = []
with torch.no_grad():
    for data in testloader:
        images, labels = data
        output = net(images)
        class_probs_batch = [F.softmax(el, dim=0) for el in output]

        class_probs.append(class_probs_batch)
        class_label.append(labels)

test_probs = torch.cat([torch.stack(batch) for batch in class_probs])
test_label = torch.cat(class_label)

# helper function
defadd_pr_curve_tensorboard(class_index, test_probs, test_label, global_step=0):
'''
    Takes in a "class_index" from 0 to 9 and plots the corresponding
    precision-recall curve
    '''
    tensorboard_truth = test_label == class_index
    tensorboard_probs = test_probs[:, class_index]

    writer.add_pr_curve(classes[class_index],
                        tensorboard_truth,
                        tensorboard_probs,
                        global_step=global_step)
    writer.close()

# plot all the pr curves
for i in range(len(classes)):
    add_pr_curve_tensorboard(i, test_probs, test_label)

您现在会看到一个“PR 曲线”标签页,其中包含每个类别的精确率-召回率曲线。您可以随意查看;您会发现,在某些类别上,模型的“曲线下面积”接近 100%,而在其他类别上,这个面积较低:

../_static/img/tensorboard_pr_curves.png

这就是对 TensorBoard 及其与 PyTorch 集成的介绍。当然,您可以在 Jupyter Notebook 中完成 TensorBoard 的所有功能,但使用 TensorBoard 时,您默认可以获得交互式的可视化效果。

本页目录