更新于 2026年7月25日

在网络模型的训练过程中,通常我们都需要观察其损失值或准确率的变化趋势来确定模型的优化方向,例如学习率的动态调整、惩罚项系数等等。同时,对于图像处理方向的朋友来说可能还希望能够可视化模型的特征图或者是样本分类类别在空间中的分布情况等。虽然这些结果我们可以在网络训练结果后取对应的变量通过matplotlib进行可视化,但是我们更希望的是在模型训练的过程中就对其各种状态进行可视化。

因此,对于上述需求我们可以借助谷歌开源的Tensorboard工具来进行实现。在本篇文章中,我们将会详细介绍如何在PyTorch中通过Tensorboard来对各类变量及指标进行可视化。

9.1 安装与调试#

如果需要在PyTorch中使用Tensorboard除了需要安装Tensorboard工具本身之外,还需要安装的便是TensorFlow本身。因为Tensorboard在使用中会依赖于TensorFlow框架。

9.1.1 安装启动#

对于TensorFlow和Tensorboard的安装,我们只需要执行安装TensorFlow的命令便可以同时完成两者的安装:

1 pip install tensorflow

同时,由于我们只是借助于Tensorboard来进行可视化,因此在安装TensorFlow的时候不用区分是GPU还是CPU版本的,我们测试了都可以。也就是说假如你在某台主机上装了GPU版本的PyTorch,而不管你是装的GPU版还是CPU版的TensorFlow,Tensorboard都可以正常使用。

在安装成功之后通过可以通过如下命令来进行测试:

1 tensorboard --logdir=runs

并会出现如下提示:

1 TensorBoard 1.15.0 at http://localhost:6006/ (Press CTRL+C to quit)

也就是说此时我们便可以通过127.0.0.1:6006这个链接来访问Tensorboard的可视化页面,如图9-1所示。

图 9-1. Tensorboard启动成功图
图 9-1. Tensorboard启动成功图

如果你发现打不开这里地址,那么可以尝试通过如下命令来进行启动,然后再通过127.0.0.1:6006这个链接来访问。

1 tensorboard --logdir=runs --host 0.0.0.0

命令中的 --logdir 用来指定可视化文件的目录地址,后续我们会详细介绍。

9.1.2 远程连接#

上面我们介绍了如何在本地安装与启动 Tensorboard,但是更常见的一种场景便是在远程主机上运行代码,但是需要在本地电脑上查看可视化的运行结果。如果需要实现这种目的通常来说有两种方法,下面就来分别进行介绍。

(1) 通过IP直接访问

在通过IP直接访问的方案中,不管你是在类似于腾讯云或阿里云上租用的主机还是实验室的专用主机,在根据第9.1.1节中的步骤完成 Tensorboard 安装并启动后,你在自己电脑上都可以通过主机IP来进行访问,例如:

1 http://10.67.25.113:6006

需要注意的是,上面的IP对于公网主机(如腾讯云)来说指的是主机的公网IP,对于实验室或学校的主机来说指的则是局域网的内网IP。同时,如果在主机上启动Tensorboard后发现在本地并不能够打开,那么可以通过如下方式来进行排查:

情况一:互联网主机

  • 在后台的安全策略里面查看一下6006这个端口有没有被打开,如果没有则需要打开;

  • 查看IP是否为公网IP,在主机的后台管理页面可以看到。

情况二:局域网主机

  • 查看本地电脑是否和主机处于同一网段;

  • 查看主机的6006端口是否打开,如果没有可以通过如下命令打开

1 firewall-cmd --zone=public --list-ports # 查看已开放端口
2 firewall-cmd --zone=public --add-port=5672/tcp --permanent #开放5672端口
3 firewall-cmd --zone=public --remove-port=5672/tcp --permanent #关闭5672
4 firewall-cmd --reload   # 配置立即生效

(2) SSH转发访问

当然,除了通过直接IP访问之外,我们还可以借助SSH反向隧道技术来进行访问,例如服务器只开了22端口而且你没有权限打开其它端口的情况。在这种情况下,你可以通过下面两种方式来进行远程连接:

方式一:命令行终端

如果你的命令行终端支持SSH命令(例如较新的Windows10 的CMD或者Linux等)的话,那么可以直接通过下面这一条命令来进行连接:

1 ssh -L 16006:127.0.0.1:6006 username@ip

这条命令的含义就是将服务器上6006端口的信息通过SSH转发到本地的16006端口,其中16006是本地的任意端口(无限制),只要不和本地应用有冲突就行;后面则是对应的用户名和IP。

上述命令连接成功并根据第9.1.1节中的命令在远程主机上启动 Tensorboard之后,在本地通过浏览器打开如下地址即可:

1 http://127.0.0.1:16006

方式二:Xshell工具

如果你的电脑终端不支持SSH命令的话,那么你还可以通过Xshell工具来实现SSH反向代理。首先你需要安装好Xshell工具,安装完成后再按照如下步骤配置。

第1步:新建连接

图 9-2. 新建连接(一)
图 9-2. 新建连接(一)

如图2所示,点击新建连接。

然后再根据图9-3所示的界面配置主机信息。

图 9-3. 新建连接(二)
图 9-3. 新建连接(二)

第2步:配置代理

进一步,如图9-4所示点击侧边栏的隧道,并点击右侧的添加按钮。

图 9-4. 配置代理(一)
图 9-4. 配置代理(一)

接着再根据图9-5所示的示例进行端口代理配置。

图 9-5. 配置代理(二)
图 9-5. 配置代理(二)

配置完成后点击图9-6中的确认即可。

图 9-6. 配置代理(三)
图 9-6. 配置代理(三)

完成上述两步配置之后,再双击刚刚这个新建的连接输入用户名和密码之后即可登录到主机并对相应的端口进行了监听与转发。最后我们同样只需要先在当前的命令行中启动Tensorboard,再在本地浏览器中通过如下地址进行访问即可:

1 http://127.0.0.1:16006

9.2 使用 Tensorboard#

下面,我们将先通过一个简单的示例来展示如何可视化标量数据并在Tensorboard中进行显示;然后再来依次介绍一些常用的可视化方法。本节所有示例代码可在[12]处获取。

9.2.1 add_scalar 方法#

这个方法通常用来可视化网络训练时的各类标量参数,例如损失、学习率和准确率等。如下便是add_scalar方法的使用示例:

1 from torch.utils.tensorboard import SummaryWriter
2 if __name__ == '__main__':     
3     writer = SummaryWriter(log_dir="runs/result_1", flush_secs=120)
4     for n_iter in range(100):
5         writer.add_scalar(tag='Loss/train',
6                           scalar_value=np.random.random(),
7                           global_step=n_iter)
8         writer.add_scalar('Loss/test', np.random.random(), n_iter)
9     writer.close()

在上述代码中,第1行用来导入相关的可视化模块;第3行是实例化一个可视化类对象,log_dir 用于指定可视化数据的保存路径,flush_secs 表示指定多少秒将数据写入到本地一次(默认为120秒);第5~7行则是利用 add_scalar 方法来对相关标量进行可视化,其中 tag 表示对应的标签信息。

在上述代码运行之前,先进入到该代码文件所在的目录,然后运行如下命令来启动 Tensorboard:

1 tensorboard --logdir=runs
2 	
3 TensorBoard 1.15.0 at http://localhost:6006/ (Press CTRL+C to quit)

可以看出,logdir 后面的参数就是上面代码第3行里的参数。同时,根据提示在浏览器中打开上述链接便可以看到如图9-1所示的界面。

接着开始运行上述程序,此时便会在当前目录中生成如图9-7所示的文件(夹),其中 result_1 便是前面所指定的子目录,而以 events.out 开始的文件则是生成的相关可视化事件。

图 9-7. 可视化数据文件图
图 9-7. 可视化数据文件图

当程序运行时Tensorboard便会加载图9-7中所示的文件并在网页端进行渲染,如图9-8所示。

图 9-8. Tensorboard可视化结果图
图 9-8. Tensorboard可视化结果图

如图9-8所示为Tensorboard的可视化结果图,其中右边的 Loss 标签就是上面第5行代码中指定的 Loss/train 参数的前缀部分,也就是说如果想把若干个图放到一个标签下,那么就要保持其前缀一致,例如这里的 Loss/train 和 Loss/test 这两个图都将被放在Loss这个标签下。同时,在勾选左上角的 “Show data download links” 后,还能点击图片下方的按钮来分别下载SVG矢量图、原始图片的CSV或JSON数据。

在图9-8的左边部分,Smoothing 参数用来调整右侧可视化结果的平滑度;Horizontal Axis 用来切换不同的显示模式;Runs下面用来勾选需要可视化的结果,例如后续在初始化 SummaryWriter() 时指定 log_dir="runs/result_2" ,那么在result_1下方便会再出现一个result_2的选项,这时我们可以选择多个结果同时可视化展示。

下面,我们开始逐一介绍几个常用的可视化方法。

9.2.2 add_graph 方法#

从名字可以看出 add_graph 方法是用于可视化模型的网络结构图,其用法示例如下:

1 import torchvision
2 def add_graph(writer):
3     img = torch.rand([1, 3, 64, 64], dtype=torch.float32)
4     model = torchvision.models.AlexNet(num_classes=10)
5     writer.add_graph(model, input_to_model=img) #类似于TensorFlow 1.x中的feed

为了示例简洁,我们这里又把 SummaryWriter() 中的 add_graph 方法写成了一个函数。在上述代码中,第4行用于返回一个网络模型;第5行则是对网络结构图进行可视化,其中 input_to_model 参数为模型所接收的输入,这类似于 TensorFlow 1.x 版本中的 feed_dict 参数。

上述代码开始运行之后,便可以在网页端看到如图9-9所示的可视化结果。

图 9-9. 网络结构图
图 9-9. 网络结构图

如图9-9所示便是可视化后的网络结构图,对于右侧网络结构中的每个模块都可以双击进行展开,而左边则是相关模式的切换。

9.2.3 add_scalars 方法#

这个方法与 add_scalar 的差别在于 add_scalars 在一张图中可以绘制多个曲线,此时只需我们要以字典的形式传入需要可视化的参数即可,如下为 add_scalars 方法的使用示例:

 1 def add_scalars(writer):
 2     r = 5
 3     for i in range(100):
 4         writer.add_scalars(main_tag='scalars1/P1',
 5                            tag_scalar_dict={'xsinx': i  np.sin(i / r),
 6                                             'xcosx': i  np.cos(i / r),
 7                                             'tanx': np.tan(i / r)},
 8                            global_step=i)
 9         writer.add_scalars('scalars1/P2',
10                            {'xsinx': i  np.sin(i / (2  r)),
11                             'xcosx': i  np.cos(i / (2  r)),
12                             'tanx': np.tan(i / (2  r))}, i)
13         writer.add_scalars(main_tag='scalars2/Q1',
14                            tag_scalar_dict={'xsinx':i  np.sin((2  i) / r),
15                                             'xcosx':i  np.cos((2  i) / r),
16                                             'tanx':np.tan((2  i) / r)},
17                            global_step=i)
18         writer.add_scalars('scalars2/Q2',
19                            {'xsinx': i  np.sin(i / (0.5  r)),
20                             'xcosx': i  np.cos(i / (0.5  r)),
21                             'tanx': np.tan(i / (0.5  r))}, i)

在上述代码中,我们一共画了4个图,分别对应代码中的4个 add_scalars;同时在每张图里面都都对应了3条曲线,也即 add_scalars 方法里的 tag_scalar_dict 参数;并且这里一共用了2个标签来进行分隔,即 scalars1scalars2 。可视化的结果如图9-10所示。

图 9-10. add_scalars可视化结果图
图 9-10. add_scalars可视化结果图

9.2.4 add_histogram 方法#

直方图一般被用于可视化网络层中参数的分布情况,其使用示例也比较简单, 代码如下所示:

1 def add_histogram(writer):
2     for i in range(10):
3         x = np.random.random(1000)
4         writer.add_histogram('distribution centers/p1', x + i, i)
5         writer.add_histogram('distribution centers/p2', x + i  2, i)

上述代码运行结束后,其可视化后结果如图9-11所示。

图 9-11. add_histogram可视化结果图
图 9-11. add_histogram可视化结果图

9.2.5 add_image 方法#

add_image 方法通常是用来可视化相应的像素矩阵,例如本地图片,或者是特征图等,其示例代码如下所示:

1 def add_image(writer):
2     from PIL import Image
3     img1 = np.random.randn(1, 100, 100)
4     writer.add_image('img/imag1', img1)
5     img2 = np.random.randn(100, 100, 3)
6     writer.add_image('img/imag2', img2, dataformats='HWC')
7     img = Image.open('./dufu.png')
8     img_array = np.array(img)
9     writer.add_image('local/dufu', img_array, dataformats='HWC')

在上述代码中,第3~4行用于生成一个形状为[C,H,W]的3维矩阵并进行可视化;第5~6行则是生成形状为[H,W,C]的3维矩阵并可视化,同时需要在add_image中指定矩阵的维度信息,因此可以看出add_image方法接受的默认格式为[C,H,W];第7~9行则是先从本地读取一张图片,然后再对其进行可视化,如图9-12所示。

图 9-12. add_image可视化结果图
图 9-12. add_image可视化结果图

如图9-12所示,上面部分则是两个大小为 的像素矩阵可视化结果。下面部分则是本地图片的可视化结果。

9.2.6 add_images 方法

从名字可以看出,该方法是一次性可视化多张像素矩阵图,使用示例如下:

1 def add_images(writer):
2     img1 = np.random.randn(8, 100, 100, 1)
3     writer.add_images('imgs/imags1', img1, dataformats='NHWC')
4     img2 = np.zeros((16, 3, 100, 100))
5     for i in range(16):
6         img2[i, 0] = np.arange(0, 10000).reshape(100, 100) / 10000 / 16  i
7         img2[i, 1] = (1 - np.arange(0, 10000).reshape(100, 100)/10000)/16  i
8     writer.add_images('imgs/imags2', img2)  # Default is :math:(N, 3, H, W)

在上述代码中,第2~3行用于生成8张通道数为1的像素矩阵并进行可视化。第4~8行则是生成16张通道数为3的像素矩阵并进行可视化。最后可视化的结果如图9-13所示。

图 9-13. add_images可视化结果图
图 9-13. add_images可视化结果图

如图9-13所示,左边是8张通道数为1的像素矩阵可视化结果。右边是16张通道数为3的像素矩阵可视化结果。

9.2.7 add_figure 方法#

这个方法的作用是用来将 matplotlib 包中的 figure 对象可视化到 Tensorboard 的网页端,用于展示一些较为复杂的图片,其示例用法如下:

1 def add_figure(writer):
2     fig = plt.figure(figsize=(5, 4))
3     ax = fig.add_axes([0.12, 0.1, 0.85, 0.8])
4     xx = np.arange(-5, 5, 0.01)
5     ax.plot(xx, np.sin(xx), label="sin(x)")
6     ax.legend()
7     fig.suptitle('Sin(x) figure\n\n', fontweight="bold")
8     writer.add_figure("figure", fig, 4)

在上述代码中,第2~7行为根据 matplotlib 包绘制相应的图像,其中第3行用来指定;第8行则是将其在 Tensorboard 中进行可视化;第9行则是直接在程序里进行可视化。最后可视化的结果如图9-14所示。

图 9-14. add_figure 可视化结果图
图 9-14. add_figure 可视化结果图

如果要一次在 Tensorboard 中可视化一组图像的话,可以通过如下方式实现:

 1 def add_figures(writer, images, labels):
 2     text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
 3                    'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
 4     labels = [text_labels[int(i)] for i in labels]
 5     fit, ax = plt.subplots(len(images)//5,5,figsize=(10,2len(images)//5))
 6     for i, axi in enumerate(ax.flat):
 7         image, label = images[i].reshape([28, 28]).numpy(), labels[i]
 8         axi.imshow(image)
 9         axi.set_title(label)
10         axi.set(xticks=[], yticks=[])
11     writer.add_figure("figure", fit)

在上述代码中,我们选择是的FashionMNIST数据集进行的可视化;第5行代码用来生成一个包含有若干个子图的画布;第6~10行是分别用来画出每一个子图;第10行用来去掉横纵坐标的信息;第11行则是将其在Tensorboard中进行展示。最终可视化后的结果如图9-15所示。

图 9-15. add_figure可视化结果图
图 9-15. add_figure可视化结果图

9.2.8 add_pr_curve 方法#

add_pr_curve 这个方法是用来在训练过程中可视化 Precision-Recall 曲线,即观察在不同阈值下精确率与召回率的平衡情况。用法示例如下所示:

 1 def add_pr_curve(writer):
 2     from sklearn.linear_model import LogisticRegression
 3     from sklearn.preprocessing import label_binarize
 4     def get_dataset():
 5         from sklearn.datasets import load_iris
 6         from sklearn.model_selection import train_test_split
 7         x, y = load_iris(return_X_y=True)
 8         random_state = np.random.RandomState(2020)
 9         n_samples, n_features = x.shape
10         # 为数据增加噪音维度以便更好观察pr曲线
11         x = np.concatenate([x, random_state.randn(
12                       n_samples, 100  n_features)], axis=1)
13         x_train, x_test, y_train, y_test = train_test_split(
14               x, y, test_size=0.5,random_state=random_state)
15         return x_train, x_test, y_train, y_test
16 
17     x_train, x_test, y_train, y_test = get_dataset()
18     model = LogisticRegression(multi_class="ovr")
19     model.fit(x_train, y_train)
20     y_scores = model.predict_proba(x_test)  # shape: (n,3)
21 
22     b_y = label_binarize(y_test, classes=[0, 1, 2])  # shape: (n,3)
23     for i in range(3):
24         writer.add_pr_curve(f"pr_curve/label_{i}", b_y[:, i],
25                               y_scores[:, i], global_step=1)

在上述代码中,第2~19行代码用来根据逻辑回归生成预测结果,其中第11行用来给原始数据加入噪音,目的是为了可视化得到更加真实的PR曲线;第21行用来将原始标签转化为one-hot编码形式的标签;第22~23行则是分别根据每个类别的预测结果画出对应的PR曲线。运行上述代码将会得到类似如图9-16所示的结果。

图 9-16. add_pr_curve可视化结果图
图 9-16. add_pr_curve可视化结果图

9.2.9 add_embedding 方法#

这个方法作用是在三维空间中对高维向量进行可视化,默认情况下是对高维向量以PCA方法进行降维处理。add_embedding() 方法主要有三个比较重要的参数 matmetadatalabel_img ,下面依次来进行介绍。

  • mat:用来指定可视化结果中每个点的坐标,形状为$(N, D)$,不能为空,例如对词向量可视化时mat就是词向量矩阵,图片分类时mat可以是分类层的输出结果;

  • metadata:用来指定每个点对应的标签信息,是一个包含$N$个元素的字符串列表,为空时则默认为[‘1’,‘2’,….,‘N’];

  • label_img:用来指定每个点对应可视化信息,形状为$(N, C, H, W)$,可以为空,例如图片分类时label_img就是每一张真实图片的可视化结果。

  • 进一步,我们便可以通过如下代码来进行3维空间的高维向量可视化:

 1 def add_embedding(writer):
 2     import tensorflow as tf
 3     import tensorboard as tb
 4     tf.io.gfile = tb.compat.tensorflow_stub.io.gfile
 5     import keyword
 6     import torch
 7     # 随机生成100个标签信息
 8     meta = []
 9     while len(meta) < 100:
10         meta = meta + keyword.kwlist  # get some strings
11     meta = meta[:100]
12     for i, v in enumerate(meta):
13         meta[i] = v + str(i)
14     # 随机生成100个标签图片
15     label_img = torch.rand(100, 3, 10, 32)
16     for i in range(100):
17         label_img[i] = i / 100.0
18     data_points = torch.randn(100, 5)  # 随机生成100个点
19     writer.add_embedding(mat=data_points, metadata=meta, 
20         label_img=label_img, global_step=1)

在上述代码中,第2~4行用于解决TensorFlow1.x版本的兼容性问题;第8~13行则是随机生成100个字符串标签信息;第15~17行则是生成标签对应的图片;第18行则是随机生成需要可视化的高维向量。上述代码运行结束后便会得到如图9-17所示的结果。

图 9-17. add_embedding可视化结果图
图 9-17. add_embedding可视化结果图

如图9-17所示,字符串就是上面代码中对应的metadata参数,黑色方块就是对应的label_img参数,而方块背后的点(图中看不到)就是对应的mat参数。这里我们只是用了随机数据生成了上面这张图,在下一小节中我们将会用一个实际的例子来进行展示。

9.3 使用实例#

9.3.1 定义模型#

这里以 LeNet5 网络模型进行示例,所以首先需要定义模型的前向传播过程,代码如下:

 1 import torch.nn as nn
 2 
 3 class LeNet5(nn.Module):
 4     def __init__(self, ):
 5         super(LeNet5, self).__init__()
 6         self.conv = nn.Sequential(  
 7             nn.Conv2d(1, 6, 5, padding=2),  
 8             nn.ReLU(),  
 9             nn.MaxPool2d(2, 2),  
10             nn.Conv2d(6, 16, 5), 
11             nn.ReLU(),
12             nn.MaxPool2d(2, 2)) 
13 
14         self.fc = nn.Sequential(
15             nn.Flatten(),
16             nn.Linear(16  5  5, 120),
17             nn.ReLU(),
18             nn.Linear(120, 84),
19             nn.ReLU(),
20             nn.Linear(84, 10))
21 
22     def forward(self, img, labels=None):
23         output = self.conv(img)
24         logits = self.fc(output)
25         if labels is not None:
26             loss_fct = nn.CrossEntropyLoss(reduction='mean')
27             loss = loss_fct(logits, labels)
28             return loss, logits
29         else:
30             return logits

在上述代码中,第25~30行为根据不同的输入情况返回不同的结果。其余部的代码相对较为简单这里就不再赘述了。

9.3.2 定义分类模型#

第1步:数据集构造

首先,我们需要构造训练模型时使用到的数据集,这里还是以FashionMNIST为例进行示例。构造代码如下所示:

 1 text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
 2                'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
 3 
 4 def load_dataset(batch_size=64):
 5     mnist_train = torchvision.datasets.FashionMNIST(download=True,
 6                         root='~/Datasets/FashionMNIST',train=True,
 7                                   transform=transforms.ToTensor())
 8     mnist_test = torchvision.datasets.FashionMNIST(download=True,
 9                       root='~/Datasets/FashionMNIST',train=False, 
10                                   transform=transforms.ToTensor())
11     train_iter = torch.utils.data.DataLoader(mnist_train,
12                  batch_size=batch_size,shuffle=True,num_workers=1)
13     test_iter = torch.utils.data.DataLoader(mnist_test,
14                  batch_size=batch_size,shuffle=True,num_workers=1)
15     return train_iter, test_iter

在上述代码中,第1~2行为定义的每个标签序号所对应的标签名,用于在使用add_embedding可视化预测结果时展示每个样本的标签名称;第5~15行则是分别构造训练集和测试集的DataLoader对象。 第2步:定义分类模型 进一步,我们需要定义一个类来实现模型的整个训练和推理过程。首先定义这个类的初始化方法,代码如下:

 1 class MyModel:
 2     def __init__(self,
 3                  batch_size=64,
 4                  epochs=3,
 5                  learning_rate=0.01):
 6         self.batch_size = batch_size
 7         self.epochs = epochs
 8         self.learning_rate = learning_rate
 9         self.model_save_path = 'model.pt'
10         self.device = torch.device('cuda:0' 
11                     if torch.cuda.is_available() else 'cpu')
12         self.model = LeNet5()

第2步:定义评估方法

在这里,我们先定义一个评估函数,用来计算在测试集上模型的准确率。同时返回我们在使用Tensorboard可视化时需要用到的相关变量,代码如下:

 1     @staticmethod
 2     def evaluate(data_iter, net, device):
 3         net.eval()
 4         all_logits = []
 5         y_labels = []
 6         images = []
 7         with torch.no_grad():
 8             acc_sum, n = 0.0, 0
 9             for x, y in data_iter:
10                 x, y = x.to(device), y.to(device)
11                 logits = net(x)
12                 acc_sum += (logits.argmax(1) == y).float().sum().item()
13                 n += len(y)
14                 all_logits.append(logits)
15                 y_pred = logits.argmax(1).view(-1)
16                 y_labels += (text_labels[i] for i in y_pred)
17                 images.append(x)
18             net.train()
19             return acc_sum / n, torch.cat(all_logits, dim=0),
20                             y_labels, torch.cat(images, dim=0)

在上述代码中,第1行表示将这个方法声明为静态方法,因为函数里面没有使用到相关类成员;第4~6行分别定义了3个列表用于保存所有样本的预测logits向量、标签文本和原始表示;第10~13行用来累计预测正确样本的个数;第14~17分别用来处理得到在使用add_embedding时所需要用到的变量;第19行则是返回所有需要用到的结果。

第3步:定义训练过程

在完成上述步骤后便可以来实现模型训练部分的代码,同时对需要可视化的变量进行记录。由于这部分代码较长,下面就分块进行介绍。

 1     def train(self):
 2         train_iter, test_iter = load_dataset(self.batch_size)
 3         last_epoch = -1
 4         if os.path.exists('./model.pt'):
 5             checkpoint = torch.load('./model.pt')
 6             last_epoch = checkpoint['last_epoch']
 7             self.model.load_state_dict(checkpoint['model_state_dict'])
 8 
 9         num_training_steps = len(train_iter)  self.epochs
10         optimizer = torch.optim.Adam([{"params": self.model.parameters(),
11                                        "initial_lr": self.learning_rate}])
12         scheduler = get_cosine_schedule_with_warmup(optimizer, num_warmup_steps=300,
13                                  num_training_steps=num_training_steps,
14                                  num_cycles=2, last_epoch=last_epoch)

在上述代码中,第4~7行用来判断本地是否存在之前保存的模型,如果存在则直接载入,而 last_epoch 是用来获取得到之前模型结束训练时的状态,目的是能够使得Tensorboard在可视化的时候能够接着之前的数据集进行可视化。第10~14行则是用来分别定义优化器和学习率动态调整策略。

进一步,实现模型训练时损失、准确率和学习率的可视化过程,代码如下:

 1         writer = SummaryWriter("runs/nin")
 2         max_test_acc = 0
 3         for epoch in range(self.epochs):
 4             for i, (x, y) in enumerate(train_iter):
 5                 x, y = x.to(self.device), y.to(self.device)
 6                 loss, logits = self.model(x, y)
 7                 optimizer.zero_grad()
 8                 loss.backward()
 9                 optimizer.step()
10                 scheduler.step()
11                 if i % 50 == 0:
12                     acc = (logits.argmax(1) == y).float().mean()
13                     print(f"# Epochs [{epoch + 1}/{ self.epochs}]-batch"
14                     f"[{len(train_iter)}/{i}]-acc {acc}-loss {loss.item()}")
15                     writer.add_scalar('Training/Accuracy', acc, 
16                                           scheduler.last_epoch)
17                 writer.add_scalar('Training/Loss', loss.item(), 
18                                           scheduler.last_epoch)
19                 writer.add_scalar('Training/Learning Rate', 
20                                   scheduler.get_last_lr()[0], 
21                                   scheduler.last_epoch)

在上述代码中,第1行用来实例化 SummaryWriter 用于后续可视化操作;第5~14行则是用来执行整个模型的训练过程;第15~18行则是用来分别对训练集上的准确率、损失和学习率进行可视化。

最后一步便是通过 add_embedding 来对预测结果进行可视化,代码如下:

1             acc, all_logits, y_labels, label_img = 
2                           self.evaluate(test_iter,self.model, self.device)
3             writer.add_scalar('Testing/Accuracy',acc, scheduler.last_epoch)
4             writer.add_embedding(mat=all_logits,  # 所有点
5                                  metadata=y_labels,  # 标签名称
6                                  label_img=label_img,  # 标签图片
7                                  global_step=scheduler.last_epoch)

在上述代码中,第1~2行主要用来获取 add_embedding 所需要的遍历;第3~7行则是分别对测试集上的准确率和预测结果进行可视化。

9.3.3 可视化展示#

在完成所有部分的编码工作后,便可以通过如下代码来运行整个模型:

1 if __name__ == '__main__':
2     model = MyModel()
3     model.train()

在程序运行开始后,便可以通过第9.1节中的方式启动 Tensorboard 前端界面,并可以看到如图9-18所示的可视化结果。

图 9-18. LeNet5训练可视化结果图
图 9-18. LeNet5训练可视化结果图

如图9-18所示便是模型在训练集上的准确率、学习率和损失的变化结果。进一步,我们可以将分类后的结果在空间中进行展示,如图9-19所示。

图 9-19. LeNet5模型预测标签可视化结果图(一)
图 9-19. LeNet5模型预测标签可视化结果图(一)

如图19所示便是模型在测试集上的预测结果经过 add_embedding 方法可视化后的结果,其中每个小方块都表示一个原始样本,每种颜色代表一个类别。进一步,点击任意方块便可以查看该样本的相关信息,如图9-20所示。

图 9-20. LeNet5模型预测标签可视化结果图(二)
图 9-20. LeNet5模型预测标签可视化结果图(二)

如图9-20所示便是ankle boot的可视化结果,并且可以发现只要点击其中一个样本,与它类别相同的样本也会被标记出来。当然,该页面还有其它相应的功能大家可以试着去探索,这里就不进行介绍了。

到此,对于Tensorboard的使用方法就介绍完了。

您当前阅读的系列内容有完整版高清 PDF ,点击右侧了解

近200页高清 PDF + 80页配套PPT、高清无水印网络结构图,打印学习更方便!

查看详情
阅读 --

第5节 基于BERT预训练模型的文本蕴含任务

本文是 BERT 精读系列第5讲,详细讲解如何基于 huggingface bert-base-uncased 预训练权重在 MNLI 自然语言推断任务上微调文本蕴含模型。覆盖文本对分类与单文本分类的核心差异:Segment …

第6节 基于BERT预训练模型的SWAG选择任务

本文是 BERT 精读系列第6讲,详细讲解如何基于 huggingface bert-base-uncased 预训练权重在 SWAG 常识推理四选一任务上微调。覆盖问答选择与文本蕴含的核心差异:将问题与每个候选答案分别拼接成 4 个序列, …

第7节 自定义学习率动态调整

本文是 BERT 精读系列第7讲,作为 BERT 第8讲 SQuAD 问答任务的过渡篇,系统讲清 Transformer 论文中提出的 Noam 动态学习率调整策略:从 warmup 公式 d_model^{-0.5} · …

第8节 基于BERT预训练模型的SQuAD问答任务

本文是 BERT 精读系列第8讲,详细讲解如何基于 huggingface bert-base-uncased 在 SQuAD 斯坦福问答数据集上微调阅读理解模型。覆盖问题回答与文本蕴含的核心差异:把 (问题, 描述) 拼接后让 BERT …