感谢:ZOMI酱
通常我们训练神经网络模型的时候,默认使用的数据类型为单精度FP32。近年来,为了加快训练时间、减少网络训练时候所占用的内存,并且保存训练出来的模型精度持平的条件下,业界提出越来越多的混合精度训练的方法。这里的混合精度训练是指在训练的过程中,同时使用单精度(FP32)和半精度(FP16)。
浮点数据类型主要分为双精度(FP64)、单精度(FP32)、半精度(FP16)。在神经网络模型的训练过程中,一般默认采用单精度(FP32)浮点数据类型,来表示网络模型权重和其他参数。在了解混合精度训练之前,这里简单了解浮点数据类型。
根据IEEE二进制浮点数算术标准(IEEE 754)的定义,浮点数据类型分为双精度(FP64)、单精度(FP32)、半精度(FP16)三种,其中每一种都有三个不同的位来表示。FP64表示采用8个字节共64位,来进行的编码存储的一种数据类型;同理,FP32表示采用4个字节共32位来表示;FP16则是采用2字节共16位来表示。如图所示:
从图中可以看出,与FP32相比,FP16的存储空间是FP32的一半,FP32则是FP64的一半。主要分为三个部分:
以FP16为例子,第一位符号位sign表示正负符号;接着5个比特位表示指数exponent,全0和全1有特殊用途,因此二进制范围为00001~11110;最后10个比特位表示分数fraction。假设S
表示sign bit的十进制值,E
表示exponent的十进制值,fraction
表示fraction的十进制值,则公式为:
x=(−1)S×2E−15×(1+fraction1024)
同理,假设M
为分数值,则一个规则化的FP32的真值为:
x=(−1)S×2E−127×(1.M)
一个规格化的FP64的真值为:
x=(−1)S×2E−1023×(1.M)
FP16可以表示的最大值为 0 11110 1111111111,计算方法为:
(−1)0×230−15×1.1111111111=1.1111111111(b)×215=1.9990234375(d)×215=65504
其中b
表示二进制值(binary),d
表示十进制值(decimal)。
FP16可以表示的最小值为 0 00001 0000000000,计算方法为:
(−1)1×21−15=−2−14=−6.104×10−5=−65504
因此FP16的最大取值范围是[-65504, 65504],能表示的精度范围是 2−24,超过这个数值的数字会被直接置0。
首先来看看为什么需要混合精度。使用FP16训练神经网络,相对比使用FP32带来的优点有:
但是使用FP16同样会带来一些问题,其中最重要的是精度溢出和舍入误差。
MindSpore混合精度典型的计算流程如下图所示:
本文通过自动混合精度和手动混合精度的样例来讲解计算流程。
使用自动混合精度,需要调用Model
接口,将待训练网络和优化器作为输入传进去,该接口会把网络模型的的算子转换成FP16算子。
除
BatchNorm
算子和Loss涉及到的算子外因为精度问题,仍然使用FP32执行运算。
使用Model
接口具体的实现步骤为:
引入MindSpore的模型训练接口Model
;
定义网络:该步骤和正常的网络定义相同(无需新增任何配置);
创建数据集:该步骤可参考数据处理;
使用Model
接口封装网络模型、优化器和损失函数,设置amp_level
参数,详情参考MindSpore API。该步骤MindSpore会自动选择合适的算子自动进行FP32到FP16的类型转换。
下面是基础的代码样例,首先导入必须的库和声明,并定义LeNet5网络模型。
import numpy as np
import mindspore.nn as nn
from mindspore.nn import Accuracy
import mindspore as ms
from mindspore.common.initializer import Normal
from mindspore import dataset as ds
ms.set_context(mode=ms.GRAPH_MODE)
ms.set_context(device_target="GPU")
class LeNet5(nn.Cell):
"""
Lenet network
Args:
num_class (int): Number of classes. Default: 10.
num_channel (int): Number of channels. Default: 1.
Returns:
Tensor, output tensor
"""
def __init__(self, num_class=10, num_channel=1):
super(LeNet5, self).__init__()
self.conv1 = nn.Conv2d(num_channel, 6, 5, pad_mode='valid')
self.conv2 = nn.Conv2d(6, 16, 5, pad_mode='valid')
self.fc1 = nn.Dense(16 * 5 * 5, 120, weight_init=Normal(0.02))
self.fc2 = nn.Dense(120, 84, weight_init=Normal(0.02))
self.fc3 = nn.Dense(84, num_class, weight_init=Normal(0.02))
self.relu = nn.ReLU()
self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2)
self.flatten = nn.Flatten()
def construct(self, x):
x = self.max_pool2d(self.relu(self.conv1(x)))
x = self.max_pool2d(self.relu(self.conv2(x)))
x = self.flatten(x)
x = self.relu(self.fc1(x))
x = self.relu(self.fc2(x))
x = self.fc3(x)
return x
接着创建一个虚拟的随机数据集,用于样例模型的数据输入。
# create dataset
def get_data(num, img_size=(1, 32, 32), num_classes=10, is_onehot=True):
for _ in range(num):
img = np.random.randn(*img_size)
target = np.random.randint(0, num_classes)
target_ret = np.array([target]).astype(np.float32)
if is_onehot:
target_onehot = np.zeros(shape=(num_classes,))
target_onehot[target] = 1
target_ret = target_onehot.astype(np.float32)
yield img.astype(np.float32), target_ret
def create_dataset(num_data=1024, batch_size=32, repeat_size=1):
input_data = ds.GeneratorDataset(list(get_data(num_data)), column_names=['data', 'label'])
input_data = input_data.batch(batch_size, drop_remainder=True)
input_data = input_data.repeat(repeat_size)
return input_data
设置amp_level
参数,使用Model
接口封装网络模型、优化器和损失函数。
ds_train = create_dataset()
# Initialize network
network = LeNet5(10)
# Define Loss and Optimizer
net_loss = nn.SoftmaxCrossEntropyWithLogits(reduction="mean")
net_opt = nn.Momentum(network.trainable_params(), learning_rate=0.01, momentum=0.9)
# Set amp level
model = ms.Model(network, net_loss, net_opt, metrics={"Accuracy": Accuracy()}, amp_level="O3")
# Run training
model.train(epoch=10, train_dataset=ds_train)
TotalTime = 1.29408, [19] [parse]: 0.449277 [symbol_resolve]: 0.524724, [1] [Cycle 1]: 0.524189, [1] [resolve]: 0.524178 [combine_like_graphs]: 0.00118984 [inference_opt_prepare]: 0.000437367 [elininate_unused_parameter]: 0.000120089 [abstract_specialize]: 0.0697742 [auto_monad]: 0.00147299 [inline]: 8.08202e-06 [py_pre_ad]: 8.5216e-07 [pipeline_split]: 6.4522e-06 [optimize]: 0.209156, [14] [simplify_data_structures]: 0.000270152 [opt_a]: 0.204985, [3] [Cycle 1]: 0.179181, [25] [expand_dump_flag]: 1.03367e-05 [switch_simplify]: 0.000675488 [a_1]: 0.00937402 [recompute_prepare]: 8.37147e-05 [updatestate_depend_eliminate]: 0.000645219 [updatestate_assign_eliminate]: 6.78673e-05 [updatestate_loads_eliminate]: 0.000229622 [parameter_eliminate]: 2.73902e-06 ... 0.03% : 0.000172s : 1: opt.transforms.opt_after_cconv 0.01% : 0.000050s : 1: opt.transforms.opt_b 0.05% : 0.000266s : 1: opt.transforms.opt_trans_graph 0.00% : 0.000024s : 1: opt.transforms.stop_gradient_special_op
MindSpore目前还支持手动混合精度(一般不建议使用手动混合精度,除非自定义特殊网络和特性开发)。
假定在网络中只有一个Dense Layer使用FP16计算,其他Layer都用FP32计算。
混合精度配置以Cell为单位,Cell默认是FP32类型。
以下是一个手动混合精度的实现步骤:
定义网络:该步骤与自动混合精度中的步骤2类似;
配置混合精度:通过to_float(ms.float16)
把Cell中涉及的算子配置成FP16;
使用TrainOneStepCell
封装网络模型和优化器。
下面是基础的代码样例,首先导入必须的库和声明。
import numpy as np
import mindspore.nn as nn
from mindspore.nn import Accuracy
import mindspore as ms
from mindspore.common.initializer import Normal
from mindspore import dataset as ds
import mindspore.ops as ops
ms.set_context(mode=ms.GRAPH_MODE, device_target="GPU")
网络定义无论是使用FP32还是FP16都是使用相同的方式,区别在于定义网络后,在初始化网络模型的时候声明dense层使用FP16进行计算,即net.dense.to_float(mstype.float16)
。
class LeNet5(nn.Cell):
"""
Lenet network
Args:
num_class (int): Number of classes. Default: 10.
num_channel (int): Number of channels. Default: 1.
Returns:
Tensor, output tensor
"""
def __init__(self, num_class=10, num_channel=1):
super(LeNet5, self).__init__()
self.conv1 = nn.Conv2d(num_channel, 6, 5, pad_mode='valid')
self.conv2 = nn.Conv2d(6, 16, 5, pad_mode='valid')
self.fc1 = nn.Dense(16 * 5 * 5, 120, weight_init=Normal(0.02))
self.fc2 = nn.Dense(120, 84, weight_init=Normal(0.02))
self.fc3 = nn.Dense(84, num_class, weight_init=Normal(0.02))
self.relu = nn.ReLU()
self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2)
self.flatten = nn.Flatten()
self.cast = ops.Cast()
def construct(self, x):
x = self.conv1(x)
x = self.cast(x, ms.float32)
x = self.relu(x)
x = self.max_pool2d(x)
x = self.max_pool2d(self.relu(self.conv2(x)))
x = self.flatten(x)
x = self.relu(self.fc1(x))
x = self.relu(self.fc2(x))
x = self.fc3(x)
return x
# create dataset
def get_data(num, img_size=(1, 32, 32), num_classes=10, is_onehot=True):
for _ in range(num):
img = np.random.randn(*img_size)
target = np.random.randint(0, num_classes)
target_ret = np.array([target]).astype(np.float32)
if is_onehot:
target_onehot = np.zeros(shape=(num_classes,))
target_onehot[target] = 1
target_ret = target_onehot.astype(np.float32)
yield img.astype(np.float32), target_ret
def create_dataset(num_data=1024, batch_size=32, repeat_size=1):
input_data = ds.GeneratorDataset(list(get_data(num_data)), column_names=['data', 'label'])
input_data = input_data.batch(batch_size, drop_remainder=True)
input_data = input_data.repeat(repeat_size)
return input_data
ds_train = create_dataset()
network = LeNet5(10)
net_loss = nn.SoftmaxCrossEntropyWithLogits(reduction="mean")
net_opt = nn.Momentum(network.trainable_params(), learning_rate=0.01, momentum=0.9)
network.conv1.to_float(ms.float16)
model = ms.Model(network, net_loss, net_opt, metrics={"Accuracy": Accuracy()}, amp_level="O2")
model.train(epoch=2, train_dataset=ds_train)
TotalTime = 1.30477, [19] [parse]: 0.0026434 [symbol_resolve]: 0.941243, [1] [Cycle 1]: 0.939962, [1] [resolve]: 0.93995 [combine_like_graphs]: 0.00173236 [inference_opt_prepare]: 0.000601928 [elininate_unused_parameter]: 8.18716e-05 [abstract_specialize]: 0.117281 [auto_monad]: 0.00242396 [inline]: 1.78907e-06 [py_pre_ad]: 9.74163e-07 [pipeline_split]: 4.01773e-06 [optimize]: 0.177669, [14] [simplify_data_structures]: 0.000384738 [opt_a]: 0.17035, [3] [Cycle 1]: 0.131339, [25] [expand_dump_flag]: 1.71131e-05 [switch_simplify]: 0.000906539 [a_1]: 0.0198893 [recompute_prepare]: 0.000163792 [updatestate_depend_eliminate]: 0.00138791 [updatestate_assign_eliminate]: 0.000138173 [updatestate_loads_eliminate]: 0.000540169 [parameter_eliminate]: 9.56003e-06 ... 0.06% : 0.000602s : 2: opt.transforms.opt_after_cconv 0.01% : 0.000076s : 1: opt.transforms.opt_b 0.04% : 0.000415s : 1: opt.transforms.opt_trans_graph 0.00% : 0.000025s : 1: opt.transforms.stop_gradient_special_op
约束:使用混合精度时,只能由自动微分功能生成反向网络,不能由用户自定义生成反向网络,否则可能会导致MindSpore产生数据格式不匹配的异常信息。
损失缩放(Loss Scale)技术主要是作用于混合精度训练的过程当中。
在混合精度训练的过程中,会使用FP16类型来替代FP32类型进行数据存储,从而达到减少内存和提高计算速度的效果。但是由于FP16类型要比FP32类型表示的范围小很多,所以当参数(如梯度)在训练过程中变得很小时,就会发生数据下溢的情况。而Loss Scale损失缩放,正是为了解决FP16类型数据下溢问题而提出的。
其主要思想是在计算损失值loss的时候,将loss扩大一定的倍数。由于链式法则的存在,梯度也会相应扩大,然后在优化器更新权重时再缩小相应的倍数,从而避免了数据下溢的情况又不影响计算结果。
MindSpore中提供了两种Loss Scale的方式,分别是FixedLossScaleManager
和DynamicLossScaleManager
,需要和Model配合使用。在使用Model构建模型时,可配置混合精度策略amp_level
和Loss Scale方式loss_scale_manager
。
首先来看看为什么需要混合精度。使用FP16训练神经网络,相对比使用FP32带来的优点有:
但是使用FP16同样会带来一些问题,其中最重要的是精度溢出和舍入误差,Loss Scale就是为了解决精度溢出而提出的。
如图所示,如果仅仅使用FP32训练,模型收敛得比较好,但是如果用了混合精度训练,会存在网络模型无法收敛的情况。原因是梯度的值太小,使用FP16表示会造成了数据下溢出(Underflow)的问题,导致模型不收敛,如图中灰色的部分。于是需要引入损失缩放(Loss Scale)技术。
下面是在网络模型训练阶段, 某一层的激活函数梯度分布式中,其中有68%的网络模型激活参数位0,另外有4%的精度在2−32,2−20这个区间内,直接使用FP16对这里面的数据进行表示,会截断下溢的数据,所有的梯度值都会变为0。
为了解决梯度过小数据下溢的问题,对前向计算出来的Loss值进行放大操作,也就是把FP32的参数乘以某一个因子系数后,把可能溢出的小数位数据往前移,平移到FP16能表示的数据范围内。根据链式求导法则,放大Loss后会作用在反向传播的每一层梯度,这样比在每一层梯度上进行放大更加高效。
损失放大是需要结合混合精度实现的,其主要的主要思路是:
动态损失缩放(Dynamic Loss Scale):上面提到的损失缩放都是使用一个默认值对损失值进行缩放,为了充分利用FP16的动态范围,可以更好地缓解舍入误差,尽量使用比较大的放大倍数。总结动态损失缩放算法,就是每当梯度溢出时候减少损失缩放规模,并且间歇性地尝试增加损失规模,从而实现在不引起溢出的情况下使用最高损失缩放因子,更好地恢复精度。
动态损失缩放的算法如下:
下面将会分别介绍MindSpore中,使用损失缩放算法的主要两个API FixedLossScaleManager和DynamicLossScaleManager。
FixedLossScaleManager
在进行缩放的时候,不会改变scale的大小,scale的值由入参loss_scale控制,可以由用户指定,不指定则取默认值。
FixedLossScaleManager
的另一个参数是drop_overflow_update
,用来控制发生溢出时是否更新参数。
一般情况下LossScale功能不需要和优化器配合使用,但使用FixedLossScaleManager
时,如果drop_overflow_update
为False,那么优化器需设置loss_scale
的值,且loss_scale
的值要与FixedLossScaleManager
的相同。
FixedLossScaleManager
具体用法如下:
import numpy as np
import mindspore as ms
import mindspore.nn as nn
from mindspore.nn import Accuracy
from mindspore.common.initializer import Normal
from mindspore import dataset as ds
#ms.set_seed(0)
ms.set_context(mode=ms.GRAPH_MODE, device_target="GPU")
class LeNet5(nn.Cell):
"""
Lenet network
Args:
num_class (int): Number of classes. Default: 10.
num_channel (int): Number of channels. Default: 1.
Returns:
Tensor, output tensor
"""
def __init__(self, num_class=10, num_channel=1):
super(LeNet5, self).__init__()
self.conv1 = nn.Conv2d(num_channel, 6, 5, pad_mode='valid')
self.conv2 = nn.Conv2d(6, 16, 5, pad_mode='valid')
self.fc1 = nn.Dense(16 * 5 * 5, 120, weight_init=Normal(0.02))
self.fc2 = nn.Dense(120, 84, weight_init=Normal(0.02))
self.fc3 = nn.Dense(84, num_class, weight_init=Normal(0.02))
self.relu = nn.ReLU()
self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2)
self.flatten = nn.Flatten()
def construct(self, x):
x = self.max_pool2d(self.relu(self.conv1(x)))
x = self.max_pool2d(self.relu(self.conv2(x)))
x = self.flatten(x)
x = self.relu(self.fc1(x))
x = self.relu(self.fc2(x))
x = self.fc3(x)
return x
# create dataset
def get_data(num, img_size=(1, 32, 32), num_classes=10, is_onehot=True):
for _ in range(num):
img = np.random.randn(*img_size)
target = np.random.randint(0, num_classes)
target_ret = np.array([target]).astype(np.float32)
if is_onehot:
target_onehot = np.zeros(shape=(num_classes,))
target_onehot[target] = 1
target_ret = target_onehot.astype(np.float32)
yield img.astype(np.float32), target_ret
def create_dataset(num_data=1024, batch_size=32, repeat_size=1):
input_data = ds.GeneratorDataset(list(get_data(num_data)), column_names=['data', 'label'])
input_data = input_data.batch(batch_size, drop_remainder=True)
input_data = input_data.repeat(repeat_size)
return input_data
ds_train = create_dataset()
# Initialize network
network = LeNet5(10)
# Define Loss and Optimizer
net_loss = nn.SoftmaxCrossEntropyWithLogits(reduction="mean")
# Define Loss Scale, optimizer and model
#1) Drop the parameter update if there is an overflow
loss_scale_manager = ms.FixedLossScaleManager()
net_opt = nn.Momentum(network.trainable_params(), learning_rate=0.01, momentum=0.9)
model = ms.Model(network, net_loss, net_opt, metrics={"Accuracy": Accuracy()}, amp_level="O0", loss_scale_manager=loss_scale_manager)
#2) Execute parameter update even if overflow occurs
loss_scale = 1024.0
loss_scale_manager = ms.FixedLossScaleManager(loss_scale, False)
net_opt = nn.Momentum(network.trainable_params(), learning_rate=0.01, momentum=0.9, loss_scale=loss_scale)
model = ms.Model(network, net_loss, net_opt, metrics={"Accuracy": Accuracy()}, amp_level="O0", loss_scale_manager=loss_scale_manager)
# Run training
model.train(epoch=10, train_dataset=ds_train, callbacks=[ms.LossMonitor()])
TotalTime = 0.639526, [19] [parse]: 0.00137553 [symbol_resolve]: 0.0630952, [1] [Cycle 1]: 0.0626392, [1] [resolve]: 0.0626309 [combine_like_graphs]: 0.00123225 [inference_opt_prepare]: 0.000407694 [elininate_unused_parameter]: 0.000182617 [abstract_specialize]: 0.0623443 [auto_monad]: 0.00156646 [inline]: 1.93249e-06 [py_pre_ad]: 9.71369e-07 [pipeline_split]: 2.88989e-06 [optimize]: 0.477379, [14] [simplify_data_structures]: 0.00029841 [opt_a]: 0.473795, [3] [Cycle 1]: 0.450451, [25] [expand_dump_flag]: 1.45491e-05 [switch_simplify]: 0.000713205 [a_1]: 0.00994622 [recompute_prepare]: 8.40612e-05 [updatestate_depend_eliminate]: 0.000666355 [updatestate_assign_eliminate]: 6.59283e-05 [updatestate_loads_eliminate]: 0.000232871 [parameter_eliminate]: 2.64868e-06 ... 0.16% : 0.000156s : 1: opt.transforms.opt_after_cconv 0.04% : 0.000044s : 1: opt.transforms.opt_b 0.24% : 0.000240s : 1: opt.transforms.opt_trans_graph 0.02% : 0.000018s : 1: opt.transforms.stop_gradient_special_op epoch: 1 step: 32, loss is 2.301311731338501 epoch: 2 step: 32, loss is 2.2960867881774902 epoch: 3 step: 32, loss is 2.292977809906006 epoch: 4 step: 32, loss is 2.2935791015625 epoch: 5 step: 32, loss is 2.3079633712768555 epoch: 6 step: 32, loss is 2.3191769123077393 epoch: 7 step: 32, loss is 2.3069581985473633 epoch: 8 step: 32, loss is 2.2944517135620117 epoch: 9 step: 32, loss is 2.3150291442871094 epoch: 10 step: 32, loss is 2.3247132301330566
前面提到了使用FixedLossScaleManager
且drop_overflow_update
为False时,优化器需要配合使用。
这是由于采用此方式进行配置时,梯度与loss_scale
系数之间的除法运算在优化器中进行。优化器设置与FixedLossScaleManager
相同的loss_scale
,训练结果才是正确的。
后续MindSpore会优化不同场景下溢出检测功能的用法,并逐步移除优化器中的
loss_scale
参数,到时便无需配置优化器的loss_scale
参数。
需要注意的是,当前MindSpore提供的部分优化器如AdamWeightDecay
,未提供loss_scale
参数。如果使用FixedLossScaleManager
,且drop_overflow_update
配置为False,优化器中未能进行梯度与loss_scale
之间的除法运算,此时需要自定义TrainOneStepCell
,并在其中对梯度除loss_scale
,以使最终的计算结果正确,定义方式如下:
import mindspore as ms
from mindspore import nn, ops
grad_scale = ops.MultitypeFuncGraph("grad_scale")
@grad_scale.register("Tensor", "Tensor")
def gradient_scale(scale, grad):
return grad * ops.cast(scale, ops.dtype(grad))
class CustomTrainOneStepCell(nn.TrainOneStepCell):
def __init__(self, network, optimizer, sens=1.0):
super(CustomTrainOneStepCell, self).__init__(network, optimizer, sens)
self.hyper_map = ops.HyperMap()
self.reciprocal_sense = ms.Tensor(1 / sens, ms.float32)
def scale_grad(self, gradients):
gradients = self.hyper_map(ops.partial(grad_scale, self.reciprocal_sense), gradients)
return gradients
def construct(self, *inputs):
loss = self.network(*inputs)
sens = ops.fill(loss.dtype, loss.shape, self.sens)
# calculate gradients, the sens will equal to the loss_scale
grads = self.grad(self.network, self.weights)(*inputs, sens)
# gradients / loss_scale
grads = self.scale_grad(grads)
# reduce gradients in distributed scenarios
grads = self.grad_reducer(grads)
loss = ops.depend(loss, self.optimizer(grads))
return loss
loss_scale
,训练过程中梯度值会放大loss_scale
倍。loss_scale
系数之间的除法运算,还原梯度。nn.TrainOneStepCell
定义construct
的计算逻辑,并在获取梯度后调用scale_grad
。自定义TrainOneStepCell
后,需要手动构建训练网络,如下:
from mindspore import nn
network = LeNet5(10)
# Define Loss and Optimizer
net_loss = nn.SoftmaxCrossEntropyWithLogits(reduction="mean")
net_opt = nn.AdamWeightDecay(network.trainable_params(), learning_rate=0.01)
# Define LossScaleManager
loss_scale = 1024.0
loss_scale_manager = ms.FixedLossScaleManager(loss_scale, False)
# Build train network
net_with_loss = nn.WithLossCell(network, net_loss)
net_with_train = CustomTrainOneStepCell(net_with_loss, net_opt, loss_scale)
构建训练网络后可以直接运行或通过Model运行:
epochs = 2
#1) Execute net_with_train
ds_train = create_dataset()
for epoch in range(epochs):
for d in ds_train.create_dict_iterator():
result = net_with_train(d["data"], d["label"])
#2) Define Model and run
model = ms.Model(net_with_train)
ds_train = create_dataset()
model.train(epoch=epochs, train_dataset=ds_train)
TotalTime = 0.721387, [19] [parse]: 0.00567112 [symbol_resolve]: 0.0858919, [1] [Cycle 1]: 0.0850383, [1] [resolve]: 0.085027 [combine_like_graphs]: 0.00157277 [inference_opt_prepare]: 0.000521986 [elininate_unused_parameter]: 0.000218714 [abstract_specialize]: 0.363722 [auto_monad]: 0.00308862 [inline]: 2.36649e-06 [py_pre_ad]: 1.74344e-06 [pipeline_split]: 4.85033e-06 [optimize]: 0.181153, [14] [simplify_data_structures]: 0.000518564 [opt_a]: 0.171543, [3] [Cycle 1]: 0.128218, [25] [expand_dump_flag]: 2.20183e-05 [switch_simplify]: 0.00109332 [a_1]: 0.0204419 [recompute_prepare]: 0.000202411 [updatestate_depend_eliminate]: 0.00116004 [updatestate_assign_eliminate]: 0.000448607 [updatestate_loads_eliminate]: 0.000705524 [parameter_eliminate]: 3.32016e-06 ... 0.33% : 0.000470s : 1: opt.transforms.opt_after_cconv 0.11% : 0.000148s : 1: opt.transforms.opt_b 0.45% : 0.000631s : 1: opt.transforms.opt_trans_graph 0.01% : 0.000019s : 1: opt.transforms.stop_gradient_special_op
在此场景下使用Model
进行训练时,loss_scale_manager
和amp_level
无需配置,因为CustomTrainOneStepCell
中已经包含了混合精度的计算逻辑。
DynamicLossScaleManager
在训练过程中可以动态改变scale的大小,在没有发生溢出的情况下,要尽可能保持较大的scale。
DynamicLossScaleManager
会首先将scale设置为一个初始值,该值由入参init_loss_scale控制。
在训练过程中,如果不发生溢出,在更新scale_window次参数后,会尝试扩大scale的值,如果发生了溢出,则跳过参数更新,并缩小scale的值,入参scale_factor是控制扩大或缩小的步数,scale_window控制没有发生溢出时,最大的连续更新步数。
具体用法如下,仅需将FixedLossScaleManager
样例中定义LossScale,优化器和模型部分的代码改成如下代码:
# Define Loss Scale, optimizer and model
scale_factor = 4
scale_window = 3000
loss_scale_manager = ms.DynamicLossScaleManager(scale_factor, scale_window)
net_opt = nn.Momentum(network.trainable_params(), learning_rate=0.01, momentum=0.9)
model = ms.Model(network, net_loss, net_opt, metrics={"Accuracy": Accuracy()}, amp_level="O0", loss_scale_manager=loss_scale_manager)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。