训练看板和溯源
概述
训练过程中的标量、图像、计算图以及模型超参等信息记录到文件中,通过可视化界面供用户查看。
操作流程
准备训练脚本,并在训练脚本中指定标量、图像、计算图、模型超参等信息记录到summary日志文件,接着运行训练脚本。
启动MindInsight,并通过启动参数指定summary日志文件目录,启动成功后,根据IP和端口访问可视化界面,默认访问地址为
http://127.0.0.1:8080
。在训练过程中,有数据写入summary日志文件时,即可在页面中查看可视的数据。
准备训练脚本
Summary数据收集
当前MindSpore支持将标量、图像、计算图、模型超参等信息保存到summary日志文件中,并通过可视化界面进行展示。
MindSpore目前支持三种方式将数据记录到summary日志文件中。
方式一:通过 SummaryCollector
自动收集
在MindSpore中通过 Callback
机制提供支持快速简易地收集一些常见的信息,包括计算图,损失值,学习率,参数权重等信息的 Callback
, 叫做 SummaryCollector
。
在编写训练脚本时,仅需要实例化 SummaryCollector
,并将其应用到 model.train
或者 model.eval
中,
即可自动收集一些常见信息。SummaryCollector
详细的用法可以参考 API
文档中 mindspore.train.callback.SummaryCollector
。
样例代码如下:
import mindspore.nn as nn
from mindspore import context
from mindspore import Tensor
from mindspore.train import Model
from mindspore.common.initializer import TruncatedNormal
from mindspore.ops import operations as P
from mindspore.train.callback import SummaryCollector
"""AlexNet initial."""
def conv(in_channels, out_channels, kernel_size, stride=1, padding=0, pad_mode="valid"):
weight = weight_variable()
return nn.Conv2d(in_channels, out_channels,
kernel_size=kernel_size, stride=stride, padding=padding,
weight_init=weight, has_bias=False, pad_mode=pad_mode)
def fc_with_initialize(input_channels, out_channels):
weight = weight_variable()
bias = weight_variable()
return nn.Dense(input_channels, out_channels, weight, bias)
def weight_variable():
return TruncatedNormal(0.02) # 0.02
class AlexNet(nn.Cell):
def __init__(self, num_classes=10, channel=3):
super(AlexNet, self).__init__()
self.conv1 = conv(channel, 96, 11, stride=4)
self.conv2 = conv(96, 256, 5, pad_mode="same")
self.conv3 = conv(256, 384, 3, pad_mode="same")
self.conv4 = conv(384, 384, 3, pad_mode="same")
self.conv5 = conv(384, 256, 3, pad_mode="same")
self.relu = nn.ReLU()
self.max_pool2d = P.MaxPool(ksize=3, strides=2)
self.flatten = nn.Flatten()
self.fc1 = fc_with_initialize(6*6*256, 4096)
self.fc2 = fc_with_initialize(4096, 4096)
self.fc3 = fc_with_initialize(4096, num_classes)
def construct(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.max_pool2d(x)
x = self.conv2(x)
x = self.relu(x)
x = self.max_pool2d(x)
x = self.conv3(x)
x = self.relu(x)
x = self.conv4(x)
x = self.relu(x)
x = self.conv5(x)
x = self.relu(x)
x = self.max_pool2d(x)
x = self.flatten(x)
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
x = self.relu(x)
x = self.fc3(x)
return x
context.set_context(mode=context.GRAPH_MODE)
network = AlexNet(num_classes=10)
loss = nn.SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=True, reduction="mean")
lr = Tensor(0.1)
opt = nn.Momentum(network.trainable_params(), lr, momentum=0.9)
model = Model(network, loss, opt)
ds_train = create_dataset('./dataset_path')
# Init a SummaryCollector callback instance, and use it in model.train or model.eval
summary_collector = SummaryCollector(summary_dir='./summary_dir', collect_freq=1)
# Note: dataset_sink_mode should be set to False, else you should modify collect freq in SummaryCollector
model.train(epoch=1, ds_train, callbacks=[summary_collector], dataset_sink_mode=False)
ds_eval = create_dataset('./dataset_path')
model.eval(ds_eval, callbacks=[summary_collector])
方式二:结合Summary算子和 SummaryCollector
,自定义收集网络中的数据
MindSpore除了提供 SummaryCollector
能够自动收集一些常见数据,还提供了Summary算子,支持在网络中自定义收集其他的数据,比如每一个卷积层的输入,或在损失函数中的损失值等。记录方式如下面的步骤所示。
步骤一:在继承 nn.Cell
的衍生类的 construct
函数中调用Summary算子来采集图像或标量数据或者其他数据。
比如,定义网络时,在网络的 construct
中记录图像数据;定义损失函数时,在损失函数的 construct
中记录损失值。
如果要记录动态学习率,可以定义优化器时,在优化器的 construct
中记录学习率。
样例代码如下:
from mindspore import context, Tensor, nn
from mindspore.common import dtype as mstype
from mindspore.ops import operations as P
from mindspore.ops import functional as F
from mindspore.nn import Optimizer
class CrossEntropyLoss(nn.Cell):
"""Loss function definition."""
def __init__(self):
super(CrossEntropyLoss, self).__init__()
self.cross_entropy = P.SoftmaxCrossEntropyWithLogits()
self.mean = P.ReduceMean()
self.one_hot = P.OneHot()
self.on_value = Tensor(1.0, mstype.float32)
self.off_value = Tensor(0.0, mstype.float32)
# Init ScalarSummary
self.sm_scalar = P.ScalarSummary()
def construct(self, logits, label):
label = self.one_hot(label, F.shape(logits)[1], self.on_value, self.off_value)
loss = self.cross_entropy(logits, label)[0]
loss = self.mean(loss, (-1,))
# Record loss
self.sm_scalar("loss", loss)
return loss
class MyOptimizer(Optimizer):
"""Optimizer definition."""
def __init__(self, learning_rate, params, ......):
......
# Initialize ScalarSummary
self.sm_scalar = P.ScalarSummary()
self.histogram_summary = P.HistogramSummary()
self.weight_names = [param.name for param in self.parameters]
def construct(self, grads):
......
# Record learning rate here
self.sm_scalar("learning_rate", learning_rate)
# Record weight
self.histogram_summary(self.weight_names[0], self.paramters[0])
# Record gradient
self.histogram_summary(self.weight_names[0] + ".gradient", grads[0])
......
class Net(nn.Cell):
"""Net definition."""
def __init__(self):
super(Net, self).__init__()
......
# Init ImageSummary
self.sm_image = P.ImageSummary()
def construct(self, data):
# Record image by Summary operator
self.sm_image("image", data)
......
return out
步骤二:在训练脚本中,实例化 SummaryCollector
,并将其应用到 model.train
。
样例代码如下:
from mindspore import Model, nn, context
from mindspore.train.callback import SummaryCollector
context.set_context(mode=context.GRAPH_MODE)
net = Net()
loss_fn = CrossEntropyLoss()
optim = MyOptimizer(learning_rate=0.01, params=network.trainable_params())
model = Model(net, loss_fn=loss_fn, optimizer=optim, metrics=None)
train_ds = create_mindrecord_dataset_for_training()
summary_collector = SummaryCollector(summary_dir='./summary_dir', collect_freq=1)
model.train(epoch=2, train_ds, callbacks=[summary_collector])
方式三:自定义Callback记录数据
MindSpore支持自定义Callback, 并允许在自定义Callback中将数据记录到summary日志文件中, 并通过可视化页面进行查看。
下面的伪代码则展示在CNN网络中,开发者可以利用带有原始标签和预测标签的网络输出,生成混淆矩阵的图片,
然后通过 SummaryRecord
模块记录到summary日志文件中。
SummaryRecord
详细的用法可以参考 API
文档中 mindspore.train.summary.SummaryRecord
。
样例代码如下:
from mindspore.train.callback import Callback
from mindspore.train.summary import SummaryRecord
class ConfusionMatrixCallback(Callback):
def __init__(self, summary_dir):
self._summary_dir = summary_dir
def __enter__(self):
# init you summary record in here, when the train script run, it will be inited before training
self.summary_record = SummaryRecord(summary_dir)
def __exit__(self, *exc_args):
# Note: you must close the summary record, it will release the process pool resource
# else your training script will not exit from training.
self.summary_record.close()
return self
def step_end(self, run_context):
cb_params = run_context.run_context.original_args()
# create a confusion matric image, and record it to summary file
confusion_martrix = create_confusion_matrix(cb_params)
self.summary_record.add_value('image', 'confusion_matrix', confusion_matric)
self.summary_record.record(cb_params.cur_step)
# init you train script
...
confusion_martrix = ConfusionMartrixCallback(summary_dir='./summary_dir')
model.train(cnn_network, callbacks=[confusion_martrix])
上面的三种方式,支持记录计算图, 损失值等多种数据。除此以外,MindSpore还支持保存训练中其他阶段的计算图,通过
将训练脚本中 context.set_context
的 save_graphs
选项设置为 True
, 可以记录其他阶段的计算图,其中包括算子融合后的计算图。
在保存的文件中,ms_output_after_hwopt.pb
即为算子融合后的计算图,可以使用可视化页面对其进行查看。
目前MindSpore仅支持在Ascend 910 AI处理器上导出算子融合后的计算图。
在训练中使用Summary算子收集数据时,
HistogramSummary
算子会影响性能,所以请尽量少地使用。
可视化组件
训练看板
用户从训练列表中选择指定的训练,进入训练看板。
标量可视化
标量可视化用于展示训练过程中,标量的变化趋势情况。
图1:标量趋势图
图1展示了神经网络在训练过程中损失值的变化过程。横坐标是训练步骤,纵坐标是损失值。
图中右上角有几个按钮功能,从左到右功能分别是全屏展示,切换Y轴比例,开启/关闭框选,分步回退和还原图形。
全屏展示即全屏展示该标量曲线,再点击一次即可恢复。
切换Y轴比例是指可以将Y轴坐标进行对数转换。
开启/关闭框选是指可以框选图中部分区域,并放大查看该区域, 可以在已放大的图形上叠加框选。
分步回退是指对同一个区域连续框选并放大查看时,可以逐步撤销操作。
还原图形是指进行了多次框选后,点击此按钮可以将图还原回原始状态。
图2:标量可视化功能区
图2展示的标量可视化的功能区,提供了根据选择不同标签,水平轴的不同维度和平滑度来查看标量信息的功能。
标签:提供了对所有标签进行多项选择的功能,用户可以通过勾选所需的标签,查看对应的标量信息。
水平轴:可以选择“步骤”、“相对时间”、“绝对时间”中的任意一项,来作为标量曲线的水平轴。
平滑度:可以通过调整平滑度,对标量曲线进行平滑处理。
标量合成:可以选中两条标量曲线进行合成并展示在一个图中,以方便对两条曲线进行对比或者查看合成后的图。
图3:Accuracy和Loss的标量合成图
图3展示Accuracy曲线和Loss曲线的标量合成图。标量合成的功能区与标量可视化的功能区相似。其中与标量可视化功能区不一样的地方,在于标签选择时,标量合成功能最多只能同时选择两个标签,将其曲线合成并展示。
参数分布图可视化
参数分布图用于将用户所指定的张量以直方图的形式进行展示。
图4: 直方图展示
图4将用户所记录的张量以直方图的形式进行展示。点击图中右上角,可以将图放大。
图5: 参数分布图功能区
图5展示参数分布图的功能区,包含以下内容:
标签选择:提供了对所有标签进行多项选择的功能,用户可以通过勾选所需的标签,查看对应的直方图。
纵轴:可以选择
步骤
、相对时间
、绝对时间
中的任意一项,来作为直方图纵轴显示的数据。视角:可以选择
正视
和俯视
中的一种。正视
是指从正面的角度查看直方图,此时不同步骤之间的数据会覆盖在一起。俯视
是指偏移以45度角俯视直方图区域,这时可以呈现不同步骤之间数据的差异。
计算图可视化
计算图可视化用于展示计算图的图结构,数据流以及控制流的走向,支持展示summary日志文件与通过context
的save_graphs
参数导出的pb
文件。
图6:计算图展示区
图6展示了计算图的网络结构。如图中所展示的,在展示区中,选中其中一个算子(图中圈红算子),可以看到该算子有两个输入和一个输出(实线代表算子的数据流走向)。
图7:计算图功能区
图7展示了计算图可视化的功能区,包含以下内容:
文件选择框: 可以选择查看不同文件的计算图。
搜索框:可以对节点进行搜索,输入节点名称点击回车,即可展示该节点。
缩略图:展示整个网络图结构的缩略图,在查看超大图结构时,方便查看当前浏览的区域。
节点信息:展示选中的节点的基本信息,包括节点的名称、属性、输入节点、输出节点等信息。
图例:展示的是计算图中各个图标的含义。
数据图可视化
数据图可视化用于展示单次模型训练的数据处理和数据增强信息。
图8:数据图功能区
图8展示的数据图功能区包含以下内容:
图例:展示数据溯源图中各个图标的含义。
数据处理流水线:展示训练所使用的数据处理流水线,可以选择图中的单个节点查看详细信息。
节点信息:展示选中的节点的基本信息,包括使用的数据处理和增强算子的名称、参数等。
图像可视化
图像可视化用于展示用户所指定的图片。
图9:图像可视化
图9展示通过滑动图中“步骤”滑条,查看不同步骤的图片。
图10:图像可视化功能区
图10展示图像可视化的功能区,提供了选择查看不同标签,不同亮度和不同对比度来查看图片信息。
标签:提供了对所有标签进行多项选择的功能,用户可以通过勾选所需的标签,查看对应的图片信息。
亮度调整:可以调整所展示的所有图片亮度。
对比度调整:可以调整所展示的所有图片对比度。
模型溯源
模型溯源可视化用于展示所有训练的模型参数信息。
图11:模型参数选择区
图11展示的模型参数选择区,列举了可供查看的模型参数标签。用户可以通过勾选所需的标签,查看相应的模型参数。
图12:模型溯源功能区
图12展示的模型溯源功能区,图像化展示了模型的参数信息。用户可以通过选择列的特定区域,展示区域范围内的模型信息。
图13:模型列表
图13分组展示所有模型信息,用户可以按指定列进行升序或降序展示模型信息。
数据溯源
数据溯源可视化用于展示所有训练的数据处理和数据增强信息。
图14:数据处理和增强算子选择区
图14展示的数据处理和数据增强算子选择区,列举了可供查看的数据处理和增强算子的名称。用户可以通过勾选所需的标签,查看相应的参数等信息。
图15:数据溯源功能区
图15展示的数据溯源功能区,图像化展示了数据处理和数据增强使用的参数信息。用户可以通过选择列的特定区域,展示区域范围内的参数信息。
图16:数据溯源列表
图16展示所有模型训练的数据处理和数据增强信息。
如果用户筛选模型溯源随后切换到数据溯源页面时,折线图将展示最新一次筛选过的模型溯源列。
对比看板
对比看板可视用于多个训练之间的标量曲线对比。
图17: 标量对比曲线图
图17展示了多个训练之间的标量曲线对比效果,横坐标是训练步骤,纵坐标是标量值。
图中右上角有几个按钮功能,从左到右功能分别是全屏展示,切换Y轴比例,开启/关闭框选,分步回退和还原图形。
全屏展示即全屏展示该标量曲线,再点击一次即可恢复。
切换Y轴比例是指可以将Y轴坐标进行对数转换。
开启/关闭框选是指可以框选图中部分区域,并放大查看该区域, 可以在已放大的图形上叠加框选。
分步回退是指对同一个区域连续框选并放大查看时,可以逐步撤销操作。
还原图形是指进行了多次框选后,点击此按钮可以将图还原回原始状态。
图18:对比看板可视功能区
图18展示的对比看板可视的功能区,提供了根据选择不同训练或标签,水平轴的不同维度和平滑度来进行标量对比的功能。
训练: 提供了对所有训练进行多项选择的功能,用户可以通过勾选或关键字筛选所需的训练。
标签:提供了对所有标签进行多项选择的功能,用户可以通过勾选所需的标签,查看对应的标量信息。
水平轴:可以选择“步骤”、“相对时间”、“绝对时间”中的任意一项,来作为标量曲线的水平轴。
平滑度:可以通过调整平滑度,对标量曲线进行平滑处理。
规格
为了控制列出summary列表的用时,MindInsight最多支持发现999个summary列表条目。
为了控制内存占用,MindInsight对标签(tag)数目和步骤(step)数目进行了限制:
每个训练看板的最大标签数量为300个标签。标量标签、图片标签、计算图标签、参数分布图(直方图)标签的数量总和不得超过300个。特别地,每个训练看板最多有10个计算图标签。当实际标签数量超过这一限制时,将依照MindInsight的处理顺序,保留最近处理的300个标签。
每个训练看板的每个标量标签最多有1000个步骤的数据。当实际步骤的数目超过这一限制时,将对数据进行随机采样,以满足这一限制。
每个训练看板的每个图片标签最多有10个步骤的数据。当实际步骤的数目超过这一限制时,将对数据进行随机采样,以满足这一限制。
每个训练看板的每个参数分布图(直方图)标签最多有50个步骤的数据。当实际步骤的数目超过这一限制时,将对数据进行随机采样,以满足这一限制。
出于性能上的考虑,MindInsight对比看板使用缓存机制加载训练的标量曲线数据,并进行以下限制:
对比看板只支持在缓存中的训练进行比较标量曲线对比。
缓存最多保留最新(按修改时间排列)的15个训练。
用户最多同时对比5个训练的标量曲线。