ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

深度学习:深度学习计算

2022-08-13 12:30:25  阅读:168  来源: 互联网

标签:__ 初始化 nn self 学习 参数 计算 深度 Block


1、模型构造

  • 可以通过继承Block类来构造模型。
  • Sequential类继承自Block类。
  • 虽然Sequential类可以使模型构造更加简单,但直接继承Block类可以极大地拓展模型构造的灵活性。

1.1继承Block类来构造模型

Block类是nn模块里提供的一个模型构造类,我们可以继承它来定义我们想要的模型。下面继承Block类构造本节开头提到的多层感知机。这里定义的MLP类重载了Block类的__init__函数和forward函数。它们分别用于创建模型参数和定义前向计算。前向计算也即正向传播。

from mxnet import nd
from mxnet.gluon import nn
class MLP(nn.Block):
    #声明带有模型参数的层,这里声明了两个全连接层
    def __init__(self, **kwargs):
        # 调用MLP父类Block的构造函数来进行必要的初始化。这样在构造实例时还可以指定其他函数
        # 参数,如“模型参数的访问、初始化和共享”一节将介绍的模型参数params
        super(MLP, self).__init__(**kwargs)
        self.hidden = nn.Dense(256, activation='relu')  # 隐藏层
        self.output = nn.Dense(10)  # 输出层
    #定义模型的前向计算,即如何根据输入x计算返回所需要的模型输出
    def forward(self, x):
        return self.output(self.hidden(x))

1.2Sequential类继承自Block

class MySequential(nn.Block):
    def __init__(self, **kwargs):
        super(MySequential, self).__init__(**kwargs)

    def add(self, block):
        # block是一个Block子类实例,假设它有一个独一无二的名字。我们将它保存在Block类的
        # 成员变量_children里,其类型是OrderedDict。当MySequential实例调用
        # initialize函数时,系统会自动对_children里所有成员初始化
        self._children[block.name] = block

    def forward(self, x):
        # OrderedDict保证会按照成员添加时的顺序遍历成员
        for block in self._children.values():
            x = block(x)
        return x

1.3构造复杂的模型


class FancyMLP(nn.Block):
    def __init__(self, **kwargs):
        super(FancyMLP, self).__init__(**kwargs)
        # 使用get_constant创建的随机权重参数不会在训练中被迭代(即常数参数)
        self.rand_weight = self.params.get_constant(
            'rand_weight', nd.random.uniform(shape=(20, 20)))
        self.dense = nn.Dense(20, activation='relu')

    def forward(self, x):
        x = self.dense(x)
        # 使用创建的常数参数,以及NDArray的relu函数和dot函数
        x = nd.relu(nd.dot(x, self.rand_weight.data()) + 1)
        # 复用全连接层。等价于两个全连接层共享参数
        x = self.dense(x)
        # 控制流,这里我们需要调用asscalar函数来返回标量进行比较
        while x.norm().asscalar() > 1:
            x /= 2
        if x.norm().asscalar() < 0.8:
            x *= 10
        return x.sum()

class NestMLP(nn.Block):
    def __init__(self, **kwargs):
        super(NestMLP, self).__init__(**kwargs)
        self.net = nn.Sequential()
        self.net.add(nn.Dense(64, activation='relu'),
                     nn.Dense(32, activation='relu'))
        self.dense = nn.Dense(16, activation='relu')

    def forward(self, x):
        return self.dense(self.net(x))

net = nn.Sequential()
net.add(NestMLP(), nn.Dense(20), FancyMLP())

net.initialize()
net(X)

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

from mxnet import init, nd
from mxnet.gluon import nn

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)  # 前向计算

2.2访问模型参数

对于使用Sequential类构造的神经网络,我们可以通过方括号[]来访问网络的任一层。

对于Sequential实例中含模型参数的层,我们可以通过Block类的params属性来访问该层包含的所有参数。

下面,访问多层感知机net中隐藏层的所有参数。索引0表示隐藏层为Sequential实例最先添加的层。

2.3初始化模型参数

2.4自定义初始化方法

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

在下面的例子里,我们令权重有一半概率初始化为0,有另一半概率初始化为\([-10,-5]\)和\([5,10]\)两个区间里均匀分布的随机数。

3、模型参数的延后与初始化

  • 系统将真正的参数初始化延后到获得足够信息时才执行的行为叫作延后初始化。
  • 延后初始化的主要好处是让模型构造更加简单。例如,我们无须人工推测每个层的输入个数。
  • 也可以避免延后初始化。

3.1延后初始化

当调用initialize函数时,由于隐藏层输入个数依然未知,系统也无法得知该层权重参数的形状。

只有在当我们将形状是(2, 20)的输入X传进网络做前向计算net(X)时,系统才推断出该层的权重参数形状为(256, 20)。

因此,这时候我们才能真正开始初始化参数。
系统将真正的参数初始化延后到获得足够信息时才执行的行为叫作延后初始化(deferred initialization)。

它可以让模型的创建更加简单:只需要定义每个层的输出大小,而不用人工推测它们的输入个数。

这对于之后将介绍的定义多达数十甚至数百层的网络来说尤其方便。

3.2避免延后初始化

如果系统在调用initialize函数时能够知道所有参数的形状,那么延后初始化就不会发生。

  • 第一种情况是我们要对已初始化的模型重新初始化时。因为参数形状不会发生变化,所以系统能够立即进行重新初始化。
  • 第二种情况是我们在创建层的时候指定了它的输入个数,使系统不需要额外的信息来推测参数形状。

4、自定义层

4.1不含模型参数的自定义层

如何定义一个不含模型参数的自定义层:
下面的CenteredLayer类通过继承Block类自定义了一个将输入减掉均值后输出的层,并将层的计算定义在了forward函数里。这个层里不含模型参数。

from mxnet import gluon, nd
from mxnet.gluon import nn
class CenteredLayer(nn.Block):
    def __init__(self, **kwargs):
        super(CenteredLayer, self).__init__(**kwargs)
    def forward(self, x):
        return x - x.mean()

4.2含模型参数的自定义层

自定义含模型参数的自定义层。其中的模型参数可以通过训练学出。

在自定义含模型参数的层时,我们可以利用Block类自带的ParameterDict类型的成员变量params

  • 它是一个由字符串类型的参数名字映射到Parameter类型的模型参数的字典。我们可以通过get函数从ParameterDict创建Parameter实例。
class MyDense(nn.Block):
    # units为该层的输出个数,in_units为该层的输入个数
    def __init__(self, units, in_units, **kwargs):
        super(MyDense, self).__init__(**kwargs)
        self.weight = self.params.get('weight', shape=(in_units, units))
        self.bias = self.params.get('bias', shape=(units,))

    def forward(self, x):
        linear = nd.dot(x, self.weight.data()) + self.bias.data()
        return nd.relu(linear)

5、读取和存储

  • 通过save函数和load函数可以很方便地读写NDArray
  • 通过load_parameters函数和save_parameters函数可以很方便地读写Gluon模型的参数。

标签:__,初始化,nn,self,学习,参数,计算,深度,Block
来源: https://www.cnblogs.com/caolanying/p/16582781.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有