• 4.2 模型参数的访问、初始化和共享


    模型参数的访问、初始化和共享

    使用默认方式初始化它的参数,并做一次前向计算。

    #导包
    from mxnet import init, nd
    from mxnet.gluon import nn
    #实例化Sequential类
    net = nn.Sequential()
    #添加隐藏层
    net.add(nn.Dense(256, activation='relu'))
    #添加输出层
    net.add(nn.Dense(10))
    # 使用默认初始化方式
    net.initialize() 
    
    X = nd.random.uniform(shape=(2, 20))
    Y = net(X)  # 前向计算
    

    访问模型参数

    对于使用Sequential类构造的神经网络,我们可以通过方括号[]来访问网络的任一层.对于Sequential实例中含模型参数的层,可以通过Block类的params属性来访问该层包含的所有参数.访问多层感知机net中隐藏层的所有参数。索引0表示隐藏层为Sequential实例最先添加的层:

    in:
    net[0].params, type(net[0].params)
    out:
    (dense2_ (
       Parameter dense0_weight (shape=(256, 20), dtype=float32)
       Parameter dense0_bias (shape=(256,), dtype=float32)
     ),
     mxnet.gluon.parameter.ParameterDict)
    

    得到了一个由参数名称映射到参数实例的字典(类型为ParameterDict类).为了访问特定参数,既可以通过名字来访问字典里的元素,也可以直接使用它的变量名。

    net[0].params['dense4_weight'], net[0].weight
    (Parameter dense0_weight (shape=(256, 20), dtype=float32),
     Parameter dense0_weight (shape=(256, 20), dtype=float32))
    

    Gluon里参数类型为Parameter类,它包含参数和梯度的数值,可以分别通过data函数和grad函数来访问

    #shape=(256,20),权重参数
    net[0].weight.data()
    

    权重梯度的形状和权重的形状一样。因为还没有进行反向传播计算,所以梯度的值全为(0)

    net[0].weight.grad()
    NDArray 256x20 @cpu(0)
    

    输出层偏置:

    net[1].bias.data()
    

    可以使用collect_params函数来获取net变量所有嵌套(例如通过add函数嵌套)的层所包含的所有参数。它返回的同样是一个由参数名称到参数实例的字典。

    net.collect_params()
    

    这个函数可以通过正则表达式来匹配参数名,从而筛选需要的参数。

    net.collect_params('.*weight')
    

    初始化模型参数

    (MXNet)init模块里提供了多种预设的初始化方法。

    # 非首次对模型初始化需要指定force_reinit为真
    net.initialize(init=init.Normal(sigma=0.01), force_reinit=True)
    net[0].weight.data()[0]
    

    使用常数来初始化权重参数。

    #初始化权重参数是常数=1
    net.initialize(init=init.Constant(1), force_reinit=True)
    net[0].weight.data()[0]
    

    如果只想对某个特定参数进行初始化,我们可以调用Parameter类的initialize函数
    隐藏层的权重使用Xavier随机初始化方法。

    net[0].weight.initialize(init=init.Xavier(), force_reinit=True)
    net[0].weight.data()[0]
    

    自定义初始化方法

    需要的初始化方法并没有在init模块中提供。这时,可以实现一个Initializer类的子类,从而能够像使用其他初始化方法那样使用它
    通常,我们只需要实现_init_weight这个函数,并将其传入的NDArray修改成初始化的结果

    #Initializer 源码:
    def _init_weight(self, name, arr):
            """Abstract method to Initialize weight."""
            raise NotImplementedError("Must override it")
    

    下面的_init_weight复写了基类的函数

    #实现MyInit类,继承Initializer类
    class MyInit(init.Initializer):
        #复写基类函数
        def _init_weight(self, name, data):
            print('Init', name, data.shape)
            #生成[-10,10]区间内均匀分布随机数
            data[:] = nd.random.uniform(low=-10, high=10, shape=data.shape)
            #如果data的绝对值大于等于5就是原数,否则就是0
            data *= data.abs() >= 5
    
    net.initialize(MyInit(), force_reinit=True)
    net[0].weight.data()[0]
    

    通过Parameter类的set_data函数来直接改写模型参数
    将隐藏层参数在现有的基础上加1

    #使用set_data函数
    net[0].weight.set_data(net[0].weight.data() + 1)
    net[0].weight.data()[0]
    

    共享模型参数

    在有些情况下,我们希望在多个层之间共享模型参数
    它在构造层的时候指定使用特定的参数。如果不同层使用同一份参数,那么它们在前向计算和反向传播时都会共享相同的参数
    让模型的第二隐藏层(shared变量)和第三隐藏层共享模型参数:

    #实例化Sequential
    net = nn.Sequential()
    #初始化一个层shared
    shared = nn.Dense(8, activation='relu')
    #添加层,先添加第一个层,再添加第二个层shared,添加第三个层时指定第三个层的params=shared.params
    net.add(nn.Dense(8, activation='relu'),
            shared,
            nn.Dense(8, activation='relu', params=shared.params),
            nn.Dense(10))
    #初始化net参数
    net.initialize()
    #定义输入值
    X = nd.random.uniform(shape=(2, 20))
    net(X)
    #比较权重参数是否相等
    net[1].weight.data()[0] == net[2].weight.data()[0]
    
  • 相关阅读:
    HttpModule,HttpHandler,HttpHandlerFactory
    IHttpModule实现URL重写
    HttpModule与HttpHandler详解
    IHttpModule接口
    VS中新建网站和新建项目web应用程序的区别?(实际应用总结一点)
    slf4j简介
    SQL条件表达式
    Windows命令查看文件MD5
    Final对象
    Seasar2框架:AOP
  • 原文地址:https://www.cnblogs.com/strategist-614/p/14411480.html
Copyright © 2020-2023  润新知