pytorch入门笔记06

  1. 1. TensorBoard可视化模型,数据,和训练
    1. 1.1. 设置TensorBoard
    2. 1.2. 向Tensorboard写入
    3. 1.3. 用Tensorboard查看模型
    4. 1.4. 添加一个“投影器”到TensorBoard
    5. 1.5. 用TensorBoard跟踪模型训练
    6. 1.6. 用TensorBoard评估训练模型

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 plt
import numpy as np

import torch
import torchvision
import torchvision.transforms as transforms
import torch.utils.data as Data

import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.tensorboard import SummaryWriter

# 参数
batch_size = 4

# transforms
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))]
)
# datasets
trainset = torchvision.datasets.FashionMNIST(
'./FashionMnist',
download=True,
train=True,
transform=transform
)
testset = torchvision.datasets.FashionMNIST(
'./FashionMnist',
download=True,
train=False,
transform=transform
)

# DataLoaders
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的先装上

1
pip install tensorboard

从torch.utils中导入tensorboard,定义一个SummaryWriter。

1
2
3
from torch.utils.tensorboard import SummaryWriter
# 定义一个log文件位置
writer = 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)

# 写到tensorboard当中
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]

# 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”,这会让图像更容易查看因为他们的背景是白色的:

用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]列表
inputs, labels = data

# 梯度参数赋0
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:
# ...记录running loss 的日志
writer.add_scalar('train_loss', running_loss / 1000,
epoch * len(trainLoader) + i)
# ...将模型对一个随机mini-batch的预测记录Matplotlib图标记录日志
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
# 1. 在一个test_size x num_class的tensor中获得预测概率
# 2. 获取test_size Tensor中的preds

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%在“曲线下方区域”,然而其他类型中要更低。