pytorch-handbook/chapter4/4.2.2-tensorboardx.ipynb
2019-10-24 09:07:19 +08:00

530 lines
17 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'1.3.0'"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import torch\n",
"import numpy as np\n",
"import torch.nn as nn\n",
"import torch.nn.functional as F\n",
"from PIL import Image\n",
"from torchvision import transforms\n",
"from torchvision import models,datasets\n",
"torch.__version__"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 4.2.2 使用Tensorboard在 PyTorch 中进行可视化 \n",
"\n",
"## Tensorboard 简介\n",
"Tensorboard是tensorflow内置的一个可视化工具它通过将tensorflow程序输出的日志文件的信息可视化使得tensorflow程序的理解、调试和优化更加简单高效。\n",
"Tensorboard的可视化依赖于tensorflow程序运行输出的日志文件因而tensorboard和tensorflow程序在不同的进程中运行。\n",
"TensorBoard给我们提供了极其方便而强大的可视化环境。它可以帮助我们理解整个神经网络的学习过程、数据的分布、性能瓶颈等等。\n",
"\n",
"tensorboard虽然是tensorflow内置的可视化工具但是他们跑在不同的进程中所以Github上已经有大神将tensorboard应用到Pytorch中 [链接在这里]( https://github.com/lanpa/tensorboardX)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tensorboard 安装\n",
"首先需要安装tensorboard\n",
"\n",
"`pip install tensorboard`\n",
"\n",
"\n",
"\n",
"~~ 然后再安装tensorboardx ~~\n",
"\n",
"~~ `pip install tensorboardx` ~~\n",
"pytorch 1.1以后的版本内置了SummaryWriter 函数,所以不需要再安装tensorboardx了\n",
"\n",
"安装完成后与 visdom一样执行独立的命令\n",
"`tensorboard --logdir logs` 即可启动,默认的端口是 6006,在浏览器中打开 `http://localhost:6006/` 即可看到web页面。\n",
"\n",
"这里要说明的是 微软的Edge浏览器css会无法加载使用chrome正常显示"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 页面\n",
"与visdom不同tensorboard针对不同的类型人为的区分多个标签每一个标签页面代表不同的类型。\n",
"下面我们根据不同的页面功能做个简单的介绍,更多详细内容请参考官网\n",
"### SCALAR\n",
"对标量数据进行汇总和记录,通常用来可视化训练过程中随着迭代次数准确率(val acc)、损失值(train/test loss)、学习率(learning rate)、每一层的权重和偏置的统计量(mean、std、max/min)等的变化曲线\n",
"### IMAGES\n",
"可视化当前轮训练使用的训练/测试图片或者 feature maps\n",
"### GRAPHS\n",
"可视化计算图的结构及计算图上的信息,通常用来展示网络的结构\n",
"### HISTOGRAMS\n",
"可视化张量的取值分布,记录变量的直方图(统计张量随着迭代轮数的变化情况)\n",
"### PROJECTOR\n",
"全称Embedding Projector 高维向量进行可视化"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 使用\n",
"在使用前请先去确认执行`tensorboard --logdir logs` 并保证 `http://localhost:6006/` 页面能够正常打开\n",
"\n",
"### 图像展示\n",
"首先介绍比较简单的功能查看我们训练集和数据集中的图像这里我们使用现成的图像作为展示。这里使用wikipedia上的一张猫的图片[这里](https://en.wikipedia.org/wiki/Cat#/media/File:Felis_silvestris_catus_lying_on_rice_straw.jpg)\n",
"\n",
"引入 tensorboardX 包"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [],
"source": [
"# 这里的引用也要修改成torch的引用\n",
"#from tensorboardX import SummaryWriter\n",
"from torch.utils.tensorboard import SummaryWriter"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(1280, 853)"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cat_img = Image.open('./1280px-Felis_silvestris_catus_lying_on_rice_straw.jpg')\n",
"cat_img.size"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这是一张1280x853的图我们先把她变成224x224的图片因为后面要使用的是vgg16"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [],
"source": [
"transform_224 = transforms.Compose([\n",
" transforms.Resize(224), # 这里要说明下 Scale 已经过期了使用Resize\n",
" transforms.CenterCrop(224),\n",
" transforms.ToTensor(),\n",
" ])\n",
"cat_img_224=transform_224(cat_img)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"将图片展示在tebsorboard中"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [],
"source": [
"writer = SummaryWriter(log_dir='./logs', comment='cat image') # 这里的logs要与--logdir的参数一样\n",
"writer.add_image(\"cat\",cat_img_224)\n",
"writer.close()# 执行close立即刷新否则将每120秒自动刷新"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"浏览器访问 `http://localhost:6006/#images` 即可看到猫的图片 \n",
"### 更新损失函数\n",
"更新损失函数和训练批次我们与visdom一样使用模拟展示这里用到的是tensorboard的SCALAR页面"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {},
"outputs": [],
"source": [
"x = torch.FloatTensor([100])\n",
"y = torch.FloatTensor([500])\n",
"\n",
"for epoch in range(30):\n",
" x = x * 1.2\n",
" y = y / 1.1\n",
" loss = np.random.random()\n",
" with SummaryWriter(log_dir='./logs', comment='train') as writer: #可以直接使用python的with语法自动调用close方法\n",
" writer.add_histogram('his/x', x, epoch)\n",
" writer.add_histogram('his/y', y, epoch)\n",
" writer.add_scalar('data/x', x, epoch)\n",
" writer.add_scalar('data/y', y, epoch)\n",
" writer.add_scalar('data/loss', loss, epoch)\n",
" writer.add_scalars('data/data_group', {'x': x,\n",
" 'y': y}, epoch)\n",
"\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"浏览器访问 `http://localhost:6006/#scalars` 即可看到图形\n",
"### 使用PROJECTOR对高维向量可视化\n",
"PROJECTOR的的原理是通过PCAT-SNE等方法将高维向量投影到三维坐标系降维度。Embedding Projector从模型运行过程中保存的checkpoint文件中读取数据默认使用主成分分析法PCA将高维数据投影到3D空间中也可以通过设置设置选择T-SNE投影方法这里做一个简单的展示。\n",
"\n",
"我们还是用第三章的mnist代码"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [],
"source": [
"BATCH_SIZE=512 \n",
"EPOCHS=20 \n",
"train_loader = torch.utils.data.DataLoader(\n",
" datasets.MNIST('data', train=True, download=True, \n",
" transform=transforms.Compose([\n",
" transforms.ToTensor(),\n",
" transforms.Normalize((0.1307,), (0.3081,))\n",
" ])),\n",
" batch_size=BATCH_SIZE, shuffle=True)"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [],
"source": [
"class ConvNet(nn.Module):\n",
" def __init__(self):\n",
" super().__init__()\n",
" # 1,28x28\n",
" self.conv1=nn.Conv2d(1,10,5) # 10, 24x24\n",
" self.conv2=nn.Conv2d(10,20,3) # 128, 10x10\n",
" self.fc1 = nn.Linear(20*10*10,500)\n",
" self.fc2 = nn.Linear(500,10)\n",
" def forward(self,x):\n",
" in_size = x.size(0)\n",
" out = self.conv1(x) #24\n",
" out = F.relu(out)\n",
" out = F.max_pool2d(out, 2, 2) #12\n",
" out = self.conv2(out) #10\n",
" out = F.relu(out)\n",
" out = out.view(in_size,-1)\n",
" out = self.fc1(out)\n",
" out = F.relu(out)\n",
" out = self.fc2(out)\n",
" out = F.log_softmax(out,dim=1)\n",
" return out\n",
"model = ConvNet()\n",
"optimizer = torch.optim.Adam(model.parameters())"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [],
"source": [
"def train(model, train_loader, optimizer, epoch):\n",
" n_iter=0\n",
" model.train()\n",
" for batch_idx, (data, target) in enumerate(train_loader):\n",
" optimizer.zero_grad()\n",
" output = model(data)\n",
" loss = F.nll_loss(output, target)\n",
" loss.backward()\n",
" optimizer.step()\n",
" if(batch_idx+1)%30 == 0: \n",
" n_iter=n_iter+1\n",
" print('Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n",
" epoch, batch_idx * len(data), len(train_loader.dataset),\n",
" 100. * batch_idx / len(train_loader), loss.item()))\n",
" #相对于以前的训练方法 主要增加了以下内容\n",
" out = torch.cat((output.data, torch.ones(len(output), 1)), 1) # 因为是投影到3D的空间所以我们只需要3个维度\n",
" with SummaryWriter(log_dir='./logs', comment='mnist') as writer: \n",
" #使用add_embedding方法进行可视化展示\n",
" writer.add_embedding(\n",
" out,\n",
" metadata=target.data,\n",
" label_img=data.data,\n",
" global_step=n_iter)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这里节省时间,只训练一次"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Train Epoch: 0 [14848/60000 (25%)]\tLoss: 0.352312\n",
"Train Epoch: 0 [30208/60000 (50%)]\tLoss: 0.202950\n",
"Train Epoch: 0 [45568/60000 (75%)]\tLoss: 0.156494\n"
]
}
],
"source": [
"train(model, train_loader, optimizer, 0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"打开 `http://localhost:6006/#projector` 即可看到效果。\n",
"\n",
"目前测试投影这部分也是有问题的,根据官网文档的代码进行测试,也显示不出来,正在找原因\n",
"\n",
"### 绘制网络结构\n",
"在pytorch中我们可以使用print直接打印出网络的结构但是这种方法可视化效果不好这里使用tensorboard的GRAPHS来实现网络结构的可视化。\n",
"由于pytorch使用的是动态图计算所以我们这里要手动进行一次前向的传播.\n",
"\n",
"使用Pytorch已经构建好的模型进行展示"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"VGG(\n",
" (features): Sequential(\n",
" (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (1): ReLU(inplace=True)\n",
" (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (3): ReLU(inplace=True)\n",
" (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
" (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (6): ReLU(inplace=True)\n",
" (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (8): ReLU(inplace=True)\n",
" (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
" (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (11): ReLU(inplace=True)\n",
" (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (13): ReLU(inplace=True)\n",
" (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (15): ReLU(inplace=True)\n",
" (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
" (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (18): ReLU(inplace=True)\n",
" (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (20): ReLU(inplace=True)\n",
" (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (22): ReLU(inplace=True)\n",
" (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
" (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (25): ReLU(inplace=True)\n",
" (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (27): ReLU(inplace=True)\n",
" (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
" (29): ReLU(inplace=True)\n",
" (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
" )\n",
" (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))\n",
" (classifier): Sequential(\n",
" (0): Linear(in_features=25088, out_features=4096, bias=True)\n",
" (1): ReLU(inplace=True)\n",
" (2): Dropout(p=0.5, inplace=False)\n",
" (3): Linear(in_features=4096, out_features=4096, bias=True)\n",
" (4): ReLU(inplace=True)\n",
" (5): Dropout(p=0.5, inplace=False)\n",
" (6): Linear(in_features=4096, out_features=1000, bias=True)\n",
" )\n",
")\n"
]
}
],
"source": [
"vgg16 = models.vgg16(pretrained=True) # 这里下载预训练好的模型\n",
"print(vgg16) # 打印一下这个模型"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在前向传播前,先要把图片做一些调整"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [],
"source": [
"transform_2 = transforms.Compose([\n",
" transforms.Resize(224), \n",
" transforms.CenterCrop((224,224)),\n",
" transforms.ToTensor(),\n",
" transforms.Normalize(mean=[0.485, 0.456, 0.406],\n",
" std=[0.229, 0.224, 0.225])\n",
"])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"使用上一张猫的图片进行前向传播"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"torch.Size([1, 3, 224, 224])"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vgg16_input=transform_2(cat_img)[np.newaxis]# 因为pytorch的是分批次进行的所以我们这里建立一个批次为1的数据集\n",
"vgg16_input.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"开始前向传播,打印输出值"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"287"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"out = vgg16(vgg16_input)\n",
"_, preds = torch.max(out.data, 1)\n",
"label=preds.numpy()[0]\n",
"label"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"将结构图在tensorboard进行展示"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [],
"source": [
"with SummaryWriter(log_dir='./logs', comment='vgg161') as writer:\n",
" writer.add_graph(vgg16, vgg16_input)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"对于Pytorch的1.3版本来说,实测 SummaryWriter在处理结构图的时候是有问题的或者是需要加什么参数目前我还没找到所以建议大家继续使用tensorboardx。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "deep learning",
"language": "python",
"name": "dl"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}