213 lines
9.4 KiB
Python
213 lines
9.4 KiB
Python
# Copyright (c) 2024 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.
|
||
|
||
# [AUTO-GENERATED] Unit test for paddle.nn.initializer.Orthogonal
|
||
# 自动生成的单测,覆盖 paddle.nn.initializer.orthogonal 模块中未覆盖的代码
|
||
# Target: cover uncovered lines 157-271 in paddle/python/paddle/nn/initializer/orthogonal.py
|
||
|
||
"""
|
||
测试模块:paddle.nn.initializer.Orthogonal
|
||
Test Module: paddle.nn.initializer.Orthogonal
|
||
|
||
本测试覆盖以下功能:
|
||
This test covers the following functions:
|
||
1. Orthogonal 初始化器在动态图模式下的使用 / Orthogonal initializer in dynamic graph mode
|
||
- rows > cols 情况:列向量正交 / rows > cols case: columns are orthogonal
|
||
- rows < cols 情况:行向量正交 / rows < cols case: rows are orthogonal
|
||
- rows == cols 情况:行列均正交 / rows == cols case: both rows and columns are orthogonal
|
||
- gain 参数测试 / gain parameter test
|
||
2. Orthogonal 初始化器在静态图模式下的使用 / Orthogonal initializer in static graph mode
|
||
- 覆盖静态图代码路径 lines 157-271 / covers static graph code path
|
||
|
||
覆盖的未覆盖行:157, 161, 167, 181, 187, 193, 204, 210, 218-219, 226, 234, 240-241, 247, 254, 256, 264, 271
|
||
|
||
注意:paddle.nn.Linear(in, out) 的weight形状为 [in, out]
|
||
Note: paddle.nn.Linear(in, out) weight shape is [in, out]
|
||
所以 Linear(10, 15) → weight [10, 15],rows=10 < cols=15
|
||
"""
|
||
|
||
import unittest
|
||
|
||
import numpy as np
|
||
|
||
import paddle
|
||
|
||
|
||
class TestOrthogonalInitializerDynamic(unittest.TestCase):
|
||
"""测试动态图模式下Orthogonal初始化器
|
||
Test Orthogonal initializer in dynamic graph mode"""
|
||
|
||
def setUp(self):
|
||
"""设置测试环境 / Set up test environment"""
|
||
paddle.disable_static()
|
||
|
||
def test_rows_greater_than_cols(self):
|
||
"""测试rows > cols的情况,weight [15, 10],列向量应正交
|
||
Test rows > cols case, weight [15, 10], columns should be orthogonal
|
||
Linear(10, 15) → weight shape [10, 15], rows=10 < cols=15
|
||
So we use Linear(15, 10) → weight shape [15, 10], rows=15 > cols=10"""
|
||
weight_attr = paddle.ParamAttr(
|
||
initializer=paddle.nn.initializer.Orthogonal()
|
||
)
|
||
# Linear(out=10, in=15) → weight [15, 10], but Paddle Linear(in, out)
|
||
# Linear(15, 10) → weight [15, 10], rows=15 > cols=10
|
||
linear = paddle.nn.Linear(15, 10, weight_attr=weight_attr)
|
||
weight = linear.weight.numpy()
|
||
self.assertEqual(weight.shape, (15, 10))
|
||
# W^T * W 应接近单位矩阵 / W^T * W should be close to identity (10x10)
|
||
wtw = np.matmul(weight.T, weight)
|
||
identity = np.eye(10)
|
||
np.testing.assert_allclose(wtw, identity, atol=1e-5)
|
||
|
||
def test_rows_less_than_cols(self):
|
||
"""测试rows < cols的情况,weight [10, 15],行向量应正交
|
||
Test rows < cols case, weight [10, 15], rows should be orthogonal
|
||
Linear(10, 15) → weight [10, 15], rows=10 < cols=15"""
|
||
weight_attr = paddle.ParamAttr(
|
||
initializer=paddle.nn.initializer.Orthogonal()
|
||
)
|
||
linear = paddle.nn.Linear(10, 15, weight_attr=weight_attr)
|
||
weight = linear.weight.numpy()
|
||
self.assertEqual(weight.shape, (10, 15))
|
||
# W * W^T 应接近单位矩阵 / W * W^T should be close to identity (10x10)
|
||
wwt = np.matmul(weight, weight.T)
|
||
identity = np.eye(10)
|
||
np.testing.assert_allclose(wwt, identity, atol=1e-5)
|
||
|
||
def test_square_matrix(self):
|
||
"""测试rows == cols的情况(10x10),行列均正交
|
||
Test rows == cols case (10x10), both rows and columns are orthogonal"""
|
||
weight_attr = paddle.ParamAttr(
|
||
initializer=paddle.nn.initializer.Orthogonal()
|
||
)
|
||
linear = paddle.nn.Linear(10, 10, weight_attr=weight_attr)
|
||
weight = linear.weight.numpy()
|
||
self.assertEqual(weight.shape, (10, 10))
|
||
# W * W^T 应接近单位矩阵 / W * W^T should be close to identity
|
||
wwt = np.matmul(weight, weight.T)
|
||
identity = np.eye(10)
|
||
np.testing.assert_allclose(wwt, identity, atol=1e-5)
|
||
|
||
def test_with_gain(self):
|
||
"""测试带gain参数的Orthogonal初始化
|
||
Test Orthogonal initialization with gain parameter"""
|
||
gain = 2.0
|
||
weight_attr = paddle.ParamAttr(
|
||
initializer=paddle.nn.initializer.Orthogonal(gain=gain)
|
||
)
|
||
linear = paddle.nn.Linear(10, 10, weight_attr=weight_attr)
|
||
weight = linear.weight.numpy()
|
||
# W * W^T / gain^2 应接近单位矩阵
|
||
# W * W^T / gain^2 should be close to identity
|
||
wwt = np.matmul(weight, weight.T) / (gain**2)
|
||
identity = np.eye(10)
|
||
np.testing.assert_allclose(wwt, identity, atol=1e-5)
|
||
|
||
def test_conv2d_orthogonal(self):
|
||
"""测试在Conv2D上使用Orthogonal初始化(维度>2)
|
||
Test Orthogonal initialization on Conv2D (dimension > 2)"""
|
||
weight_attr = paddle.ParamAttr(
|
||
initializer=paddle.nn.initializer.Orthogonal()
|
||
)
|
||
conv = paddle.nn.Conv2D(3, 8, 3, weight_attr=weight_attr)
|
||
weight = conv.weight.numpy()
|
||
self.assertEqual(len(weight.shape), 4) # [out_c, in_c, kH, kW]
|
||
|
||
|
||
class TestOrthogonalInitializerStatic(unittest.TestCase):
|
||
"""测试静态图模式下的Orthogonal初始化器,覆盖未覆盖的静态图代码路径
|
||
Test Orthogonal initializer in static graph mode, covering uncovered static paths"""
|
||
|
||
def test_static_graph_rows_greater_cols(self):
|
||
"""测试静态图模式下rows > cols的Orthogonal初始化
|
||
Test Orthogonal init with rows > cols in static graph mode
|
||
Linear(15, 8) → weight [15, 8], rows=15 > cols=8"""
|
||
paddle.enable_static()
|
||
try:
|
||
main_prog = paddle.static.Program()
|
||
startup_prog = paddle.static.Program()
|
||
with paddle.static.program_guard(main_prog, startup_prog):
|
||
weight_attr = paddle.ParamAttr(
|
||
initializer=paddle.nn.initializer.Orthogonal()
|
||
)
|
||
linear = paddle.nn.Linear(15, 8, weight_attr=weight_attr)
|
||
|
||
exe = paddle.static.Executor(paddle.CPUPlace())
|
||
exe.run(startup_prog)
|
||
result = exe.run(main_prog, fetch_list=[linear.weight])
|
||
weight = result[0]
|
||
self.assertEqual(weight.shape, (15, 8))
|
||
# W^T * W 应接近单位矩阵 / W^T * W should be close to identity (8x8)
|
||
wtw = np.matmul(weight.T, weight)
|
||
identity = np.eye(8)
|
||
np.testing.assert_allclose(wtw, identity, atol=1e-4)
|
||
finally:
|
||
paddle.disable_static()
|
||
|
||
def test_static_graph_rows_less_cols(self):
|
||
"""测试静态图模式下rows < cols的Orthogonal初始化(触发transpose分支)
|
||
Test Orthogonal init with rows < cols in static graph (triggers transpose branch)
|
||
Linear(8, 15) → weight [8, 15], rows=8 < cols=15"""
|
||
paddle.enable_static()
|
||
try:
|
||
main_prog = paddle.static.Program()
|
||
startup_prog = paddle.static.Program()
|
||
with paddle.static.program_guard(main_prog, startup_prog):
|
||
weight_attr = paddle.ParamAttr(
|
||
initializer=paddle.nn.initializer.Orthogonal()
|
||
)
|
||
linear = paddle.nn.Linear(8, 15, weight_attr=weight_attr)
|
||
|
||
exe = paddle.static.Executor(paddle.CPUPlace())
|
||
exe.run(startup_prog)
|
||
result = exe.run(main_prog, fetch_list=[linear.weight])
|
||
weight = result[0]
|
||
self.assertEqual(weight.shape, (8, 15))
|
||
# W * W^T 应接近单位矩阵 / W * W^T should be close to identity (8x8)
|
||
wwt = np.matmul(weight, weight.T)
|
||
identity = np.eye(8)
|
||
np.testing.assert_allclose(wwt, identity, atol=1e-4)
|
||
finally:
|
||
paddle.disable_static()
|
||
|
||
def test_static_graph_with_gain(self):
|
||
"""测试静态图模式下带gain参数的Orthogonal初始化
|
||
Test Orthogonal init with gain parameter in static graph mode"""
|
||
paddle.enable_static()
|
||
try:
|
||
gain = 1.5
|
||
main_prog = paddle.static.Program()
|
||
startup_prog = paddle.static.Program()
|
||
with paddle.static.program_guard(main_prog, startup_prog):
|
||
weight_attr = paddle.ParamAttr(
|
||
initializer=paddle.nn.initializer.Orthogonal(gain=gain)
|
||
)
|
||
linear = paddle.nn.Linear(6, 6, weight_attr=weight_attr)
|
||
|
||
exe = paddle.static.Executor(paddle.CPUPlace())
|
||
exe.run(startup_prog)
|
||
result = exe.run(main_prog, fetch_list=[linear.weight])
|
||
weight = result[0]
|
||
# W * W^T / gain^2 应接近单位矩阵
|
||
# W * W^T / gain^2 should be close to identity
|
||
wwt = np.matmul(weight, weight.T) / (gain**2)
|
||
identity = np.eye(6)
|
||
np.testing.assert_allclose(wwt, identity, atol=1e-4)
|
||
finally:
|
||
paddle.disable_static()
|
||
|
||
|
||
if __name__ == '__main__':
|
||
unittest.main()
|