pytorch可視化教程:訓練過程+網絡結構(1)
作者 | 錦恢@知乎
來源 | https://zhuanlan.zhihu.com/p/220403674
編輯 | 極市平臺
導讀
本文大致想說一下pytorch下的網絡結構可視化和訓練過程可視化。
一、網絡結構的可視化我們訓練神經網絡時,除了隨著step或者epoch觀察損失函數的****,從而建立對目前網絡優化的基本認知外,也可以通過一些額外的可視化庫來可視化我們的神經網絡結構圖。這將更加地高效地向讀者展現目前的網絡結構。
為了可視化神經網絡,我們先建立一個簡單的卷積層神經網絡:
import torch
import torch.nn as nn
class ConvNet(nn.Module):
def __init__(self):
super(ConvNet, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(1, 16, 3, 1, 1),
nn.ReLU(),
nn.AvgPool2d(2, 2)
)
self.conv2 = nn.Sequential(
nn.Conv2d(16, 32, 3, 1, 1),
nn.ReLU(),
nn.MaxPool2d(2, 2)
)
self.fc = nn.Sequential(
nn.Linear(32 * 7 * 7, 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU()
)
self.out = nn.Linear(64, 10)
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
output = self.out(x)
return output
輸出網絡結構:
MyConvNet = ConvNet()
print(MyConvNet)
輸出結果:
ConvNet(
(conv1): Sequential(
(0): Conv2d(1, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): AvgPool2d(kernel_size=2, stride=2, padding=0)
)
(conv2): Sequential(
(0): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(fc): Sequential(
(0): Linear(in_features=1568, out_features=128, bias=True)
(1): ReLU()
(2): Linear(in_features=128, out_features=64, bias=True)
(3): ReLU()
)
(out): Linear(in_features=64, out_features=10, bias=True)
)
有了基本的神經網絡后,我們分別通過HiddenLayer和PyTorchViz庫來可視化上述的卷積層神經網絡。
1.1 通過HiddenLayer可視化網絡需要說明的是,這兩個庫都是基于Graphviz開發的,因此倘若你的電腦上沒有安裝并且沒有添加環境變量,請自行安裝Graphviz工具,安裝教程
首先當然是安裝庫啦,打開cmd,輸入:
pip install hiddenlayer
繪制的基本程序如下:
import hiddenlayer as h
vis_graph = h.build_graph(MyConvNet, torch.zeros([1 ,1, 28, 28])) # 獲取繪制圖像的對象
vis_graph.theme = h.graph.THEMES["blue"].copy() # 指定主題顏色
vis_graph.save("./demo1.png") # 保存圖像的路徑
效果如下:
先安裝庫:
pip install torchviz
這里我們只使用可視化函數make_dot()來獲取繪圖對象,基本使用和HiddenLayer差不多,不同的地方在于PyTorch繪圖之前可以指定一個網絡的輸入值和預測值。
from torchviz import make_dot
x = torch.randn(1, 1, 28, 28).requires_grad_(True) # 定義一個網絡的輸入值
y = MyConvNet(x) # 獲取網絡的預測值
MyConvNetVis = make_dot(y, params=dict(list(MyConvNet.named_parameters()) + [('x', x)]))
MyConvNetVis.format = "png"
# 指定文件生成的文件夾
MyConvNetVis.directory = "data"
# 生成文件
MyConvNetVis.view()
打開與上述代碼相同根目錄下的data文件夾,里面會有一個.gv文件和一個.png文件,其中的.gv文件是Graphviz工具生成圖片的腳本代碼,.png是.gv文件編譯生成的圖片,直接打開.png文件就行。
默認情況下,上述程序運行后會自動打開.png文件
生成圖片:
觀察我們的網絡的每一步的損失函數或準確率的變化可以有效地幫助我們判斷當前訓練過程的優劣。如果能將這些過程可視化,那么我們判斷的準確性和舒適性都會有所增加。
此處主要講通過可視化神器tensorboardX和剛剛用到的HiddenLayer來實現訓練過程的可視化。
為了訓練網絡,我們先導入訓練網絡需要的數據,此處就導入MNIST數據集,并做訓練前的一些基本的數據處理。
import torchvision
import torch.utils.data as Data
# 準備訓練用的MNIST數據集
train_data = torchvision.datasets.MNIST(
root = "./data/MNIST", # 提取數據的路徑
train=True, # 使用MNIST內的訓練數據
transform=torchvision.transforms.ToTensor(), # 轉換成torch.tensor
download=False # 如果是第一次運行的話,置為True,表示下載數據集到root目錄
)
# 定義loader
train_loader = Data.DataLoader(
dataset=train_data,
batch_size=128,
shuffle=True,
num_workers=0
)
test_data = torchvision.datasets.MNIST(
root="./data/MNIST",
train=False, # 使用測試數據
download=False
)
# 將測試數據壓縮到0-1
test_data_x = test_data.data.type(torch.FloatTensor) / 255.0
test_data_x = torch.unsqueeze(test_data_x, dim=1)
test_data_y = test_data.targets
# 打印一下測試數據和訓練數據的shape
print("test_data_x.shape:", test_data_x.shape)
print("test_data_y.shape:", test_data_y.shape)
for x, y in train_loader:
print(x.shape)
print(y.shape)
break
結果:
test_data_x.shape: torch.Size([10000, 1, 28, 28])2.1 通過tensorboardX可視化訓練過程
test_data_y.shape: torch.Size([10000])
torch.Size([128, 1, 28, 28])
torch.Size([128])
tensorboard是谷歌開發的深度學習框架tensorflow的一套深度學習可視化神器,在pytorch團隊的努力下,他們開發出了tensorboardX來讓pytorch的玩家也能享受tensorboard的福利。
先安裝相關的庫:
pip install tensorboardX
pip install tensorboard
并將tensorboard.exe所在的文件夾路徑加入環境變量path中(比如我的tensorboard.exe的路徑為D:\Python376\Scripts\tensorboard.exe,那么就在path中加入D:\Python376\Scripts)
下面是tensorboardX的使用過程。基本使用為,先通過tensorboardX下的SummaryWriter類獲取一個日志編寫器對象。然后通過這個對象的一組方法往日志中添加事件,即生成相應的圖片,最后啟動前端服務器,在localhost中就可以看到最終的結果了。
訓練網絡,并可視化網絡訓練過程的代碼如下:
from tensorboardX import SummaryWriter
logger = SummaryWriter(log_dir="data/log")
# 獲取優化器和損失函數
optimizer = torch.optim.Adam(MyConvNet.parameters(), lr=3e-4)
loss_func = nn.CrossEntropyLoss()
log_step_interval = 100 # 記錄的步數間隔
for epoch in range(5):
print("epoch:", epoch)
# 每一輪都遍歷一遍數據加載器
for step, (x, y) in enumerate(train_loader):
# 前向計算->計算損失函數->(從損失函數)反向傳播->更新網絡
predict = MyConvNet(x)
loss = loss_func(predict, y)
optimizer.zero_grad() # 清空梯度(可以不寫)
loss.backward() # 反向傳播計算梯度
optimizer.step() # 更新網絡
global_iter_num = epoch * len(train_loader) + step + 1 # 計算當前是從訓練開始時的第幾步(全局迭代次數)
if global_iter_num % log_step_interval == 0:
# 控制臺輸出一下
print("global_step:{}, loss:{:.2}".format(global_iter_num, loss.item()))
# 添加的第一條日志:損失函數-全局迭代次數
logger.add_scalar("train loss", loss.item() ,global_step=global_iter_num)
# 在測試集上預測并計算正確率
test_predict = MyConvNet(test_data_x)
_, predict_idx = torch.max(test_predict, 1) # 計算softmax后的最大值的索引,即預測結果
acc = accuracy_score(test_data_y, predict_idx)
# 添加第二條日志:正確率-全局迭代次數
logger.add_scalar("test accuary", acc.item(), global_step=global_iter_num)
# 添加第三條日志:這個batch下的128張圖像
img = vutils.make_grid(x, nrow=12)
logger.add_image("train image sample", img, global_step=global_iter_num)
# 添加第三條日志:網絡中的參數分布直方圖
for name, param in MyConvNet.named_parameters():
logger.add_histogram(name, param.data.numpy(), global_step=global_iter_num)
運行完后,我們通過cmd來到與代碼同一級的目錄(如果你使用的是pycharm,可以通過pycharm中的終端)輸入指令tensorboard --logdir="./data/log",啟動服務器。
logdir后面的參數是日志文件的文件夾的路徑
然后在谷歌瀏覽器中訪問紅框框中的url,便可得到可視化界面,點擊上面的頁面控件,可以查看我們通過add_scalar、add_image和add_histogram得到的圖像,而且各方面做得都很絲滑。
以下是筆者安裝使用tensorboard時遇到的一些錯誤。
好,作為一名沒有裝過TensorFlow的windows玩家,筆者下面開始踩坑。踩完后,直接把幾個可能的錯誤呈上。
第一個錯誤,運行tensorboard --logdir="./data/log",遇到報錯,內容為有重復的tensorboard的包。
解決方法:找到site-packages(如果你是像我一樣全局安裝的,那么找到解釋器那一級目錄的site-packages,如果是在項目虛擬環境中安裝的,那么找到項目中的site-packages),刪去下圖中紅框框標出來的文件夾。
第二個錯誤,在解決第一個錯誤后,再次運行命令,還是報錯,內容為編碼出錯。由于筆者做過一點前端,在學習webpack項目時,曾經被告知項目路徑不能含有中文,否則會有編碼錯誤,而剛才的報錯中涉及到了前端服務器的啟動,因此,筆者想到從文件名入手。
解決方法:確保命令涉及的文件路徑、所有程序涉及到文件不含中文。筆者是計算機名字含有中文,然后tensorboard的日志文件是以本地計算機名為后綴的,所以筆者將計算機名修改成了英文,重啟后再輸入指令就ok了。
*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。