Skip to content

Latest commit

ย 

History

History
385 lines (287 loc) ยท 15.9 KB

tensorboard_tutorial.rst

File metadata and controls

385 lines (287 loc) ยท 15.9 KB

TensorBoard๋กœ ๋ชจ๋ธ, ๋ฐ์ดํ„ฐ, ํ•™์Šต ์‹œ๊ฐํ™”ํ•˜๊ธฐ

:doc:`/beginner/deep_learning_60min_blitz` ์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ , nn.Module ์˜ ์„œ๋ธŒํด๋ž˜์Šค(subclass)๋กœ ์ •์˜ํ•œ ๋ชจ๋ธ์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต๊ธ‰(feed)ํ•˜๊ณ , ํ•™์Šต ๋ฐ์ดํ„ฐ๋กœ ๋ชจ๋ธ์„ ํ•™์Šตํ•˜๊ณ  ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค. ์ง„ํ–‰ ์ƒํ™ฉ์„ ์‚ดํŽด๋ณด๊ธฐ ์œ„ํ•ด, ํ•™์Šต์ด ์ง„ํ–‰ ์ค‘์ผ ๋•Œ ํ•™์Šต์ด ์ž˜ ๋˜๊ณ  ์žˆ๋Š”์ง€๋ฅผ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด ๋ช‡๋ช‡ ์ˆ˜์น˜๋“ค(statistic)์„ ์ถœ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•๋„ ์žˆ์Šต๋‹ˆ๋‹ค: PyTorch๋Š” ์‹ ๊ฒฝ๋ง ํ•™์Šต ๋‚ด์—ญ์„ ์‹œ๊ฐํ™”ํ•˜๋Š” ๋„๊ตฌ์ธ TensorBoard์™€ ํ†ตํ•ฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” PyTorch์˜ torchvision.datasets ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ Fashion-MNIST dataset ์œผ๋กœ ์ผ๋ถ€ ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ๋‹ค์Œ์˜ ๋‚ด์šฉ๋“ค์„ ๋ฐฐ์›๋‹ˆ๋‹ค:

  1. (์ด์ „ ํŠœํ† ๋ฆฌ์–ผ๊ณผ ๊ฑฐ์˜ ๋น„์Šทํ•˜๊ฒŒ) ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์ ์ ˆํžˆ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  2. TensorBoard๋ฅผ ์„ค์ •(set up)ํ•ฉ๋‹ˆ๋‹ค.
  3. TensorBoard์— ๊ธฐ๋ก(write)ํ•ฉ๋‹ˆ๋‹ค.
  4. TensorBoard๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋ธ ๊ตฌ์กฐ๋ฅผ ์‚ดํŽด๋ด…๋‹ˆ๋‹ค.
  5. ์•ฝ๊ฐ„์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ TensorBoard์—์„œ ์ด์ „ ํŠœํ† ๋ฆฌ์–ผ์—์„œ ๋งŒ๋“  ์‹œ๊ฐํ™”์˜ ๋Œ€ํ™”์‹(interactive) ๋ฒ„์ „์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๊ตฌ์ฒด์ ์œผ๋กœ #5์—์„œ๋Š” ๋‹ค์Œ ๋‚ด์šฉ๋“ค์„ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค:

  • ํ•™์Šต ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์‚ฌ(inspect)ํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•
  • ํ•™์Šต์— ๋”ฐ๋ฅธ ๋ชจ๋ธ์˜ ์„ฑ๋Šฅ์„ ์ถ”์ (track)ํ•˜๋Š” ๋ฐฉ๋ฒ•
  • ํ•™์Šต์ด ์™„๋ฃŒ๋œ ๋ชจ๋ธ์˜ ์„ฑ๋Šฅ์„ ํ‰๊ฐ€(assess)ํ•˜๋Š” ๋ฐฉ๋ฒ•

:doc:`/beginner/blitz/cifar10_tutorial` ์™€ ๋น„์Šทํ•œ ์ฝ”๋“œ๋กœ ์‹œ์ž‘ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

# imports
import matplotlib.pyplot as plt
import numpy as np

import torch
import torchvision
import torchvision.transforms as transforms

import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

# 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)

# ๋ถ„๋ฅ˜ ๊ฒฐ๊ณผ๋ฅผ ์œ„ํ•œ ์ƒ์ˆ˜
classes = ('T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
        'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle Boot')

# ์ด๋ฏธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ ํ—ฌํผ(helper) ํ•จ์ˆ˜
# (์•„๋ž˜ `plot_classes_preds` ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉ)
def matplotlib_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)))

์ด์ „ ํŠœํ† ๋ฆฌ์–ผ๊ณผ ์œ ์‚ฌํ•œ ๋ชจ๋ธ ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•˜๋˜, ์ด๋ฏธ์ง€์˜ ์ฑ„๋„์ด 3๊ฐœ์—์„œ 1๊ฐœ๋กœ, ํฌ๊ธฐ๊ฐ€ 32x32์—์„œ 28x28๋กœ ๋ณ€๊ฒฝ๋œ ๊ฒƒ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์•ฝ๊ฐ„๋งŒ ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค:

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()

๋™์ผํ•œ optimizer ์™€ criterion ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค:

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

1. TensorBoard ์„ค์ •

์ด์ œ torch.utils ์˜ tensorboard ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ , TensorBoard์— ์ •๋ณด๋ฅผ ์ œ๊ณต(write)ํ•˜๋Š” SummaryWriter ๋ฅผ ์ฃผ์š”ํ•œ ๊ฐ์ฒด์ธ SummaryWriter ๋ฅผ ์ •์˜ํ•˜์—ฌ TensorBoard๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

from torch.utils.tensorboard import SummaryWriter

# ๊ธฐ๋ณธ `log_dir` ์€ "runs"์ด๋ฉฐ, ์—ฌ๊ธฐ์„œ๋Š” ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ์ง€์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค
writer = SummaryWriter('runs/fashion_mnist_experiment_1')

์œ„ ํ–‰(line)์€ runs/fashion_mnist_experiment_1 ํด๋”๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

2. TensorBoard์— ๊ธฐ๋กํ•˜๊ธฐ

์ด์ œ TensorBoard์— ์ด๋ฏธ์ง€(๊ตฌ์ฒด์ ์œผ๋กœ๋Š” make_grid ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ทธ๋ฆฌ๋“œ(grid))๋ฅผ ์จ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

# ์ž„์˜์˜ ํ•™์Šต ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
dataiter = iter(trainloader)
images, labels = next(dataiter)

# ์ด๋ฏธ์ง€ ๊ทธ๋ฆฌ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
img_grid = torchvision.utils.make_grid(images)

# ์ด๋ฏธ์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
matplotlib_imshow(img_grid, one_channel=True)

# tensorboard์— ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
writer.add_image('four_fashion_mnist_images', img_grid)

์ด์ œ ๋ช…๋ น์ค„(command line)์—์„œ

tensorboard --logdir=runs

๋ฅผ ์‹คํ–‰ํ•˜๊ณ , http://localhost:6006 ์„ ์—ด์–ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ™”๋ฉด์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

../../_static/img/tensorboard_first_view.png

์ง€๊ธˆ๊นŒ์ง€ TensorBoard๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€๋ฅผ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค! ๊ทธ๋Ÿฌ๋‚˜, ์ด ์˜ˆ์ œ๋Š” Jupyter Notebook์—์„œ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค - TensorBoard๋Š” ๋Œ€ํ™”ํ˜• ์‹œ๊ฐํ™”๋ฅผ ๋งŒ๋“œ๋Š”๋ฐ ํŠนํžˆ ๋›ฐ์–ด๋‚ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์— ๊ทธ๋Ÿฐ ๊ธฐ๋Šฅ๋“ค ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ดํŽด๋ณด๊ณ , ํŠœํ† ๋ฆฌ์–ผ์˜ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์—์„œ ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋Šฅ๋“ค์„ ๋” ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

3. TensorBoard๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋ธ ์‚ดํŽด๋ณด๊ธฐ(inspect)

TensorBoard์˜ ๊ฐ•์  ์ค‘ ํ•˜๋‚˜๋Š” ๋ณต์žกํ•œ ๋ชจ๋ธ ๊ตฌ์กฐ๋ฅผ ์‹œ๊ฐํ™”ํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ๋งŒ๋“  ๋ชจ๋ธ์„ ์‹œ๊ฐํ™”ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

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

TensorBoard๋ฅผ ์ƒˆ๋กœ๊ณ ์นจ(refresh)ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด "Graphs" ํƒญ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

../../_static/img/tensorboard_model_viz.png

์•„๋ž˜์—์„œ "Net"์„ ๋”๋ธ”ํด๋ฆญํ•˜์—ฌ ํŽผ์ณ๋ณด๋ฉด, ๋ชจ๋ธ์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐœ๋ณ„ ์—ฐ์‚ฐ(operation)๋“ค์— ๋Œ€ํ•ด ์ž์„ธํžˆ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

TensorBoard๋Š” ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ์™€ ๊ฐ™์€ ๊ณ ์ฐจ์› ๋ฐ์ดํ„ฐ๋ฅผ ์ €์ฐจ์› ๊ณต๊ฐ„์— ์‹œ๊ฐํ™”ํ•˜๋Š”๋ฐ ๋งค์šฐ ํŽธ๋ฆฌํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค; ์•ž์œผ๋กœ ์ด ๋‚ด์šฉ์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

4. TensorBoard์— "Projector" ์ถ”๊ฐ€ํ•˜๊ธฐ

add_embedding ๋ฉ”์†Œ๋“œ(method)๋ฅผ ํ†ตํ•ด ๊ณ ์ฐจ์› ๋ฐ์ดํ„ฐ์˜ ์ €์ฐจ์› ํ‘œํ˜„(representation)์„ ์‹œ๊ฐํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# ํ—ฌํผ(helper) ํ•จ์ˆ˜
def select_n_random(data, labels, n=100):
    '''
    ๋ฐ์ดํ„ฐ์…‹์—์„œ n๊ฐœ์˜ ์ž„์˜์˜ ๋ฐ์ดํ„ฐํฌ์ธํŠธ(datapoint)์™€ ๊ทธ์— ํ•ด๋‹นํ•˜๋Š” ๋ผ๋ฒจ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค
    '''
    assert len(data) == len(labels)

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

# ์ž„์˜์˜ ์ด๋ฏธ์ง€๋“ค๊ณผ ์ •๋‹ต(target) ์ธ๋ฑ์Šค๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค
images, labels = select_n_random(trainset.data, trainset.targets)

# ๊ฐ ์ด๋ฏธ์ง€์˜ ๋ถ„๋ฅ˜ ๋ผ๋ฒจ(class label)์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
class_labels = [classes[lab] for lab in labels]

# ์ž„๋ฒ ๋”ฉ(embedding) ๋‚ด์—ญ์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค
features = images.view(-1, 28 * 28)
writer.add_embedding(features,
                    metadata=class_labels,
                    label_img=images.unsqueeze(1))
writer.close()

์ด์ œ TensorBoard์˜ "Projector" ํƒญ์—์„œ - ๊ฐ๊ฐ์€ 784 ์ฐจ์›์ธ - 100๊ฐœ์˜ ์ด๋ฏธ์ง€๊ฐ€ 3์ฐจ์› ๊ณต๊ฐ„์— ํˆฌ์‚ฌ(project)๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ด๊ฒƒ์€ ๋Œ€ํ™”์‹์ž…๋‹ˆ๋‹ค: ํด๋ฆญํ•˜๊ณ  ๋“œ๋ž˜๊ทธ(drag)ํ•˜์—ฌ 3์ฐจ์›์œผ๋กœ ํˆฌ์˜๋œ ๊ฒƒ์„ ํšŒ์ „ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ ์‹œ๊ฐํ™”๋ฅผ ๋” ํŽธํžˆ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ํŒ์ด ์žˆ์Šต๋‹ˆ๋‹ค: ์ขŒ์ธก ์ƒ๋‹จ์—์„œ "Color by: label"์„ ์„ ํƒํ•˜๊ณ , "์•ผ๊ฐ„๋ชจ๋“œ(night mode)"๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋ฉด ์ด๋ฏธ์ง€ ๋ฐฐ๊ฒฝ์ด ํฐ์ƒ‰์ด ๋˜์–ด ๋” ํŽธํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

../../_static/img/tensorboard_projector.png

์ง€๊ธˆ๊นŒ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์ถฉ๋ถ„ํžˆ ์‚ดํŽด๋ณด์•˜์œผ๋ฏ€๋กœ, ์ด์ œ ํ•™์Šต ๊ณผ์ •๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ TensorBoard๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ชจ๋ธ ํ•™์Šต๊ณผ ํ‰๊ฐ€(evaluation)๋ฅผ ๋” ๋ช…ํ™•ํžˆ ์ถ”์ (track)ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

5. TensorBoard๋กœ ๋ชจ๋ธ ํ•™์Šต ์ถ”์ ํ•˜๊ธฐ

์ด์ „ ์˜ˆ์ œ์—์„œ๋Š” ๋‹จ์ˆœํžˆ ๋ชจ๋ธ ํ•™์Šต ์ค‘ ์†์‹ค(running loss)์„ 2000๋ฒˆ ๋ฐ˜๋ณตํ•  ๋•Œ๋งˆ๋‹ค ์ถœ๋ ฅ ํ•˜๊ธฐ๋งŒ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ TensorBoard์— ํ•™์Šต ์ค‘ ์†์‹ค์„ ๊ธฐ๋กํ•˜๋Š” ๊ฒƒ ๋Œ€์‹ ์— plot_classes_preds ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ชจ๋ธ์˜ ์˜ˆ์ธก ๊ฒฐ๊ณผ๋ฅผ ํ•จ๊ป˜ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

# ํ—ฌํผ ํ•จ์ˆ˜

def images_to_probs(net, 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)]


def plot_classes_preds(net, images, labels):
    '''
    ํ•™์Šต๋œ ์‹ ๊ฒฝ๋ง๊ณผ ๋ฐฐ์น˜๋กœ๋ถ€ํ„ฐ ๊ฐ€์ ธ์˜จ ์ด๋ฏธ์ง€ / ๋ผ๋ฒจ์„ ์‚ฌ์šฉํ•˜์—ฌ matplotlib
    Figure๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‹ ๊ฒฝ๋ง์˜ ์˜ˆ์ธก ๊ฒฐ๊ณผ / ํ™•๋ฅ ๊ณผ ํ•จ๊ป˜ ์ •๋‹ต์„ ๋ณด์—ฌ์ฃผ๋ฉฐ,
    ์˜ˆ์ธก ๊ฒฐ๊ณผ๊ฐ€ ๋งž์•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์ƒ‰์„ ๋‹ค๋ฅด๊ฒŒ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. "images_to_probs"
    ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    '''
    preds, probs = images_to_probs(net, images)
    # ๋ฐฐ์น˜์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์™€ ์˜ˆ์ธก ๊ฒฐ๊ณผ / ์ •๋‹ต๊ณผ ํ•จ๊ป˜ ํ‘œ์‹œ(plot)ํ•ฉ๋‹ˆ๋‹ค
    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 ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, ํ•™์Šต์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ ๋ฐฐ์น˜์— ํฌํ•จ๋œ 4๊ฐœ์˜ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ๋ชจ๋ธ์˜ ์˜ˆ์ธก ๊ฒฐ๊ณผ์™€ ์ •๋‹ต์„ ๋น„๊ต(versus)ํ•˜์—ฌ ๋ณด์—ฌ์ฃผ๋Š” ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

running_loss = 0.0
for epoch in range(1):  # ๋ฐ์ดํ„ฐ์…‹์„ ์—ฌ๋Ÿฌ๋ฒˆ ๋ฐ˜๋ณต

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

        # [inputs, labels]์˜ ๋ชฉ๋ก์ธ data๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ์„ ๋ฐ›์€ ํ›„;
        inputs, labels = data

        # ๋ณ€ํ™”๋„(Gradient) ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ 0์œผ๋กœ ๋งŒ๋“ค๊ณ 
        optimizer.zero_grad()

        # ์ˆœ์ „ํŒŒ + ์—ญ์ „ํŒŒ + ์ตœ์ ํ™”๋ฅผ ํ•œ ํ›„
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if i % 1000 == 999:    # ๋งค 1000 ๋ฏธ๋‹ˆ๋ฐฐ์น˜๋งˆ๋‹ค...

            # ...ํ•™์Šต ์ค‘ ์†์‹ค(running loss)์„ ๊ธฐ๋กํ•˜๊ณ 
            writer.add_scalar('training loss',
                            running_loss / 1000,
                            epoch * len(trainloader) + i)

            # ...๋ฌด์ž‘์œ„ ๋ฏธ๋‹ˆ๋ฐฐ์น˜(mini-batch)์— ๋Œ€ํ•œ ๋ชจ๋ธ์˜ ์˜ˆ์ธก ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ฃผ๋„๋ก
            # Matplotlib Figure๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค
            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" ํƒญ์—์„œ ์Šคํฌ๋กค์„ ๋‚ด๋ ค "์˜ˆ์ธก vs. ์ •๋‹ต(predictions vs. actuals)" ์‹œ๊ฐํ™” ๋ถ€๋ถ„์—์„œ ์ด ๋‚ด์šฉ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค; ์˜ˆ๋ฅผ ๋“ค์–ด ํ•™์Šต์„ ๋‹จ์ง€ 3000๋ฒˆ ๋ฐ˜๋ณตํ•˜๊ธฐ๋งŒ ํ•ด๋„, ์‹ ๋ขฐ๋„๋Š” ๋†’์ง„ ์•Š์ง€๋งŒ, ๋ชจ๋ธ์€ ์…”์ธ ์™€ ์šด๋™ํ™”(sneakers), ์ฝ”ํŠธ์™€ ๊ฐ™์€ ๋ถ„๋ฅ˜๋“ค์„ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค:

../../_static/img/tensorboard_images.png

์ด์ „ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ๋ชจ๋ธ์ด ํ•™์Šต ์™„๋ฃŒ๋œ ํ›„์— ๊ฐ ๋ถ„๋ฅ˜๋ณ„ ์ •ํ™•๋„(per-class accuracy)๋ฅผ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค; ์—ฌ๊ธฐ์„œ๋Š” TensorBoard๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ๋ถ„๋ฅ˜๋ณ„ ์ •๋ฐ€๋„-์žฌํ˜„์œจ(precision-recall) ๊ณก์„ ( ์—ฌ๊ธฐ ์— ์ข‹์€ ์„ค๋ช…์ด ์žˆ์Šต๋‹ˆ๋‹ค)์„ ๊ทธ๋ ค๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

6. TensorBoard๋กœ ํ•™์Šต๋œ ๋ชจ๋ธ ํ‰๊ฐ€ํ•˜๊ธฐ

# 1. ์˜ˆ์ธก ํ™•๋ฅ ์„ test_size x num_classes ํ…์„œ๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
# 2. ์˜ˆ์ธก ๊ฒฐ๊ณผ๋ฅผ test_size ํ…์„œ๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
# ์‹คํ–‰ํ•˜๋Š”๋ฐ 10์ดˆ ์ดํ•˜ ์†Œ์š”
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()

# ๋ชจ๋“  ์ •๋ฐ€๋„-์žฌํ˜„์œจ(precision-recall; pr) ๊ณก์„ ์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค
for i in range(len(classes)):
    add_pr_curve_tensorboard(i, test_probs, test_preds)

์ด์ œ "PR Curves" ํƒญ์—์„œ ๊ฐ ๋ถ„๋ฅ˜๋ณ„ ์ •๋ฐ€๋„-์žฌํ˜„์œจ ๊ณก์„ ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๋ ค๋ณด๋ฉด์„œ ์‚ดํŽด๋ณด์‹ญ์‹œ์˜ค; ์ผ๋ถ€ ๋ถ„๋ฅ˜๋Š” ๊ฑฐ์˜ 100%์˜ "์˜์—ญ์ด ๊ณก์„  ์•„๋ž˜"์— ์žˆ๊ณ , ๋‹ค๋ฅธ ๋ถ„๋ฅ˜๋“ค์€ ์ด ์˜์—ญ์ด ๋” ์ ์Šต๋‹ˆ๋‹ค:

../../_static/img/tensorboard_pr_curves.png

์—ฌ๊ธฐ๊นŒ์ง€ TensorBoard์™€ PyTorch์˜ ํ†ตํ•ฉ์— ๋Œ€ํ•ด ์†Œ๊ฐœํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  TensorBoard์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ๋“ค์„ Jupyter Notebook์—์„œ๋„ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, TensorBoard๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋Œ€ํ™”ํ˜• ์‹œ๊ฐํ™”๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.