其他分享
首页 > 其他分享> > 深度学习:深度学习计算

深度学习:深度学习计算

作者:互联网

1、模型构造

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

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、读取和存储

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