Paddle网络结构中的层和模型

Posted 卓晴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Paddle网络结构中的层和模型相关的知识,希望对你有一定的参考价值。

简 介: 这是 Paddle中的模型与层 的内容学习笔记。对于Paddle中的层的构造,操作进行了初步的测试与相关的学习。

关键词 LayerPaddle

模型与层
文章目录
在Paddle中定
义模型与层
子层接口
层中的变量成员
执行层的功能
保存模型参数
总 结

 

§01 型与层


  型是深度学习中的重要概念之一。模型的核心功能是将一组输入变量经过一系列计算,映射到另一组输出变量,该映射函数即代表一种深度学习算法。在Paddle框架中,模型包括以下两方面内容:

  • 一系列层的组合用于进行映射(前向执行)
  • 一些参数变量在训练过程中实时更新

  本文档中,你将学习如何定义与使用Paddle模型,并了解模型与层的关系。

一、在Paddle中定义模型与层

  在Paddle中,大多数模型由一系列层组成,层是模型的基础逻辑执行单元。层中持有两方面内容:

  • 一方面是计算所需的变量,以临时变量或参数的形式作为层的成员持有
  • 另一方面则持有一个或多个具体的Operator来完成相应的计算。

1、模型与层

  从零开始构建变量、Operator,从而组建层、模型是一个很复杂的过程,并且当中难以避免的会出现很多冗余代码,因此Paddle提供了基础数据类型 paddle.nn.Layer ,来方便你快速的实现自己的层和模型。模型和层都可以基于 paddle.nn.Layer 扩充实现,因此也可以说模型只是一种特殊的层。下面将演示如何利用 paddle.nn.Layer 建立自己的模型:

class Model(paddle.nn.Layer):

    def __init__(self):
        super(Model, self).__init__()
        self.flatten = paddle.nn.Flatten()

    def forward(self, inputs):
        y = self.flatten(inputs)
        return y

  当前示例中,通过继承 paddle.nn.Layer 的方式构建了一个模型类型 Model ,模型中仅包含一个 paddle.nn.Flatten 层。模型执行时,输入变量inputs会被 paddle.nn.Flatten 层展平。

2、测试用例

x = paddle.to_tensor([[1,2,3],[4,5,6]])
print(x)

model = Model()
y = model(x)
print(y)
Tensor(shape=[2, 3], dtype=int64, place=CPUPlace, stop_gradient=True,
       [[1, 2, 3],
        [4, 5, 6]])
Tensor(shape=[2, 3], dtype=int64, place=CPUPlace, stop_gradient=True,
       [[1, 2, 3],
        [4, 5, 6]])

  这是什么鬼?结果怎么没有被层展平呢?

  将前面的代码修改:

class Model(paddle.nn.Layer):

    def __init__(self):
        super(Model, self).__init__()

    def forward(self, inputs):
        y = self.Flatten(inputs)
        return y

    def Flatten(self, x):
        xx = x.numpy().flatten()
        return paddle.to_tensor(xx)

x = paddle.to_tensor([[1,2,3],[4,5,6]])
print(x)

model = Model()
y = model(x)
print(y)

  可以得到想要的结果了:

Tensor(shape=[2, 3], dtype=int64, place=CPUPlace, stop_gradient=True,
       [[1, 2, 3],
        [4, 5, 6]])
Tensor(shape=[6], dtype=int64, place=CPUPlace, stop_gradient=True,
       [1, 2, 3, 4, 5, 6])

二、子层接口

  如果想要访问或修改一个模型中定义的层,则可以调用SubLayer相关的接口。

1、继承子层

  以上文创建的简单模型为例, 如果想要查看模型中定义的所有子层:

class Model(paddle.nn.Layer):

    def __init__(self):
        super(Model, self).__init__()
        self.flatten = paddle.nn.Flatten()

    def forward(self, inputs):
        y = self.Flatten(inputs)
        return y
[Flatten()]
----------------------
('flatten', Flatten())

  以看到,通过调用 model.sublayers()接口,打印出了前述模型中持有的全部子层(这时模型中只有一个 paddle.nn.Flatten子层)。

  而遍历 model.named_sublayers() 时,每一轮循环会拿到一组 ( 子层名称('flatten'),子层对象(paddle.nn.Flatten))的元组。

  下面增加self中的一个层次,可以看到多出了更多的层。

class Model(paddle.nn.Layer):

    def __init__(self):
        super(Model, self).__init__()
        self.flatten = paddle.nn.Flatten()
        self.f1   = paddle.nn.Flatten()

    def forward(self, inputs):
        y = self.Flatten(inputs)
        return y

model = Model()
print(model.sublayers())

print("----------------------")

for item in model.named_sublayers():
    print(item)
[Flatten(), Flatten()]
----------------------
('flatten', Flatten())
('f1', Flatten())

2、增加子层

  接下来如果想要进一步添加一个子层,则可以调用 add_sublayer() 接口:

fc = paddle.nn.Linear(10, 3)
model.add_sublayer("fc", fc)
print(model.sublayers())
[Flatten(), Linear(in_features=10, out_features=3, dtype=float32)]

  可以看到 model.add_sublayer() 向模型中添加了一个 paddle.nn.Linear 子层,这样模型中总共有 paddle.nn.Flattenpaddle.nn.Linear 两个子层了。

3、修改子层

  通过上述方法可以往模型中添加成千上万个子层,当模型中子层数量较多时,如何高效地对所有子层进行统一修改呢?

  Paddle 提供了 apply() 接口。通过这个接口,可以自定义一个函数,然后将该函数批量作用在所有子层上:

def function(layer):
    print(layer)

model.apply(function)
Flatten()
Linear(in_features=10, out_features=3, dtype=float32)
Model(
  (flatten): Flatten()
  (fc): Linear(in_features=10, out_features=3, dtype=float32)
)

  当前例子中,定义了一个以layer作为参数的函数function,用来打印传入的layer信息。通过调用 model.apply() 接口,将function作用在模型的所有子层中,也因此输出信息中打印了model中所有子层的信息。

  另外一个批量访问子层的接口是 children() 或者 named_children() 。这两个接口通过Iterator的方式访问每个子层:

sublayer_iter = model.children()
for sublayer in sublayer_iter:
    print(sublayer)
Flatten()
Linear(in_features=10, out_features=3, dtype=float32)

  可以看到,遍历 model.children() 时,每一轮循环都可以按照子层注册顺序拿到对应 paddle.nn.Layer 的对象。

三、层中的变量成员

1、参数变量添加与修改

  有的时候希望向网络中添加一个参数作为输入。比如在使用图像风格转换模型时,会使用参数作为输入图像,在训练过程中不断更新该图像参数,最终拿到风格转换后的图像。

  这时可以通过 create_parameter()add_parameter() 组合,来创建并记录参数:

class Model(paddle.nn.Layer):

    def __init__(self):
        super(Model, self).__init__()
        img = self.create_parameter([1,3,256,256])
        self.add_parameter("img", img)
        self.flatten = paddle.nn.Flatten()

    def forward(self):
        y = self.flatten(self.img)
        return y

  上述例子创建并向模型中添加了一个名字为"img"的参数。随后可以直接通过调用model.img来访问该参数。

  对于已经添加的参数,可以通过 parameters() 或者 named_parameters() 来访问

model = Model()
model.parameters()
print('--------------------------------------------')
for item in model.named_parameters():
    print(item)
[Parameter containing:
Tensor(shape=[1, 3, 256, 256], dtype=float32, place=CPUPlace, stop_gradient=False,
       [[[[-0.00323536,  0.00417978,  0.00387184, ..., -0.00263438,
            0.00336105, -0.00079275],
          [-0.00398997,  0.00305213,  0.00338405, ...,  0.00321609,
            0.00385862,  0.00383085],
          [ 0.00456822,  0.00335924, -0.00396630, ..., -0.00260351,
            0.00388722,  0.00292703],
          ...,
          ...,
          [-0.00302772, -0.00052290, -0.00259735, ...,  0.00325148,
            0.00051726,  0.00464376],
          [ 0.00238924, -0.00105374,  0.00219904, ..., -0.00279356,
           -0.00214116, -0.00319181],
          [ 0.00180969,  0.00476100,  0.00380237, ...,  0.00249749,
            0.00374650,  0.00050141]]]])]
---------------------以上是关于Paddle网络结构中的层和模型的主要内容,如果未能解决你的问题,请参考以下文章

深度学习模型性能及网络调参

森说AI:用paddle2.x完成resnet50模型转写并实现前向对齐

森说AI:用paddle2.x完成resnet50模型转写并实现前向对齐

Paddle内置的网络模型

分层网络模型介绍

查找每个 Docker 映像的层和层大小