未验证 提交 e45c3fa5 编写于 作者: C chentianyu03 提交者: GitHub

Add LayerDict class (#31951)

* add layerdict class

* add docs and test cases for LayerDict class

* remove the arguments type in function define

* add update inputs type check
上级 54344964
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import unittest
import numpy as np
import paddle
from collections import OrderedDict
class TestLayerDict(unittest.TestCase):
def test_layer_dict(self):
layers = OrderedDict([
('conv1d', paddle.nn.Conv1D(3, 2, 3)),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
])
layers_dicts = paddle.nn.LayerDict(sublayers=layers)
def check_layer_dict():
self.assertEqual(len(layers), len(layers_dicts))
for k1, k2 in zip(layers, layers_dicts):
self.assertIs(layers[k1], layers_dicts[k2])
for k, v in zip(layers, layers_dicts.children()):
self.assertIs(layers[k], v)
for k in layers_dicts:
self.assertIs(layers[k], layers_dicts[k])
for k in layers.keys():
self.assertTrue(k in layers_dicts)
for k1, k2 in zip(layers.keys(), layers_dicts.keys()):
self.assertEqual(k1, k2)
for k, v in layers_dicts.items():
self.assertIs(layers[k], v)
for v1, v2 in zip(layers.values(), layers_dicts.values()):
self.assertIs(v1, v2)
check_layer_dict()
layers['linear'] = paddle.nn.Linear(2, 4)
layers_dicts['linear'] = layers['linear']
check_layer_dict()
sublayer = OrderedDict([
('sigmod', paddle.nn.Sigmoid()),
('relu', paddle.nn.ReLU()),
])
layers.update(sublayer)
layers_dicts.update(sublayer)
check_layer_dict()
del layers['conv1d']
del layers_dicts['conv1d']
check_layer_dict()
l = layers_dicts.pop('linear')
self.assertIs(layers['linear'], l)
layers.pop('linear')
check_layer_dict()
layers_dicts.clear()
self.assertEqual(0, len(layers_dicts))
layers.clear()
check_layer_dict()
list_format_layers = [
('conv1d', paddle.nn.Conv1D(3, 2, 3)),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
]
layers = OrderedDict(list_format_layers)
layers_dicts.update(list_format_layers)
check_layer_dict()
def test_layer_dict_error_inputs(self):
layers = [
('conv1d', paddle.nn.Conv1D(3, 2, 3), "conv1d"),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
]
layers_dicts = paddle.nn.LayerDict()
self.assertRaises(ValueError, layers_dicts.update, layers)
self.assertRaises(AssertionError, layers_dicts.update, 1)
if __name__ == '__main__':
unittest.main()
......@@ -151,6 +151,8 @@ from .layer.distance import PairwiseDistance #DEFINE_ALIAS
from .layer.vision import PixelShuffle
from .layer.container import LayerDict #DEFINE_ALIAS
from .layer import loss #DEFINE_ALIAS
from .layer import conv #DEFINE_ALIAS
from .layer import vision #DEFINE_ALIAS
......
......@@ -23,6 +23,7 @@ from . import rnn
from . import vision
from . import distance
from . import transformer
from . import container
from .activation import *
from .loss import *
......@@ -99,3 +100,4 @@ from .norm import LocalResponseNorm #DEFINE_ALIAS
from .vision import PixelShuffle #DEFINE_ALIAS
from .distance import PairwiseDistance #DEFINE_ALIAS
from .container import LayerDict #DEFINE_ALIAS
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import OrderedDict
from ...fluid.dygraph.layers import Layer
from six.moves import collections_abc
__all__ = ['LayerDict', ]
class LayerDict(Layer):
"""
LayerDict holds sublayers in the ordered dictionary, and sublayers it contains are properly registered.
Holded sublayers can be accessed like a regular ordered python dictionary.
Parameters:
sublayers (LayerDict|OrderedDict|list[(key,Layer)...], optional): iterable of key/value pairs, the type of value is 'paddle.nn.Layer' .
Examplex:
.. code-block:: python
import paddle
import numpy as np
from collections import OrderedDict
sublayers = OrderedDict([
('conv1d', paddle.nn.Conv1D(3, 2, 3)),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
('conv3d', paddle.nn.Conv3D(4, 6, (3, 3, 3))),
])
layers_dict = paddle.nn.LayerDict(sublayers=sublayers)
l = layers_dict['conv1d']
for k in layers_dict:
l = layers_dict[k]
len(layers_dict)
#3
del layers_dict['conv2d']
len(layers_dict)
#2
conv1d = layers_dict.pop('conv1d')
len(layers_dict)
#1
layers_dict.clear()
len(layers_dict)
#0
"""
def __init__(self, sublayers=None):
super(LayerDict, self).__init__()
if sublayers is not None:
self.update(sublayers)
def __getitem__(self, key):
return self._sub_layers[key]
def __setitem__(self, key, sublayer):
return self.add_sublayer(key, sublayer)
def __delitem__(self, key):
del self._sub_layers[key]
def __len__(self):
return len(self._sub_layers)
def __iter__(self):
return iter(self._sub_layers)
def __contains__(self, key):
return key in self._sub_layers
def clear(self):
"""
Clear all the sublayers in the LayerDict.
Parameters:
None.
Examplex:
.. code-block:: python
import paddle
from collections import OrderedDict
sublayers = OrderedDict([
('conv1d', paddle.nn.Conv1D(3, 2, 3)),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
('conv3d', paddle.nn.Conv3D(4, 6, (3, 3, 3))),
])
layer_dict = paddle.nn.LayerDict(sublayers=sublayers)
len(layer_dict)
#3
layer_dict.clear()
len(layer_dict)
#0
"""
self._sub_layers.clear()
def pop(self, key):
"""
Remove the key from the LayerDict and return the layer of the key.
Parameters:
key (str): the key to be removed.
Examples:
.. code-block:: python
import paddle
from collections import OrderedDict
sublayers = OrderedDict([
('conv1d', paddle.nn.Conv1D(3, 2, 3)),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
('conv3d', paddle.nn.Conv3D(4, 6, (3, 3, 3))),
])
layer_dict = paddle.nn.LayerDict(sublayers=sublayers)
len(layer_dict)
#3
layer_dict.pop('conv2d')
len(layer_dict)
#2
"""
v = self[key]
del self[key]
return v
def keys(self):
"""
Return the iterable of the keys in LayerDict.
Parameters:
None.
Examples:
.. code-block:: python
import paddle
from collections import OrderedDict
sublayers = OrderedDict([
('conv1d', paddle.nn.Conv1D(3, 2, 3)),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
('conv3d', paddle.nn.Conv3D(4, 6, (3, 3, 3))),
])
layer_dict = paddle.nn.LayerDict(sublayers=sublayers)
for k in layer_dict.keys():
print(k)
#conv1d
#conv2d
#conv3d
"""
return self._sub_layers.keys()
def items(self):
"""
Return the iterable of the key/value pairs in LayerDict.
Parameters:
None.
Examples:
.. code-block:: python
import paddle
from collections import OrderedDict
sublayers = OrderedDict([
('conv1d', paddle.nn.Conv1D(3, 2, 3)),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
('conv3d', paddle.nn.Conv3D(4, 6, (3, 3, 3))),
])
layer_dict = paddle.nn.LayerDict(sublayers=sublayers)
for k, v in layer_dict.items():
print(k, ":", v)
#conv1d : Conv1D(3, 2, kernel_size=[3], data_format=NCL)
#conv2d : Conv2D(3, 2, kernel_size=[3, 3], data_format=NCHW)
#conv3d : Conv3D(4, 6, kernel_size=[3, 3, 3], data_format=NCDHW)
"""
return self._sub_layers.items()
def values(self):
"""
Return the iterable of the values in LayerDict.
Parameters:
None.
Examples:
.. code-block:: python
import paddle
from collections import OrderedDict
sublayers = OrderedDict([
('conv1d', paddle.nn.Conv1D(3, 2, 3)),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
('conv3d', paddle.nn.Conv3D(4, 6, (3, 3, 3))),
])
layer_dict = paddle.nn.LayerDict(sublayers=sublayers)
for v in layer_dict.values():
print(v)
#Conv1D(3, 2, kernel_size=[3], data_format=NCL)
#Conv2D(3, 2, kernel_size=[3, 3], data_format=NCHW)
#Conv3D(4, 6, kernel_size=[3, 3, 3], data_format=NCDHW)
"""
return self._sub_layers.values()
def update(self, sublayers):
"""
Update the key/values pairs in sublayers to the LayerDict, overwriting the existing keys.
Parameters:
sublayers (LayerDict|OrderedDict|list[(key,Layer)...]): iterable of key/value pairs, the type of value is 'paddle.nn.Layer' .
Examples:
.. code-block:: python
import paddle
from collections import OrderedDict
sublayers = OrderedDict([
('conv1d', paddle.nn.Conv1D(3, 2, 3)),
('conv2d', paddle.nn.Conv2D(3, 2, 3)),
('conv3d', paddle.nn.Conv3D(4, 6, (3, 3, 3))),
])
new_sublayers = OrderedDict([
('relu', paddle.nn.ReLU()),
('conv2d', paddle.nn.Conv2D(4, 2, 4)),
])
layer_dict = paddle.nn.LayerDict(sublayers=sublayers)
layer_dict.update(new_sublayers)
for k, v in layer_dict.items():
print(k, ":", v)
#conv1d : Conv1D(3, 2, kernel_size=[3], data_format=NCL)
#conv2d : Conv2D(4, 2, kernel_size=[4, 4], data_format=NCHW)
#conv3d : Conv3D(4, 6, kernel_size=[3, 3, 3], data_format=NCDHW)
#relu : ReLU()
"""
assert isinstance(
sublayers, collections_abc.Iterable
), "The type of sublayers is not iterable of key/value pairs, the type of sublayers is " + type(
sublayers).__name__
if isinstance(sublayers,
(OrderedDict, LayerDict, collections_abc.Mapping)):
for key, layer in sublayers.items():
self.add_sublayer(key, layer)
else:
# handle this format [(key1, layer1), (key2, layer2)...]
for i, kv in enumerate(sublayers):
if len(kv) != 2:
raise ValueError("The length of the " + str(i) +
"'s element in sublayers is " + str(
len(kv)) + ", which must be 2.")
self.add_sublayer(kv[0], kv[1])
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册