本节笔记内容具体是学习tensorboard中的两个方法分别是scalar和histogram,一共分为3个部分:(1)首先学习SummaryWriter类;(2)其次,学习两个基本方法记录标量add_scalar和直方图可视化add_histogram;(3)最后,使用scalar和histogram来监控模型指标(分别有Loss曲线、Acuracy曲线以及参数分布、参数所对应的梯度分布情况)
学习之前,回顾tensorboard运行机制:
首先在python脚本里①记录要可视化的数据,然后,这些②数据以event file形式存储到硬盘中,最后在③终端读取event file在tensorboard可视化,展示在web端。
在python脚本中怎样记录想要可视化的数据?要在python脚本中记录数据并以event file保存到硬盘中就需要SummaryWriter类。
SummaryWriter
功能:提供创建event file的高级接口
Class SummaryWriter(object)
def_init_(self,log_dir=None,comment='',
purge_step=None,max_queue=10,
flush_secs=120,filename_suffix='')
主要属性:
log_dir:event file 输出文件夹
comment:不指定log_dir时,文件名后缀
filename_suffix:event file文件名后缀
3个属性都与要创建的路径有关。
(1)log_dir:event_file 输出文件夹,通常采用默认参数即不设置;如果不设置log_dir,会在当前 .py文件当前文件夹下创建1个runs文件夹(如:runs/Aug18_16-09-46_LAPTOP-73TM5PNOtest_tensorboard/event…)
(2)comment:不指定log_dir时,添加文件名后缀 (3)filename_suffix:添加 event file文件名后缀
实验
(1)设置log_dir,创建出来的文件有什么特点?
(2)不设置log_dir,创建出来的文件有什么特点?
通常不会采用默认形式,而是要设置log_dir的具体路径,保证代码和训练数据隔离开来,便于管理。
学习了怎样event file路径,接下来学习具体方法。
1、add_scalar
功能:记录标量
add_scalar(tag,scalar_value,global_step=None,walltime=None)
tag:图像的标签名,图的唯一标识
scalar_value:要记录的标量
global_step:x轴(通常以1个epoch或iteration为周期)
该方法使用受限,只能记录一条曲线;但是在模型训练时,想要监控训练集和测试集曲线对比情况,add_scalar方法就不能使用了。因此,还提供add_scalars方法。
2、add_scalars()
功能:记录标量,可以绘制多条曲线
add_scalar(main_tag,tag_scalar_dict,global_step=None,walltime=None)
main_tag:该图像的标签名
tag_scalar_dict:利用字典的形式记录多条曲线,字典dict的key是变量的tag,value是变量的值
观察参数的分布情况即统计、绘制直方图。
功能:统计直方图与多分位数折线图
add_histogram(tag,values,global_step=None,bins='tensorflow',walltime=None)
tag:图像的标签名
values:要统计的参数(通常有权值、偏置及其对应的梯度)
global_step:y轴(是epoch数)
bins:取直方图的bins(通常采用‘tensorflow’)
随机创建1个标准正态分布和均匀分布,绘制其参数的统计图。
(2)多分位数折线图distributions
下面利用上述方法监控模型的Loss、Accuracy曲线以及参数的分布和参数的梯度分布。
# ============================ step 5/5 训练 ============================
train_curve = list()
valid_curve = list()
iter_count = 0
# 构建 SummaryWriter
writer = SummaryWriter(comment='test_your_comment', filename_suffix="_test_your_filename_suffix")
for epoch in range(MAX_EPOCH):
loss_mean = 0.
correct = 0.
total = 0.
net.train()
for i, data in enumerate(train_loader):
iter_count += 1
# forward
inputs, labels = data
outputs = net(inputs)
# backward
optimizer.zero_grad()
loss = criterion(outputs, labels)
loss.backward()
# update weights
optimizer.step()
# 统计分类情况
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).squeeze().sum().numpy()
# 打印训练信息
loss_mean += loss.item()
train_curve.append(loss.item())
if (i+1) % log_interval == 0:
loss_mean = loss_mean / log_interval
print("Training:Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(
epoch, MAX_EPOCH, i+1, len(train_loader), loss_mean, correct / total))
loss_mean = 0.
# 训练集:每个iteration记录数据,保存于event file
writer.add_scalars("Loss", {"Train": loss.item()}, iter_count)
writer.add_scalars("Accuracy", {"Train": correct / total}, iter_count)
# 训练集——这就是监控过程!!!每个epoch,记录梯度,权值(从named_parameters中获取参数的 名字name,然后对每个参数的数据name+'data'、梯度name+'_grad'记录。)
for name, param in net.named_parameters():
writer.add_histogram(name + '_grad', param.grad, epoch)
writer.add_histogram(name + '_data', param, epoch)
scheduler.step() # 更新学习率
# validate the model
if (epoch+1) % val_interval == 0:
correct_val = 0.
total_val = 0.
loss_val = 0.
net.eval()
with torch.no_grad():
for j, data in enumerate(valid_loader):
inputs, labels = data
outputs = net(inputs)
loss = criterion(outputs, labels)
_, predicted = torch.max(outputs.data, 1)
total_val += labels.size(0)
correct_val += (predicted == labels).squeeze().sum().numpy()
loss_val += loss.item()
valid_curve.append(loss.item())
print("Valid:\t Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(
epoch, MAX_EPOCH, j+1, len(valid_loader), loss_val, correct / total))
# 验证集:记录数据,保存于event file
writer.add_scalars("Loss", {"Valid": np.mean(valid_curve)}, iter_count)
writer.add_scalars("Accuracy", {"Valid": correct / total}, iter_count)