1619 lines
57 KiB
Python
1619 lines
57 KiB
Python
# Copyright (c) 2018 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.
|
|
import unittest
|
|
from collections import OrderedDict
|
|
|
|
import paddle
|
|
from paddle import Tensor, nn
|
|
|
|
|
|
class Module(nn.Module):
|
|
# class Module(nn.Layer):
|
|
def __init__(self, **kwargs):
|
|
super().__init__(**kwargs)
|
|
|
|
|
|
class SubModule(nn.Module):
|
|
def __init__(self, **kwargs):
|
|
super().__init__(**kwargs)
|
|
self.linear = nn.Linear(10, 5)
|
|
|
|
|
|
class SubModule1(nn.Module):
|
|
def __init__(self, input_size=10, output_size=5):
|
|
super().__init__()
|
|
self.linear = nn.Linear(input_size, output_size)
|
|
self.activation = nn.ReLU()
|
|
self.register_buffer('running_mean', paddle.zeros([output_size]))
|
|
|
|
def forward(self, x):
|
|
out = self.linear(x)
|
|
out = self.activation(out)
|
|
return out
|
|
|
|
|
|
class NestedModule(nn.Module):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.layer1 = SubModule1(10, 8)
|
|
self.layer2 = SubModule1(8, 6)
|
|
self.layer3 = SubModule1(6, 4)
|
|
self.final_layer = nn.Linear(4, 2)
|
|
|
|
|
|
class TestRegisterBuffer(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module = Module()
|
|
|
|
def test_register_buffer_basic(self):
|
|
buffer_tensor = paddle.to_tensor([1.0, 2.0, 3.0])
|
|
self.module.register_buffer('test_buffer', buffer_tensor)
|
|
self.assertTrue(hasattr(self.module, 'test_buffer'))
|
|
self.assertIn('test_buffer', self.module._buffers)
|
|
|
|
all_buffers = list(self.module.buffers(recurse=True))
|
|
self.assertTrue(len(all_buffers) > 0)
|
|
self.assertTrue(any(isinstance(b, paddle.Tensor) for b in all_buffers))
|
|
|
|
def test_register_buffer_persistent(self):
|
|
persistent_buffer = paddle.to_tensor([4.0, 5.0, 6.0])
|
|
self.module.register_buffer(
|
|
'persistent_buf', persistent_buffer, persistent=True
|
|
)
|
|
self.assertIn('persistent_buf', self.module._buffers)
|
|
self.assertNotIn(
|
|
'persistent_buf', self.module._non_persistent_buffers_set
|
|
)
|
|
|
|
def test_register_buffer_non_persistent(self):
|
|
non_persistent_buffer = paddle.to_tensor([7.0, 8.0, 9.0])
|
|
self.module.register_buffer(
|
|
'non_persistent_buf', non_persistent_buffer, persistent=False
|
|
)
|
|
self.assertIn('non_persistent_buf', self.module._buffers)
|
|
self.assertIn(
|
|
'non_persistent_buf', self.module._non_persistent_buffers_set
|
|
)
|
|
|
|
|
|
class TestRegisterParameter(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module = Module()
|
|
|
|
def test_register_parameter_basic(self):
|
|
param_tensor = paddle.to_tensor([1.0, 2.0, 3.0], stop_gradient=False)
|
|
param = nn.Parameter(param_tensor)
|
|
|
|
self.module.register_parameter('test_param', param)
|
|
|
|
self.assertTrue(hasattr(self.module, 'test_param'))
|
|
self.assertIn('test_param', self.module._parameters)
|
|
self.assertTrue(paddle.allclose(self.module.test_param, param))
|
|
self.assertTrue(self.module.test_param.trainable)
|
|
|
|
def test_register_parameter_none(self):
|
|
self.module.register_parameter('none_param', None)
|
|
|
|
self.assertTrue(hasattr(self.module, 'none_param'))
|
|
self.assertIn('none_param', self.module._parameters)
|
|
self.assertIsNone(self.module.none_param)
|
|
|
|
def test_register_parameter_with_tensor(self):
|
|
param_tensor = paddle.to_tensor([1.0, 2.0, 3.0], stop_gradient=False)
|
|
|
|
self.module.register_parameter('test_param', nn.Parameter(param_tensor))
|
|
|
|
self.assertIn('test_param', self.module._parameters)
|
|
self.assertIsInstance(self.module.test_param, nn.Parameter)
|
|
self.assertTrue(paddle.allclose(self.module.test_param, param_tensor))
|
|
|
|
|
|
class TestAddModule(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module = Module()
|
|
|
|
def test_add_module_basic(self):
|
|
submodule = nn.Linear(10, 5)
|
|
self.module.add_module('linear', submodule)
|
|
|
|
self.assertTrue(hasattr(self.module, 'linear'))
|
|
self.assertIn('linear', self.module._modules)
|
|
self.assertEqual(self.module.linear, submodule)
|
|
self.assertIsInstance(self.module.linear, nn.Linear)
|
|
|
|
def test_register_module_basic(self):
|
|
submodule = nn.Linear(10, 5)
|
|
self.module.register_module('linear', submodule)
|
|
|
|
self.assertTrue(hasattr(self.module, 'linear'))
|
|
self.assertIn('linear', self.module._modules)
|
|
self.assertEqual(self.module.linear, submodule)
|
|
self.assertIsInstance(self.module.linear, nn.Linear)
|
|
|
|
def test_add_module_none(self):
|
|
self.module.add_module('empty_module', None)
|
|
|
|
self.assertTrue(hasattr(self.module, 'empty_module'))
|
|
self.assertIn('empty_module', self.module._modules)
|
|
self.assertIsNone(self.module.empty_module)
|
|
|
|
def test_add_module_hierarchy(self):
|
|
child_module = SubModule()
|
|
self.module.add_module('child', child_module)
|
|
|
|
self.assertIn('child', self.module._modules)
|
|
self.assertIn('linear', child_module._modules)
|
|
self.assertIsInstance(child_module.linear, nn.Linear)
|
|
|
|
def test_module_forward(self):
|
|
submodule = nn.Linear(10, 5)
|
|
self.module.add_module('linear', submodule)
|
|
|
|
input_tensor = paddle.ones([2, 10])
|
|
output = self.module.linear(input_tensor)
|
|
|
|
self.assertEqual(output.shape, [2, 5])
|
|
self.assertIsInstance(output, Tensor)
|
|
|
|
|
|
class TestGetSubmodule(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module = Module()
|
|
|
|
def test_get_submodule_basic(self):
|
|
submodule = nn.Linear(10, 5)
|
|
self.module.add_module('linear', submodule)
|
|
|
|
retrieved_module = self.module.get_submodule('linear')
|
|
self.assertEqual(retrieved_module, submodule)
|
|
self.assertIsInstance(retrieved_module, nn.Linear)
|
|
|
|
def test_get_submodule_nested(self):
|
|
nested_module = NestedModule()
|
|
self.module.add_module('nested', nested_module)
|
|
|
|
test_cases = [
|
|
'nested',
|
|
'nested.layer1',
|
|
'nested.layer1.linear',
|
|
'nested.layer2.activation',
|
|
'nested.final_layer',
|
|
]
|
|
|
|
for target in test_cases:
|
|
with self.subTest(target=target):
|
|
module = self.module.get_submodule(target)
|
|
self.assertIsInstance(module, nn.Module)
|
|
|
|
def test_get_submodule_empty_target(self):
|
|
result = self.module.get_submodule('')
|
|
self.assertEqual(result, self.module)
|
|
|
|
def test_get_parameter_basic(self):
|
|
param_tensor = paddle.to_tensor([1.0, 2.0, 3.0], stop_gradient=False)
|
|
param = nn.Parameter(param_tensor)
|
|
self.module.register_parameter('test_param', param)
|
|
|
|
retrieved_param = self.module.get_parameter('test_param')
|
|
self.assertIs(retrieved_param, param)
|
|
self.assertIsInstance(retrieved_param, nn.Parameter)
|
|
self.assertTrue(paddle.allclose(retrieved_param, param_tensor))
|
|
|
|
def test_get_parameter_nested(self):
|
|
nested_module = NestedModule()
|
|
self.module.add_module('nested', nested_module)
|
|
|
|
test_cases = [
|
|
'nested.layer1.linear.weight',
|
|
'nested.layer1.linear.bias',
|
|
'nested.final_layer.weight',
|
|
'nested.final_layer.bias',
|
|
]
|
|
|
|
for target in test_cases:
|
|
with self.subTest(target=target):
|
|
param = self.module.get_parameter(target)
|
|
self.assertIsInstance(param, nn.Parameter)
|
|
self.assertTrue(param.trainable)
|
|
|
|
def test_get_parameter_vs_get_submodule(self):
|
|
nested_module = NestedModule()
|
|
self.module.add_module('nested', nested_module)
|
|
|
|
module = self.module.get_submodule('nested.layer1.linear')
|
|
self.assertIsInstance(module, nn.Linear)
|
|
|
|
weight_param = self.module.get_parameter('nested.layer1.linear.weight')
|
|
self.assertIsInstance(weight_param, nn.Parameter)
|
|
self.assertTrue(paddle.allclose(weight_param, module.weight))
|
|
|
|
def test_get_parameter_gradients(self):
|
|
nested_module = NestedModule()
|
|
self.module.add_module('nested', nested_module)
|
|
|
|
param = self.module.get_parameter('nested.layer1.linear.weight')
|
|
|
|
x = paddle.ones([1, 10])
|
|
y = nested_module.layer1.linear(x)
|
|
loss = y.sum()
|
|
loss.backward()
|
|
|
|
self.assertIsNotNone(param.grad)
|
|
self.assertEqual(param.grad.shape, param.shape)
|
|
|
|
def test_get_submodule_error(self):
|
|
with self.assertRaises(AttributeError):
|
|
self.module.get_submodule('invalid_name')
|
|
|
|
def test_get_parameter_reeor(self):
|
|
with self.assertRaises(AttributeError) as cm:
|
|
self.module.get_parameter("nonexistent_param")
|
|
self.assertIn("has no attribute `nonexistent_param`", str(cm.exception))
|
|
|
|
self.module.fake_attr = "I am not a parameter"
|
|
with self.assertRaises(AttributeError) as cm:
|
|
self.module.get_parameter("fake_attr")
|
|
self.assertIn("`fake_attr` is not an nn.Parameter", str(cm.exception))
|
|
|
|
self.module.register_buffer(
|
|
"fake_param", paddle.to_tensor([1.0, 2.0, 3.0])
|
|
)
|
|
with self.assertRaises(AttributeError) as cm:
|
|
self.module.get_parameter("fake_param")
|
|
self.assertIn("`fake_param` is not an nn.Parameter", str(cm.exception))
|
|
|
|
def test_get_extra_state_raises(self):
|
|
with self.assertRaises(RuntimeError) as cm:
|
|
self.module.get_extra_state()
|
|
|
|
|
|
class TestSetSubmodule(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module = NestedModule()
|
|
|
|
def test_replace_top_level(self):
|
|
new_module = SubModule1(8, 6)
|
|
self.module.set_submodule("layer2", new_module)
|
|
self.assertIs(self.module.layer2, new_module)
|
|
|
|
def test_replace_nested_submodule(self):
|
|
new_linear = nn.Linear(6, 4)
|
|
self.module.set_submodule("layer3.linear", new_linear)
|
|
self.assertIs(self.module.layer3.linear, new_linear)
|
|
|
|
def test_add_new_non_strict(self):
|
|
new_mod = nn.Linear(10, 10)
|
|
self.module.set_submodule("extra", new_mod)
|
|
self.assertIs(self.module.extra, new_mod)
|
|
|
|
def test_strict_missing_attr_raises(self):
|
|
new_mod = nn.Linear(1, 1)
|
|
with self.assertRaises(AttributeError):
|
|
self.module.set_submodule("not_exist", new_mod, strict=True)
|
|
|
|
def test_non_module_input_raises(self):
|
|
with self.assertRaises(ValueError):
|
|
self.module.set_submodule("layer1", "not_a_module")
|
|
|
|
def test_empty_target_raises(self):
|
|
with self.assertRaises(ValueError):
|
|
self.module.set_submodule("", nn.Linear(1, 1))
|
|
|
|
def test_non_module_attr_raises(self):
|
|
self.module.some_value = 10
|
|
with self.assertRaises(AttributeError):
|
|
self.module.set_submodule("some_value", nn.Linear(1, 1))
|
|
|
|
|
|
class TestLoadStateDict(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module = Module()
|
|
|
|
def test_load_state_dict_basic(self):
|
|
self.module.register_parameter(
|
|
'custom_param', nn.Parameter(paddle.ones([3, 3]))
|
|
)
|
|
self.module.register_buffer('custom_buffer', paddle.zeros([2, 2]))
|
|
original_state = self.module.state_dict()
|
|
|
|
with paddle.no_grad():
|
|
self.module.custom_param.set_value(
|
|
self.module.custom_param * 2 + 1.0
|
|
)
|
|
self.module.custom_buffer.set_value(paddle.ones([2, 2]))
|
|
|
|
result = self.module.load_state_dict(original_state)
|
|
|
|
current_state = self.module.state_dict()
|
|
for key in original_state:
|
|
self.assertTrue(
|
|
paddle.allclose(original_state[key], current_state[key])
|
|
)
|
|
|
|
self.assertEqual(len(result.missing_keys), 0)
|
|
self.assertEqual(len(result.unexpected_keys), 0)
|
|
|
|
def test_load_state_dict_strict_mode(self):
|
|
self.module.register_parameter(
|
|
'test_param', nn.Parameter(paddle.ones([3]))
|
|
)
|
|
original_state = self.module.state_dict()
|
|
|
|
modified_state = original_state.copy()
|
|
modified_state['extra_param'] = paddle.ones([5])
|
|
modified_state.pop('test_param')
|
|
|
|
with self.assertRaises(RuntimeError) as context:
|
|
self.module.load_state_dict(modified_state, strict=True)
|
|
|
|
error_msg = str(context.exception)
|
|
self.assertIn("Missing key(s)", error_msg)
|
|
self.assertIn("Unexpected key(s)", error_msg)
|
|
|
|
def test_load_state_dict_non_strict_mode(self):
|
|
self.module.register_parameter('param1', nn.Parameter(paddle.ones([3])))
|
|
self.module.register_buffer('buffer1', paddle.zeros([2]))
|
|
original_state = self.module.state_dict()
|
|
|
|
modified_state = original_state.copy()
|
|
modified_state['extra_param'] = paddle.ones([5])
|
|
modified_state.pop('buffer1')
|
|
|
|
result = self.module.load_state_dict(modified_state, strict=False)
|
|
|
|
self.assertIn('buffer1', result.missing_keys)
|
|
self.assertIn('extra_param', result.unexpected_keys)
|
|
|
|
self.assertTrue(paddle.allclose(self.module.param1, paddle.ones([3])))
|
|
|
|
def test_load_state_dict_assign(self):
|
|
self.module.register_parameter('weight', nn.Parameter(paddle.ones([1])))
|
|
self.module.register_buffer('buffer', paddle.ones([1]))
|
|
old_weight = self.module.weight
|
|
old_buffer = self.module.buffer
|
|
self.module.weight.trainable = False
|
|
state_weight = nn.Parameter(paddle.full([1], 3.0))
|
|
state_dict = {
|
|
'weight': state_weight,
|
|
'buffer': paddle.full([1], 5.0),
|
|
}
|
|
|
|
result = self.module.load_state_dict(state_dict, assign=True)
|
|
|
|
self.assertIs(self.module.weight, state_weight)
|
|
self.assertIs(self.module.buffer, state_dict['buffer'])
|
|
self.assertTrue(
|
|
paddle.allclose(self.module.weight, state_dict['weight'])
|
|
)
|
|
self.assertTrue(
|
|
paddle.allclose(self.module.buffer, state_dict['buffer'])
|
|
)
|
|
self.assertFalse(self.module.weight.trainable)
|
|
self.assertIsNot(self.module.weight, old_weight)
|
|
self.assertIsNot(self.module.buffer, old_buffer)
|
|
self.assertEqual(len(result.missing_keys), 0)
|
|
self.assertEqual(len(result.unexpected_keys), 0)
|
|
|
|
|
|
class TestNamedParameters(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module = Module()
|
|
|
|
def test_named_parameters_basic(self):
|
|
param1 = paddle.create_parameter([3, 4], dtype='float32')
|
|
param2 = paddle.create_parameter([2, 2], dtype='float32')
|
|
self.module.register_parameter('weight', param1)
|
|
self.module.register_parameter('bias', param2)
|
|
|
|
named_params = dict(self.module.named_parameters())
|
|
|
|
self.assertIn('weight', named_params)
|
|
self.assertIn('bias', named_params)
|
|
self.assertEqual(len(named_params), 2)
|
|
|
|
self.assertTrue(paddle.allclose(named_params['weight'], param1))
|
|
self.assertTrue(paddle.allclose(named_params['bias'], param2))
|
|
|
|
def test_named_parameters_with_prefix(self):
|
|
param = paddle.create_parameter([5], dtype='float32')
|
|
self.module.register_parameter('test_param', param)
|
|
|
|
names_without_prefix = [
|
|
name for name, _ in self.module.named_parameters(prefix="")
|
|
]
|
|
self.assertEqual(names_without_prefix, ['test_param'])
|
|
|
|
names_with_prefix = [
|
|
name for name, _ in self.module.named_parameters(prefix="module")
|
|
]
|
|
self.assertEqual(names_with_prefix, ['module.test_param'])
|
|
|
|
def test_named_parameters_recurse_false(self):
|
|
sublayer = nn.Linear(10, 5)
|
|
self.module.add_sublayer('linear', sublayer)
|
|
|
|
main_param = paddle.create_parameter([3], dtype='float32')
|
|
self.module.register_parameter('main_param', main_param)
|
|
|
|
non_recurse_names = [
|
|
name for name, _ in self.module.named_parameters(recurse=False)
|
|
]
|
|
self.assertEqual(non_recurse_names, ['main_param'])
|
|
|
|
recurse_names = [
|
|
name for name, _ in self.module.named_parameters(recurse=True)
|
|
]
|
|
self.assertIn('main_param', recurse_names)
|
|
self.assertIn('linear.weight', recurse_names)
|
|
self.assertIn('linear.bias', recurse_names)
|
|
|
|
def test_named_parameters_remove_duplicate(self):
|
|
shared_param = paddle.create_parameter([4, 4], dtype='float32')
|
|
|
|
self.module.register_parameter('weight1', shared_param)
|
|
self.module.register_parameter('weight2', shared_param)
|
|
|
|
without_duplicate = list(
|
|
self.module.named_parameters(remove_duplicate=False)
|
|
)
|
|
names_no_dedup = [name for name, _ in without_duplicate]
|
|
self.assertEqual(len(names_no_dedup), 2)
|
|
self.assertIn('weight1', names_no_dedup)
|
|
self.assertIn('weight2', names_no_dedup)
|
|
|
|
param_dict = dict(without_duplicate)
|
|
self.assertIs(param_dict['weight1'], param_dict['weight2'])
|
|
|
|
with_duplicate = list(
|
|
self.module.named_parameters(remove_duplicate=True)
|
|
)
|
|
names_dedup = [name for name, _ in with_duplicate]
|
|
self.assertEqual(len(names_dedup), 1)
|
|
self.assertIn('weight1', names_dedup)
|
|
|
|
def test_named_parameters_empty_module(self):
|
|
named_params = list(self.module.named_parameters())
|
|
self.assertEqual(len(named_params), 0)
|
|
|
|
def test_named_parameters_complex_hierarchy(self):
|
|
child1 = nn.Linear(10, 8)
|
|
child2 = nn.Linear(8, 6)
|
|
child1.add_sublayer('child2', child2)
|
|
self.module.add_sublayer('child1', child1)
|
|
|
|
self.module.register_parameter(
|
|
'global_param', paddle.create_parameter([3], dtype='float32')
|
|
)
|
|
|
|
all_names = [name for name, _ in self.module.named_parameters()]
|
|
|
|
expected_names = [
|
|
'global_param',
|
|
'child1.weight',
|
|
'child1.bias',
|
|
'child1.child2.weight',
|
|
'child1.child2.bias',
|
|
]
|
|
|
|
self.assertEqual(set(all_names), set(expected_names))
|
|
self.assertEqual(len(all_names), len(expected_names))
|
|
|
|
def test_named_parameters_with_buffers(self):
|
|
param = paddle.create_parameter([5], dtype='float32')
|
|
buffer = paddle.to_tensor([1, 2, 3])
|
|
|
|
self.module.register_parameter('param', param)
|
|
self.module.register_buffer('buffer', buffer)
|
|
|
|
param_names = [name for name, _ in self.module.named_parameters()]
|
|
buffer_names = [name for name, _ in self.module.named_buffers()]
|
|
|
|
self.assertEqual(param_names, ['param'])
|
|
self.assertEqual(buffer_names, ['buffer'])
|
|
|
|
self.assertNotIn('buffer', param_names)
|
|
self.assertNotIn('param', buffer_names)
|
|
|
|
|
|
class TestNamedModules(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module = Module()
|
|
|
|
def test_modules_basic(self):
|
|
child1 = SubModule()
|
|
child2 = nn.ReLU()
|
|
self.module.add_sublayer('submodule', child1)
|
|
self.module.add_sublayer('activation', child2)
|
|
|
|
modules = list(self.module.modules())
|
|
|
|
self.assertEqual(len(modules), 4)
|
|
|
|
def test_named_modules_basic(self):
|
|
child1 = SubModule()
|
|
child2 = nn.ReLU()
|
|
self.module.add_sublayer('submodule', child1)
|
|
self.module.add_sublayer('activation', child2)
|
|
|
|
named_modules = dict(self.module.named_modules())
|
|
|
|
self.assertIn('', named_modules)
|
|
self.assertIn('submodule', named_modules)
|
|
self.assertIn('activation', named_modules)
|
|
self.assertIn('submodule.linear', named_modules)
|
|
self.assertEqual(len(named_modules), 4)
|
|
|
|
self.assertIs(named_modules[''], self.module)
|
|
self.assertIs(named_modules['submodule'], child1)
|
|
self.assertIs(named_modules['activation'], child2)
|
|
self.assertIs(named_modules['submodule.linear'], child1.linear)
|
|
|
|
def test_named_modules_with_prefix(self):
|
|
child = SubModule()
|
|
self.module.add_sublayer('child', child)
|
|
|
|
names_without_prefix = [
|
|
name for name, _ in self.module.named_modules(prefix="")
|
|
]
|
|
self.assertIn('', names_without_prefix)
|
|
self.assertIn('child', names_without_prefix)
|
|
self.assertIn('child.linear', names_without_prefix)
|
|
|
|
names_with_prefix = [
|
|
name for name, _ in self.module.named_modules(prefix="model")
|
|
]
|
|
self.assertIn('model', names_with_prefix)
|
|
self.assertIn('model.child', names_with_prefix)
|
|
self.assertIn('model.child.linear', names_with_prefix)
|
|
self.assertNotIn('', names_with_prefix)
|
|
|
|
def test_named_modules_memo_parameter(self):
|
|
nested_module = NestedModule()
|
|
self.module.add_sublayer('nested', nested_module)
|
|
|
|
memo_set = set()
|
|
first_pass = list(self.module.named_modules(memo=memo_set))
|
|
|
|
self.assertIn(self.module, memo_set)
|
|
self.assertIn(nested_module, memo_set)
|
|
self.assertIn(nested_module.layer1, memo_set)
|
|
|
|
second_pass = list(self.module.named_modules(memo=memo_set))
|
|
|
|
self.assertEqual(len(second_pass), 0)
|
|
|
|
def test_named_modules_remove_duplicate(self):
|
|
shared_module = nn.Dropout(0.5)
|
|
|
|
self.module.add_sublayer('dropout1', shared_module)
|
|
self.module.add_sublayer('dropout2', shared_module)
|
|
|
|
without_dedup = list(self.module.named_modules(remove_duplicate=False))
|
|
names_no_dedup = [name for name, _ in without_dedup]
|
|
self.assertEqual(len(names_no_dedup), 3)
|
|
self.assertIn('dropout1', names_no_dedup)
|
|
self.assertIn('dropout2', names_no_dedup)
|
|
|
|
module_dict = dict(without_dedup)
|
|
self.assertIs(module_dict['dropout1'], module_dict['dropout2'])
|
|
|
|
with_dedup = list(self.module.named_modules(remove_duplicate=True))
|
|
names_dedup = [name for name, _ in with_dedup]
|
|
self.assertEqual(len(names_dedup), 2)
|
|
|
|
dropout_names = [name for name in names_dedup if 'dropout' in name]
|
|
self.assertEqual(len(dropout_names), 1)
|
|
|
|
def test_named_modules_complex_hierarchy(self):
|
|
nested_module = NestedModule()
|
|
self.module.add_sublayer('complex', nested_module)
|
|
|
|
all_modules = dict(self.module.named_modules())
|
|
|
|
expected_paths = {
|
|
'',
|
|
'complex',
|
|
'complex.layer1',
|
|
'complex.layer2',
|
|
'complex.layer3',
|
|
'complex.final_layer',
|
|
'complex.layer1.linear',
|
|
'complex.layer1.activation',
|
|
'complex.layer2.linear',
|
|
'complex.layer2.activation',
|
|
'complex.layer3.linear',
|
|
'complex.layer3.activation',
|
|
}
|
|
|
|
self.assertEqual(set(all_modules.keys()), expected_paths)
|
|
|
|
self.assertIs(all_modules[''], self.module)
|
|
self.assertIs(all_modules['complex'], nested_module)
|
|
self.assertIs(all_modules['complex.layer1'], nested_module.layer1)
|
|
self.assertIs(
|
|
all_modules['complex.layer1.linear'], nested_module.layer1.linear
|
|
)
|
|
self.assertIs(
|
|
all_modules['complex.final_layer'], nested_module.final_layer
|
|
)
|
|
|
|
def test_named_modules_empty_module(self):
|
|
named_modules = list(self.module.named_modules())
|
|
self.assertEqual(len(named_modules), 1)
|
|
self.assertEqual(named_modules[0][0], '')
|
|
self.assertIs(named_modules[0][1], self.module)
|
|
|
|
|
|
class TestGetBuffer(unittest.TestCase):
|
|
def setUp(self):
|
|
self.model = NestedModule()
|
|
|
|
def test_get_existing_buffer(self):
|
|
buf = self.model.get_buffer("layer1.running_mean")
|
|
self.assertIsInstance(buf, paddle.Tensor)
|
|
self.assertTrue(paddle.allclose(buf, paddle.zeros([8])))
|
|
|
|
def test_get_nested_buffer(self):
|
|
buf = self.model.get_buffer("layer2.running_mean")
|
|
self.assertEqual(buf.shape[0], 6)
|
|
|
|
def test_get_final_layer_error(self):
|
|
with self.assertRaises(AttributeError):
|
|
_ = self.model.get_buffer("final_layer.bias")
|
|
|
|
def test_nonexistent_layer_error(self):
|
|
with self.assertRaises(AttributeError):
|
|
_ = self.model.get_buffer("nonexistent.running_mean")
|
|
|
|
def test_nonexistent_buffer_error(self):
|
|
with self.assertRaises(AttributeError):
|
|
_ = self.model.get_buffer("layer1.not_a_buffer")
|
|
|
|
|
|
class TestModuleDeviceTransfer(unittest.TestCase):
|
|
def setUp(self):
|
|
self.model = NestedModule()
|
|
|
|
@unittest.skipIf(
|
|
not paddle.is_compiled_with_cuda(), "Paddle not compiled with CUDA"
|
|
)
|
|
def test_cuda(self):
|
|
model_gpu = self.model.cuda()
|
|
for name, p in model_gpu.named_parameters():
|
|
self.assertTrue(
|
|
p.place.is_gpu_place(), f"{name} not on GPU with device=None"
|
|
)
|
|
for name, b in model_gpu.named_buffers():
|
|
self.assertTrue(
|
|
b.place.is_gpu_place(),
|
|
f"{name} buffer not on GPU with device=None",
|
|
)
|
|
|
|
model_gpu = self.model.cuda(0)
|
|
for name, p in model_gpu.named_parameters():
|
|
self.assertTrue(
|
|
p.place.is_gpu_place(), f"{name} not on GPU when using index 0"
|
|
)
|
|
for name, b in model_gpu.named_buffers():
|
|
self.assertTrue(
|
|
b.place.is_gpu_place(), f"{name} buffer not on GPU with index 0"
|
|
)
|
|
|
|
cuda_place = paddle.CUDAPlace(0)
|
|
model_gpu = self.model.cuda(cuda_place)
|
|
for name, p in model_gpu.named_parameters():
|
|
self.assertTrue(
|
|
p.place.is_gpu_place(),
|
|
f"{name} not on GPU when using CUDAPlace",
|
|
)
|
|
for name, b in model_gpu.named_buffers():
|
|
self.assertTrue(
|
|
b.place.is_gpu_place(),
|
|
f"{name} buffer not on GPU when using CUDAPlace",
|
|
)
|
|
|
|
with self.assertRaises(TypeError):
|
|
self.model.cuda("gpu:0")
|
|
|
|
@unittest.skipIf(
|
|
not hasattr(paddle, "is_compiled_with_xpu")
|
|
or not paddle.is_compiled_with_xpu(),
|
|
"Paddle not built with XPU",
|
|
)
|
|
def test_xpu(self):
|
|
model_xpu = self.model.xpu()
|
|
for name, p in model_xpu.named_parameters():
|
|
self.assertTrue(
|
|
p.place.is_xpu_place(), f"{name} not moved to XPU (device=None)"
|
|
)
|
|
for name, b in model_xpu.named_buffers():
|
|
self.assertTrue(
|
|
b.place.is_xpu_place(),
|
|
f"{name} buffer not moved to XPU (device=None)",
|
|
)
|
|
|
|
model_xpu = self.model.xpu(0)
|
|
for name, p in model_xpu.named_parameters():
|
|
self.assertTrue(
|
|
p.place.is_xpu_place(), f"{name} not moved to XPU (device=0)"
|
|
)
|
|
for name, b in model_xpu.named_buffers():
|
|
self.assertTrue(
|
|
b.place.is_xpu_place(),
|
|
f"{name} buffer not moved to XPU (device=0)",
|
|
)
|
|
|
|
xpu_place = paddle.XPUPlace(0)
|
|
model_xpu = self.model.xpu(xpu_place)
|
|
for name, p in model_xpu.named_parameters():
|
|
self.assertTrue(
|
|
p.place.is_xpu_place(), f"{name} not moved to XPU (XPUPlace)"
|
|
)
|
|
for name, b in model_xpu.named_buffers():
|
|
self.assertTrue(
|
|
b.place.is_xpu_place(),
|
|
f"{name} buffer not moved to XPU (XPUPlace)",
|
|
)
|
|
|
|
with self.assertRaises(TypeError):
|
|
self.model.xpu("xpu:0")
|
|
|
|
def test_cpu(self):
|
|
model_cpu = self.model.cpu()
|
|
for name, p in model_cpu.named_parameters():
|
|
self.assertTrue(p.place.is_cpu_place(), f"{name} not on CPU")
|
|
for name, b in model_cpu.named_buffers():
|
|
self.assertTrue(b.place.is_cpu_place(), f"{name} buffer not on CPU")
|
|
|
|
|
|
class TestType(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module = Module()
|
|
self.module.linear = nn.Linear(3, 2)
|
|
self.module.bn = nn.BatchNorm1D(2)
|
|
self.module.register_parameter(
|
|
'weight',
|
|
paddle.create_parameter(
|
|
shape=[5, 3],
|
|
dtype=paddle.float32,
|
|
default_initializer=nn.initializer.Constant(1.0),
|
|
),
|
|
)
|
|
self.module.register_buffer(
|
|
'buffer', paddle.ones([3, 2], dtype=paddle.float32)
|
|
)
|
|
|
|
def test_type(self):
|
|
self.module.type(paddle.float64)
|
|
self.assertEqual(self.module.weight.dtype, paddle.float64)
|
|
self.assertEqual(self.module.buffer.dtype, paddle.float64)
|
|
|
|
self.module.type('int8')
|
|
self.assertEqual(self.module.weight.dtype, paddle.int8)
|
|
self.assertEqual(self.module.buffer.dtype, paddle.int8)
|
|
for name, param in self.module.named_parameters():
|
|
self.assertEqual(param.dtype, paddle.int8)
|
|
for name, buf in self.module.named_buffers():
|
|
self.assertEqual(buf.dtype, paddle.int8)
|
|
|
|
def test_double(self):
|
|
self.module.double()
|
|
self.assertEqual(self.module.weight.dtype, paddle.float64)
|
|
self.assertEqual(self.module.buffer.dtype, paddle.float64)
|
|
|
|
def test_half(self):
|
|
self.module.half()
|
|
self.assertEqual(self.module.weight.dtype, paddle.float16)
|
|
self.assertEqual(self.module.buffer.dtype, paddle.float16)
|
|
|
|
def test_type_error(self):
|
|
with self.assertRaises(ValueError):
|
|
self.module.type("invalid_dtype")
|
|
|
|
|
|
class TestStateDict(unittest.TestCase):
|
|
def setUp(self):
|
|
self.model = NestedModule()
|
|
self.model1 = SubModule()
|
|
|
|
def test_state_dict_basic(self):
|
|
state = self.model.state_dict()
|
|
self.assertIsInstance(state, OrderedDict)
|
|
self.assertGreater(len(state), 0)
|
|
|
|
def test_state_dict_contains_buffers(self):
|
|
state = self.model.state_dict()
|
|
buffer_keys = [k for k in state.keys() if "running_mean" in k]
|
|
self.assertTrue(len(buffer_keys) > 0)
|
|
for k in buffer_keys:
|
|
self.assertIn("running_mean", k)
|
|
self.assertTrue(isinstance(state[k], paddle.Tensor))
|
|
|
|
def test_state_dict_prefix_structure(self):
|
|
state = self.model.state_dict()
|
|
expected_prefixes = [
|
|
"layer1.linear.weight",
|
|
"layer2.linear.weight",
|
|
"layer3.linear.weight",
|
|
"final_layer.weight",
|
|
]
|
|
for prefix in expected_prefixes:
|
|
match = [k for k in state.keys() if k.startswith(prefix)]
|
|
self.assertTrue(len(match) > 0, f"Missing prefix: {prefix}")
|
|
|
|
def test_state_dict_keep_vars(self):
|
|
state1 = self.model1.state_dict(keep_vars=True)
|
|
state2 = self.model1.state_dict(keep_vars=False)
|
|
|
|
for k in state1.keys():
|
|
if hasattr(state1[k], "stop_gradient"):
|
|
self.assertFalse(state1[k].stop_gradient)
|
|
self.assertTrue(state2[k].stop_gradient)
|
|
|
|
def test_state_dict_with_positional_args(self):
|
|
sd_default = self.model.state_dict()
|
|
self.assertIsInstance(sd_default, dict)
|
|
|
|
dest = {}
|
|
sd1 = self.model.state_dict(dest)
|
|
self.assertIsInstance(sd1, dict)
|
|
|
|
sd2 = self.model.state_dict({}, "wfs")
|
|
self.assertIsInstance(sd2, dict)
|
|
|
|
sd3 = self.model.state_dict({}, False, "wfs")
|
|
self.assertIsInstance(sd3, dict)
|
|
|
|
sd4 = self.model.state_dict({}, "wfs", False)
|
|
self.assertIsInstance(sd4, dict)
|
|
|
|
sd5 = self.model.state_dict({}, False, "wfs", False, False)
|
|
self.assertIsInstance(sd5, dict)
|
|
|
|
|
|
class TestTrain(unittest.TestCase):
|
|
def setUp(self):
|
|
self.model = NestedModule()
|
|
|
|
def test_train_sets_training_true(self):
|
|
self.model.train(True)
|
|
self.assertTrue(self.model.training)
|
|
for name, submodule in self.model.named_children():
|
|
self.assertTrue(submodule.training, f"{name} not in training mode")
|
|
|
|
def test_train_sets_training_false(self):
|
|
self.model.train(False)
|
|
self.assertFalse(self.model.training)
|
|
for name, submodule in self.model.named_children():
|
|
self.assertFalse(submodule.training, f"{name} not in eval mode")
|
|
|
|
def test_train_invalid_argument(self):
|
|
with self.assertRaises(ValueError):
|
|
self.model.train("True")
|
|
|
|
|
|
class TestGrad(unittest.TestCase):
|
|
def setUp(self):
|
|
self.model = SubModule1(10, 5)
|
|
|
|
def test_requires_grad(self):
|
|
for p in self.model.parameters():
|
|
self.assertFalse(p.stop_gradient)
|
|
|
|
self.model.requires_grad_(False)
|
|
for p in self.model.parameters():
|
|
self.assertTrue(p.stop_gradient)
|
|
|
|
self.model.requires_grad_(True)
|
|
for p in self.model.parameters():
|
|
self.assertFalse(p.stop_gradient)
|
|
|
|
def test_zero_grad(self):
|
|
x = paddle.randn([4, 10])
|
|
y = self.model(x).sum()
|
|
y.backward()
|
|
|
|
for p in self.model.parameters():
|
|
self.assertIsNotNone(p.grad)
|
|
|
|
self.model.zero_grad(set_to_none=False)
|
|
for p in self.model.parameters():
|
|
self.assertIsNotNone(p.grad)
|
|
self.assertTrue(paddle.allclose(p.grad, paddle.zeros_like(p.grad)))
|
|
|
|
self.model.zero_grad()
|
|
for p in self.model.parameters():
|
|
self.assertIsNone(p.grad)
|
|
|
|
|
|
# test ModuleList
|
|
class TestModuleListBasic(unittest.TestCase):
|
|
def test_initialization_empty(self):
|
|
module_list = nn.ModuleList()
|
|
self.assertEqual(len(module_list), 0)
|
|
self.assertEqual(list(module_list), [])
|
|
|
|
def test_initialization_with_modules(self):
|
|
modules = [nn.Linear(10, 5), nn.ReLU(), nn.Dropout(0.5)]
|
|
module_list = nn.ModuleList(modules)
|
|
self.assertEqual(len(module_list), 3)
|
|
self.assertIsInstance(module_list[0], nn.Linear)
|
|
self.assertIsInstance(module_list[1], nn.ReLU)
|
|
self.assertIsInstance(module_list[2], nn.Dropout)
|
|
|
|
def test_get_abs_string_index(self):
|
|
modules = [nn.Linear(10, 5), nn.ReLU(), nn.Dropout(0.5)]
|
|
module_list = nn.ModuleList(modules)
|
|
self.assertEqual(module_list._get_abs_string_index(0), "0")
|
|
self.assertEqual(module_list._get_abs_string_index(1), "1")
|
|
self.assertEqual(module_list._get_abs_string_index(-1), "2")
|
|
self.assertEqual(module_list._get_abs_string_index(-2), "1")
|
|
|
|
def test_get_abs_string_index_out_of_range(self):
|
|
module_list = nn.ModuleList([nn.Linear(10, 5)])
|
|
|
|
with self.assertRaises(IndexError):
|
|
module_list._get_abs_string_index(1)
|
|
|
|
with self.assertRaises(IndexError):
|
|
module_list._get_abs_string_index(-2)
|
|
|
|
|
|
class TestModuleListDir(unittest.TestCase):
|
|
def test_dir_filters_numeric_keys(self):
|
|
module_list = nn.ModuleList([nn.Linear(10, 5), nn.ReLU()])
|
|
module_list.extra = nn.Linear(5, 2)
|
|
d = dir(module_list)
|
|
self.assertIn("extra", d)
|
|
self.assertNotIn("0", d)
|
|
self.assertNotIn("1", d)
|
|
|
|
|
|
class TestModuleListIndexing(unittest.TestCase):
|
|
def setUp(self):
|
|
self.modules = [nn.Linear(10, 5), nn.ReLU(), nn.Dropout(0.5), nn.Tanh()]
|
|
self.module_list = nn.ModuleList(self.modules)
|
|
|
|
def test_getitem_int(self):
|
|
self.assertIs(self.module_list[0], self.modules[0])
|
|
self.assertIs(self.module_list[1], self.modules[1])
|
|
self.assertIs(self.module_list[-1], self.modules[3])
|
|
self.assertIs(self.module_list[-2], self.modules[2])
|
|
|
|
def test_getitem_slice(self):
|
|
# Test basic slicing
|
|
slice_result = self.module_list[1:3]
|
|
self.assertIsInstance(slice_result, nn.ModuleList)
|
|
self.assertEqual(len(slice_result), 2)
|
|
self.assertIs(slice_result[0], self.modules[1])
|
|
self.assertIs(slice_result[1], self.modules[2])
|
|
|
|
# Test step slicing
|
|
slice_step = self.module_list[::2]
|
|
self.assertEqual(len(slice_step), 2)
|
|
self.assertIs(slice_step[0], self.modules[0])
|
|
self.assertIs(slice_step[1], self.modules[2])
|
|
|
|
# Test negative slicing
|
|
slice_neg = self.module_list[-2:]
|
|
self.assertEqual(len(slice_neg), 2)
|
|
self.assertIs(slice_neg[0], self.modules[2])
|
|
self.assertIs(slice_neg[1], self.modules[3])
|
|
|
|
def test_setitem(self):
|
|
new_module = nn.Sigmoid()
|
|
self.module_list[1] = new_module
|
|
self.assertIs(self.module_list[1], new_module)
|
|
self.assertIsNot(self.module_list[1], self.modules[1])
|
|
|
|
def test_setitem_negative_index(self):
|
|
new_module = nn.ELU()
|
|
self.module_list[-1] = new_module
|
|
self.assertIs(self.module_list[3], new_module)
|
|
|
|
def test_delitem_int(self):
|
|
original_length = len(self.module_list)
|
|
del self.module_list[1]
|
|
|
|
self.assertEqual(len(self.module_list), original_length - 1)
|
|
self.assertIs(self.module_list[0], self.modules[0])
|
|
self.assertIs(self.module_list[1], self.modules[2])
|
|
self.assertIs(self.module_list[2], self.modules[3])
|
|
|
|
def test_delitem_slice(self):
|
|
# Delete middle slice
|
|
del self.module_list[1:3]
|
|
self.assertEqual(len(self.module_list), 2)
|
|
self.assertIs(self.module_list[0], self.modules[0])
|
|
self.assertIs(self.module_list[1], self.modules[3])
|
|
|
|
# Reset and test deleting from start
|
|
self.module_list = nn.ModuleList(self.modules)
|
|
del self.module_list[:2]
|
|
self.assertEqual(len(self.module_list), 2)
|
|
self.assertIs(self.module_list[0], self.modules[2])
|
|
self.assertIs(self.module_list[1], self.modules[3])
|
|
|
|
def test_delitem_negative_index(self):
|
|
original_length = len(self.module_list)
|
|
del self.module_list[-1]
|
|
self.assertEqual(len(self.module_list), original_length - 1)
|
|
self.assertIs(self.module_list[-1], self.modules[2])
|
|
|
|
|
|
class TestModuleListOperations(unittest.TestCase):
|
|
def setUp(self):
|
|
self.modules1 = [nn.Linear(10, 5), nn.ReLU()]
|
|
self.modules2 = [nn.Dropout(0.5), nn.Tanh()]
|
|
self.module_list1 = nn.ModuleList(self.modules1)
|
|
self.module_list2 = nn.ModuleList(self.modules2)
|
|
|
|
def test_len(self):
|
|
self.assertEqual(len(self.module_list1), 2)
|
|
self.assertEqual(len(self.module_list2), 2)
|
|
|
|
def test_iter(self):
|
|
modules_from_iter = list(iter(self.module_list1))
|
|
self.assertEqual(len(modules_from_iter), 2)
|
|
self.assertIs(modules_from_iter[0], self.modules1[0])
|
|
self.assertIs(modules_from_iter[1], self.modules1[1])
|
|
|
|
def test_iadd(self):
|
|
original_len = len(self.module_list1)
|
|
self.module_list1 += self.modules2
|
|
|
|
self.assertEqual(
|
|
len(self.module_list1), original_len + len(self.modules2)
|
|
)
|
|
self.assertIs(self.module_list1[0], self.modules1[0])
|
|
self.assertIs(self.module_list1[1], self.modules1[1])
|
|
self.assertIs(self.module_list1[2], self.modules2[0])
|
|
self.assertIs(self.module_list1[3], self.modules2[1])
|
|
|
|
def test_add(self):
|
|
combined = self.module_list1 + self.module_list2
|
|
self.assertIsInstance(combined, nn.ModuleList)
|
|
self.assertEqual(len(combined), 4)
|
|
self.assertIs(combined[0], self.modules1[0])
|
|
self.assertIs(combined[1], self.modules1[1])
|
|
self.assertIs(combined[2], self.modules2[0])
|
|
self.assertIs(combined[3], self.modules2[1])
|
|
|
|
# Original lists should be unchanged
|
|
self.assertEqual(len(self.module_list1), 2)
|
|
self.assertEqual(len(self.module_list2), 2)
|
|
|
|
def test_insert(self):
|
|
new_module = nn.Sigmoid()
|
|
self.module_list1.insert(1, module=new_module)
|
|
|
|
self.assertEqual(len(self.module_list1), 3)
|
|
self.assertIs(self.module_list1[0], self.modules1[0])
|
|
self.assertIs(self.module_list1[1], new_module)
|
|
self.assertIs(self.module_list1[2], self.modules1[1])
|
|
|
|
def test_insert_at_beginning(self):
|
|
new_module = nn.ELU()
|
|
self.module_list1.insert(0, new_module)
|
|
self.assertIs(self.module_list1[0], new_module)
|
|
self.assertIs(self.module_list1[1], self.modules1[0])
|
|
|
|
def test_insert_at_end(self):
|
|
new_module = nn.LeakyReLU()
|
|
self.module_list1.insert(2, new_module)
|
|
self.assertIs(self.module_list1[2], new_module)
|
|
|
|
def test_append(self):
|
|
new_module = nn.Softmax()
|
|
original_len = len(self.module_list1)
|
|
result = self.module_list1.append(module=new_module)
|
|
|
|
self.assertEqual(len(self.module_list1), original_len + 1)
|
|
self.assertIs(self.module_list1[-1], new_module)
|
|
self.assertIs(result, self.module_list1)
|
|
|
|
def test_pop_int(self):
|
|
popped = self.module_list1.pop(0)
|
|
self.assertIs(popped, self.modules1[0])
|
|
self.assertEqual(len(self.module_list1), 1)
|
|
self.assertIs(self.module_list1[0], self.modules1[1])
|
|
|
|
def test_pop_negative_index(self):
|
|
popped = self.module_list1.pop(-1)
|
|
self.assertIs(popped, self.modules1[1])
|
|
self.assertEqual(len(self.module_list1), 1)
|
|
|
|
def test_pop_slice(self):
|
|
modules = [nn.Linear(10, 5), nn.ReLU(), nn.Dropout(0.5), nn.Tanh()]
|
|
module_list = nn.ModuleList(modules)
|
|
|
|
popped = module_list.pop(slice(1, 3))
|
|
self.assertIsInstance(popped, nn.ModuleList)
|
|
self.assertEqual(len(popped), 2)
|
|
self.assertIs(popped[0], modules[1])
|
|
self.assertIs(popped[1], modules[2])
|
|
self.assertEqual(len(module_list), 2)
|
|
|
|
def test_extend(self):
|
|
additional_modules = [nn.Dropout(0.3), nn.Sigmoid()]
|
|
original_len = len(self.module_list1)
|
|
result = self.module_list1.extend(modules=additional_modules)
|
|
|
|
self.assertEqual(
|
|
len(self.module_list1), original_len + len(additional_modules)
|
|
)
|
|
self.assertIs(self.module_list1[2], additional_modules[0])
|
|
self.assertIs(self.module_list1[3], additional_modules[1])
|
|
self.assertIs(result, self.module_list1)
|
|
|
|
def test_extent_error(self):
|
|
with self.assertRaises(TypeError):
|
|
self.module_list1.extend(123)
|
|
|
|
|
|
class TestModuleListFunctionality(unittest.TestCase):
|
|
def test_module_list_parameters(self):
|
|
linear1 = nn.Linear(10, 5)
|
|
linear2 = nn.Linear(5, 2)
|
|
module_list = nn.ModuleList([linear1, linear2])
|
|
|
|
params = dict(module_list.named_parameters())
|
|
self.assertIn('0.weight', params)
|
|
self.assertIn('0.bias', params)
|
|
self.assertIn('1.weight', params)
|
|
self.assertIn('1.bias', params)
|
|
|
|
def test_module_list_forward(self):
|
|
class TestModule(nn.Layer):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.layers = nn.ModuleList(
|
|
[nn.Linear(10, 5), nn.ReLU(), nn.Linear(5, 2)]
|
|
)
|
|
|
|
def forward(self, x):
|
|
for layer in self.layers:
|
|
x = layer(x)
|
|
return x
|
|
|
|
model = TestModule()
|
|
x = paddle.ones([2, 10])
|
|
output = model(x)
|
|
|
|
self.assertEqual(output.shape, [2, 2])
|
|
self.assertIsInstance(output, paddle.Tensor)
|
|
|
|
def test_module_list_state_dict(self):
|
|
linear1 = nn.Linear(10, 5)
|
|
linear2 = nn.Linear(5, 2)
|
|
module_list = nn.ModuleList([linear1, linear2])
|
|
|
|
state_dict = module_list.state_dict()
|
|
expected_keys = {'0.weight', '0.bias', '1.weight', '1.bias'}
|
|
self.assertEqual(set(state_dict.keys()), expected_keys)
|
|
|
|
def test_module_list_gradients(self):
|
|
linear1 = nn.Linear(10, 5)
|
|
linear2 = nn.Linear(5, 1)
|
|
module_list = nn.ModuleList([linear1, linear2])
|
|
|
|
x = paddle.ones([1, 10])
|
|
y = module_list[1](module_list[0](x))
|
|
loss = y.sum()
|
|
loss.backward()
|
|
|
|
self.assertIsNotNone(module_list[0].weight.grad)
|
|
self.assertIsNotNone(module_list[1].weight.grad)
|
|
|
|
|
|
class TestModuleListEdgeCases(unittest.TestCase):
|
|
def test_empty_operations(self):
|
|
empty_list = nn.ModuleList()
|
|
|
|
self.assertEqual(len(empty_list), 0)
|
|
self.assertEqual(list(empty_list), [])
|
|
|
|
module = nn.Linear(5, 3)
|
|
empty_list.append(module)
|
|
self.assertEqual(len(empty_list), 1)
|
|
self.assertIs(empty_list[0], module)
|
|
|
|
def test_single_element_operations(self):
|
|
module = nn.ReLU()
|
|
single_list = nn.ModuleList([module])
|
|
|
|
self.assertEqual(len(single_list), 1)
|
|
self.assertIs(single_list[0], module)
|
|
|
|
del single_list[0]
|
|
self.assertEqual(len(single_list), 0)
|
|
|
|
def test_duplicate_modules(self):
|
|
shared_module = nn.Dropout(0.5)
|
|
module_list = nn.ModuleList([shared_module, shared_module])
|
|
|
|
self.assertEqual(len(module_list), 2)
|
|
self.assertIs(module_list[0], module_list[1])
|
|
|
|
def test_module_list_with_none(self):
|
|
module_list = nn.ModuleList([nn.Linear(5, 3), None, nn.ReLU()])
|
|
self.assertEqual(len(module_list), 3)
|
|
self.assertIsNone(module_list[1])
|
|
|
|
|
|
# test ModuleDict
|
|
class TestModuleDictBasic(unittest.TestCase):
|
|
def test_initialization_empty(self):
|
|
module_dict = nn.ModuleDict()
|
|
self.assertEqual(len(module_dict), 0)
|
|
self.assertEqual(list(module_dict), [])
|
|
|
|
def test_initialization_with_modules(self):
|
|
modules = {
|
|
'linear': nn.Linear(10, 5),
|
|
'activation': nn.ReLU(),
|
|
'dropout': nn.Dropout(0.5),
|
|
}
|
|
module_dict = nn.ModuleDict(modules)
|
|
|
|
self.assertEqual(len(module_dict), 3)
|
|
self.assertIsInstance(module_dict['linear'], nn.Linear)
|
|
self.assertIsInstance(module_dict['activation'], nn.ReLU)
|
|
self.assertIsInstance(module_dict['dropout'], nn.Dropout)
|
|
|
|
def test_initialization_with_ordered_dict(self):
|
|
modules = OrderedDict(
|
|
[
|
|
('conv', nn.Conv2D(3, 16, 3)),
|
|
('bn', nn.BatchNorm2D(16)),
|
|
('pool', nn.MaxPool2D(2)),
|
|
]
|
|
)
|
|
module_dict = nn.ModuleDict(modules)
|
|
|
|
self.assertEqual(len(module_dict), 3)
|
|
self.assertIsInstance(module_dict['conv'], nn.Conv2D)
|
|
self.assertIsInstance(module_dict['bn'], nn.BatchNorm2D)
|
|
self.assertIsInstance(module_dict['pool'], nn.MaxPool2D)
|
|
|
|
|
|
class TestModuleDictAccessMethods(unittest.TestCase):
|
|
def setUp(self):
|
|
self.modules = {
|
|
'linear1': nn.Linear(10, 5),
|
|
'relu': nn.ReLU(),
|
|
'linear2': nn.Linear(5, 2),
|
|
'sigmoid': nn.Sigmoid(),
|
|
}
|
|
self.module_dict = nn.ModuleDict(self.modules)
|
|
|
|
def test_getitem(self):
|
|
self.assertIs(self.module_dict['linear1'], self.modules['linear1'])
|
|
self.assertIs(self.module_dict['relu'], self.modules['relu'])
|
|
self.assertIs(self.module_dict['linear2'], self.modules['linear2'])
|
|
|
|
def test_getitem_key_error(self):
|
|
with self.assertRaises(KeyError):
|
|
_ = self.module_dict['nonexistent']
|
|
|
|
def test_setitem(self):
|
|
new_module = nn.Tanh()
|
|
self.module_dict['tanh'] = new_module
|
|
self.assertIs(self.module_dict['tanh'], new_module)
|
|
self.assertEqual(len(self.module_dict), 5)
|
|
|
|
def test_setitem_overwrite(self):
|
|
new_linear = nn.Linear(10, 8)
|
|
original_length = len(self.module_dict)
|
|
self.module_dict['linear1'] = new_linear
|
|
|
|
self.assertEqual(len(self.module_dict), original_length)
|
|
self.assertIs(self.module_dict['linear1'], new_linear)
|
|
self.assertIsNot(self.module_dict['linear1'], self.modules['linear1'])
|
|
|
|
def test_delitem(self):
|
|
original_length = len(self.module_dict)
|
|
del self.module_dict['relu']
|
|
|
|
self.assertEqual(len(self.module_dict), original_length - 1)
|
|
self.assertNotIn('relu', self.module_dict)
|
|
self.assertIn('linear1', self.module_dict)
|
|
self.assertIn('linear2', self.module_dict)
|
|
|
|
def test_delitem_key_error(self):
|
|
with self.assertRaises(KeyError):
|
|
del self.module_dict['nonexistent']
|
|
|
|
def test_contains(self):
|
|
self.assertIn('linear1', self.module_dict)
|
|
self.assertIn('relu', self.module_dict)
|
|
self.assertNotIn('nonexistent', self.module_dict)
|
|
|
|
def test_keys(self):
|
|
keys = list(self.module_dict.keys())
|
|
expected_keys = ['linear1', 'relu', 'linear2', 'sigmoid']
|
|
self.assertEqual(set(keys), set(expected_keys))
|
|
self.assertEqual(len(keys), len(expected_keys))
|
|
|
|
def test_values(self):
|
|
values = list(self.module_dict.values())
|
|
self.assertEqual(len(values), 4)
|
|
self.assertIn(self.modules['linear1'], values)
|
|
self.assertIn(self.modules['relu'], values)
|
|
self.assertIn(self.modules['linear2'], values)
|
|
|
|
def test_items(self):
|
|
items = list(self.module_dict.items())
|
|
self.assertEqual(len(items), 4)
|
|
|
|
keys, values = zip(*items)
|
|
self.assertEqual(set(keys), set(self.modules.keys()))
|
|
self.assertEqual(set(values), set(self.modules.values()))
|
|
|
|
def test_iter(self):
|
|
keys_from_iter = list(iter(self.module_dict))
|
|
expected_keys = ['linear1', 'relu', 'linear2', 'sigmoid']
|
|
self.assertEqual(set(keys_from_iter), set(expected_keys))
|
|
|
|
|
|
class TestModuleDictOperations(unittest.TestCase):
|
|
def setUp(self):
|
|
self.initial_modules = {'conv': nn.Conv2D(3, 16, 3), 'relu': nn.ReLU()}
|
|
self.module_dict = nn.ModuleDict(self.initial_modules)
|
|
|
|
def test_clear(self):
|
|
self.assertEqual(len(self.module_dict), 2)
|
|
self.module_dict.clear()
|
|
self.assertEqual(len(self.module_dict), 0)
|
|
self.assertEqual(list(self.module_dict.keys()), [])
|
|
|
|
def test_pop(self):
|
|
original_length = len(self.module_dict)
|
|
popped_module = self.module_dict.pop('conv')
|
|
|
|
self.assertEqual(len(self.module_dict), original_length - 1)
|
|
self.assertIs(popped_module, self.initial_modules['conv'])
|
|
self.assertNotIn('conv', self.module_dict)
|
|
self.assertIn('relu', self.module_dict)
|
|
|
|
def test_pop_key_error(self):
|
|
with self.assertRaises(KeyError):
|
|
self.module_dict.pop('nonexistent')
|
|
|
|
def test_update_with_dict(self):
|
|
new_modules = {'bn': nn.BatchNorm2D(16), 'pool': nn.MaxPool2D(2)}
|
|
self.module_dict.update(modules=new_modules)
|
|
|
|
self.assertEqual(len(self.module_dict), 4)
|
|
self.assertIn('conv', self.module_dict)
|
|
self.assertIn('relu', self.module_dict)
|
|
self.assertIn('bn', self.module_dict)
|
|
self.assertIn('pool', self.module_dict)
|
|
|
|
def test_update_with_ordered_dict(self):
|
|
new_modules = OrderedDict(
|
|
[('dropout', nn.Dropout(0.5)), ('linear', nn.Linear(16, 10))]
|
|
)
|
|
self.module_dict.update(new_modules)
|
|
|
|
self.assertEqual(len(self.module_dict), 4)
|
|
self.assertIn('dropout', self.module_dict)
|
|
self.assertIn('linear', self.module_dict)
|
|
|
|
def test_update_with_module_dict(self):
|
|
other_dict = nn.ModuleDict({'sigmoid': nn.Sigmoid(), 'tanh': nn.Tanh()})
|
|
self.module_dict.update(other_dict)
|
|
|
|
self.assertEqual(len(self.module_dict), 4)
|
|
self.assertIn('sigmoid', self.module_dict)
|
|
self.assertIn('tanh', self.module_dict)
|
|
|
|
def test_update_with_iterable(self):
|
|
new_modules = [('bn', nn.BatchNorm2D(16)), ('pool', nn.MaxPool2D(2))]
|
|
self.module_dict.update(new_modules)
|
|
|
|
self.assertEqual(len(self.module_dict), 4)
|
|
self.assertIn('bn', self.module_dict)
|
|
self.assertIn('pool', self.module_dict)
|
|
|
|
def test_update_overwrite_existing(self):
|
|
new_conv = nn.Conv2D(3, 32, 3)
|
|
self.module_dict.update({'conv': new_conv})
|
|
|
|
self.assertEqual(len(self.module_dict), 2)
|
|
self.assertIs(self.module_dict['conv'], new_conv)
|
|
self.assertIsNot(self.module_dict['conv'], self.initial_modules['conv'])
|
|
|
|
def test_update_invalid_iterable_element(self):
|
|
with self.assertRaises(TypeError):
|
|
self.module_dict.update([nn.Linear(5, 3)])
|
|
|
|
def test_update_invalid_pair_length(self):
|
|
with self.assertRaises(ValueError):
|
|
self.module_dict.update([('key', 'module', 'extra')])
|
|
|
|
def test_update_error(self):
|
|
with self.assertRaises(AssertionError):
|
|
self.module_dict.update(123)
|
|
|
|
|
|
class TestModuleDictFunctionality(unittest.TestCase):
|
|
def test_module_dict_parameters(self):
|
|
module_dict = nn.ModuleDict(
|
|
{'linear1': nn.Linear(10, 5), 'linear2': nn.Linear(5, 2)}
|
|
)
|
|
|
|
params = dict(module_dict.named_parameters())
|
|
self.assertIn('linear1.weight', params)
|
|
self.assertIn('linear1.bias', params)
|
|
self.assertIn('linear2.weight', params)
|
|
self.assertIn('linear2.bias', params)
|
|
|
|
def test_module_dict_forward(self):
|
|
class TestModel(nn.Layer):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.layers = nn.ModuleDict(
|
|
{
|
|
'linear1': nn.Linear(10, 5),
|
|
'activation': nn.ReLU(),
|
|
'linear2': nn.Linear(5, 2),
|
|
}
|
|
)
|
|
|
|
def forward(self, x):
|
|
x = self.layers['linear1'](x)
|
|
x = self.layers['activation'](x)
|
|
x = self.layers['linear2'](x)
|
|
return x
|
|
|
|
model = TestModel()
|
|
x = paddle.ones([2, 10])
|
|
output = model(x)
|
|
|
|
self.assertEqual(output.shape, [2, 2])
|
|
self.assertIsInstance(output, paddle.Tensor)
|
|
|
|
def test_module_dict_state_dict(self):
|
|
module_dict = nn.ModuleDict(
|
|
{'conv': nn.Conv2D(3, 16, 3), 'bn': nn.BatchNorm2D(16)}
|
|
)
|
|
|
|
state_dict = module_dict.state_dict()
|
|
expected_keys = {
|
|
'conv.weight',
|
|
'conv.bias',
|
|
'bn.weight',
|
|
'bn.bias',
|
|
'bn._mean',
|
|
'bn._variance',
|
|
}
|
|
actual_keys = set(state_dict.keys())
|
|
self.assertTrue(expected_keys.issubset(actual_keys))
|
|
|
|
def test_module_dict_gradients(self):
|
|
module_dict = nn.ModuleDict(
|
|
{'linear1': nn.Linear(10, 5), 'linear2': nn.Linear(5, 1)}
|
|
)
|
|
|
|
x = paddle.ones([1, 10])
|
|
y = module_dict['linear2'](module_dict['linear1'](x))
|
|
loss = y.sum()
|
|
loss.backward()
|
|
|
|
self.assertIsNotNone(module_dict['linear1'].weight.grad)
|
|
self.assertIsNotNone(module_dict['linear2'].weight.grad)
|
|
|
|
|
|
class TestModuleDictEdgeCases(unittest.TestCase):
|
|
def test_empty_operations(self):
|
|
empty_dict = nn.ModuleDict()
|
|
|
|
self.assertEqual(len(empty_dict), 0)
|
|
self.assertEqual(list(empty_dict.keys()), [])
|
|
self.assertEqual(list(empty_dict.values()), [])
|
|
|
|
module = nn.Linear(5, 3)
|
|
empty_dict['linear'] = module
|
|
self.assertEqual(len(empty_dict), 1)
|
|
self.assertIs(empty_dict['linear'], module)
|
|
|
|
def test_single_element_operations(self):
|
|
module = nn.ReLU()
|
|
single_dict = nn.ModuleDict({'activation': module})
|
|
|
|
self.assertEqual(len(single_dict), 1)
|
|
self.assertIs(single_dict['activation'], module)
|
|
|
|
del single_dict['activation']
|
|
self.assertEqual(len(single_dict), 0)
|
|
|
|
def test_duplicate_modules(self):
|
|
shared_module = nn.Dropout(0.5)
|
|
module_dict = nn.ModuleDict(
|
|
{'dropout1': shared_module, 'dropout2': shared_module}
|
|
)
|
|
|
|
self.assertEqual(len(module_dict), 2)
|
|
self.assertIs(module_dict['dropout1'], module_dict['dropout2'])
|
|
|
|
def test_special_key_names(self):
|
|
module_dict = nn.ModuleDict()
|
|
module_dict['key-with-dash'] = nn.Linear(5, 3)
|
|
module_dict['key_with_underscore'] = nn.ReLU()
|
|
module_dict['key.with.dots'] = nn.Sigmoid()
|
|
module_dict['123numeric'] = nn.Tanh()
|
|
|
|
self.assertEqual(len(module_dict), 4)
|
|
self.assertIn('key-with-dash', module_dict)
|
|
self.assertIn('key_with_underscore', module_dict)
|
|
self.assertIn('key.with.dots', module_dict)
|
|
self.assertIn('123numeric', module_dict)
|
|
|
|
def test_module_dict_with_none(self):
|
|
module_dict = nn.ModuleDict(
|
|
{
|
|
'linear': nn.Linear(5, 3),
|
|
'none_module': None,
|
|
'activation': nn.ReLU(),
|
|
}
|
|
)
|
|
self.assertEqual(len(module_dict), 3)
|
|
self.assertIsNone(module_dict['none_module'])
|
|
|
|
def test_key_ordering(self):
|
|
modules = OrderedDict(
|
|
[
|
|
('z_last', nn.Linear(5, 3)),
|
|
('a_first', nn.ReLU()),
|
|
('m_middle', nn.Sigmoid()),
|
|
]
|
|
)
|
|
module_dict = nn.ModuleDict(modules)
|
|
|
|
keys = list(module_dict.keys())
|
|
self.assertEqual(keys, ['z_last', 'a_first', 'm_middle'])
|
|
|
|
|
|
class TestModuleDictIntegration(unittest.TestCase):
|
|
def test_combined_with_module_list(self):
|
|
linear_layers = nn.ModuleList([nn.Linear(10, 5), nn.Linear(5, 2)])
|
|
activations = nn.ModuleDict(
|
|
{'relu': nn.ReLU(), 'sigmoid': nn.Sigmoid()}
|
|
)
|
|
|
|
class CombinedModel(nn.Layer):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.layers = linear_layers
|
|
self.activations = activations
|
|
|
|
def forward(self, x):
|
|
x = self.layers[0](x)
|
|
x = self.activations['relu'](x)
|
|
x = self.layers[1](x)
|
|
x = self.activations['sigmoid'](x)
|
|
return x
|
|
|
|
model = CombinedModel()
|
|
x = paddle.ones([2, 10])
|
|
output = model(x)
|
|
|
|
self.assertEqual(output.shape, [2, 2])
|
|
self.assertIsInstance(output, paddle.Tensor)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|