Files
paddlepaddle--paddle/test/distribution/test_distribution_cauchy_static.py
T
2026-07-13 12:40:42 +08:00

478 lines
15 KiB
Python

# 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.
import sys
import unittest
import numpy as np
from distribution.config import ATOL, DEVICES, RTOL
from parameterize import (
TEST_CASE_NAME,
parameterize_cls,
parameterize_func,
place,
)
sys.path.append("../../distribution")
from test_distribution_cauchy import CauchyNumpy, _kstest
import paddle
from paddle.distribution import Cauchy
from paddle.distribution.kl import kl_divergence
np.random.seed(2023)
paddle.seed(2023)
paddle.enable_static()
default_dtype = paddle.get_default_dtype()
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'params'),
# params: name, loc, scale, loc_other, scale_other, value
[
(
'params',
(
# 1-D params
(
'params_not_iterable',
0.3,
1.2,
-1.2,
2.3,
3.4,
),
(
'params_not_iterable_and_broadcast_for_value',
0.3,
1.2,
-1.2,
2.3,
np.array([[0.1, 1.2], [1.2, 3.4]], dtype=default_dtype),
),
# N-D params
(
'params_tuple_0305',
(0.3, 0.5),
0.7,
-1.2,
2.3,
3.4,
),
(
'params_tuple_03050104',
((0.3, 0.5), (0.1, 0.4)),
0.7,
-1.2,
2.3,
3.4,
),
),
)
],
test_pir=True,
)
class CauchyTestFeature(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
self.params_len = len(self.params)
with paddle.static.program_guard(self.program):
self.init_numpy_data(self.params)
self.init_static_data(self.params)
def init_numpy_data(self, params):
self.log_prob_np = []
self.prob_np = []
self.cdf_np = []
self.entropy_np = []
self.kl_np = []
self.shapes = []
for _, loc, scale, loc_other, scale_other, value in params:
rv_np = CauchyNumpy(loc=loc, scale=scale)
rv_np_other = CauchyNumpy(loc=loc_other, scale=scale_other)
self.log_prob_np.append(rv_np.log_prob(value))
self.prob_np.append(rv_np.prob(value))
self.cdf_np.append(rv_np.cdf(value))
self.entropy_np.append(rv_np.entropy())
self.kl_np.append(rv_np.kl_divergence(rv_np_other))
# paddle return data ndim>0
self.shapes.append(
(np.array(loc) + np.array(scale) + np.array(value)).shape
or (1,)
)
def init_static_data(self, params):
with paddle.static.program_guard(self.program):
rv_paddles = []
rv_paddles_other = []
values = []
for name, loc, scale, loc_other, scale_other, value in params:
if not isinstance(value, np.ndarray):
value = paddle.full([1], value, dtype=default_dtype)
else:
value = paddle.to_tensor(value, place=self.place)
# We should set name in static mode, or the executor confuse rv_paddles[i].
rv_paddles.append(
Cauchy(
loc=paddle.to_tensor(loc),
scale=paddle.to_tensor(scale),
name=name,
)
)
rv_paddles_other.append(
Cauchy(
loc=paddle.to_tensor(loc_other),
scale=paddle.to_tensor(scale_other),
name=name,
)
)
values.append(value)
results = self.executor.run(
self.program,
feed={},
fetch_list=[
[
rv_paddles[i].log_prob(values[i]),
rv_paddles[i].prob(values[i]),
rv_paddles[i].cdf(values[i]),
rv_paddles[i].entropy(),
rv_paddles[i].kl_divergence(rv_paddles_other[i]),
kl_divergence(rv_paddles[i], rv_paddles_other[i]),
]
for i in range(self.params_len)
],
)
self.log_prob_paddle = []
self.prob_paddle = []
self.cdf_paddle = []
self.entropy_paddle = []
self.kl_paddle = []
self.kl_func_paddle = []
for i in range(self.params_len):
(
_log_prob,
_prob,
_cdf,
_entropy,
_kl,
_kl_func,
) = results[i * 6 : (i + 1) * 6]
self.log_prob_paddle.append(_log_prob)
self.prob_paddle.append(_prob)
self.cdf_paddle.append(_cdf)
self.entropy_paddle.append(_entropy)
self.kl_paddle.append(_kl)
self.kl_func_paddle.append(_kl_func)
def test_all(self):
for i in range(self.params_len):
self._test_log_prob(i)
self._test_prob(i)
self._test_cdf(i)
self._test_entropy(i)
self._test_kl_divergence(i)
def _test_log_prob(self, i):
np.testing.assert_allclose(
self.log_prob_np[i],
self.log_prob_paddle[i],
rtol=RTOL.get(default_dtype),
atol=ATOL.get(default_dtype),
)
# check shape
self.assertTrue(self.log_prob_paddle[i].shape == self.shapes[i])
def _test_prob(self, i):
np.testing.assert_allclose(
self.prob_np[i],
self.prob_paddle[i],
rtol=RTOL.get(default_dtype),
atol=ATOL.get(default_dtype),
)
# check shape
self.assertTrue(self.prob_paddle[i].shape == self.shapes[i])
def _test_cdf(self, i):
np.testing.assert_allclose(
self.cdf_np[i],
self.cdf_paddle[i],
rtol=RTOL.get(default_dtype),
atol=ATOL.get(default_dtype),
)
# check shape
self.assertTrue(self.cdf_paddle[i].shape == self.shapes[i])
def _test_entropy(self, i):
np.testing.assert_allclose(
self.entropy_np[i],
self.entropy_paddle[i],
rtol=RTOL.get(default_dtype),
atol=ATOL.get(default_dtype),
)
def _test_kl_divergence(self, i):
np.testing.assert_allclose(
self.kl_np[i],
self.kl_paddle[i],
rtol=RTOL.get(default_dtype),
atol=ATOL.get(default_dtype),
)
np.testing.assert_allclose(
self.kl_np[i],
self.kl_func_paddle[i],
rtol=RTOL.get(default_dtype),
atol=ATOL.get(default_dtype),
)
@place(DEVICES)
@parameterize_cls(
(
TEST_CASE_NAME,
'loc',
'scale',
'shape',
'expected_shape',
),
[
# 1-D params
(
'params_1d',
[0.1],
[1.2],
[100],
[100, 1],
),
# N-D params
(
'params_2d',
[0.3],
[1.2, 2.3],
[100],
[100, 2],
),
],
test_pir=True,
)
class CauchyTestSample(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program):
self.init_numpy_data(self.loc, self.scale, self.shape)
self.init_static_data(self.loc, self.scale, self.shape)
def init_numpy_data(self, loc, scale, shape):
self.rv_np = CauchyNumpy(loc=loc, scale=scale)
self.sample_np = self.rv_np.sample(shape)
def init_static_data(self, loc, scale, shape):
with paddle.static.program_guard(self.program):
self.rv_paddle = Cauchy(
loc=paddle.to_tensor(loc),
scale=paddle.to_tensor(scale),
)
[self.sample_paddle, self.rsample_paddle] = self.executor.run(
self.program,
feed={},
fetch_list=[
self.rv_paddle.sample(shape),
self.rv_paddle.rsample(shape),
],
)
def test_sample(self):
with paddle.static.program_guard(self.program):
self.assertEqual(
list(self.sample_paddle.shape), self.expected_shape
)
for i in range(self.expected_shape[-1]):
self.assertTrue(
_kstest(
self.sample_np[..., i].reshape(-1),
self.sample_paddle[..., i].reshape(-1),
)
)
def test_rsample(self):
"""Compare two samples from `rsample` method, one from scipy and another from paddle."""
with paddle.static.program_guard(self.program):
self.assertEqual(
list(self.rsample_paddle.shape), self.expected_shape
)
for i in range(self.expected_shape[-1]):
self.assertTrue(
_kstest(
self.sample_np[..., i].reshape(-1),
self.rsample_paddle[..., i].reshape(-1),
)
)
@place(DEVICES)
@parameterize_cls([TEST_CASE_NAME], ['CauchyTestError'], test_pir=True)
class CauchyTestError(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
@parameterize_func(
[
((0.3,),), # tuple
([0.3],), # list
(np.array([0.3]),), # ndarray
(-1j + 1,), # complex
('0',), # str
]
)
def test_bad_init_type(self, param):
"""Test bad init for loc/scale"""
with paddle.static.program_guard(self.program):
with self.assertRaises(TypeError):
[_] = self.executor.run(
self.program,
feed={},
fetch_list=[Cauchy(loc=0.0, scale=param).scale],
)
with self.assertRaises(TypeError):
[_] = self.executor.run(
self.program,
feed={},
fetch_list=[Cauchy(loc=param, scale=1.0).loc],
)
def test_bad_property(self):
"""For property like mean/variance/stddev which is undefined in math,
we should raise `ValueError` instead of `NotImplementedError`.
"""
with paddle.static.program_guard(self.program):
rv = Cauchy(loc=0.0, scale=1.0)
with self.assertRaises(ValueError):
_ = rv.mean
with self.assertRaises(ValueError):
_ = rv.variance
with self.assertRaises(ValueError):
_ = rv.stddev
@parameterize_func(
[
(100,), # int
(100.0,), # float
]
)
def test_bad_sample_shape_type(self, shape):
with paddle.static.program_guard(self.program):
rv = Cauchy(loc=0.0, scale=1.0)
with self.assertRaises(TypeError):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[rv.sample(shape)]
)
with self.assertRaises(TypeError):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[rv.rsample(shape)]
)
@parameterize_func(
[
(1,), # int
(1.0,), # float
([1.0],), # list
((1.0),), # tuple
(np.array(1.0),), # ndarray
]
)
def test_bad_value_type(self, value):
with paddle.static.program_guard(self.program):
rv = Cauchy(loc=0.0, scale=1.0)
with self.assertRaises(TypeError):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[rv.log_prob(value)]
)
with self.assertRaises(TypeError):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[rv.prob(value)]
)
with self.assertRaises(TypeError):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[rv.cdf(value)]
)
@parameterize_func(
[
(np.array(1.0),), # ndarray or other distribution
]
)
def test_bad_kl_other_type(self, other):
with paddle.static.program_guard(self.program):
rv = Cauchy(loc=0.0, scale=1.0)
with self.assertRaises(TypeError):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[rv.kl_divergence(other)]
)
@parameterize_func(
[
(paddle.to_tensor([0.1, 0.2, 0.3]),),
]
)
def test_bad_broadcast(self, value):
with paddle.static.program_guard(self.program):
rv = Cauchy(
loc=paddle.to_tensor(0.0), scale=paddle.to_tensor((1.0, 2.0))
)
# `logits, value = paddle.broadcast_tensors([self.logits, value])`
# raise ValueError in dygraph, raise TypeError in static.
with self.assertRaises((TypeError, ValueError)):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[rv.cdf(value)]
)
with self.assertRaises((TypeError, ValueError)):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[rv.log_prob(value)]
)
with self.assertRaises((TypeError, ValueError)):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[rv.prob(value)]
)
if __name__ == '__main__':
unittest.main()