184 lines
6.1 KiB
Python
184 lines
6.1 KiB
Python
# Copyright (c) 2026 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.
|
|
|
|
"""
|
|
模型保存加载高级测试 / Advanced Model Save/Load Tests
|
|
|
|
测试目标 / Test Target:
|
|
paddle 模型保存和加载功能
|
|
|
|
覆盖的模块 / Covered Modules:
|
|
- paddle.save/load: 张量和字典保存
|
|
- paddle.jit.save/load: JIT模型保存
|
|
- model.state_dict/set_state_dict: 模型状态
|
|
- paddle.Model.save/load: 高级模型API
|
|
|
|
作用 / Purpose:
|
|
补充模型持久化API的测试,提升覆盖率。
|
|
"""
|
|
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
|
|
import numpy as np
|
|
|
|
import paddle
|
|
from paddle import nn
|
|
|
|
paddle.disable_static()
|
|
|
|
|
|
class SimpleModel(nn.Layer):
|
|
"""简单测试模型 / Simple test model"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.fc1 = nn.Linear(4, 8)
|
|
self.fc2 = nn.Linear(8, 2)
|
|
|
|
def forward(self, x):
|
|
x = paddle.nn.functional.relu(self.fc1(x))
|
|
return self.fc2(x)
|
|
|
|
|
|
class TestModelStatDict(unittest.TestCase):
|
|
"""测试模型状态字典 / Test model state dict"""
|
|
|
|
def test_state_dict_keys(self):
|
|
"""测试状态字典键 / Test state dict keys"""
|
|
model = SimpleModel()
|
|
state_dict = model.state_dict()
|
|
self.assertIn('fc1.weight', state_dict)
|
|
self.assertIn('fc1.bias', state_dict)
|
|
self.assertIn('fc2.weight', state_dict)
|
|
self.assertIn('fc2.bias', state_dict)
|
|
|
|
def test_state_dict_shapes(self):
|
|
"""测试状态字典形状 / Test state dict shapes"""
|
|
model = SimpleModel()
|
|
state_dict = model.state_dict()
|
|
self.assertEqual(list(state_dict['fc1.weight'].shape), [4, 8])
|
|
self.assertEqual(list(state_dict['fc1.bias'].shape), [8])
|
|
|
|
def test_set_state_dict(self):
|
|
"""测试设置状态字典 / Test set state dict"""
|
|
model1 = SimpleModel()
|
|
model2 = SimpleModel()
|
|
# Copy weights from model1 to model2
|
|
state_dict = model1.state_dict()
|
|
model2.set_state_dict(state_dict)
|
|
# Verify weights are same
|
|
for key in state_dict:
|
|
np.testing.assert_allclose(
|
|
model1.state_dict()[key].numpy(),
|
|
model2.state_dict()[key].numpy(),
|
|
)
|
|
|
|
|
|
class TestSaveLoad(unittest.TestCase):
|
|
"""测试保存加载 / Test save and load"""
|
|
|
|
def test_save_load_tensor(self):
|
|
"""测试张量保存加载 / Test tensor save and load"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
path = os.path.join(tmpdir, 'tensor.pd')
|
|
x = paddle.randn([3, 4])
|
|
paddle.save(x, path)
|
|
loaded = paddle.load(path)
|
|
np.testing.assert_allclose(x.numpy(), loaded.numpy())
|
|
|
|
def test_save_load_dict(self):
|
|
"""测试字典保存加载 / Test dict save and load"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
path = os.path.join(tmpdir, 'data.pd')
|
|
data = {'weights': paddle.randn([4, 8]), 'bias': paddle.zeros([8])}
|
|
paddle.save(data, path)
|
|
loaded = paddle.load(path)
|
|
np.testing.assert_allclose(
|
|
data['weights'].numpy(), loaded['weights'].numpy()
|
|
)
|
|
np.testing.assert_allclose(
|
|
data['bias'].numpy(), loaded['bias'].numpy()
|
|
)
|
|
|
|
def test_save_load_model_weights(self):
|
|
"""测试模型权重保存加载 / Test model weights save and load"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
path = os.path.join(tmpdir, 'model.pd')
|
|
model = SimpleModel()
|
|
original_weights = {
|
|
k: v.numpy().copy() for k, v in model.state_dict().items()
|
|
}
|
|
paddle.save(model.state_dict(), path)
|
|
|
|
new_model = SimpleModel()
|
|
new_model.set_state_dict(paddle.load(path))
|
|
for key in original_weights:
|
|
np.testing.assert_allclose(
|
|
original_weights[key], new_model.state_dict()[key].numpy()
|
|
)
|
|
|
|
|
|
class TestJITSaveLoad(unittest.TestCase):
|
|
"""测试JIT保存加载 / Test JIT save and load"""
|
|
|
|
def test_jit_save_load(self):
|
|
"""测试JIT模型保存加载 / Test JIT model save and load"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
model = SimpleModel()
|
|
x = paddle.randn([2, 4])
|
|
|
|
# Save with JIT
|
|
save_path = os.path.join(tmpdir, 'model')
|
|
net = paddle.jit.to_static(
|
|
model,
|
|
input_spec=[
|
|
paddle.static.InputSpec(shape=[None, 4], dtype='float32')
|
|
],
|
|
)
|
|
paddle.jit.save(net, save_path)
|
|
|
|
# Load and run
|
|
loaded_model = paddle.jit.load(save_path)
|
|
result = loaded_model(x)
|
|
self.assertEqual(result.shape, [2, 2])
|
|
|
|
def test_jit_save_preserves_output(self):
|
|
"""测试JIT保存保留输出 / Test JIT save preserves output"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
model = SimpleModel()
|
|
model.eval()
|
|
x = paddle.randn([3, 4])
|
|
original_output = model(x)
|
|
|
|
save_path = os.path.join(tmpdir, 'model')
|
|
net = paddle.jit.to_static(
|
|
model,
|
|
input_spec=[
|
|
paddle.static.InputSpec(shape=[None, 4], dtype='float32')
|
|
],
|
|
)
|
|
paddle.jit.save(net, save_path)
|
|
|
|
loaded_model = paddle.jit.load(save_path)
|
|
loaded_output = loaded_model(x)
|
|
np.testing.assert_allclose(
|
|
original_output.numpy(), loaded_output.numpy(), rtol=1e-5
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|