PyTorch入门(七)TensorBoard入门

  PyTorch模型的可视化工具:

  • Visdom
  • TensorBoard
  • Pytorchviz
  • Netron

TensorBoard简介

  TensorBoard是TensorFlow自带的一个强大的可视化工具,也是一个Web应用程序套件,可以记录训练过程的数字、图像等内容,以方便研究人员观察神经网络训练过程。

  对于PyTorch等其它深度学习框架来说,目前还没有功能像TensorBoard一样全面的类似工具,一些已有的工具功能也有限,或使用起来比较困难。

  TensorBoard提供的机器学习实验所需的可视化功能和工具如下:

  • 跟踪和可视化损失及准确率等指标
  • 可视化模型图
  • 查看权重、偏差或其它张量随时间变化的直方图
  • 将嵌入向量投影到较低维度空间
  • 显示图片、文字和音频数据
  • 剖析TensorFlow程序

  如果要使用TensorBoard,首先需要安装tensorflow, tensorboard, tensorboardX, 代码如下:

pip3 install tensorflow
pip3 install tensorboard
pip3 install tensorboardX

其中,tensorboardX这个工具可使得TensorFlow外的其它深度学习框架也可以使用TensorBoard的便捷功能。

  TensorBoard目前支持7种可视化,包括Scalars, Images, Audio, Graphs, Distributions, Histograms, Embeddings, 主要功能如下:

  • Scalars: 展示训练过程中的准确率、损失值、权重/偏差的变化情况
  • Images: 展示训练过程中记录的图像
  • Audio: 展示训练过程中记录的音频
  • Graphs: 展示模型的数据流图,以及训练在各个设备上消耗的内存和时间
  • Distributions: 展示训练过程中记录的数据的分布图
  • Histograms: 展示训练过程中记录的数据的柱状图
  • Embeddings: 展示词向量的投影分布

  启动TensorBoard:

tonsorboard --logdir=./run/

TensorBoard基础操作

  1. 可视化数值

使用add_scalar方法来记录数字常量,一般使用add_scalar方法来记录训练过程中的loss, arrcuracy, learning rate等数值的变化,直观地监控训练过程。

示例代码:

# import modules
from tensorboardX import SummaryWriter
# add_scalar
writer = SummaryWriter('run/scalar')

for i in range(10):
    writer.add_scalar('指数', 3**i, global_step=i)

在tensorboard中查看scalar

  1. 可视化图片

使用add_images方法来记录图像数据,一般会使用add_images来实时观察模型的生成效果,或者可视化分割、目标检测的结果,帮助调试模型。

示例代码:

# add_images
import cv2

writer = SummaryWriter('run/image')

for i in range(1, 4):
    writer.add_images('', 
                      cv2.cvtColor(cv2.imread('./image/image{}.png'.format(i)), cv2.COLOR_BGR2RGB), 
                      global_step=i, 
                      dataformats='HWC')

在tensorboard中查看图片

  1. 可视化统计图

使用add_histogram方法来记录一组数据的直方图。可以通过观察数据、训练参数、特征的直方图了解到它们大致的分布情况,辅助神经网络的训练过程。

示例代码:

# add_histogram
import numpy as np

writer = SummaryWriter('run/histogram')
writer.add_histogram('正态分布中心化', np.random.normal(0, 1, 1000), global_step=1)
writer.add_histogram('正态分布中心化', np.random.normal(0, 2, 1000), global_step=50)
writer.add_histogram('正态分布中心化', np.random.normal(0, 3, 1000), global_step=100)

在TensorBoard可视化界面中,我们会发现DISTRIBUTIONS和HISTOGRAMS两栏,它们都是用来观察数据分布的。在HISTOGRAMS中,同一数据不同步数的直方图可以上下错位排布(OFFSET)也可以重叠排布(OVERLAY)。

在tensorboard中查看柱状图
4. 可视化模型图

使用add_graph方法来可视化一个神经网络。该方法可以将神经网络模型可视化,显示模型中的操作和网络层。

示例代码如下:

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

dummy_input = (torch.zeros(1, 3),)
writer = SummaryWriter('run/graph')

# simple MLP model
class LinearInLinear(nn.Module):
    def __init__(self):
        super(LinearInLinear, self).__init__()
        self.l = nn.Linear(3, 5)

    def forward(self, x):
        return self.l(x)

writer.add_graph(LinearInLinear(), dummy_input)

在tensorboard中查看模型图

  1. 可视化向量

使用add_embedding方法可以在二维或三维空间可视化Embedding向量。add_embedding方法是一个很实用的方法,不仅可以将高维特征使用PCA, T-SNE等方法降维至二维平面或三维空间,还可以观察每一个数据点在降维前的特征空间的K近邻情况。

下面的例子中我们取MNIST训练集中的前30个数据,将图像展开成一维向量作为Embedding,使用TensorBoardX进行可视化。

示例代码如下:

# add_embedding
import torchvision

writer = SummaryWriter('run/vector')
mnist = torchvision.datasets.MNIST('./', download=False)
writer.add_embedding(mnist.data.reshape((-1, 28*28))[:30, :],
                     metadata=mnist.targets[:30],
                     label_img = mnist.data[:30, :, :].reshape((-1, 1, 28, 28)).float()/255,
                     global_step=0
                    )

可以发现,虽然还没有做任何特征提取工作,但MNIST数据已经呈现出聚类的效果,相同数字之间距离更近一些。
在tensorboard中查看向量嵌入

TensorBoard实战

  1. 例子1:在模型训练过程中记录loss和accuracy. Python示例代码如下:
# -*- coding: utf-8 -*-
import torch
from numpy import vstack
from numpy import argmax
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder, LabelBinarizer
from sklearn.metrics import accuracy_score
from torch.optim import SGD, Adam
from torch.utils.data import Dataset, DataLoader, random_split
from torch.nn import Linear, ReLU, Softmax, Module, CrossEntropyLoss
from torch.nn.init import kaiming_uniform_, xavier_uniform_

from tensorboardX import SummaryWriter


# dataset definition
class CSVDataset(Dataset):
    # load the dataset
    def __init__(self, path):
        # load the csv file as a dataframe
        df = read_csv(path, header=None)
        # store the inputs and outputs
        self.X = df.values[:, :-1]
        self.y = df.values[:, -1]
        # ensure input data is floats
        self.X = self.X.astype('float32')
        # label encode target and ensure the values are floats
        self.y = LabelEncoder().fit_transform(self.y)

    # number of rows in the dataset
    def __len__(self):
        return len(self.X)

    # get a row at an index
    def __getitem__(self, idx):
        return [self.X[idx], self.y[idx]]

    # get indexes for train and test rows
    def get_splits(self, n_test=0.3):
        # determine sizes
        test_size = round(n_test * len(self.X))
        train_size = len(self.X) - test_size
        # calculate the split
        return random_split(self, [train_size, test_size])


# model definition
class MLP(Module):
    # define model elements
    def __init__(self, n_inputs):
        super(MLP, self).__init__()
        # input to first hidden layer
        self.hidden1 = Linear(n_inputs, 5)
        kaiming_uniform_(self.hidden1.weight, nonlinearity='relu')
        self.act1 = ReLU()
        # second hidden layer
        self.hidden2 = Linear(5, 6)
        kaiming_uniform_(self.hidden2.weight, nonlinearity='relu')
        self.act2 = ReLU()
        # third hidden layer and output
        self.hidden3 = Linear(6, 3)
        xavier_uniform_(self.hidden3.weight)

    # forward propagate input
    def forward(self, X):
        # input to first hidden layer
        X = self.hidden1(X)
        X = self.act1(X)
        # second hidden layer
        X = self.hidden2(X)
        X = self.act2(X)
        # output layer
        X = self.hidden3(X)
        return X


class Model(object):
    def __init__(self, file_path, model):
        self.writer = SummaryWriter('./run/mlp_demo')
        # load the dataset
        dataset = CSVDataset(file_path)
        # calculate split
        train, test = dataset.get_splits()
        # prepare data loaders
        self.train_dl = DataLoader(train, batch_size=4, shuffle=True)
        self.test_dl = DataLoader(test, batch_size=1024, shuffle=False)
        # model
        self.model = model

    # train the model
    def train(self):
        criterion = CrossEntropyLoss()
        optimizer = Adam(self.model.parameters())
        # enumerate epochs
        for epoch in range(100):
            init_loss = torch.Tensor([0.0])
            # enumerate mini batches
            for i, (inputs, targets) in enumerate(self.train_dl):
                targets = targets.long()
                # clear the gradients
                optimizer.zero_grad()
                # compute the model output
                yhat = self.model(inputs)
                # calculate loss
                loss = criterion(yhat, targets)
                # credit assignment
                loss.backward()
                print("epoch: {}, batch: {}, loss: {}".format(epoch, i, loss.data))
                init_loss += loss.data
                # update model weights
                optimizer.step()

            self.writer.add_scalar('Loss/Train', init_loss/(i+1), epoch)
            test_accuracy = self.evaluate_model()
            self.writer.add_scalar('Accuracy/Test', test_accuracy, epoch)

    # evaluate the model
    def evaluate_model(self):
        predictions, actuals = [], []
        for i, (inputs, targets) in enumerate(self.test_dl):
            # evaluate the model on the test set
            yhat = self.model(inputs)
            # retrieve numpy array
            yhat = yhat.detach().numpy()
            actual = targets.numpy()
            # convert to class labels
            yhat = argmax(yhat, axis=1)
            # reshape for stacking
            actual = actual.reshape((len(actual), 1))
            yhat = yhat.reshape((len(yhat), 1))
            # store
            predictions.append(yhat)
            actuals.append(actual)
        predictions, actuals = vstack(predictions), vstack(actuals)
        # calculate accuracy
        acc = accuracy_score(actuals, predictions)
        return acc


if __name__ == '__main__':
    # train the model
    Model('iris.csv', MLP(4)).train()

在训练过程中的训练集的损失值以及验证集的准确率如下:

在tensorboard中查看loss和accuracy

  1. 例子2: 利用TensorBoard查看ONNX文件

需安装Python第三方模块onnx, Python代码如下:

# -*- coding: utf-8 -*-
from tensorboardX import SummaryWriter

with SummaryWriter('./run/onnx') as w:
    w.add_onnx_graph('iris.onnx')

在TensorBoard中选择Graphs, Run选项选择onnx,模型图如下:

在tensorboard中查看onnx模型图
从中可以看出,TensorBoard对于ONNX模型文件支持不是太好,可以尝试使用Netron.

参考文献

  1. tensorboardX Tutorials: https://tensorboardx.readthedocs.io/en/latest/tutorial.html#tutorials
  2. 动手学PyTorch深度学习建模与应用,王国平著
  3. PyTorch 使用 TensorboardX 进行网络可视化:https://www.pytorchtutorial.com/pytorch-tensorboardx/
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值