本文最后编辑于 前,其中的内容可能需要更新。
TensorBoard可视化模型,数据,和训练 这里用FashionMnist数据集作为例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import matplotlib.pyplot as pltimport numpy as npimport torchimport torchvisionimport torchvision.transforms as transformsimport torch.utils.data as Dataimport torch.nn as nnimport torch.nn.functional as Fimport torch.optim as optimfrom torch.utils.tensorboard import SummaryWriterbatch_size = 4 transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5 ,), (0.5 ,))] ) trainset = torchvision.datasets.FashionMNIST( './FashionMnist' , download=True , train=True , transform=transform ) testset = torchvision.datasets.FashionMNIST( './FashionMnist' , download=True , train=False , transform=transform ) trainLoader = Data.DataLoader(trainset, batch_size=batch_size, shuffle=True , num_workers=0 ) testLoader = Data.DataLoader(testset, batch_size=batch_size, shuffle=True , num_workers=0 ) classes = ('T-shirt/top' , 'Trouser' , 'Pullover' , 'Dress' , 'Coat' , 'Sandal' , 'Shirt' , 'Sneaker' , 'Bag' , 'Ankle Boot' ) def matplotlib_imshow (img, one_channel=False ): if one_channel: img = img.mean(dim=0 ) img = img / 2 + 0.5 npimg = img.numpy() if one_channel: plt.imshow(npimg, cmap="Greys" ) else : plt.imshow(np.transpose(npimg, (1 , 2 , 0 )))
这块没什么难度,和前面加载数据是一样的,不懂得话见前面的笔记。
创建一个简单的网络模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Net (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 ) def forward (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()
这块和前面笔记一样的,只不过注意下这里Mnist数据集是单通道的,28x28的格式,相应的地方需要改动。
定义优化器和损失函数
1 2 criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001 , momentum=0.9 )
设置TensorBoard 这里多说一句没有tensorboard的先装上
从torch.utils中导入tensorboard,定义一个SummaryWriter。
1 2 3 from torch.utils.tensorboard import SummaryWriterwriter = SummaryWriter('runs/fashion_mnist_experiment1' )
向Tensorboard写入 写入一个图片到Tensorboard,使用make_grid生成的网格(多个图片布局到一张上)
1 2 3 4 5 6 7 8 9 10 11 12 13 dataiter = iter (trainLoader) images, lables = dataiter.next () img_grid = torchvision.utils.make_grid(images) matplotlib_imshow(img_grid, one_channel=True ) writer.add_image('four_fashion_mnist_images' , img_grid) writer.close()
这里一定记得要close掉,不然tensorboard报错。后面的例子都是用完writer之后要关闭。
跑命令
1 tensorboard --logdir=runs
logdir后面就是log文件位置。跑完之后会在控制台显示访问那个网址。如图
点击即可访问。
用Tensorboard查看模型 TensorBoard的强大之一是他能够将复杂的模型结构可视化,让我们看下我们做的模型。
1 2 writer.add_graph(net, images) writer.close()
刷新Tensorboard之后你能看见一个“Graph”标签。
双击“Net”后,能看见网络被展开,查看组成模型的各个操作的详细视图。TensorBoard有一个非常方便的功能来可视化高维数据,如低维空间中的图像数据;下面我们将讨论这个问题。
添加一个“投影器”到TensorBoard 我们可以通过add_embedding方法可视化高维数据的低维表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def select_n_random (data, labels, n=100 ): ''' 从数据集中随机选择n个数据点和对应的标签 ''' assert len (data) == len (labels) perm = torch.randperm(len (data)) return data[perm][:n], labels[perm][:n] images, labels = select_n_random(trainset.data, trainset.targets) class_labels = [classes[lab] for lab in labels] 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”,这会让图像更容易查看因为他们的背景是白色的:
用TensorBoard跟踪模型训练 在前面的例子里,我们简单每2000此迭代打印模型跑的误差。现在,我们将把运行损失记录到TensorBoard,并查看模型通过plot_classes_preds函数做出的预测。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 def images_to_probs (net, images ): ''' 从一个训练网络和一个列表的图片中生成预测和对应可能性 ''' output = net(images) _, 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)] def plot_class_preds (net, images, labels ): ''' 生成matplotlib图使用训练网络,连同图像 以及从一批数据中提取的标签,这些标签显示了网络的顶级预测 用它的概率,和实际的标签一起,给这个上色 基于预测是否正确的信息。 使用"images_to_probs"函数。 ''' preds, probs = images_to_probs(net, images) 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批次写入结果到Tensor board,而不是打印到控制台;用add_scalar方法完成。
此外,在训练时,我们将生成一张图像,显示模型的预测与该批处理中包含的4张图像的实际结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 running_loss = 0.0 for epoch in range (1 ): for i, data in enumerate (trainLoader,0 ): inputs, labels = data optimizer.zero_grad() outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() if i % 1000 == 999 : writer.add_scalar('train_loss' , running_loss / 1000 , epoch * len (trainLoader) + i) writer.add_figure("predictions vs. actuals" , plot_class_preds(net, inputs, labels), global_step=epoch*len (trainLoader) + i) running_loss = 0.0 writer.close() print ('Finish Training' )
你可以在Scalar标签出查看15000次迭代训练中的运行误差
用TensorBoard评估训练模型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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) def add_pr_curve_tensorboard (class_index, test_probs, test_label, global_step=0 ): ''' 接收一个从0到9的“class_index”并绘制相应的precision-recall曲线 ''' 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() for i in range (len (classes)): add_pr_curve_tensorboard(i, test_probs, test_label)
你会看到一个“PR Curves”标签,包含了每个类的PR曲线。到处看看看,你会看到一些类型的模型几乎100%在“曲线下方区域”,然而其他类型中要更低。