网络参数

在OpenI运行下载Notebook下载样例代码查看源文件

MindSpore提供了关于变量、网络相关参数的初始化模块,用户可以通过封装算子来调用字符串、Initializer子类或自定义Tensor等方式完成对网络参数进行初始化。

下面图中蓝色表示具体的执行算子,绿色的表示张量Tensor,张量作为神经网络模型中的数据在网络中不断流动,主要包括网络模型的数据输入,算子的输入输出数据等;红色的为变量Parameter,作为网络模型或者模型中算子的属性,及其反向图中产生的中间变量和临时变量。

parameter.png

本章主要介绍数据类型dtype、变量Parameter、变量元组ParameterTuple、网络的初始化方法和网络参数更新。

数据类型 dtype

MindSpore张量支持不同的数据类型dtype,包含int8、int16、int32、int64、uint8、uint16、uint32、uint64、float16、float32、float64、bool_,与NumPy的数据类型一一对应。详见 mindspore.dtype

在MindSpore的运算处理流程中,Python中的int数会被转换为定义的int64类型,float数会被转换为定义的float32类型。

以下代码,打印MindSpore的数据类型int32。

[1]:
import mindspore as ms

data_type = ms.int32
print(data_type)
Int32

数据类型转换接口

MindSpore提供了以下几个接口,实现与NumPy数据类型和Python内置的数据类型间的转换。

  • dtype_to_nptype:将MindSpore的数据类型转换为NumPy对应的数据类型。

  • dtype_to_pytype:将MindSpore的数据类型转换为Python对应的内置数据类型。

  • pytype_to_dtype:将Python内置的数据类型转换为MindSpore对应的数据类型。

以下代码实现了不同数据类型间的转换,并打印转换后的类型。

[2]:
import mindspore as ms

np_type = ms.dtype_to_nptype(ms.int32)
ms_type = ms.pytype_to_dtype(int)
py_type = ms.dtype_to_pytype(ms.float64)

print(np_type)
print(ms_type)
print(py_type)
<class 'numpy.int32'>
Int64
<class 'float'>

变量 Parameter

MindSpore的变量(Parameter)表示在网络训练时,需要被更新的参数。例如,在前行计算的时候最常见的nn.conv算子的变量有权重weight和偏置bias;在构建反向图和反向传播计算的时候,会产生很多中间变量,用于暂存一阶梯度信息、中间输出值等。

变量初始化

变量Parameter的初始化方法有很多种,可以接收TensorInitializer等不同的数据类型。

  • default_input:为输入数据,支持传入TensorInitializerintfloat四种数据类型;

  • name:可设置变量的名称,用于在网络中区别于其他变量;

  • requires_grad:表示在网络训练过程,是否需要计算参数梯度,如果不需要计算参数梯度,将requires_grad设置为False

下面的示例代码中,使用intfloat数据类型直接创建Parameter:

[1]:
import mindspore as ms

x = ms.Parameter(default_input=2.0, name='x')
y = ms.Parameter(default_input=5.0, name='y')
z = ms.Parameter(default_input=5, name='z', requires_grad=False)

print(type(x))
print(x, "value:", x.asnumpy())
print(y, "value:", y.asnumpy())
print(z, "value:", z.asnumpy())
<class 'mindspore.common.parameter.ParameterTensor'>
Parameter (name=x, shape=(), dtype=Float32, requires_grad=True) value: 2.0
Parameter (name=y, shape=(), dtype=Float32, requires_grad=True) value: 5.0
Parameter (name=z, shape=(), dtype=Int32, requires_grad=False) value: 5

下面示例代码中,使用MindSpore的张量Tensor创建Parameter:

[2]:
import numpy as np
import mindspore as ms

my_tensor = ms.Tensor(np.arange(2 * 3).reshape((2, 3)))
x = ms.Parameter(default_input=my_tensor, name="tensor")

print(x)
Parameter (name=tensor, shape=(2, 3), dtype=Int64, requires_grad=True)

下面示例代码中,使用Initializer创建Parameter:

[6]:
from mindspore.common.initializer import initializer as init
import mindspore as ms

x = ms.Parameter(default_input=init('ones', [1, 2, 3], ms.float32), name='x')
print(x)
Parameter (name=x, shape=(1, 2, 3), dtype=Float32, requires_grad=True)

属性

变量Parameter的默认属性有变量名称name、形状shape、数据类型dtype和是否需要进行求导requires_grad

下例通过Tensor初始化一个变量Parameter,并获取变量Parameter的相关属性。示例代码如下:

[4]:
my_tensor = ms.Tensor(np.arange(2 * 3).reshape((2, 3)))
x = ms.Parameter(default_input=my_tensor, name="x")

print("x: ", x)
print("x.data: ", x.data)
x:  Parameter (name=x, shape=(2, 3), dtype=Int64, requires_grad=True)
x.data:  Parameter (name=x, shape=(2, 3), dtype=Int64, requires_grad=True)

变量操作

  1. clone:克隆变量张量Parameter,克隆完成后可以给新的变量Parameter指定新的名称。

[9]:
x = ms.Parameter(default_input=init('ones', [1, 2, 3], ms.float32))
x_clone = x.clone()
x_clone.name = "x_clone"

print(x)
print(x_clone)
Parameter (name=Parameter, shape=(1, 2, 3), dtype=Float32, requires_grad=True)
Parameter (name=x_clone, shape=(1, 2, 3), dtype=Float32, requires_grad=True)
  1. set_data:修改变量Parameter的数据或形状shape

其中,set_data方法有dataslice_shape两种入参。data表示变量Parameter新传入的数据;slice_shape表示是否修改变量Parameter的形状shape,默认为False。

[11]:
x = ms.Parameter(ms.Tensor(np.ones((1, 2)), ms.float32), name="x", requires_grad=True)
print(x, x.asnumpy())

y = x.set_data(ms.Tensor(np.zeros((1, 2)), ms.float32))
print(y, y.asnumpy())

z = x.set_data(ms.Tensor(np.ones((1, 4)), ms.float32), slice_shape=True)
print(z, z.asnumpy())
Parameter (name=x, shape=(1, 2), dtype=Float32, requires_grad=True) [[1. 1.]]
Parameter (name=x, shape=(1, 2), dtype=Float32, requires_grad=True) [[0. 0.]]
Parameter (name=x, shape=(1, 4), dtype=Float32, requires_grad=True) [[1. 1. 1. 1.]]
  1. init_data:并行场景下存在参数的形状发生变化的情况,用户可以调用Parameterinit_data方法得到原始数据。

[9]:
x = ms.Parameter(ms.Tensor(np.ones((1, 2)), ms.float32), name="x", requires_grad=True)

print(x.init_data(), x.init_data().asnumpy())
Parameter (name=x, shape=(1, 2), dtype=Float32, requires_grad=True) [[1. 1.]]

变量参数更新

MindSpore提供了网络参数更新功能,使用nn.ParameterUpdate可对网络参数进行更新,其输入的参数类型必须为张量,且张量shape需要与原网络参数shape保持一致。

更新网络的权重参数示例如下:

[14]:
import numpy as np
import mindspore as ms
from mindspore import nn

# 构建网络
network = nn.Dense(3, 4)

# 获取网络的权重参数
param = network.parameters_dict()['weight']
print("Parameter:\n", param.asnumpy())

# 更新权重参数
update = nn.ParameterUpdate(param)
weight = ms.Tensor(np.arange(12).reshape((4, 3)), ms.float32)
output = update(weight)
print("Parameter update:\n", output)
Parameter:
 [[-0.0164615  -0.01204428 -0.00813806]
 [-0.00270927 -0.0113328  -0.01384139]
 [ 0.00849093  0.00351116  0.00989969]
 [ 0.00233028  0.00649209 -0.0021333 ]]
Parameter update:
 [[ 0.  1.  2.]
 [ 3.  4.  5.]
 [ 6.  7.  8.]
 [ 9. 10. 11.]]

变量元组 Parameter Tuple

变量元组ParameterTuple,用于保存多个Parameter,继承于元组tuple,提供克隆功能。

如下示例提供ParameterTuple创建方法:

[10]:
import numpy as np
import mindspore as ms
from mindspore.common.initializer import initializer

# 创建
x = ms.Parameter(default_input=ms.Tensor(np.arange(2 * 3).reshape((2, 3))), name="x")
y = ms.Parameter(default_input=initializer('ones', [1, 2, 3], ms.float32), name='y')
z = ms.Parameter(default_input=2.0, name='z')
params = ms.ParameterTuple((x, y, z))

# 从params克隆并修改名称为"params_copy"
params_copy = params.clone("params_copy")

print(params)
print(params_copy)
(Parameter (name=x, shape=(2, 3), dtype=Int64, requires_grad=True), Parameter (name=y, shape=(1, 2, 3), dtype=Float32, requires_grad=True), Parameter (name=z, shape=(), dtype=Float32, requires_grad=True))
(Parameter (name=params_copy.x, shape=(2, 3), dtype=Int64, requires_grad=True), Parameter (name=params_copy.y, shape=(1, 2, 3), dtype=Float32, requires_grad=True), Parameter (name=params_copy.z, shape=(), dtype=Float32, requires_grad=True))

网络参数初始化

MindSpore提供了多种网络参数初始化的方式,并在部分算子中封装了参数初始化的功能。本节以Conv2d算子为例,分别介绍使用Initializer子类,字符串和自定义Tensor等方式对网络中的参数进行初始化。

Initializer初始化

使用Initializer对网络参数进行初始化,示例代码如下:

[11]:
import numpy as np
import mindspore.nn as nn
import mindspore as ms
from mindspore.common import initializer as init

ms.set_seed(1)

input_data = ms.Tensor(np.ones([1, 3, 16, 50], dtype=np.float32))
# 卷积层,输入通道为3,输出通道为64,卷积核大小为3*3,权重参数使用正态分布生成的随机数
net = nn.Conv2d(3, 64, 3, weight_init=init.Normal(0.2))
# 网络输出
output = net(input_data)

字符串初始化

使用字符串对网络参数进行初始化,字符串的内容需要与Initializer的名称保持一致(字母不区分大小写),使用字符串方式进行初始化将使用Initializer类中的默认参数。

例如使用字符串Normal等同于使用InitializerNormal(),示例如下:

[12]:
import numpy as np
import mindspore.nn as nn
import mindspore as ms

ms.set_seed(1)

input_data = ms.Tensor(np.ones([1, 3, 16, 50], dtype=np.float32))
net = nn.Conv2d(3, 64, 3, weight_init='Normal')
output = net(input_data)

张量初始化

用户也可以通过自定义Tensor的方式,来对网络模型中算子的参数进行初始化,示例代码如下:

[13]:
import numpy as np
import mindspore.nn as nn
import mindspore as ms

init_data = ms.Tensor(np.ones([64, 3, 3, 3]), dtype=ms.float32)
input_data = ms.Tensor(np.ones([1, 3, 16, 50], dtype=np.float32))

net = nn.Conv2d(3, 64, 3, weight_init=init_data)
output = net(input_data)