本節簡單總結Pytorch中用於學習率調整的函數,如何使用tensorboard可視化曲線、梯度、權重、特征圖、卷積核,以及如何使用torchvision.utils.make_grid()制作網格圖。【文中思維導圖采用MindMaster軟件】 |
1.學習率的調整
Pytorch中封裝了調整LR的函數,如下:
它們都繼承父類class _LRScheduler,需要復寫函數def get_lr(self),該函數用於計算學習率並返回:
class _LRScheduler(object):
def __init__(self, optimizer, last_epoch=-1):
······
def get_lr(self):
raise NotImplementedError
參數:
-
optimizer:優化器類實例
-
last_epoch:記錄epoch數
-
base_lrs:記錄初始學習率,該參數用於后續的學習率計算
方法:
-
step():更新下一個epoch的學習率
-
get_lr():虛函數,計算下一個epoch學習率
節省精力, 由於網上已經有人對這六個函數總結的很好,故在此引用,不再復寫。
2.tensorboard可視化工具
(1)流程
(2)如何記錄可視化的數據?
調用SummaryWriter類,代碼如下:
'''SummaryWriter類'''
class SummaryWriter(object):
def __init__(self, log_dir=None, comment='', purge_step=None, max_queue=10,
flush_secs=120, filename_suffix=''):
# 參數如下:
# log_dir:eventfile輸出文件夾地址
# comment:當不指定log_dir時,該參數為文件夾的后綴
# filename_suffix:eventfile文件名的后綴
'''實際運用時'''
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter(log_dir='./a',comment="handw_exp",filename_suffix="test1")
若不指定log_dir,則直接該項目下創建runs文件夾,可對照下圖進行理解:
各種記錄數據的方法如下:
①scalar繪制曲線(單條、多條)
'''一張圖中,只能單條曲線'''
def add_scalar(self, tag, scalar_value, global_step=None, walltime=None):
# 參數:
# tag:圖像的標簽名
# scalar_value:要記錄的標量,例如loss
# global_step:x軸
'''一張圖中,可以多條曲線'''
def add_scalars(self, main_tag, tag_scalar_dict, global_step=None, walltime=None):
# 參數:
# main_tag:總的標簽名,用於曲線索引放置
# tag_scalar_dict:要記錄的標量,例如loss
# global_step:x軸
實戰中,以 def add_scalars 為例:
iter_count = 0
for epoch in range(Max_Epoch):
······
for i, (inputs, labels) in enumerate(train_loader):
iter_count += 1
······
writer.add_scalars(main_tag="Loss", tag_scalar_dict={"Train": loss.item()}, global_step=iter_count)
writer.add_scalars("Accuracy", {"Train": correct/total}, global_step=iter_count)
if (epoch+1) % print_info_valid == 0:
······
with torch.no_grad():
for j,(inputs_valid,labels_valid) in enumerate(test_loader):
······
writer.add_scalars("Loss", {"Valid": loss_info_valid/len(test_loader)}, iter_count)
writer.add_scalars("Accuracy", {"Valid": correct_valid / total_valid}, iter_count)
writer.flush() # 及時刷新,否則無法同時觀看到訓練和驗證
writer.close()
此時通過pycharm終端,輸入 tensorboard --logdir=./a(event的地址),就會得到tensorboard的可視化網址,打開可以得到如下圖:
②histogram直方圖,查看權重、梯度,判斷是否梯度消失或發散
def add_histogram(self, tag, values, global_step=None, bins='tensorflow', walltime=None, max_bins=None):
# 參數:
# tag:圖像的標簽名
# values:要統計的參數
# global_step:y軸!!!!!!!!!!!!!(結合下圖理解)
實戰中,代碼參考如下:
# 每一個epoch,記錄各層權重、梯度
for name, param in net.named_parameters(): # 返回網絡的
writer.add_histogram(name + '_grad', param.grad, epoch)
writer.add_histogram(name + '_data', param, epoch)
貌似橫軸是大小,高度代表該數值下的個數???:
③記錄圖像(利用torchvision.utils中make_grid制作網格)
torchvision.utils.make_grid()函數定義:
def make_grid(tensor, nrow=8, padding=2,
normalize=False, range=None, scale_each=False, pad_value=0):
# 參數:
# tensor:必須是B*C*H*W形式
# nrow:指定行數
# padding:圖像與圖像之間的間隔多少個像素單位pad_value
# normalize:是否將像素值標准化到(0~255)
# range:指定標准化范圍,先將像素值規范到該range,然后再進行(0~255)轉換
# scale_each:是否對單張圖像進行range
# pad_value:指定padding的大小(黑色0、白色255等等)
實戰中,代碼參考如下:
'''調用torchvision中make_grid 網格可視化圖像'''
import torchvision.utils as vutils
img_batch,label_batch = next(iter(train_loader)) # 調用一個批次的圖片
img_grid = vutils.make_grid(img_batch, nrow=10,normalize=True) # 變為 C*H*W
writer.add_image("make_grid",img_grid, global_step=0)
writer.flush()
'''當然也可以直接調用add_image或add_images'''
def add_image(self, tag, img_tensor, global_step=None, walltime=None, dataformats='CHW'):
# 參數:
# 非常不方便,只能查看一個圖像!!!!
# 當像素值為【0,1】,則乘以255,縮放回【0,255】;若像素值不在【0,1】之間,默認是0~255范圍內。
# tag:圖像的標簽名
# img_tensor:注意shape,可以是3HW、HW3、HW、1HW,但不能是四維的,即有batch!!!!!!!(可以通過add_images解決或torchvision.utils.make_grid())
# global_step:x軸
def add_images(self, tag, img_tensor, global_step=None, walltime=None, dataformats='NCHW'):
# 參數:
# 無法指定行數!!!!!
# tag:圖像的標簽名
# img_tensor:注意shape,可以是NCHW or NHWC,但是,這里Channel在后續處理的時候只能為1或者3!!!!!
# global_step:x軸
④利用make_grid可視化特征圖
(每次都要調出對應層,一個個輸入,一個個輸出,有點麻煩,即便調用for循環,代碼也有點冗余性,下一節介紹的hook函數就可以在網絡運行過程中,直接保存特征圖)
vlaid_img,_ = next(iter(test_loader))
conv1 = net.cpu().feature[0]
fmap1 = conv1(vlaid_img) # 100*16*72*72
fmap1_first = fmap1[0,:,:,:]
fmap1_first.unsqueeze_(0).transpose_(0,1) # 16*1*72*72
fmap1_grid = vutils.make_grid(fmap1_first,4,normalize=True)
writer.add_image("fmap", fmap1,global_step=0)
從下面的特征圖可以看出: 經過卷積核操作后,得到的各種特征圖(提取邊緣后、銳化后等等)。
⑤graph可視化模型計算圖
def add_graph(self, model, input_to_model=None, verbose=False):
# 參數:
# model:模型,必須是繼承torch.nn.Module
# input_to_model:模型的輸入
# verbose:是否打印計算圖結構信息
'''可視化模型計算圖'''
input_v = torch.rand((1,3,75,75))
writer.add_graph(net, input_v)
writer.flush()