chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
file(
GLOB TEST_OPS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"test_*.py")
string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}")
foreach(TEST_OP ${TEST_OPS})
py_test_modules(${TEST_OP} MODULES ${TEST_OP})
endforeach()
set_tests_properties(test_distribution_lkj_cholesky_static PROPERTIES TIMEOUT
120)
set_pir_tests_properties()
+31
View File
@@ -0,0 +1,31 @@
# 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 paddle
DEVICES = [paddle.CPUPlace()]
if paddle.is_compiled_with_cuda():
DEVICES.append(paddle.CUDAPlace(0))
DEFAULT_DTYPE = 'float64'
TEST_CASE_NAME = 'suffix'
# All test case will use float64 for compare precision, refs:
# https://github.com/PaddlePaddle/Paddle/wiki/Upgrade-OP-Precision-to-Float64
RTOL = {
'float32': 1e-03,
'complex64': 1e-3,
'float64': 1e-5,
'complex128': 1e-5,
}
ATOL = {'float32': 0.0, 'complex64': 0, 'float64': 0.0, 'complex128': 0}
+65
View File
@@ -0,0 +1,65 @@
# 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 paddle
class Exponential(paddle.distribution.ExponentialFamily):
"""mock exponential distribution, which support computing entropy and
kl use bregman divergence
"""
_mean_carrier_measure = 0
def __init__(self, rate):
self._rate = rate
super().__init__(batch_shape=rate.shape)
@property
def rate(self):
return self._rate
def entropy(self):
return 1.0 - paddle.log(self._rate)
@property
def _natural_parameters(self):
return (-self._rate,)
def _log_normalizer(self, x):
return -paddle.log(-x)
class DummyExpFamily(paddle.distribution.ExponentialFamily):
"""dummy class extend from exponential family"""
def __init__(self, *args):
pass
def entropy(self):
return 1.0
@property
def _natural_parameters(self):
return (1.0,)
def _log_normalizer(self, x):
return -paddle.log(-x)
@paddle.distribution.register_kl(Exponential, Exponential)
def _kl_exponential_exponential(p, q):
rate_ratio = q.rate / p.rate
t1 = -rate_ratio.log()
return t1 + rate_ratio - 1
+240
View File
@@ -0,0 +1,240 @@
# 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 collections
import functools
import inspect
import re
import sys
from unittest import SkipTest
import numpy as np
from distribution import config
TEST_CASE_NAME = 'suffix'
def xrand(shape=(10, 10, 10), dtype=config.DEFAULT_DTYPE, min=1.0, max=10.0):
return (np.random.rand(*shape).astype(dtype)) * (max - min) + min
def place(devices, key='place'):
def decorate(cls):
module = sys.modules[cls.__module__].__dict__
raw_classes = {
k: v for k, v in module.items() if k.startswith(cls.__name__)
}
for raw_name, raw_cls in raw_classes.items():
for d in devices:
test_cls = dict(raw_cls.__dict__)
test_cls.update({key: d})
new_name = raw_name + '.' + d.__class__.__name__
module[new_name] = type(new_name, (raw_cls,), test_cls)
del module[raw_name]
return cls
return decorate
def parameterize_cls(fields, values=None, test_pir=False):
fields = [fields] if isinstance(fields, str) else fields
params = [dict(zip(fields, vals)) for vals in values]
def decorate(cls):
test_cls_module = sys.modules[cls.__module__].__dict__
for k, v in enumerate(params):
test_cls = dict(cls.__dict__)
test_cls.update(v)
test_cls["test_pir"] = False
name = cls.__name__ + str(k)
name = name + '.' + v.get('suffix') if v.get('suffix') else name
test_cls_module[name] = type(name, (cls,), test_cls)
if test_pir:
name = name + ".pir"
test_cls["test_pir"] = True
pir_type = type(name, (cls,), test_cls)
test_cls_module[name] = pir_type
for m in list(cls.__dict__):
if m.startswith("test"):
delattr(cls, m)
return cls
return decorate
def parameterize_func(
input, name_func=None, doc_func=None, skip_on_empty=False
):
name_func = name_func or default_name_func
def wrapper(f, instance=None):
frame_locals = inspect.currentframe().f_back.f_locals
parameters = input_as_callable(input)()
if not parameters:
if not skip_on_empty:
raise ValueError(
"Parameters iterable is empty (hint: use "
"`parameterized.expand([], skip_on_empty=True)` to skip "
"this test when the input is empty)"
)
return functools.wraps(f)(skip_on_empty_helper)
digits = len(str(len(parameters) - 1))
for num, p in enumerate(parameters):
name = name_func(
f, "{num:0>{digits}}".format(digits=digits, num=num), p
)
# If the original function has patches applied by 'mock.patch',
# re-construct all patches on the just former decoration layer
# of param_as_standalone_func so as not to share
# patch objects between new functions
nf = reapply_patches_if_need(f)
frame_locals[name] = param_as_standalone_func(p, nf, name)
frame_locals[name].__doc__ = f.__doc__
# Delete original patches to prevent new function from evaluating
# original patching object as well as re-constrfucted patches.
delete_patches_if_need(f)
f.__test__ = False
return wrapper
def reapply_patches_if_need(func):
def dummy_wrapper(orgfunc):
@functools.wraps(orgfunc)
def dummy_func(*args, **kwargs):
return orgfunc(*args, **kwargs)
return dummy_func
if hasattr(func, 'patchings'):
func = dummy_wrapper(func)
tmp_patchings = func.patchings
delattr(func, 'patchings')
for patch_obj in tmp_patchings:
func = patch_obj.decorate_callable(func)
return func
def delete_patches_if_need(func):
if hasattr(func, 'patchings'):
func.patchings[:] = []
def default_name_func(func, num, p):
base_name = func.__name__
name_suffix = f"_{num}"
if len(p.args) > 0 and isinstance(p.args[0], str):
name_suffix += "_" + to_safe_name(p.args[0])
return base_name + name_suffix
def param_as_standalone_func(p, func, name):
@functools.wraps(func)
def standalone_func(*a):
return func(*(a + p.args), **p.kwargs)
standalone_func.__name__ = name
# place_as is used by py.test to determine what source file should be
# used for this test.
standalone_func.place_as = func
# Remove __wrapped__ because py.test will try to look at __wrapped__
# to determine which parameters should be used with this test case,
# and obviously we don't need it to do any parameterization.
try:
del standalone_func.__wrapped__
except AttributeError:
pass
return standalone_func
def input_as_callable(input):
if callable(input):
return lambda: check_input_values(input())
input_values = check_input_values(input)
return lambda: input_values
def check_input_values(input_values):
if not isinstance(input_values, list):
input_values = list(input_values)
return [param.from_decorator(p) for p in input_values]
def skip_on_empty_helper(*a, **kw):
raise SkipTest("parameterized input is empty")
_param = collections.namedtuple("param", "args kwargs")
class param(_param):
def __new__(cls, *args, **kwargs):
return _param.__new__(cls, args, kwargs)
@classmethod
def explicit(cls, args=None, kwargs=None):
"""Creates a ``param`` by explicitly specifying ``args`` and
``kwargs``::
>>> param.explicit([1,2,3])
param(*(1, 2, 3))
>>> param.explicit(kwargs={"foo": 42})
param(*(), **{"foo": "42"})
"""
args = args or ()
kwargs = kwargs or {}
return cls(*args, **kwargs)
@classmethod
def from_decorator(cls, args):
"""Returns an instance of ``param()`` for ``@parameterized`` argument
``args``::
>>> param.from_decorator((42, ))
param(args=(42, ), kwargs={})
>>> param.from_decorator("foo")
param(args=("foo", ), kwargs={})
"""
if isinstance(args, param):
return args
elif isinstance(args, str):
args = (args,)
try:
return cls(*args)
except TypeError as e:
if "after * must be" not in str(e):
raise
raise TypeError(
f"Parameters must be tuples, but {args!r} is not (hint: use '({args!r}, )')",
)
def __repr__(self):
return "param(*{!r}, **{!r})".format(*self)
def to_safe_name(s):
return str(re.sub("[^a-zA-Z0-9_]+", "_", s))
# alias
parameterize = parameterize_func
param_cls = parameterize_cls
param_func = parameterize_func
+142
View File
@@ -0,0 +1,142 @@
# 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 unittest
import numpy as np
import scipy.stats
from op_test import OpTest, convert_float_to_uint16, convert_uint16_to_float
import paddle
from paddle.base import core
paddle.enable_static()
class TestDirichletOp(OpTest):
# Because dirichlet random sample have not gradient, we skip gradient check.
no_need_check_grad = True
def setUp(self):
self.op_type = "dirichlet"
self.alpha = np.array((1.0, 2.0))
self.sample_shape = (100000, 2)
self.inputs = {'Alpha': np.broadcast_to(self.alpha, self.sample_shape)}
self.attrs = {}
self.outputs = {'Out': np.zeros(self.sample_shape)}
def test_check_output(self):
self.check_output_customized(self._hypothesis_testing)
def _hypothesis_testing(self, outs):
self.assertEqual(outs[0].shape, self.sample_shape)
self.assertTrue(np.all(outs[0] > 0.0))
sample = outs[0][:, 0].astype(np.float64)
self.assertLess(
scipy.stats.kstest(
sample,
# scipy dirichlet have not cdf, use beta to replace it.
scipy.stats.beta(a=self.alpha[0], b=self.alpha[1]).cdf,
)[0],
0.01,
)
class TestDirichletFP16Op(OpTest):
# Because dirichlet random sample have not gradient, we skip gradient check.
no_need_check_grad = True
def setUp(self):
self.op_type = "dirichlet"
self.alpha = np.array((1.0, 2.0))
self.sample_shape = (100000, 2)
self.dtype = np.float16
self.inputs = {
'Alpha': np.broadcast_to(self.alpha, self.sample_shape).astype(
self.dtype
)
}
self.attrs = {}
self.outputs = {'Out': np.zeros(self.sample_shape).astype(self.dtype)}
def test_check_output(self):
self.check_output_customized(self._hypothesis_testing)
def _hypothesis_testing(self, outs):
self.assertEqual(outs[0].shape, self.sample_shape)
self.assertTrue(np.all(outs[0] > 0.0))
sample = outs[0][:, 0].astype(np.float64)
self.assertLess(
scipy.stats.kstest(
sample,
# scipy dirichlet have not cdf, use beta to replace it.
scipy.stats.beta(a=self.alpha[0], b=self.alpha[1]).cdf,
)[0],
0.01,
)
@unittest.skipIf(
not core.is_compiled_with_cuda()
or not core.is_bfloat16_supported(core.CUDAPlace(0)),
"core is not compiled with CUDA and not support the bfloat16",
)
class TestDirichletBF16Op(OpTest):
# Because dirichlet random sample have not gradient, we skip gradient check.
no_need_check_grad = True
def setUp(self):
self.op_type = "dirichlet"
self.alpha = np.array((1.0, 2.0))
self.sample_shape = (10000, 2)
self.dtype = np.uint16
self.np_dtype = np.float32
self.inputs = {
'Alpha': np.broadcast_to(self.alpha, self.sample_shape).astype(
self.np_dtype
)
}
self.attrs = {}
self.outputs = {
'Out': np.zeros(self.sample_shape).astype(self.np_dtype)
}
self.inputs['Alpha'] = convert_float_to_uint16(self.inputs['Alpha'])
self.outputs['Out'] = convert_float_to_uint16(self.outputs['Out'])
self.place = core.CUDAPlace(0)
def test_check_output(self):
self.check_output_with_place_customized(
self._hypothesis_testing, place=core.CUDAPlace(0)
)
def _hypothesis_testing(self, outs):
outs = convert_uint16_to_float(outs)
self.assertEqual(outs[0].shape, self.sample_shape)
self.assertTrue(np.all(outs[0] > 0.0))
self.assertLess(
scipy.stats.kstest(
outs[0][:, 0],
# scipy dirichlet have not cdf, use beta to replace it.
scipy.stats.beta(a=self.alpha[0], b=self.alpha[1]).cdf,
)[0],
0.3, # The bfloat16 test difference is below 0.3
)
if __name__ == '__main__':
unittest.main()
+30
View File
@@ -0,0 +1,30 @@
# Copyright (c) 2020 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.
class DistributionNumpy:
def sample(self):
raise NotImplementedError
def entropy(self):
raise NotImplementedError
def kl_divergence(self, other):
raise NotImplementedError
def log_prob(self, value):
raise NotImplementedError
def probs(self, value):
raise NotImplementedError
@@ -0,0 +1,584 @@
# 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 unittest
import numpy as np
import scipy.special
import scipy.stats
from distribution.config import ATOL, DEVICES, RTOL
from parameterize import (
TEST_CASE_NAME,
parameterize_cls,
parameterize_func,
place,
)
from test_distribution import DistributionNumpy
import paddle
from paddle.base.data_feeder import convert_dtype
from paddle.distribution import Bernoulli
from paddle.distribution.kl import kl_divergence
np.random.seed(2023)
paddle.seed(2023)
# Smallest representable number.
EPS = {
'float32': np.finfo('float32').eps,
'float64': np.finfo('float64').eps,
}
def _clip_probs_ndarray(probs, dtype):
"""Clip probs from [0, 1] to (0, 1) with ``eps``"""
eps = EPS.get(dtype)
return np.clip(probs, a_min=eps, a_max=1 - eps).astype(dtype)
def _sigmoid(z):
return scipy.special.expit(z)
def _kstest(samples_a, samples_b, temperature=1):
"""Uses the Kolmogorov-Smirnov test for goodness of fit."""
_, p_value = scipy.stats.ks_2samp(samples_a, samples_b)
return not (p_value < 0.02 * (min(1, temperature)))
class BernoulliNumpy(DistributionNumpy):
def __init__(self, probs):
probs = np.array(probs)
if str(probs.dtype) not in ['float32', 'float64']:
self.dtype = 'float32'
else:
self.dtype = probs.dtype
self.batch_shape = np.shape(probs)
self.probs = _clip_probs_ndarray(
np.array(probs, dtype=self.dtype), str(self.dtype)
)
self.logits = self._probs_to_logits(self.probs, is_binary=True)
self.rv = scipy.stats.bernoulli(self.probs.astype('float64'))
@property
def mean(self):
return self.rv.mean().astype(self.dtype)
@property
def variance(self):
return self.rv.var().astype(self.dtype)
def sample(self, shape):
shape = np.array(shape, dtype='int')
if shape.ndim:
shape = shape.tolist()
else:
shape = [shape.tolist()]
return self.rv.rvs(size=shape + list(self.batch_shape)).astype(
self.dtype
)
def log_prob(self, value):
return self.rv.logpmf(value).astype(self.dtype)
def prob(self, value):
return self.rv.pmf(value).astype(self.dtype)
def cdf(self, value):
return self.rv.cdf(value).astype(self.dtype)
def entropy(self):
return (
np.maximum(
self.logits,
0,
)
- self.logits * self.probs
+ np.log(1 + np.exp(-np.abs(self.logits)))
).astype(self.dtype)
def kl_divergence(self, other):
"""
.. math::
KL[a || b] = Pa * Log[Pa / Pb] + (1 - Pa) * Log[(1 - Pa) / (1 - Pb)]
"""
p_a = self.probs
p_b = other.probs
return (
p_a * np.log(p_a / p_b) + (1 - p_a) * np.log((1 - p_a) / (1 - p_b))
).astype(self.dtype)
def _probs_to_logits(self, probs, is_binary=False):
return (
(np.log(probs) - np.log1p(-probs)) if is_binary else np.log(probs)
).astype(self.dtype)
class BernoulliTest(unittest.TestCase):
def setUp(self):
paddle.disable_static(self.place)
with paddle.base.dygraph.guard(self.place):
# just for convenience
self.dtype = self.expected_dtype
# init numpy with `dtype`
self.init_numpy_data(self.probs, self.dtype)
# init paddle and check dtype convert.
self.init_dynamic_data(self.probs, self.default_dtype, self.dtype)
def init_numpy_data(self, probs, dtype):
probs = np.array(probs).astype(dtype)
self.rv_np = BernoulliNumpy(probs)
def init_dynamic_data(self, probs, default_dtype, dtype):
self.rv_paddle = Bernoulli(probs)
self.assertTrue(
dtype == convert_dtype(self.rv_paddle.probs.dtype),
(dtype, self.rv_paddle.probs.dtype),
)
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'probs', 'default_dtype', 'expected_dtype'),
[
# 0-D probs
('probs_00_32', paddle.full((), 0.0), 'float32', 'float32'),
('probs_03_32', paddle.full((), 0.3), 'float32', 'float32'),
('probs_10_32', paddle.full((), 1.0), 'float32', 'float32'),
(
'probs_00_64',
paddle.full((), 0.0, dtype='float64'),
'float64',
'float64',
),
(
'probs_03_64',
paddle.full((), 0.3, dtype='float64'),
'float64',
'float64',
),
(
'probs_10_64',
paddle.full((), 1.0, dtype='float64'),
'float64',
'float64',
),
# 1-D probs
('probs_00', 0.0, 'float64', 'float32'),
('probs_03', 0.3, 'float64', 'float32'),
('probs_10', 1.0, 'float64', 'float32'),
('probs_tensor_03_32', paddle.to_tensor([0.3]), 'float32', 'float32'),
(
'probs_tensor_03_64',
paddle.to_tensor([0.3], dtype='float64'),
'float64',
'float64',
),
(
'probs_tensor_03_list_32',
paddle.to_tensor(
[
0.3,
]
),
'float32',
'float32',
),
(
'probs_tensor_03_list_64',
paddle.to_tensor(
[
0.3,
],
dtype='float64',
),
'float64',
'float64',
),
# N-D probs
(
'probs_tensor_0305',
paddle.to_tensor((0.3, 0.5)),
'float32',
'float32',
),
(
'probs_tensor_03050104',
paddle.to_tensor(((0.3, 0.5), (0.1, 0.4))),
'float32',
'float32',
),
],
)
class BernoulliTestFeature(BernoulliTest):
def test_mean(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self.rv_paddle.mean,
self.rv_np.mean,
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
def test_variance(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self.rv_paddle.variance,
self.rv_np.variance,
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
@parameterize_func(
[
(
paddle.to_tensor(
[
0.0,
]
),
),
(
paddle.to_tensor(
[0.0],
),
),
(paddle.to_tensor([1.0]),),
(paddle.to_tensor([0.0], dtype='float64'),),
]
)
def test_log_prob(self, value):
with paddle.base.dygraph.guard(self.place):
if convert_dtype(value.dtype) == convert_dtype(
self.rv_paddle.probs.dtype
):
log_prob = self.rv_paddle.log_prob(value)
np.testing.assert_allclose(
log_prob,
self.rv_np.log_prob(value),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
self.assertTrue(self.dtype == convert_dtype(log_prob.dtype))
else:
with self.assertWarns(UserWarning):
self.rv_paddle.log_prob(value)
@parameterize_func(
[
(
paddle.to_tensor(
[
0.0,
]
),
),
(paddle.to_tensor([0.0]),),
(paddle.to_tensor([1.0]),),
(paddle.to_tensor([0.0], dtype='float64'),),
]
)
def test_prob(self, value):
with paddle.base.dygraph.guard(self.place):
if convert_dtype(value.dtype) == convert_dtype(
self.rv_paddle.probs.dtype
):
prob = self.rv_paddle.prob(value)
np.testing.assert_allclose(
prob,
self.rv_np.prob(value),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
self.assertTrue(self.dtype == convert_dtype(prob.dtype))
else:
with self.assertWarns(UserWarning):
self.rv_paddle.prob(value)
@parameterize_func(
[
(
paddle.to_tensor(
[
0.0,
]
),
),
(paddle.to_tensor([0.0]),),
(paddle.to_tensor([0.3]),),
(paddle.to_tensor([0.7]),),
(paddle.to_tensor([1.0]),),
(paddle.to_tensor([0.0], dtype='float64'),),
]
)
def test_cdf(self, value):
with paddle.base.dygraph.guard(self.place):
if convert_dtype(value.dtype) == convert_dtype(
self.rv_paddle.probs.dtype
):
cdf = self.rv_paddle.cdf(value)
np.testing.assert_allclose(
cdf,
self.rv_np.cdf(value),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
self.assertTrue(self.dtype == convert_dtype(cdf.dtype))
else:
with self.assertWarns(UserWarning):
self.rv_paddle.cdf(value)
def test_entropy(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self.rv_paddle.entropy(),
self.rv_np.entropy(),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
def test_kl_divergence(self):
with paddle.base.dygraph.guard(self.place):
other_probs = paddle.to_tensor([0.9], dtype=self.dtype)
rv_paddle_other = Bernoulli(other_probs)
rv_np_other = BernoulliNumpy(other_probs)
np.testing.assert_allclose(
self.rv_paddle.kl_divergence(rv_paddle_other),
self.rv_np.kl_divergence(rv_np_other),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
np.testing.assert_allclose(
kl_divergence(self.rv_paddle, rv_paddle_other),
self.rv_np.kl_divergence(rv_np_other),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
@place(DEVICES)
@parameterize_cls(
(
TEST_CASE_NAME,
'probs',
'default_dtype',
'expected_dtype',
'shape',
'expected_shape',
),
[
# 0-D probs
(
'probs_0d_1d',
paddle.full((), 0.3),
'float32',
'float32',
[
100,
],
[
100,
],
),
(
'probs_0d_2d',
paddle.full((), 0.3),
'float32',
'float32',
[100, 1],
[100, 1],
),
(
'probs_0d_3d',
paddle.full((), 0.3),
'float32',
'float32',
[100, 2, 3],
[100, 2, 3],
),
# 1-D probs
(
'probs_1d_1d_32',
paddle.to_tensor([0.3]),
'float32',
'float32',
[
100,
],
[100, 1],
),
(
'probs_1d_1d_64',
paddle.to_tensor([0.3], dtype='float64'),
'float64',
'float64',
paddle.to_tensor(
[
100,
]
),
[100, 1],
),
(
'probs_1d_2d',
paddle.to_tensor([0.3]),
'float32',
'float32',
[100, 2],
[100, 2, 1],
),
(
'probs_1d_3d',
paddle.to_tensor([0.3]),
'float32',
'float32',
[100, 2, 3],
[100, 2, 3, 1],
),
# N-D probs
(
'probs_2d_1d',
paddle.to_tensor((0.3, 0.5)),
'float32',
'float32',
[
100,
],
[100, 2],
),
(
'probs_2d_2d',
paddle.to_tensor((0.3, 0.5)),
'float32',
'float32',
[100, 3],
[100, 3, 2],
),
(
'probs_2d_3d',
paddle.to_tensor((0.3, 0.5)),
'float32',
'float32',
[100, 4, 3],
[100, 4, 3, 2],
),
],
)
class BernoulliTestSample(BernoulliTest):
def test_sample(self):
with paddle.base.dygraph.guard(self.place):
sample_np = self.rv_np.sample(self.shape)
sample_paddle = self.rv_paddle.sample(self.shape)
self.assertEqual(list(sample_paddle.shape), self.expected_shape)
self.assertEqual(sample_paddle.dtype, self.rv_paddle.probs.dtype)
if self.probs.ndim:
for i in range(len(self.probs)):
self.assertTrue(
_kstest(
sample_np[..., i].reshape(-1),
sample_paddle.numpy()[..., i].reshape(-1),
)
)
else:
self.assertTrue(
_kstest(
sample_np.reshape(-1),
sample_paddle.numpy().reshape(-1),
)
)
@parameterize_func(
[
(1.0,),
(0.1,),
]
)
def test_rsample(self, temperature):
"""Compare two samples from `rsample` method, one from scipy `sample` and another from paddle `rsample`."""
with paddle.base.dygraph.guard(self.place):
sample_np = self.rv_np.sample(self.shape)
rsample_paddle = self.rv_paddle.rsample(self.shape, temperature)
self.assertEqual(list(rsample_paddle.shape), self.expected_shape)
self.assertEqual(rsample_paddle.dtype, self.rv_paddle.probs.dtype)
if self.probs.ndim:
for i in range(len(self.probs)):
self.assertTrue(
_kstest(
sample_np[..., i].reshape(-1),
(
_sigmoid(rsample_paddle.numpy()[..., i]) > 0.5
).reshape(-1),
temperature,
)
)
else:
self.assertTrue(
_kstest(
sample_np.reshape(-1),
(_sigmoid(rsample_paddle.numpy()) > 0.5).reshape(-1),
temperature,
)
)
def test_rsample_backpropagation(self):
with paddle.base.dygraph.guard(self.place):
self.rv_paddle.probs.stop_gradient = False
rsample_paddle = self.rv_paddle.rsample(self.shape)
rsample_paddle = paddle.nn.functional.sigmoid(rsample_paddle)
grads = paddle.grad([rsample_paddle], [self.rv_paddle.probs])
self.assertEqual(len(grads), 1)
self.assertEqual(grads[0].dtype, self.rv_paddle.probs.dtype)
self.assertEqual(grads[0].shape, self.rv_paddle.probs.shape)
@place(DEVICES)
@parameterize_cls([TEST_CASE_NAME], ['BernoulliTestError'])
class BernoulliTestError(unittest.TestCase):
def setUp(self):
paddle.disable_static(self.place)
@parameterize_func(
[
(
[0.3, 0.5],
paddle.to_tensor([0.1, 0.2, 0.3]),
),
]
)
def test_bad_broadcast(self, probs, value):
with paddle.base.dygraph.guard(self.place):
rv = Bernoulli(probs)
self.assertRaises(ValueError, rv.cdf, value)
self.assertRaises(ValueError, rv.log_prob, value)
self.assertRaises(ValueError, rv.prob, value)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,473 @@
# 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_bernoulli import BernoulliNumpy, _kstest, _sigmoid
import paddle
from paddle.distribution import Bernoulli
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, probs, probs_other, value
[
(
'params',
(
# 1-D probs
(
'probs_not_iterable',
0.3,
0.7,
1.0,
),
(
'probs_not_iterable_and_broadcast_for_value',
0.3,
0.7,
np.array([[0.0, 1.0], [1.0, 0.0]], dtype=default_dtype),
),
# N-D probs
(
'probs_tuple_0305',
(0.3, 0.5),
0.7,
1.0,
),
(
'probs_tuple_03050104',
((0.3, 0.5), (0.1, 0.4)),
0.7,
1.0,
),
),
)
],
)
class BernoulliTestFeature(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.mean_np = []
self.variance_np = []
self.log_prob_np = []
self.prob_np = []
self.cdf_np = []
self.entropy_np = []
self.kl_np = []
for _, probs, probs_other, value in params:
rv_np = BernoulliNumpy(probs)
rv_np_other = BernoulliNumpy(probs_other)
self.mean_np.append(rv_np.mean)
self.variance_np.append(rv_np.variance)
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))
def init_static_data(self, params):
with paddle.static.program_guard(self.program):
rv_paddles = []
rv_paddles_other = []
values = []
for _, probs, probs_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)
rv_paddles.append(Bernoulli(probs=paddle.to_tensor(probs)))
rv_paddles_other.append(
Bernoulli(probs=paddle.to_tensor(probs_other))
)
values.append(value)
results = self.executor.run(
self.program,
feed={},
fetch_list=[
[
rv_paddles[i].mean,
rv_paddles[i].variance,
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.mean_paddle = []
self.variance_paddle = []
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):
(
_mean,
_variance,
_log_prob,
_prob,
_cdf,
_entropy,
_kl,
_kl_func,
) = results[i * 8 : (i + 1) * 8]
self.mean_paddle.append(_mean)
self.variance_paddle.append(_variance)
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_mean(i)
self._test_variance(i)
self._test_log_prob(i)
self._test_prob(i)
self._test_cdf(i)
self._test_entropy(i)
self._test_kl_divergence(i)
def _test_mean(self, i):
np.testing.assert_allclose(
self.mean_np[i],
self.mean_paddle[i],
rtol=RTOL.get(default_dtype),
atol=ATOL.get(default_dtype),
)
def _test_variance(self, i):
np.testing.assert_allclose(
self.variance_np[i],
self.variance_paddle[i],
rtol=RTOL.get(default_dtype),
atol=ATOL.get(default_dtype),
)
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),
)
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),
)
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),
)
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, 'probs', 'shape', 'temperature', 'expected_shape'),
[
# 1-D probs
(
'probs_03',
(0.3,),
[
100,
],
0.1,
[100, 1],
),
# N-D probs
(
'probs_0305',
(0.3, 0.5),
[
100,
],
0.1,
[100, 2],
),
],
)
class BernoulliTestSample(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.probs, self.shape)
self.init_static_data(self.probs, self.shape, self.temperature)
def init_numpy_data(self, probs, shape):
self.rv_np = BernoulliNumpy(probs)
self.sample_np = self.rv_np.sample(shape)
def init_static_data(self, probs, shape, temperature):
with paddle.static.program_guard(self.program):
self.rv_paddle = Bernoulli(probs=paddle.to_tensor(probs))
[self.sample_paddle, self.rsample_paddle] = self.executor.run(
self.program,
feed={},
fetch_list=[
self.rv_paddle.sample(shape),
self.rv_paddle.rsample(shape, temperature),
],
)
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(len(self.probs)):
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(len(self.probs)):
self.assertTrue(
_kstest(
self.sample_np[..., i].reshape(-1),
(_sigmoid(self.rsample_paddle[..., i]) > 0.5).reshape(
-1
),
self.temperature,
)
)
@place(DEVICES)
@parameterize_cls([TEST_CASE_NAME], ['BernoulliTestError'])
class BernoulliTestError(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
@parameterize_func(
[
(0,), # int
((0.3,),), # tuple
(
[
0.3,
],
), # list
(
np.array(
[
0.3,
]
),
), # ndarray
(-1j + 1,), # complex
('0',), # str
]
)
def test_bad_init_type(self, probs):
with (
paddle.static.program_guard(self.program),
self.assertRaises(TypeError),
):
[_] = self.executor.run(
self.program, feed={}, fetch_list=[Bernoulli(probs=probs)]
)
@parameterize_func(
[
(100,), # int
(100.0,), # float
]
)
def test_bad_sample_shape_type(self, shape):
with paddle.static.program_guard(self.program):
rv = Bernoulli(0.3)
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
]
)
def test_bad_rsample_temperature_type(self, temperature):
with paddle.static.program_guard(self.program):
rv = Bernoulli(0.3)
with self.assertRaises(TypeError):
[_] = self.executor.run(
self.program,
feed={},
fetch_list=[rv.rsample([100], temperature)],
)
@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 = Bernoulli(0.3)
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 = Bernoulli(0.3)
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 = Bernoulli(paddle.to_tensor([0.3, 0.5]))
# `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()
+127
View File
@@ -0,0 +1,127 @@
# 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 numbers
import unittest
import numpy as np
import scipy.stats
from distribution.config import ATOL, DEVICES, RTOL
from parameterize import TEST_CASE_NAME, parameterize_cls, place, xrand
import paddle
np.random.seed(2022)
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'alpha', 'beta'),
[
('test-scale', 1.0, 2.0),
('test-tensor', xrand(), xrand()),
('test-broadcast', xrand((2, 1)), xrand((2, 5))),
],
)
class TestBeta(unittest.TestCase):
def setUp(self):
# scale no need convert to tensor for scale input unittest
alpha, beta = self.alpha, self.beta
if not isinstance(self.alpha, numbers.Real):
alpha = paddle.to_tensor(self.alpha)
if not isinstance(self.beta, numbers.Real):
beta = paddle.to_tensor(self.beta)
self._paddle_beta = paddle.distribution.Beta(alpha, beta)
def test_mean(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_beta.mean,
scipy.stats.beta.mean(self.alpha, self.beta),
rtol=RTOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
atol=ATOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
)
def test_variance(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_beta.variance,
scipy.stats.beta.var(self.alpha, self.beta),
rtol=RTOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
atol=ATOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
)
def test_prob(self):
value = [np.random.rand(*self._paddle_beta.alpha.shape)]
for v in value:
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_beta.prob(paddle.to_tensor(v)),
scipy.stats.beta.pdf(v, self.alpha, self.beta),
rtol=RTOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
atol=ATOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
)
def test_log_prob(self):
value = [np.random.rand(*self._paddle_beta.alpha.shape)]
for v in value:
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_beta.log_prob(paddle.to_tensor(v)),
scipy.stats.beta.logpdf(v, self.alpha, self.beta),
rtol=RTOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
atol=ATOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
)
def test_entropy(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_beta.entropy(),
scipy.stats.beta.entropy(self.alpha, self.beta),
rtol=RTOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
atol=ATOL.get(str(self._paddle_beta.alpha.numpy().dtype)),
)
def test_sample_shape(self):
cases = [
{
'input': [],
'expect': list(paddle.squeeze(self._paddle_beta.alpha).shape),
},
{
'input': [2, 3],
'expect': [
2,
3,
*paddle.squeeze(self._paddle_beta.alpha).shape,
],
},
]
for case in cases:
self.assertTrue(
self._paddle_beta.sample(case.get('input')).shape
== case.get('expect')
)
def test_errors(self):
with self.assertRaises(ValueError):
array = np.array([], dtype=np.float32)
x = paddle.to_tensor(np.reshape(array, [0]), dtype='int32')
paddle.distribution.Beta(alpha=x, beta=x)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,148 @@
# 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 unittest
import numpy as np
import parameterize as param
import scipy.stats
from distribution import config
from distribution.config import ATOL, RTOL
from parameterize import xrand
import paddle
np.random.seed(2022)
paddle.enable_static()
@param.place(config.DEVICES)
@param.parameterize_cls(
(param.TEST_CASE_NAME, 'alpha', 'beta'),
[
('test-tensor', xrand((10, 10)), xrand((10, 10))),
('test-broadcast', xrand((2, 1)), xrand((2, 5))),
('test-larger-data', xrand((10, 20)), xrand((10, 20))),
],
)
class TestBeta(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program):
# scale no need convert to tensor for scale input unittest
alpha = paddle.static.data(
'alpha', self.alpha.shape, self.alpha.dtype
)
beta = paddle.static.data('beta', self.beta.shape, self.beta.dtype)
self._paddle_beta = paddle.distribution.Beta(alpha, beta)
self.feeds = {'alpha': self.alpha, 'beta': self.beta}
def test_mean(self):
with paddle.static.program_guard(self.program):
[mean] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_beta.mean],
)
np.testing.assert_allclose(
mean,
scipy.stats.beta.mean(self.alpha, self.beta),
rtol=RTOL.get(str(self.alpha.dtype)),
atol=ATOL.get(str(self.alpha.dtype)),
)
def test_variance(self):
with paddle.static.program_guard(self.program):
[variance] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_beta.variance],
)
np.testing.assert_allclose(
variance,
scipy.stats.beta.var(self.alpha, self.beta),
rtol=RTOL.get(str(self.alpha.dtype)),
atol=ATOL.get(str(self.alpha.dtype)),
)
def test_prob(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_beta.alpha.shape,
self._paddle_beta.alpha.dtype,
)
prob = self._paddle_beta.prob(value)
random_number = np.random.rand(*self._paddle_beta.alpha.shape)
feeds = dict(self.feeds, value=random_number)
[prob] = self.executor.run(
self.program, feed=feeds, fetch_list=[prob]
)
np.testing.assert_allclose(
prob,
scipy.stats.beta.pdf(random_number, self.alpha, self.beta),
rtol=RTOL.get(str(self.alpha.dtype)),
atol=ATOL.get(str(self.alpha.dtype)),
)
def test_log_prob(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_beta.alpha.shape,
self._paddle_beta.alpha.dtype,
)
prob = self._paddle_beta.log_prob(value)
random_number = np.random.rand(*self._paddle_beta.alpha.shape)
feeds = dict(self.feeds, value=random_number)
[prob] = self.executor.run(
self.program, feed=feeds, fetch_list=[prob]
)
np.testing.assert_allclose(
prob,
scipy.stats.beta.logpdf(random_number, self.alpha, self.beta),
rtol=RTOL.get(str(self.alpha.dtype)),
atol=ATOL.get(str(self.alpha.dtype)),
)
def test_entropy(self):
with paddle.static.program_guard(self.program):
[entropy] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_beta.entropy()],
)
np.testing.assert_allclose(
entropy,
scipy.stats.beta.entropy(self.alpha, self.beta),
rtol=RTOL.get(str(self.alpha.dtype)),
atol=ATOL.get(str(self.alpha.dtype)),
)
def test_sample(self):
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_beta.sample(),
)
self.assertTrue(
data.shape
== np.broadcast_arrays(self.alpha, self.beta)[0].shape
)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,213 @@
# 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 unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution.binomial import Binomial
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'total_count', 'probs'),
[
(
'zero-dim',
np.array(1000),
np.array(0.6),
),
(
'one-dim',
1000,
np.array([0.4]).astype('float32'),
),
(
'multi-dim-total_count-probability',
parameterize.xrand((2, 1), min=1, max=100).astype('int32'),
parameterize.xrand((2, 3), dtype='float64', min=0.3, max=1),
),
],
)
class TestBinomial(unittest.TestCase):
def setUp(self):
self._dist = Binomial(
total_count=paddle.to_tensor(self.total_count),
probs=paddle.to_tensor(self.probs),
)
def test_mean(self):
mean = self._dist.mean
self.assertEqual(mean.numpy().dtype, self.probs.dtype)
np.testing.assert_allclose(
mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_variance(self):
var = self._dist.variance
self.assertEqual(var.numpy().dtype, self.probs.dtype)
np.testing.assert_allclose(
var,
self._np_variance(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_entropy(self):
entropy = self._dist.entropy()
self.assertEqual(entropy.numpy().dtype, self.probs.dtype)
np.testing.assert_allclose(
entropy,
self._np_entropy(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_sample(self):
sample_shape = ()
samples = self._dist.sample(sample_shape)
self.assertEqual(
tuple(samples.shape),
sample_shape + self._dist.batch_shape + self._dist.event_shape,
)
sample_shape = (5000,)
samples = self._dist.sample(sample_shape)
sample_mean = samples.mean(axis=0)
sample_variance = samples.var(axis=0)
np.testing.assert_allclose(
sample_mean, self._dist.mean, atol=0, rtol=0.20
)
np.testing.assert_allclose(
sample_variance, self._dist.variance, atol=0, rtol=0.20
)
def _np_variance(self):
return scipy.stats.binom.var(self.total_count, self.probs)
def _np_mean(self):
return scipy.stats.binom.mean(self.total_count, self.probs)
def _np_entropy(self):
return scipy.stats.binom.entropy(self.total_count, self.probs)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'total_count', 'probs', 'value'),
[
(
'value-same-shape',
1000,
np.array([0.12, 0.3, 0.85]).astype('float64'),
np.array([2.0, 55.0, 999.0]).astype('float64'),
),
(
'value-broadcast-shape',
10,
np.array([[0.3, 0.7], [0.5, 0.5]]),
np.array([[[4.0, 6], [8, 2]], [[2.0, 4], [9, 7]]]),
),
],
)
class TestBinomialProbs(unittest.TestCase):
def setUp(self):
self._dist = Binomial(
total_count=paddle.to_tensor(self.total_count),
probs=paddle.to_tensor(self.probs),
)
def test_prob(self):
np.testing.assert_allclose(
self._dist.prob(paddle.to_tensor(self.value)),
scipy.stats.binom.pmf(self.value, self.total_count, self.probs),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_log_prob(self):
np.testing.assert_allclose(
self._dist.log_prob(paddle.to_tensor(self.value)),
scipy.stats.binom.logpmf(self.value, self.total_count, self.probs),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'n_1', 'p_1', 'n_2', 'p_2'),
[
(
'one-dim-probability',
np.array([3333]),
parameterize.xrand((1,), dtype='float32', min=0, max=1),
np.array([3333]),
parameterize.xrand((1,), dtype='float32', min=0, max=1),
),
(
'multi-dim-probability',
np.array([25, 25, 25]),
parameterize.xrand((2, 3), dtype='float64', min=0, max=1),
np.array([25, 25, 25]),
parameterize.xrand((2, 3), dtype='float64', min=0, max=1),
),
],
)
class TestBinomialKL(unittest.TestCase):
def setUp(self):
self._dist1 = Binomial(
total_count=paddle.to_tensor(self.n_1),
probs=paddle.to_tensor(self.p_1),
)
self._dist2 = Binomial(
total_count=paddle.to_tensor(self.n_2),
probs=paddle.to_tensor(self.p_2),
)
def test_kl_divergence(self):
kl0 = self._dist1.kl_divergence(self._dist2)
kl1 = self.kl_divergence(self._dist1, self._dist2)
self.assertEqual(tuple(kl0.shape), self.p_1.shape)
self.assertEqual(tuple(kl1.shape), self.p_1.shape)
np.testing.assert_allclose(
kl0,
kl1,
rtol=config.RTOL.get(str(self.p_1.dtype)),
atol=config.ATOL.get(str(self.p_1.dtype)),
)
def kl_divergence(self, dist1, dist2):
support = np.arange(1 + self.n_1.max(), dtype=self.p_1.dtype)
support = support.reshape((-1,) + (1,) * len(self.p_1.shape))
log_prob_1 = scipy.stats.binom.logpmf(
support, dist1.total_count, dist1.probs
)
log_prob_2 = scipy.stats.binom.logpmf(
support, dist2.total_count, dist2.probs
)
return (np.exp(log_prob_1) * (log_prob_1 - log_prob_2)).sum(0)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,256 @@
# 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 unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution.binomial import Binomial
paddle.enable_static()
paddle.enable_static()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'total_count', 'probs'),
[
(
'zero-dim',
np.array(1000),
np.array(0.6),
),
(
'one-dim',
np.array([1000]),
parameterize.xrand((1,), dtype='float32', min=0, max=1),
),
(
'multi-dim',
np.array([100]),
parameterize.xrand((1, 3), dtype='float64', min=0, max=1),
),
],
)
class TestBinomial(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
probs = paddle.static.data(
'probs', self.probs.shape, self.probs.dtype
)
total_count = paddle.static.data(
'total_count', self.total_count.shape, self.total_count.dtype
)
dist = Binomial(total_count, probs)
mean = dist.mean
var = dist.variance
entropy = dist.entropy()
large_samples = dist.sample(shape=(1000,))
fetch_list = [mean, var, entropy, large_samples]
feed = {
'probs': self.probs,
'total_count': self.total_count,
}
executor.run(startup_program)
[
self.mean,
self.var,
self.entropy,
self.large_samples,
] = executor.run(main_program, feed=feed, fetch_list=fetch_list)
def test_mean(self):
self.assertEqual(str(self.mean.dtype).split('.')[-1], self.probs.dtype)
np.testing.assert_allclose(
self.mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_variance(self):
self.assertEqual(str(self.var.dtype).split('.')[-1], self.probs.dtype)
np.testing.assert_allclose(
self.var,
self._np_variance(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_entropy(self):
self.assertEqual(
str(self.entropy.dtype).split('.')[-1], self.probs.dtype
)
np.testing.assert_allclose(
self.entropy,
self._np_entropy(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_sample(self):
self.assertEqual(
str(self.large_samples.dtype).split('.')[-1], self.probs.dtype
)
sample_mean = self.large_samples.mean(axis=0)
sample_variance = self.large_samples.var(axis=0)
np.testing.assert_allclose(sample_mean, self.mean, atol=0, rtol=0.20)
np.testing.assert_allclose(sample_variance, self.var, atol=0, rtol=0.20)
def _np_variance(self):
return scipy.stats.binom.var(self.total_count, self.probs)
def _np_mean(self):
return scipy.stats.binom.mean(self.total_count, self.probs)
def _np_entropy(self):
return scipy.stats.binom.entropy(self.total_count, self.probs)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'total_count', 'probs', 'value'),
[
(
'zero-dim',
np.array(10),
np.array(0.6).astype('float64'),
np.array([2.0, 3.0, 5.0]).astype('float64'),
),
(
'value-same-shape',
np.array([10]).astype('int64'),
np.array([0.2, 0.3, 0.5]).astype('float64'),
np.array([2.0, 3.0, 5.0]).astype('float64'),
),
(
'value-broadcast-shape',
np.array([10]),
np.array([[0.3, 0.7], [0.5, 0.5]]),
np.array([[[4.0, 6.0], [8.0, 2.0]], [[2.0, 4.0], [9.0, 7.0]]]),
),
],
)
class TestBinomialProbs(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
total_count = paddle.static.data(
'total_count', self.total_count.shape, self.total_count.dtype
)
probs = paddle.static.data(
'probs', self.probs.shape, self.probs.dtype
)
value = paddle.static.data(
'value', self.value.shape, self.value.dtype
)
dist = Binomial(total_count, probs)
pmf = dist.prob(value)
feed = {
'total_count': self.total_count,
'probs': self.probs,
'value': self.value,
}
fetch_list = [pmf]
executor.run(startup_program)
[self.pmf] = executor.run(
main_program, feed=feed, fetch_list=fetch_list
)
def test_prob(self):
np.testing.assert_allclose(
self.pmf,
scipy.stats.binom.pmf(self.value, self.total_count, self.probs),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'n_1', 'p_1', 'n_2', 'p_2'),
[
(
'multi-dim-probability',
np.array([32]),
parameterize.xrand((1, 2), dtype='float64', min=0, max=1),
np.array([32]),
parameterize.xrand((1, 2), dtype='float64', min=0, max=1),
),
],
)
class TestBinomialKL(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
n_1 = paddle.static.data('n_1', self.n_1.shape, self.n_1.dtype)
p_1 = paddle.static.data('p_1', self.p_1.shape, self.p_1.dtype)
n_2 = paddle.static.data('n_2', self.n_2.shape, self.n_2.dtype)
p_2 = paddle.static.data('p_2', self.p_2.shape, self.p_2.dtype)
dist1 = Binomial(n_1, p_1)
dist2 = Binomial(n_2, p_2)
kl_dist1_dist2 = dist1.kl_divergence(dist2)
feed = {
'n_1': self.n_1,
'p_1': self.p_1,
'n_2': self.n_2,
'p_2': self.p_2,
}
fetch_list = [kl_dist1_dist2]
executor.run(startup_program)
[self.kl_dist1_dist2] = executor.run(
main_program, feed=feed, fetch_list=fetch_list
)
def test_kl_divergence(self):
kl0 = self.kl_dist1_dist2
kl1 = self.kl_divergence_scipy()
self.assertEqual(tuple(kl0.shape), self.p_1.shape)
self.assertEqual(tuple(kl1.shape), self.p_1.shape)
np.testing.assert_allclose(
kl0,
kl1,
rtol=config.RTOL.get(str(self.p_1.dtype)),
atol=config.ATOL.get(str(self.p_1.dtype)),
)
def kl_divergence_scipy(self):
support = np.arange(1 + self.n_1.max(), dtype=self.p_1.dtype)
support = support.reshape((-1,) + (1,) * len(self.p_1.shape))
log_prob_1 = scipy.stats.binom.logpmf(support, self.n_1, self.p_1)
log_prob_2 = scipy.stats.binom.logpmf(support, self.n_2, self.p_2)
return (np.exp(log_prob_1) * (log_prob_1 - log_prob_2)).sum(0)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,468 @@
# 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 unittest
import numpy as np
from test_distribution import DistributionNumpy
import paddle
from paddle import base
from paddle.distribution import Categorical, Distribution, Normal, Uniform
np.random.seed(2022)
class CategoricalNumpy(DistributionNumpy):
def __init__(self, logits):
self.logits = np.array(logits).astype('float32')
def entropy(self):
logits = self.logits - np.max(self.logits, axis=-1, keepdims=True)
e_logits = np.exp(logits)
z = np.sum(e_logits, axis=-1, keepdims=True)
prob = e_logits / z
return -1.0 * np.sum(prob * (logits - np.log(z)), axis=-1)
def kl_divergence(self, other):
logits = self.logits - np.max(self.logits, axis=-1, keepdims=True)
other_logits = other.logits - np.max(
other.logits, axis=-1, keepdims=True
)
e_logits = np.exp(logits)
other_e_logits = np.exp(other_logits)
z = np.sum(e_logits, axis=-1, keepdims=True)
other_z = np.sum(other_e_logits, axis=-1, keepdims=True)
prob = e_logits / z
return np.sum(
prob * (logits - np.log(z) - other_logits + np.log(other_z)),
axis=-1,
keepdims=True,
)
class CategoricalTest(unittest.TestCase):
def setUp(self, use_gpu=False, batch_size=3, dims=5):
self.use_gpu = use_gpu
if not use_gpu:
self.place = base.CPUPlace()
self.gpu_id = -1
else:
self.place = base.CUDAPlace(0)
self.gpu_id = 0
self.batch_size = batch_size
self.dims = dims
self.init_numpy_data(batch_size, dims)
paddle.disable_static(self.place)
self.init_dynamic_data(batch_size, dims)
paddle.enable_static()
self.test_program = base.Program()
self.executor = base.Executor(self.place)
self.init_static_data(batch_size, dims)
def init_numpy_data(self, batch_size, dims):
# input logtis is 2-D Tensor
# value used in probs and log_prob method is 1-D Tensor
self.logits_np = np.random.rand(batch_size, dims).astype('float32')
self.other_logits_np = np.random.rand(batch_size, dims).astype(
'float32'
)
self.value_np = np.array([2, 1, 3]).astype('int64')
self.logits_shape = [batch_size, dims]
# dist_shape = logits_shape[:-1], it represents the number of
# different distributions.
self.dist_shape = [batch_size]
# sample shape represents the number of samples
self.sample_shape = [2, 4]
# value used in probs and log_prob method
# If value is 1-D and logits is 2-D or higher dimension, value will be
# broadcasted to have the same number of distributions with logits.
# If value is 2-D or higher dimentsion, it should have the same number
# of distributions with logtis. ``value[:-1] = logits[:-1]
self.value_shape = [3]
def init_dynamic_data(self, batch_size, dims):
self.logits = paddle.to_tensor(self.logits_np)
self.other_logits = paddle.to_tensor(self.other_logits_np)
self.value = paddle.to_tensor(self.value_np)
def init_static_data(self, batch_size, dims):
with base.program_guard(self.test_program):
self.logits_static = paddle.static.data(
name='logits', shape=self.logits_shape, dtype='float32'
)
self.other_logits_static = paddle.static.data(
name='other_logits', shape=self.logits_shape, dtype='float32'
)
self.value_static = paddle.static.data(
name='value', shape=self.value_shape, dtype='int64'
)
def get_numpy_selected_probs(self, probability):
np_probs = np.zeros(self.dist_shape + self.value_shape)
for i in range(self.batch_size):
for j in range(3):
np_probs[i][j] = probability[i][self.value_np[j]]
return np_probs
def compare_with_numpy(self, fetch_list, tolerance=1e-6):
sample, entropy, kl, probs, log_prob = fetch_list
log_tolerance = 1e-4
np.testing.assert_equal(
sample.shape, self.sample_shape + self.dist_shape
)
np_categorical = CategoricalNumpy(self.logits_np)
np_other_categorical = CategoricalNumpy(self.other_logits_np)
np_entropy = np_categorical.entropy()
np_kl = np_categorical.kl_divergence(np_other_categorical)
np.testing.assert_allclose(
entropy, np_entropy, rtol=log_tolerance, atol=log_tolerance
)
np.testing.assert_allclose(
kl, np_kl, rtol=log_tolerance, atol=log_tolerance
)
sum_dist = np.sum(self.logits_np, axis=-1, keepdims=True)
probability = self.logits_np / sum_dist
np_probs = self.get_numpy_selected_probs(probability)
np_log_prob = np.log(np_probs)
np.testing.assert_allclose(
probs, np_probs, rtol=tolerance, atol=tolerance
)
np.testing.assert_allclose(
log_prob, np_log_prob, rtol=tolerance, atol=tolerance
)
def test_categorical_distribution_dygraph(self, tolerance=1e-6):
paddle.disable_static(self.place)
categorical = Categorical(self.logits)
other_categorical = Categorical(self.other_logits)
sample = categorical.sample(self.sample_shape).numpy()
entropy = categorical.entropy().numpy()
kl = categorical.kl_divergence(other_categorical).numpy()
probs = categorical.probs(self.value).numpy()
log_prob = categorical.log_prob(self.value).numpy()
fetch_list = [sample, entropy, kl, probs, log_prob]
self.compare_with_numpy(fetch_list)
def test_categorical_distribution_static(self, tolerance=1e-6):
paddle.enable_static()
with base.program_guard(self.test_program):
categorical = Categorical(self.logits_static)
other_categorical = Categorical(self.other_logits_static)
sample = categorical.sample(self.sample_shape)
entropy = categorical.entropy()
kl = categorical.kl_divergence(other_categorical)
probs = categorical.probs(self.value_static)
log_prob = categorical.log_prob(self.value_static)
fetch_list = [sample, entropy, kl, probs, log_prob]
feed_vars = {
'logits': self.logits_np,
'other_logits': self.other_logits_np,
'value': self.value_np,
}
self.executor.run(base.default_startup_program())
fetch_list = self.executor.run(
program=self.test_program, feed=feed_vars, fetch_list=fetch_list
)
self.compare_with_numpy(fetch_list)
class CategoricalTest2(CategoricalTest):
def init_numpy_data(self, batch_size, dims):
# input logtis is 2-D Tensor with dtype Float64
# value used in probs and log_prob method is 1-D Tensor
self.logits_np = np.random.rand(batch_size, dims).astype('float64')
self.other_logits_np = np.random.rand(batch_size, dims).astype(
'float64'
)
self.value_np = np.array([2, 1, 3]).astype('int64')
self.logits_shape = [batch_size, dims]
self.dist_shape = [batch_size]
self.sample_shape = [2, 4]
self.value_shape = [3]
def init_static_data(self, batch_size, dims):
with base.program_guard(self.test_program):
self.logits_static = paddle.static.data(
name='logits', shape=self.logits_shape, dtype='float64'
)
self.other_logits_static = paddle.static.data(
name='other_logits', shape=self.logits_shape, dtype='float64'
)
self.value_static = paddle.static.data(
name='value', shape=self.value_shape, dtype='int64'
)
class CategoricalTest3(CategoricalTest):
def init_dynamic_data(self, batch_size, dims):
# input logtis is 2-D numpy.ndarray with dtype Float32
# value used in probs and log_prob method is 1-D Tensor
self.logits = self.logits_np
self.other_logits = self.other_logits_np
self.value = paddle.to_tensor(self.value_np)
def init_static_data(self, batch_size, dims):
with base.program_guard(self.test_program):
self.logits_static = self.logits_np
self.other_logits_static = self.other_logits_np
self.value_static = paddle.static.data(
name='value', shape=self.value_shape, dtype='int64'
)
class CategoricalTest4(CategoricalTest):
def init_numpy_data(self, batch_size, dims):
# input logtis is 2-D numpy.ndarray with dtype Float64
# value used in probs and log_prob method is 1-D Tensor
self.logits_np = np.random.rand(batch_size, dims).astype('float64')
self.other_logits_np = np.random.rand(batch_size, dims).astype(
'float64'
)
self.value_np = np.array([2, 1, 3]).astype('int64')
self.logits_shape = [batch_size, dims]
self.dist_shape = [batch_size]
self.sample_shape = [2, 4]
self.value_shape = [3]
def init_dynamic_data(self, batch_size, dims):
self.logits = self.logits_np
self.other_logits = self.other_logits_np
self.value = paddle.to_tensor(self.value_np)
def init_static_data(self, batch_size, dims):
with base.program_guard(self.test_program):
self.logits_static = self.logits_np
self.other_logits_static = self.other_logits_np
self.value_static = paddle.static.data(
name='value', shape=self.value_shape, dtype='int64'
)
# test shape of logits and value used in probs and log_prob method
class CategoricalTest5(CategoricalTest):
def init_numpy_data(self, batch_size, dims):
# input logtis is 1-D Tensor
# value used in probs and log_prob method is 1-D Tensor
self.logits_np = np.random.rand(dims).astype('float32')
self.other_logits_np = np.random.rand(dims).astype('float32')
self.value_np = np.array([2, 1, 3]).astype('int64')
self.logits_shape = [dims]
self.dist_shape = []
self.sample_shape = [2, 4]
self.value_shape = [3]
def get_numpy_selected_probs(self, probability):
np_probs = np.zeros(self.value_shape)
for i in range(3):
np_probs[i] = probability[self.value_np[i]]
return np_probs
class CategoricalTest6(CategoricalTest):
def init_numpy_data(self, batch_size, dims):
# input logtis is 2-D Tensor
# value used in probs and log_prob method has the same number of batches with input
self.logits_np = np.random.rand(3, 5).astype('float32')
self.other_logits_np = np.random.rand(3, 5).astype('float32')
self.value_np = np.array([[2, 1], [0, 3], [2, 3]]).astype('int64')
self.logits_shape = [3, 5]
self.dist_shape = [3]
self.sample_shape = [2, 4]
self.value_shape = [3, 2]
def get_numpy_selected_probs(self, probability):
np_probs = np.zeros(self.value_shape)
for i in range(3):
for j in range(2):
np_probs[i][j] = probability[i][self.value_np[i][j]]
return np_probs
class CategoricalTest7(CategoricalTest):
def init_numpy_data(self, batch_size, dims):
# input logtis is 3-D Tensor
# value used in probs and log_prob method has the same number of distributions with input
self.logits_np = np.random.rand(3, 2, 5).astype('float32')
self.other_logits_np = np.random.rand(3, 2, 5).astype('float32')
self.value_np = np.array([2, 1, 3]).astype('int64')
self.logits_shape = [3, 2, 5]
self.dist_shape = [3, 2]
self.sample_shape = [2, 4]
self.value_shape = [3]
def get_numpy_selected_probs(self, probability):
np_probs = np.zeros(self.dist_shape + self.value_shape)
for i in range(3):
for j in range(2):
for k in range(3):
np_probs[i][j][k] = probability[i][j][self.value_np[k]]
return np_probs
class CategoricalTest8(CategoricalTest):
def init_dynamic_data(self, batch_size, dims):
# input logtis is 2-D list
# value used in probs and log_prob method is 1-D Tensor
self.logits = self.logits_np.tolist()
self.other_logits = self.other_logits_np.tolist()
self.value = paddle.to_tensor(self.value_np)
def init_static_data(self, batch_size, dims):
with base.program_guard(self.test_program):
self.logits_static = self.logits_np.tolist()
self.other_logits_static = self.other_logits_np.tolist()
self.value_static = paddle.static.data(
name='value', shape=self.value_shape, dtype='int64'
)
class CategoricalTest9(CategoricalTest):
def init_dynamic_data(self, batch_size, dims):
# input logtis is 2-D tuple
# value used in probs and log_prob method is 1-D Tensor
self.logits = tuple(self.logits_np.tolist())
self.other_logits = tuple(self.other_logits_np.tolist())
self.value = paddle.to_tensor(self.value_np)
def init_static_data(self, batch_size, dims):
with base.program_guard(self.test_program):
self.logits_static = tuple(self.logits_np.tolist())
self.other_logits_static = tuple(self.other_logits_np.tolist())
self.value_static = paddle.static.data(
name='value', shape=self.value_shape, dtype='int64'
)
class DistributionTestError(unittest.TestCase):
def test_distribution_error(self):
distribution = Distribution()
self.assertRaises(NotImplementedError, distribution.sample)
self.assertRaises(NotImplementedError, distribution.entropy)
normal = Normal(0.0, 1.0)
self.assertRaises(
NotImplementedError, distribution.kl_divergence, normal
)
value_npdata = np.array([0.8], dtype="float32")
value_tensor = paddle.tensor.create_tensor(dtype="float32")
self.assertRaises(
NotImplementedError, distribution.log_prob, value_tensor
)
self.assertRaises(NotImplementedError, distribution.probs, value_tensor)
def test_normal_error(self):
paddle.enable_static()
normal = Normal(0.0, 1.0)
value = [1.0, 2.0]
# type of value must be variable
self.assertRaises(TypeError, normal.log_prob, value)
value = [1.0, 2.0]
# type of value must be variable
self.assertRaises(TypeError, normal.probs, value)
shape = 1.0
# type of shape must be list
self.assertRaises(TypeError, normal.sample, shape)
seed = 1.0
# type of seed must be int
self.assertRaises(TypeError, normal.sample, [2, 3], seed)
normal_other = Uniform(1.0, 2.0)
# type of other must be an instance of Normal
self.assertRaises(TypeError, normal.kl_divergence, normal_other)
def test_uniform_error(self):
paddle.enable_static()
uniform = Uniform(0.0, 1.0)
value = [1.0, 2.0]
# type of value must be variable
self.assertRaises(TypeError, uniform.log_prob, value)
value = [1.0, 2.0]
# type of value must be variable
self.assertRaises(TypeError, uniform.probs, value)
shape = 1.0
# type of shape must be list
self.assertRaises(TypeError, uniform.sample, shape)
seed = 1.0
# type of seed must be int
self.assertRaises(TypeError, uniform.sample, [2, 3], seed)
def test_categorical_error(self):
paddle.enable_static()
categorical = Categorical([0.4, 0.6])
value = [1, 0]
# type of value must be variable
self.assertRaises(AttributeError, categorical.log_prob, value)
value = [1, 0]
# type of value must be variable
self.assertRaises(AttributeError, categorical.probs, value)
shape = 1.0
# type of shape must be list
self.assertRaises(TypeError, categorical.sample, shape)
categorical_other = Uniform(1.0, 2.0)
# type of other must be an instance of Categorical
self.assertRaises(
TypeError, categorical.kl_divergence, categorical_other
)
def test_shape_not_match_error():
# shape of value must match shape of logits
# value_shape[:-1] == logits_shape[:-1]
paddle.disable_static()
logits = paddle.rand([3, 5])
cat = Categorical(logits)
value = paddle.to_tensor([[2, 1, 3], [3, 2, 1]], dtype='int64')
cat.log_prob(value)
self.assertRaises(ValueError, test_shape_not_match_error)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,709 @@
# 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 unittest
import numpy as np
import scipy.special
import scipy.stats
from distribution.config import ATOL, DEVICES, RTOL
from parameterize import (
TEST_CASE_NAME,
parameterize_cls,
parameterize_func,
place,
)
from test_distribution import DistributionNumpy
import paddle
from paddle.base.data_feeder import convert_dtype
from paddle.distribution import Cauchy
from paddle.distribution.kl import kl_divergence
np.random.seed(2023)
paddle.seed(2023)
def _kstest(samples_a, samples_b):
"""Uses the Kolmogorov-Smirnov test for goodness of fit."""
_, p_value = scipy.stats.ks_2samp(samples_a, samples_b)
return not p_value < 0.005
class CauchyNumpy(DistributionNumpy):
def __init__(self, loc, scale):
loc = np.array(loc)
scale = np.array(scale)
if str(loc.dtype) not in ['float32', 'float64']:
self.dtype = 'float32'
else:
self.dtype = loc.dtype
self.batch_shape = (loc + scale).shape
self.loc = loc.astype(self.dtype)
self.scale = scale.astype(self.dtype)
self.rv = scipy.stats.cauchy(loc=loc, scale=scale)
def sample(self, shape):
shape = np.array(shape, dtype='int')
if shape.ndim:
shape = shape.tolist()
else:
shape = [shape.tolist()]
return self.rv.rvs(size=shape + list(self.batch_shape))
def log_prob(self, value):
return self.rv.logpdf(value)
def prob(self, value):
return self.rv.pdf(value)
def cdf(self, value):
return self.rv.cdf(value)
def entropy(self):
return self.rv.entropy()
def kl_divergence(self, other):
a_loc = self.loc
b_loc = other.loc
a_scale = self.scale
b_scale = other.scale
t1 = np.log(np.power(a_scale + b_scale, 2) + np.power(a_loc - b_loc, 2))
t2 = np.log(4 * a_scale * b_scale)
return t1 - t2
class CauchyTest(unittest.TestCase):
def setUp(self):
paddle.disable_static(self.place)
with paddle.base.dygraph.guard(self.place):
# just for convenience
self.dtype = self.expected_dtype
# init numpy with `dtype`
self.init_numpy_data(self.loc, self.scale, self.dtype)
# init paddle and check dtype convert.
self.init_dynamic_data(
self.loc, self.scale, self.default_dtype, self.dtype
)
def init_numpy_data(self, loc, scale, dtype):
loc = np.array(loc).astype(dtype)
scale = np.array(scale).astype(dtype)
self.rv_np = CauchyNumpy(loc=loc, scale=scale)
def init_dynamic_data(self, loc, scale, default_dtype, dtype):
self.rv_paddle = Cauchy(loc=loc, scale=scale)
self.assertTrue(
dtype == convert_dtype(self.rv_paddle.loc.dtype),
(dtype, self.rv_paddle.loc.dtype),
)
self.assertTrue(
dtype == convert_dtype(self.rv_paddle.scale.dtype),
(dtype, self.rv_paddle.scale.dtype),
)
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'loc', 'scale', 'default_dtype', 'expected_dtype'),
[
# 0-D params
(
'params_0d_32_1',
paddle.full((), 0.1),
paddle.full((), 1.2),
'float32',
'float32',
),
(
'params_0d_32_2',
paddle.full((), -1.2),
paddle.full((), 2.3),
'float32',
'float32',
),
(
'params_0d_64_1',
paddle.full((), 0.1, dtype='float64'),
paddle.full((), 1.2, dtype='float64'),
'float64',
'float64',
),
(
'params_0d_64_2',
paddle.full((), -1.2, dtype='float64'),
paddle.full((), 2.3, dtype='float64'),
'float64',
'float64',
),
# 1-D params
('params_float_1', 0.1, 1.2, 'float64', 'float32'),
('params_float_2', -1.2, 2.3, 'float64', 'float32'),
(
'params_tensor_32_1',
paddle.to_tensor(0.1),
paddle.to_tensor(1.2),
'float32',
'float32',
),
(
'params_tensor_32_2',
paddle.to_tensor(-1.2),
paddle.to_tensor(2.3),
'float32',
'float32',
),
(
'params_tensor_64_1',
paddle.to_tensor(0.1, dtype='float64'),
paddle.to_tensor(1.2, dtype='float64'),
'float64',
'float64',
),
(
'params_tensor_64_2',
paddle.to_tensor(-1.2, dtype='float64'),
paddle.to_tensor(2.3, dtype='float64'),
'float64',
'float64',
),
(
'params_tensor_list',
paddle.to_tensor([0.1]),
paddle.to_tensor([1.2]),
'float32',
'float32',
),
(
'params_tensor_tuple',
paddle.to_tensor((0.1,)),
paddle.to_tensor((1.2,)),
'float32',
'float32',
),
# N-D params
(
'params_0d_1d_1',
paddle.full((), 0.1),
paddle.full((1,), 1.2),
'float32',
'float32',
),
(
'params_0d_1d_2',
paddle.full((), 0.1),
paddle.to_tensor(1.2),
'float32',
'float32',
),
(
'params_1d_0d_1',
paddle.full((1,), 0.1),
paddle.full((), 1.2),
'float32',
'float32',
),
(
'params_1d_0d_2',
paddle.to_tensor(0.1),
paddle.full((), 1.2),
'float32',
'float32',
),
(
'params_0d_3d',
paddle.full((), 0.1),
paddle.to_tensor([1.1, 2.2, 3.3]),
'float32',
'float32',
),
(
'params_3d_0d',
paddle.to_tensor([0.1, -0.2, 0.3]),
paddle.full((), 1.2),
'float32',
'float32',
),
(
'params_1d_3d',
paddle.full((1,), 0.1),
paddle.to_tensor([1.1, 2.2, 3.3]),
'float32',
'float32',
),
(
'params_3d_1d',
paddle.to_tensor([0.1, -0.2, 0.3]),
paddle.full((1,), 1.2),
'float32',
'float32',
),
(
'params_3d_3d',
paddle.to_tensor([0.1, -0.2, 0.3]),
paddle.to_tensor([1.1, 2.2, 3.3]),
'float32',
'float32',
),
],
)
class CauchyTestFeature(CauchyTest):
@parameterize_func(
[
(paddle.to_tensor([-0.3]),),
(paddle.to_tensor([0.3]),),
(paddle.to_tensor([1.3]),),
(paddle.to_tensor([5.3]),),
(paddle.to_tensor(0.3, dtype='float64'),),
]
)
def test_log_prob(self, value):
with paddle.base.dygraph.guard(self.place):
if convert_dtype(value.dtype) == convert_dtype(
self.rv_paddle.loc.dtype
):
log_prob = self.rv_paddle.log_prob(value)
np.testing.assert_allclose(
log_prob,
self.rv_np.log_prob(value),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
self.assertTrue(self.dtype == convert_dtype(log_prob.dtype))
else:
with self.assertWarns(UserWarning):
self.rv_paddle.log_prob(value)
@parameterize_func(
[
(paddle.to_tensor([-0.3]),),
(paddle.to_tensor([0.3]),),
(paddle.to_tensor([1.3]),),
(paddle.to_tensor([5.3]),),
(paddle.to_tensor(0.3, dtype='float64'),),
]
)
def test_prob(self, value):
with paddle.base.dygraph.guard(self.place):
if convert_dtype(value.dtype) == convert_dtype(
self.rv_paddle.loc.dtype
):
prob = self.rv_paddle.prob(value)
np.testing.assert_allclose(
prob,
self.rv_np.prob(value),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
self.assertTrue(self.dtype == convert_dtype(prob.dtype))
else:
with self.assertWarns(UserWarning):
self.rv_paddle.prob(value)
@parameterize_func(
[
(paddle.to_tensor([-0.3]),),
(paddle.to_tensor([0.3]),),
(paddle.to_tensor([1.3]),),
(paddle.to_tensor([5.3]),),
(paddle.to_tensor(0.3, dtype='float64'),),
]
)
def test_cdf(self, value):
with paddle.base.dygraph.guard(self.place):
if convert_dtype(value.dtype) == convert_dtype(
self.rv_paddle.loc.dtype
):
cdf = self.rv_paddle.cdf(value)
np.testing.assert_allclose(
cdf,
self.rv_np.cdf(value),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
self.assertTrue(self.dtype == convert_dtype(cdf.dtype))
else:
with self.assertWarns(UserWarning):
self.rv_paddle.cdf(value)
def test_entropy(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self.rv_paddle.entropy(),
self.rv_np.entropy(),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
@parameterize_func(
[
(0.6, 5.7),
(-0.6, 5.7),
]
)
def test_kl_divergence(self, loc, scale):
with paddle.base.dygraph.guard(self.place):
# convert loc/scale to paddle's dtype(float32/float64)
rv_paddle_other = Cauchy(
loc=paddle.full((), loc, dtype=self.rv_paddle.loc.dtype),
scale=paddle.full((), scale, dtype=self.rv_paddle.scale.dtype),
)
rv_np_other = CauchyNumpy(loc=loc, scale=scale)
np.testing.assert_allclose(
self.rv_paddle.kl_divergence(rv_paddle_other),
self.rv_np.kl_divergence(rv_np_other),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
np.testing.assert_allclose(
kl_divergence(self.rv_paddle, rv_paddle_other),
self.rv_np.kl_divergence(rv_np_other),
rtol=RTOL.get(self.dtype),
atol=ATOL.get(self.dtype),
)
@place(DEVICES)
@parameterize_cls(
(
TEST_CASE_NAME,
'loc',
'scale',
'default_dtype',
'expected_dtype',
'shape',
'expected_shape',
),
[
# 0-D params
(
'params_0d_0d_sample_1d',
paddle.full((), 0.1),
paddle.full((), 1.2),
'float32',
'float32',
[100],
[100],
),
(
'params_0d_0d_sample_2d',
paddle.full((), 0.1),
paddle.full((), 1.2),
'float32',
'float32',
[100, 1],
[100, 1],
),
(
'params_0d_0d_sample_3d',
paddle.full((), 0.1),
paddle.full((), 1.2),
'float32',
'float32',
[100, 2, 3],
[100, 2, 3],
),
# 1-D params
(
'params_1d_1d_sample_1d_float',
0.1,
1.2,
'float64',
'float32',
paddle.to_tensor([100]),
[100],
),
(
'params_1d_1d_sample_1d_32',
paddle.to_tensor([0.1]),
paddle.to_tensor([1.2]),
'float32',
'float32',
paddle.to_tensor([100]),
[100, 1],
),
(
'params_1d_1d_sample_1d_64',
paddle.to_tensor([0.1], dtype='float64'),
paddle.to_tensor([1.2], dtype='float64'),
'float64',
'float64',
paddle.to_tensor([100]),
[100, 1],
),
(
'params_1d_1d_sample_2d',
paddle.to_tensor([0.1]),
paddle.to_tensor([1.2]),
'float32',
'float32',
[100, 2],
[100, 2, 1],
),
(
'params_1d_1d_sample_3d',
paddle.to_tensor([0.1]),
paddle.to_tensor([1.2]),
'float32',
'float32',
[100, 2, 3],
[100, 2, 3, 1],
),
# N-D params
(
'params_0d_1d_sample_1d',
paddle.full((), 0.3),
paddle.to_tensor([1.2]),
'float32',
'float32',
[100],
[100, 1],
),
(
'params_1d_0d_sample_1d',
paddle.to_tensor([0.3]),
paddle.full((), 1.2),
'float32',
'float32',
[100],
[100, 1],
),
(
'params_0d_1d_sample_2d',
paddle.full((), 0.3),
paddle.to_tensor([1.2]),
'float32',
'float32',
[100, 2],
[100, 2, 1],
),
(
'params_1d_0d_sample_2d',
paddle.to_tensor([0.3]),
paddle.full((), 1.2),
'float32',
'float32',
[100, 2],
[100, 2, 1],
),
(
'params_1d_2d_sample_1d',
paddle.to_tensor([0.3]),
paddle.to_tensor((1.2, 2.3)),
'float32',
'float32',
[100],
[100, 2],
),
(
'params_2d_1d_sample_1d',
paddle.to_tensor((0.3, -0.3)),
paddle.to_tensor([1.2]),
'float32',
'float32',
[100],
[100, 2],
),
(
'params_2d_2d_sample_1d',
paddle.to_tensor((0.3, -0.3)),
paddle.to_tensor((1.2, 2.3)),
'float32',
'float32',
[100],
[100, 2],
),
(
'params_2d_2d_sample_2d',
paddle.to_tensor((0.3, -0.3)),
paddle.to_tensor((1.2, 2.3)),
'float32',
'float32',
[100, 1],
[100, 1, 2],
),
(
'params_1d_2d_sample_3d',
paddle.to_tensor([0.3]),
paddle.to_tensor((1.2, 2.3)),
'float32',
'float32',
[100, 1, 2],
[100, 1, 2, 2],
),
],
)
class CauchyTestSample(CauchyTest):
def test_sample(self):
with paddle.base.dygraph.guard(self.place):
sample_np = self.rv_np.sample(self.shape)
sample_paddle = self.rv_paddle.sample(self.shape)
self.assertEqual(list(sample_paddle.shape), self.expected_shape)
self.assertEqual(sample_paddle.dtype, self.rv_paddle.loc.dtype)
if len(self.expected_shape) > len(self.shape):
for i in range(self.expected_shape[-1]):
self.assertTrue(
_kstest(
sample_np[..., i].reshape(-1),
sample_paddle.numpy()[..., i].reshape(-1),
)
)
else:
self.assertTrue(
_kstest(
sample_np.reshape(-1),
sample_paddle.numpy().reshape(-1),
)
)
def test_rsample(self):
with paddle.base.dygraph.guard(self.place):
sample_np = self.rv_np.sample(self.shape)
rsample_paddle = self.rv_paddle.rsample(self.shape)
self.assertEqual(list(rsample_paddle.shape), self.expected_shape)
self.assertEqual(rsample_paddle.dtype, self.rv_paddle.loc.dtype)
if len(self.expected_shape) > len(self.shape):
for i in range(self.expected_shape[-1]):
self.assertTrue(
_kstest(
sample_np[..., i].reshape(-1),
rsample_paddle.numpy()[..., i].reshape(-1),
)
)
else:
self.assertTrue(
_kstest(
sample_np.reshape(-1),
rsample_paddle.numpy().reshape(-1),
)
)
def test_rsample_backpropagation(self):
with paddle.base.dygraph.guard(self.place):
self.rv_paddle.loc.stop_gradient = False
self.rv_paddle.scale.stop_gradient = False
rsample_paddle = self.rv_paddle.rsample(self.shape)
grads = paddle.grad(
[rsample_paddle], [self.rv_paddle.loc, self.rv_paddle.scale]
)
self.assertEqual(len(grads), 2)
self.assertEqual(grads[0].dtype, self.rv_paddle.loc.dtype)
self.assertEqual(grads[0].shape, self.rv_paddle.loc.shape)
self.assertEqual(grads[1].dtype, self.rv_paddle.scale.dtype)
self.assertEqual(grads[1].shape, self.rv_paddle.scale.shape)
@place(DEVICES)
@parameterize_cls([TEST_CASE_NAME], ['CauchyTestError'])
class CauchyTestError(unittest.TestCase):
def setUp(self):
paddle.disable_static(self.place)
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.base.dygraph.guard(self.place):
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.base.dygraph.guard(self.place):
rv = Cauchy(loc=0.0, scale=1.0)
with self.assertRaises(TypeError):
_ = rv.sample(shape)
with self.assertRaises(TypeError):
_ = 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.base.dygraph.guard(self.place):
rv = Cauchy(loc=0.0, scale=1.0)
with self.assertRaises(TypeError):
_ = rv.log_prob(value)
with self.assertRaises(TypeError):
_ = rv.prob(value)
with self.assertRaises(TypeError):
_ = rv.cdf(value)
@parameterize_func(
[
(np.array(1.0),), # ndarray or other distribution
]
)
def test_bad_kl_other_type(self, other):
with paddle.base.dygraph.guard(self.place):
rv = Cauchy(loc=0.0, scale=1.0)
with self.assertRaises(TypeError):
_ = rv.kl_divergence(other)
@parameterize_func(
[
(
paddle.to_tensor([0.1, 0.2]),
paddle.to_tensor([0.3, 0.4]),
paddle.to_tensor([0.1, 0.2, 0.3]),
),
]
)
def test_bad_broadcast(self, loc, scale, value):
with paddle.base.dygraph.guard(self.place):
rv = Cauchy(loc=loc, scale=scale)
self.assertRaises(ValueError, rv.cdf, value)
self.assertRaises(ValueError, rv.log_prob, value)
self.assertRaises(ValueError, rv.prob, value)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,477 @@
# 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()
+234
View File
@@ -0,0 +1,234 @@
# 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.
import numbers
import unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import chi2
np.random.seed(2024)
paddle.seed(2024)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df'),
[
(
'one-dim',
parameterize.xrand(
(4,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'broadcast',
parameterize.xrand(
(2, 1),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestChi2(unittest.TestCase):
def setUp(self):
df = self.df
if not isinstance(self.df, numbers.Real):
df = paddle.to_tensor(self.df)
self._paddle_chi2 = chi2.Chi2(df)
def test_mean(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_chi2.mean,
scipy.stats.chi2.mean(self.df),
rtol=config.RTOL.get(str(self._paddle_chi2.df.numpy().dtype)),
atol=config.ATOL.get(str(self._paddle_chi2.df.numpy().dtype)),
)
def test_variance(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_chi2.variance,
scipy.stats.chi2.var(self.df),
rtol=config.RTOL.get(str(self._paddle_chi2.df.numpy().dtype)),
atol=config.ATOL.get(str(self._paddle_chi2.df.numpy().dtype)),
)
def test_entropy(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_chi2.entropy(),
scipy.stats.chi2.entropy(self.df),
rtol=config.RTOL.get(str(self.df.dtype)),
atol=config.ATOL.get(str(self.df.dtype)),
)
def test_prob(self):
value = np.random.rand(*self._paddle_chi2.df.shape)
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_chi2.prob(paddle.to_tensor(value)),
scipy.stats.chi2.pdf(value, self.df),
rtol=config.RTOL.get(str(self.df.dtype)),
atol=config.ATOL.get(str(self.df.dtype)),
)
def test_log_prob(self):
value = np.random.rand(*self._paddle_chi2.df.shape)
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_chi2.log_prob(paddle.to_tensor(value)),
scipy.stats.chi2.logpdf(value, self.df),
rtol=config.RTOL.get(str(self.df.dtype)),
atol=config.ATOL.get(str(self.df.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df'),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestChi2Sample(unittest.TestCase):
def setUp(self):
df = self.df
if not isinstance(self.df, numbers.Real):
df = paddle.to_tensor(self.df)
self._paddle_chi2 = chi2.Chi2(df)
def test_sample_shape(self):
cases = [
{
'input': (),
'expect': tuple(paddle.squeeze(self._paddle_chi2.df).shape),
},
{
'input': (2, 2),
'expect': (2, 2, *paddle.squeeze(self._paddle_chi2.df).shape),
},
]
for case in cases:
self.assertTrue(
tuple(self._paddle_chi2.sample(case.get('input')).shape)
== case.get('expect')
)
def test_sample(self):
sample_shape = (30000,)
samples = self._paddle_chi2.sample(sample_shape)
sample_values = samples.numpy()
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.chi2.mean(self.df),
rtol=0.1,
atol=config.ATOL.get(str(self._paddle_chi2.df.numpy().dtype)),
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.chi2.var(self.df),
rtol=0.1,
atol=config.ATOL.get(str(self._paddle_chi2.df.numpy().dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df'),
[
('0-dim', 0.4),
],
)
class TestChi2SampleKS(unittest.TestCase):
def setUp(self):
df = self.df
if not isinstance(self.df, numbers.Real):
df = paddle.to_tensor(self.df)
self._paddle_chi2 = chi2.Chi2(df)
def test_sample_ks(self):
sample_shape = (15000,)
samples = self._paddle_chi2.sample(sample_shape)
self.assertTrue(self._kstest(samples))
def _kstest(self, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, _ = scipy.stats.kstest(samples, scipy.stats.chi2(self.df).cdf)
return ks < 0.02
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME),
[
('chi2_test_err'),
],
)
class Chi2TestError(unittest.TestCase):
@parameterize.parameterize_func(
[
(-1.0, ValueError), # df < 0
((1.0, -1.0), ValueError), # df < 0
]
)
def test_bad_parameter(self, df, error):
with paddle.base.dygraph.guard(self.place):
self.assertRaises(error, chi2.Chi2, df)
@parameterize.parameterize_func([(10,)]) # not sequence object sample shape
def test_bad_sample_shape(self, shape):
with paddle.base.dygraph.guard(self.place):
_chi2 = chi2.Chi2(1.0)
self.assertRaises(TypeError, _chi2.sample, shape)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,285 @@
# 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.
import unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import chi2
paddle.enable_static()
np.random.seed(2024)
paddle.seed(2024)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df'),
[
(
'one-dim',
parameterize.xrand(
(4,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'broadcast',
parameterize.xrand(
(2, 1),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestChi2(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program):
df = paddle.static.data('df', self.df.shape, self.df.dtype)
self._paddle_chi2 = chi2.Chi2(df)
self.feeds = {'df': self.df}
def test_mean(self):
with paddle.static.program_guard(self.program):
[mean] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_chi2.mean],
)
np.testing.assert_allclose(
mean,
scipy.stats.chi2.mean(self.df),
rtol=config.RTOL.get(str(self.df.dtype)),
atol=config.ATOL.get(str(self.df.dtype)),
)
def test_variance(self):
with paddle.static.program_guard(self.program):
[variance] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_chi2.variance],
)
np.testing.assert_allclose(
variance,
scipy.stats.chi2.var(self.df),
rtol=config.RTOL.get(str(self.df.dtype)),
atol=config.ATOL.get(str(self.df.dtype)),
)
def test_entropy(self):
with paddle.static.program_guard(self.program):
[entropy] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_chi2.entropy()],
)
np.testing.assert_allclose(
entropy,
scipy.stats.chi2.entropy(self.df),
rtol=config.RTOL.get(str(self.df.dtype)),
atol=config.ATOL.get(str(self.df.dtype)),
)
def test_prob(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_chi2.df.shape,
self._paddle_chi2.df.dtype,
)
prob = self._paddle_chi2.prob(value)
random_number = np.random.rand(*self._paddle_chi2.df.shape).astype(
self.df.dtype
)
feeds = dict(self.feeds, value=random_number)
[prob] = self.executor.run(
self.program, feed=feeds, fetch_list=[prob]
)
np.testing.assert_allclose(
prob,
scipy.stats.chi2.pdf(random_number, self.df),
rtol=config.RTOL.get(str(self.df.dtype)),
atol=config.ATOL.get(str(self.df.dtype)),
)
def test_log_prob(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_chi2.df.shape,
self._paddle_chi2.df.dtype,
)
log_prob = self._paddle_chi2.log_prob(value)
random_number = np.random.rand(*self._paddle_chi2.df.shape).astype(
self.df.dtype
)
feeds = dict(self.feeds, value=random_number)
[log_prob] = self.executor.run(
self.program, feed=feeds, fetch_list=[log_prob]
)
np.testing.assert_allclose(
log_prob,
scipy.stats.chi2.logpdf(random_number, self.df),
rtol=config.RTOL.get(str(self.df.dtype)),
atol=config.ATOL.get(str(self.df.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df'),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestChi2Sample(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program):
df = paddle.static.data('df', self.df.shape, self.df.dtype)
self._paddle_chi2 = chi2.Chi2(df)
self.feeds = {'df': self.df}
def test_sample_shape(self):
cases = [
{
'input': (),
'expect': tuple(np.squeeze(self.df).shape),
},
{
'input': (2, 2),
'expect': (2, 2, *np.squeeze(self.df).shape),
},
]
for case in cases:
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_chi2.sample(case.get('input')),
)
self.assertTrue(data.shape == case.get('expect'))
def test_sample(self):
sample_shape = (30000,)
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_chi2.sample(sample_shape),
)
except_shape = sample_shape + np.squeeze(self.df).shape
self.assertTrue(data.shape == except_shape)
np.testing.assert_allclose(
data.mean(axis=0),
scipy.stats.chi2.mean(self.df),
rtol=0.1,
atol=config.ATOL.get(str(self.df.dtype)),
)
np.testing.assert_allclose(
data.var(axis=0),
scipy.stats.chi2.var(self.df),
rtol=0.1,
atol=config.ATOL.get(str(self.df.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df'),
[
('0-dim', 0.4),
],
)
class TestChi2SampleKS(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program):
df = paddle.static.data('df', (), 'float')
self._paddle_chi2 = chi2.Chi2(df)
self.feeds = {'df': self.df}
def test_sample(self):
sample_shape = (15000,)
with paddle.static.program_guard(self.program):
[samples] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_chi2.sample(sample_shape),
)
self.assertTrue(self._kstest(samples))
def _kstest(self, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, _ = scipy.stats.kstest(samples, scipy.stats.chi2(self.df).cdf)
return ks < 0.02
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME),
[
('chi2_test_err'),
],
)
class Chi2TestError(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
@parameterize.parameterize_func([(10,)]) # not sequence object sample shape
def test_bad_sample_shape(self, shape):
with paddle.static.program_guard(self.program):
_chi2 = chi2.Chi2(1.0)
self.assertRaises(TypeError, _chi2.sample, shape)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,89 @@
# Copyright (c) 2022 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
import numpy as np
import parameterize as param
import paddle
from paddle.distribution import constraint
np.random.seed(2022)
@param.param_cls(
(param.TEST_CASE_NAME, 'value'), [('NotImplement', np.random.rand(2, 3))]
)
class TestConstraint(unittest.TestCase):
def setUp(self):
self._constraint = constraint.Constraint()
def test_costraint(self):
with self.assertRaises(NotImplementedError):
self._constraint.check(self.value)
@param.param_cls(
(param.TEST_CASE_NAME, 'value', 'expect'), [('real', 1.0, True)]
)
class TestReal(unittest.TestCase):
def setUp(self):
self._constraint = constraint.Real()
def test_costraint(self):
self.assertEqual(self._constraint.check(self.value), self.expect)
@param.param_cls(
(param.TEST_CASE_NAME, 'lower', 'upper', 'value', 'expect'),
[('in_range', 0, 1, 0.5, True), ('out_range', 0, 1, 2, False)],
)
class TestRange(unittest.TestCase):
def setUp(self):
self._constraint = constraint.Range(self.lower, self.upper)
def test_costraint(self):
self.assertEqual(self._constraint.check(self.value), self.expect)
@param.param_cls(
(param.TEST_CASE_NAME, 'value', 'expect'),
[('positive', 1, True), ('negative', -1, False)],
)
class TestPositive(unittest.TestCase):
def setUp(self):
self._constraint = constraint.Positive()
def test_costraint(self):
self.assertEqual(self._constraint.check(self.value), self.expect)
@param.param_cls(
(param.TEST_CASE_NAME, 'value', 'expect'),
[
('simplex', paddle.to_tensor([0.5, 0.5]), True),
('non_simplex', paddle.to_tensor([-0.5, 0.5]), False),
],
)
class TestSimplex(unittest.TestCase):
def setUp(self):
self._constraint = constraint.Simplex()
def test_costraint(self):
self.assertEqual(self._constraint.check(self.value), self.expect)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,370 @@
# 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 unittest
import numpy as np
import parameterize
from distribution import config
from parameterize import (
TEST_CASE_NAME,
parameterize_cls,
parameterize_func,
)
import paddle
from paddle.distribution.continuous_bernoulli import ContinuousBernoulli
class ContinuousBernoulli_np:
def __init__(self, probs, lims=(0.48, 0.52)):
self.lims = lims
self.dtype = probs.dtype
eps_prob = 1.1920928955078125e-07
self.probs = np.clip(probs, a_min=eps_prob, a_max=1.0 - eps_prob)
def _cut_support_region(self):
return np.logical_or(
np.less_equal(self.probs, self.lims[0]),
np.greater_equal(self.probs, self.lims[1]),
)
def _cut_probs(self):
return np.where(
self._cut_support_region(),
self.probs,
self.lims[0] * np.ones_like(self.probs),
)
def _tanh_inverse(self, value):
return 0.5 * (np.log1p(value) - np.log1p(-value))
def _log_constant(self):
cut_probs = self._cut_probs()
cut_probs_below_half = np.where(
np.less_equal(cut_probs, 0.5), cut_probs, np.zeros_like(cut_probs)
)
cut_probs_above_half = np.where(
np.greater_equal(cut_probs, 0.5), cut_probs, np.ones_like(cut_probs)
)
log_constant_propose = np.log(
2.0 * np.abs(self._tanh_inverse(1.0 - 2.0 * cut_probs))
) - np.where(
np.less_equal(cut_probs, 0.5),
np.log1p(-2.0 * cut_probs_below_half),
np.log(2.0 * cut_probs_above_half - 1.0),
)
x = np.square(self.probs - 0.5)
taylor_expansion = np.log(2.0) + (4.0 / 3.0 + 104.0 / 45.0 * x) * x
return np.where(
self._cut_support_region(), log_constant_propose, taylor_expansion
)
def np_variance(self):
cut_probs = self._cut_probs()
tmp = np.divide(
np.square(cut_probs) - cut_probs, np.square(1.0 - 2.0 * cut_probs)
)
propose = tmp + np.divide(
1.0, np.square(2.0 * self._tanh_inverse(1.0 - 2.0 * cut_probs))
)
x = np.square(self.probs - 0.5)
taylor_expansion = 1.0 / 12.0 - (1.0 / 15.0 - 128.0 / 945.0 * x) * x
return np.where(self._cut_support_region(), propose, taylor_expansion)
def np_mean(self):
cut_probs = self._cut_probs()
tmp = cut_probs / (2.0 * cut_probs - 1.0)
propose = tmp + 1.0 / (2.0 * self._tanh_inverse(1.0 - 2.0 * cut_probs))
x = self.probs - 0.5
taylor_expansion = 0.5 + (1.0 / 3.0 + 16.0 / 45.0 * np.square(x)) * x
return np.where(self._cut_support_region(), propose, taylor_expansion)
def np_entropy(self):
log_p = np.log(self.probs)
log_1_minus_p = np.log1p(-self.probs)
return np.where(
np.equal(self.probs, 0.5),
np.full_like(self.probs, 0.0),
(
-self._log_constant()
+ self.np_mean() * (log_1_minus_p - log_p)
- log_1_minus_p
),
)
def np_prob(self, value):
return np.exp(self.np_log_prob(value))
def np_log_prob(self, value):
eps = 1e-8
cross_entropy = np.nan_to_num(
value * np.log(self.probs) + (1.0 - value) * np.log(1 - self.probs),
neginf=-eps,
)
return self._log_constant() + cross_entropy
def np_cdf(self, value):
cut_probs = self._cut_probs()
cdfs = (
np.power(cut_probs, value) * np.power(1.0 - cut_probs, 1.0 - value)
+ cut_probs
- 1.0
) / (2.0 * cut_probs - 1.0)
unbounded_cdfs = np.where(self._cut_support_region(), cdfs, value)
return np.where(
np.less_equal(value, 0.0),
np.zeros_like(value),
np.where(
np.greater_equal(value, 1.0),
np.ones_like(value),
unbounded_cdfs,
),
)
def np_icdf(self, value):
cut_probs = self._cut_probs()
return np.where(
self._cut_support_region(),
(
np.log1p(-cut_probs + value * (2.0 * cut_probs - 1.0))
- np.log1p(-cut_probs)
)
/ (np.log(cut_probs) - np.log1p(-cut_probs)),
value,
)
def np_kl_divergence(self, other):
part1 = -self.np_entropy()
log_q = np.log(other.probs)
log_1_minus_q = np.log1p(-other.probs)
part2 = -(
other._log_constant()
+ self.np_mean() * (log_q - log_1_minus_q)
+ log_1_minus_q
)
return part1 + part2
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'probs'),
[
('half', np.array(0.5).astype("float32")),
(
'one-dim',
parameterize.xrand((1,), min=0.0, max=1.0).astype("float64"),
),
(
'multi-dim',
parameterize.xrand((2, 3), min=0.0, max=1.0).astype("float32"),
),
],
)
class TestContinuousBernoulli(unittest.TestCase):
def setUp(self):
self._dist = ContinuousBernoulli(
probs=paddle.to_tensor(self.probs), lims=(0.48, 0.52)
)
self._np_dist = ContinuousBernoulli_np(self.probs, lims=(0.48, 0.52))
def test_mean(self):
mean = self._dist.mean
self.assertEqual(mean.numpy().dtype, self.probs.dtype)
np.testing.assert_allclose(
mean,
self._np_dist.np_mean(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_variance(self):
var = self._dist.variance
self.assertEqual(var.numpy().dtype, self.probs.dtype)
np.testing.assert_allclose(
var,
self._np_dist.np_variance(),
rtol=0.01,
atol=0.0,
)
def test_entropy(self):
entropy = self._dist.entropy()
self.assertEqual(entropy.numpy().dtype, self.probs.dtype)
np.testing.assert_allclose(
entropy,
self._np_dist.np_entropy(),
rtol=0.01,
atol=0.0,
)
def test_sample(self):
sample_shape = ()
samples = self._dist.sample(sample_shape)
self.assertEqual(samples.numpy().dtype, self.probs.dtype)
self.assertEqual(
tuple(samples.shape),
sample_shape + self._dist.batch_shape + self._dist.event_shape,
)
sample_shape = (50000,)
samples = self._dist.sample(sample_shape)
sample_mean = samples.mean(axis=0)
sample_variance = samples.var(axis=0)
np.testing.assert_allclose(
sample_mean,
self._dist.mean,
rtol=0.1,
atol=0.0,
)
np.testing.assert_allclose(
sample_variance,
self._dist.variance,
rtol=0.1,
atol=0.0,
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'probs', 'value'),
[
(
'zero-dim',
np.array(0.3).astype("float32"),
parameterize.xrand((5,), min=0.0, max=1.0).astype("float32"),
),
(
'value-same-shape',
parameterize.xrand((5,), min=0.0, max=1.0).astype("float32"),
parameterize.xrand((5,), min=0.0, max=1.0).astype("float32"),
),
(
'value-broadcast-shape',
parameterize.xrand((1,), min=0.0, max=1.0).astype("float64"),
parameterize.xrand((2, 3), min=0.0, max=1.0).astype("float64"),
),
],
)
class TestContinuousBernoulliProbs(unittest.TestCase):
def setUp(self):
self._dist = ContinuousBernoulli(
probs=paddle.to_tensor(self.probs), lims=(0.48, 0.52)
)
self._np_dist = ContinuousBernoulli_np(self.probs, lims=(0.48, 0.52))
def test_prob(self):
np.testing.assert_allclose(
self._dist.prob(paddle.to_tensor(self.value)),
self._np_dist.np_prob(self.value),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_log_prob(self):
np.testing.assert_allclose(
self._dist.log_prob(paddle.to_tensor(self.value)),
self._np_dist.np_log_prob(self.value),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_cdf(self):
np.testing.assert_allclose(
self._dist.cdf(paddle.to_tensor(self.value)),
self._np_dist.np_cdf(self.value),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_icdf(self):
np.testing.assert_allclose(
self._dist.icdf(paddle.to_tensor(self.value)),
self._np_dist.np_icdf(self.value),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'p_1', 'p_2'),
[
(
'zero-dim',
np.array(0.2).astype("float32"),
np.array(0.4).astype("float32"),
),
(
'one-dim',
parameterize.xrand((1,), min=0.0, max=1.0).astype("float32"),
parameterize.xrand((1,), min=0.0, max=1.0).astype("float32"),
),
(
'multi-dim',
parameterize.xrand((5,), min=0.0, max=1.0).astype("float64"),
parameterize.xrand((5,), min=0.0, max=1.0).astype("float64"),
),
],
)
class TestContinuousBernoulliKL(unittest.TestCase):
def setUp(self):
paddle.disable_static()
self._dist1 = ContinuousBernoulli(
probs=paddle.to_tensor(self.p_1), lims=(0.48, 0.52)
)
self._dist2 = ContinuousBernoulli(
probs=paddle.to_tensor(self.p_2), lims=(0.48, 0.52)
)
self._np_dist1 = ContinuousBernoulli_np(self.p_1, lims=(0.48, 0.52))
self._np_dist2 = ContinuousBernoulli_np(self.p_2, lims=(0.48, 0.52))
def test_kl_divergence(self):
kl0 = self._dist1.kl_divergence(self._dist2)
kl1 = self._np_dist1.np_kl_divergence(self._np_dist2)
self.assertEqual(tuple(kl0.shape), self._dist1.batch_shape)
self.assertEqual(tuple(kl1.shape), self._dist1.batch_shape)
np.testing.assert_allclose(
kl0,
kl1,
rtol=0.01,
atol=0.0,
)
@parameterize.place(config.DEVICES)
@parameterize_cls([TEST_CASE_NAME], ['ContinuousBernoulliTestError'])
class ContinuousBernoulliTestError(unittest.TestCase):
def setUp(self):
paddle.disable_static(self.place)
@parameterize_func(
[
(
paddle.to_tensor([0.3, 0.5]),
paddle.to_tensor([0.2, 0.8, 0.6]),
),
]
)
def test_bad_kl_div(self, probs1, probs2):
with paddle.base.dygraph.guard(self.place):
rv = ContinuousBernoulli(probs1)
rv_other = ContinuousBernoulli(probs2)
self.assertRaises(ValueError, rv.kl_divergence, rv_other)
if __name__ == '__main__':
unittest.main(argv=[''], verbosity=3, exit=False)
@@ -0,0 +1,336 @@
# 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 unittest
import numpy as np
import parameterize
from distribution import config
import paddle
from paddle.distribution.continuous_bernoulli import ContinuousBernoulli
class ContinuousBernoulli_np:
def __init__(self, probs, lims=(0.48, 0.52)):
self.lims = lims
self.dtype = probs.dtype
eps_prob = 1.1920928955078125e-07
self.probs = np.clip(probs, a_min=eps_prob, a_max=1.0 - eps_prob)
def _cut_support_region(self):
return np.logical_or(
np.less_equal(self.probs, self.lims[0]),
np.greater_equal(self.probs, self.lims[1]),
)
def _cut_probs(self):
return np.where(
self._cut_support_region(),
self.probs,
self.lims[0] * np.ones_like(self.probs),
)
def _tanh_inverse(self, value):
return 0.5 * (np.log1p(value) - np.log1p(-value))
def _log_constant(self):
cut_probs = self._cut_probs()
cut_probs_below_half = np.where(
np.less_equal(cut_probs, 0.5), cut_probs, np.zeros_like(cut_probs)
)
cut_probs_above_half = np.where(
np.greater_equal(cut_probs, 0.5), cut_probs, np.ones_like(cut_probs)
)
log_constant_propose = np.log(
2.0 * np.abs(self._tanh_inverse(1.0 - 2.0 * cut_probs))
) - np.where(
np.less_equal(cut_probs, 0.5),
np.log1p(-2.0 * cut_probs_below_half),
np.log(2.0 * cut_probs_above_half - 1.0),
)
x = np.square(self.probs - 0.5)
taylor_expansion = np.log(2.0) + (4.0 / 3.0 + 104.0 / 45.0 * x) * x
return np.where(
self._cut_support_region(), log_constant_propose, taylor_expansion
)
def np_variance(self):
cut_probs = self._cut_probs()
tmp = np.divide(
np.square(cut_probs) - cut_probs, np.square(1.0 - 2.0 * cut_probs)
)
propose = tmp + np.divide(
1.0, np.square(2.0 * self._tanh_inverse(1.0 - 2.0 * cut_probs))
)
x = np.square(self.probs - 0.5)
taylor_expansion = 1.0 / 12.0 - (1.0 / 15.0 - 128.0 / 945.0 * x) * x
return np.where(self._cut_support_region(), propose, taylor_expansion)
def np_mean(self):
cut_probs = self._cut_probs()
tmp = cut_probs / (2.0 * cut_probs - 1.0)
propose = tmp + 1.0 / (2.0 * self._tanh_inverse(1.0 - 2.0 * cut_probs))
x = self.probs - 0.5
taylor_expansion = 0.5 + (1.0 / 3.0 + 16.0 / 45.0 * np.square(x)) * x
return np.where(self._cut_support_region(), propose, taylor_expansion)
def np_entropy(self):
log_p = np.log(self.probs)
log_1_minus_p = np.log1p(-self.probs)
return np.where(
np.equal(self.probs, 0.5),
np.full_like(self.probs, 0.0),
(
-self._log_constant()
+ self.np_mean() * (log_1_minus_p - log_p)
- log_1_minus_p
),
)
def np_prob(self, value):
return np.exp(self.np_log_prob(value))
def np_log_prob(self, value):
eps = 1e-8
cross_entropy = np.nan_to_num(
value * np.log(self.probs) + (1.0 - value) * np.log(1 - self.probs),
neginf=-eps,
)
return self._log_constant() + cross_entropy
def np_cdf(self, value):
cut_probs = self._cut_probs()
cdfs = (
np.power(cut_probs, value) * np.power(1.0 - cut_probs, 1.0 - value)
+ cut_probs
- 1.0
) / (2.0 * cut_probs - 1.0)
unbounded_cdfs = np.where(self._cut_support_region(), cdfs, value)
return np.where(
np.less_equal(value, 0.0),
np.zeros_like(value),
np.where(
np.greater_equal(value, 1.0),
np.ones_like(value),
unbounded_cdfs,
),
)
def np_icdf(self, value):
cut_probs = self._cut_probs()
return np.where(
self._cut_support_region(),
(
np.log1p(-cut_probs + value * (2.0 * cut_probs - 1.0))
- np.log1p(-cut_probs)
)
/ (np.log(cut_probs) - np.log1p(-cut_probs)),
value,
)
def np_kl_divergence(self, other):
part1 = -self.np_entropy()
log_q = np.log(other.probs)
log_1_minus_q = np.log1p(-other.probs)
part2 = -(
other._log_constant()
+ self.np_mean() * (log_q - log_1_minus_q)
+ log_1_minus_q
)
return part1 + part2
paddle.enable_static()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'probs'),
[
(
'zero-dim',
np.array(0.7).astype("float32"),
),
(
'multi-dim',
parameterize.xrand((1, 3), min=0.0, max=1.0).astype("float32"),
),
],
)
class TestContinuousBernoulli(unittest.TestCase):
def setUp(self):
self._np_dist = ContinuousBernoulli_np(self.probs)
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
probs = paddle.static.data(
'probs', self.probs.shape, self.probs.dtype
)
dist = ContinuousBernoulli(probs, lims=(0.48, 0.52))
mean = dist.mean
var = dist.variance
entropy = dist.entropy()
large_samples = dist.sample(shape=(50000,))
fetch_list = [mean, var, entropy, large_samples]
feed = {'probs': self.probs}
executor.run(startup_program)
[
self.mean,
self.var,
self.entropy,
self.large_samples,
] = executor.run(main_program, feed=feed, fetch_list=fetch_list)
def test_mean(self):
self.assertEqual(str(self.mean.dtype).split('.')[-1], self.probs.dtype)
np.testing.assert_allclose(
self.mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_variance(self):
self.assertEqual(str(self.var.dtype).split('.')[-1], self.probs.dtype)
np.testing.assert_allclose(
self.var,
self._np_variance(),
rtol=0.01,
atol=0.0,
)
def test_entropy(self):
self.assertEqual(
str(self.entropy.dtype).split('.')[-1], self.probs.dtype
)
np.testing.assert_allclose(
self.entropy,
self._np_entropy(),
rtol=0.01,
atol=0.0,
)
def test_sample(self):
sample_mean = self.large_samples.mean(axis=0)
sample_variance = self.large_samples.var(axis=0)
np.testing.assert_allclose(sample_mean, self.mean, atol=0, rtol=0.1)
np.testing.assert_allclose(sample_variance, self.var, atol=0, rtol=0.1)
def _np_variance(self):
return self._np_dist.np_variance()
def _np_mean(self):
return self._np_dist.np_mean()
def _np_entropy(self):
return self._np_dist.np_entropy()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'probs', 'value'),
[
(
'value-broadcast-shape',
parameterize.xrand((1,), min=0.0, max=1.0).astype("float32"),
parameterize.xrand((2, 2), min=0.0, max=1.0).astype("float64"),
),
],
)
class TestContinuousBernoulliProbs(unittest.TestCase):
def setUp(self):
self._np_dist = ContinuousBernoulli_np(self.probs)
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
probs = paddle.static.data(
'probs', self.probs.shape, self.probs.dtype
)
value = paddle.static.data(
'value', self.value.shape, self.value.dtype
)
dist = ContinuousBernoulli(probs, lims=(0.48, 0.52))
pmf = dist.prob(value)
feed = {'probs': self.probs, 'value': self.value}
fetch_list = [pmf]
executor.run(startup_program)
[self.pmf] = executor.run(
main_program, feed=feed, fetch_list=fetch_list
)
def test_prob(self):
np.testing.assert_allclose(
self.pmf,
self._np_dist.np_prob(self.value),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'p_1', 'p_2'),
[
(
'multi-dim',
parameterize.xrand((2,), min=0.0, max=1.0).astype("float32"),
parameterize.xrand((2,), min=0.0, max=1.0).astype("float32"),
),
],
)
class TestContinuousBernoulliKL(unittest.TestCase):
def setUp(self):
self._np_dist1 = ContinuousBernoulli_np(self.p_1)
self._np_dist2 = ContinuousBernoulli_np(self.p_2)
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
p_1 = paddle.static.data('p_1', self.p_1.shape)
p_2 = paddle.static.data('p_2', self.p_2.shape)
dist1 = ContinuousBernoulli(p_1, lims=(0.48, 0.52))
dist2 = ContinuousBernoulli(p_2, lims=(0.48, 0.52))
kl_dist1_dist2 = dist1.kl_divergence(dist2)
feed = {'p_1': self.p_1, 'p_2': self.p_2}
fetch_list = [kl_dist1_dist2]
executor.run(startup_program)
[self.kl_dist1_dist2] = executor.run(
main_program, feed=feed, fetch_list=fetch_list
)
def test_kl_divergence(self):
kl0 = self.kl_dist1_dist2
kl1 = self._np_dist1.np_kl_divergence(self._np_dist2)
self.assertEqual(tuple(kl0.shape), self.p_1.shape)
self.assertEqual(tuple(kl1.shape), self.p_1.shape)
np.testing.assert_allclose(
kl0,
kl1,
rtol=0.01,
atol=0.0,
)
if __name__ == '__main__':
unittest.main(argv=[''], verbosity=3, exit=False)
@@ -0,0 +1,123 @@
# 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 unittest
import numpy as np
import parameterize as param
import scipy.stats
from distribution.config import ATOL, DEVICES, RTOL
import paddle
np.random.seed(2022)
@param.place(DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'concentration'),
[
('test-one-dim', param.xrand((89,))),
# ('test-multi-dim', config.xrand((10, 20, 30)))
],
)
class TestDirichlet(unittest.TestCase):
def setUp(self):
self._paddle_diric = paddle.distribution.Dirichlet(
paddle.to_tensor(self.concentration)
)
def test_mean(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_diric.mean,
scipy.stats.dirichlet.mean(self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
def test_variance(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_diric.variance,
scipy.stats.dirichlet.var(self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
def test_prob(self):
value = [np.random.rand(*self.concentration.shape)]
value = [v / v.sum() for v in value]
for v in value:
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_diric.prob(paddle.to_tensor(v)),
scipy.stats.dirichlet.pdf(v, self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
def test_log_prob(self):
value = [np.random.rand(*self.concentration.shape)]
value = [v / v.sum() for v in value]
for v in value:
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_diric.log_prob(paddle.to_tensor(v)),
scipy.stats.dirichlet.logpdf(v, self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
def test_entropy(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_diric.entropy(),
scipy.stats.dirichlet.entropy(self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
def test_natural_parameters(self):
self.assertTrue(
isinstance(self._paddle_diric._natural_parameters, tuple)
)
def test_log_normalizer(self):
self.assertTrue(
np.all(
self._paddle_diric._log_normalizer(
paddle.to_tensor(param.xrand((100, 100, 100)))
).numpy()
< 0.0
)
)
@param.place(DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'concentration'),
[('test-zero-dim', np.array(1.0))],
)
class TestDirichletException(unittest.TestCase):
def TestInit(self):
with self.assertRaises(ValueError):
paddle.distribution.Dirichlet(
paddle.squeeze(self.concentration)
)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,122 @@
# 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 unittest
import numpy as np
import scipy.stats
from distribution.config import ATOL, DEVICES, RTOL
from parameterize import TEST_CASE_NAME, parameterize_cls, place
import paddle
np.random.seed(2022)
paddle.enable_static()
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'concentration'),
[('test-one-dim', np.random.rand(89) + 5.0)],
)
class TestDirichlet(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor()
with paddle.static.program_guard(self.program):
conc = paddle.static.data(
'conc', self.concentration.shape, self.concentration.dtype
)
self._paddle_diric = paddle.distribution.Dirichlet(conc)
self.feeds = {'conc': self.concentration}
def test_mean(self):
with paddle.static.program_guard(self.program):
[out] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_diric.mean],
)
np.testing.assert_allclose(
out,
scipy.stats.dirichlet.mean(self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
def test_variance(self):
with paddle.static.program_guard(self.program):
[out] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_diric.variance],
)
np.testing.assert_allclose(
out,
scipy.stats.dirichlet.var(self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
def test_prob(self):
with paddle.static.program_guard(self.program):
random_number = np.random.rand(*self.concentration.shape)
random_number = random_number / random_number.sum()
feeds = dict(self.feeds, value=random_number)
value = paddle.static.data(
'value', random_number.shape, random_number.dtype
)
out = self._paddle_diric.prob(value)
[out] = self.executor.run(
self.program, feed=feeds, fetch_list=[out]
)
np.testing.assert_allclose(
out,
scipy.stats.dirichlet.pdf(random_number, self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
def test_log_prob(self):
with paddle.static.program_guard(self.program):
random_number = np.random.rand(*self.concentration.shape)
random_number = random_number / random_number.sum()
feeds = dict(self.feeds, value=random_number)
value = paddle.static.data(
'value', random_number.shape, random_number.dtype
)
out = self._paddle_diric.log_prob(value)
[out] = self.executor.run(
self.program, feed=feeds, fetch_list=[out]
)
np.testing.assert_allclose(
out,
scipy.stats.dirichlet.logpdf(random_number, self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
def test_entropy(self):
with paddle.static.program_guard(self.program):
[out] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_diric.entropy()],
)
np.testing.assert_allclose(
out,
scipy.stats.dirichlet.entropy(self.concentration),
rtol=RTOL.get(str(self.concentration.dtype)),
atol=ATOL.get(str(self.concentration.dtype)),
)
@@ -0,0 +1,76 @@
# 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 unittest
import mock_data as mock
import numpy as np
import parameterize
from distribution import config
import paddle
np.random.seed(2022)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'dist'),
[
(
'test-mock-exp',
mock.Exponential(
rate=paddle.rand([100, 200, 99], dtype=config.DEFAULT_DTYPE)
),
)
],
)
class TestExponentialFamily(unittest.TestCase):
def test_entropy(self):
np.testing.assert_allclose(
self.dist.entropy(),
paddle.distribution.ExponentialFamily.entropy(self.dist),
rtol=config.RTOL.get(config.DEFAULT_DTYPE),
atol=config.ATOL.get(config.DEFAULT_DTYPE),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(config.TEST_CASE_NAME, 'dist'),
[
('test-dummy', mock.DummyExpFamily(0.5, 0.5)),
(
'test-dirichlet',
paddle.distribution.Dirichlet(
paddle.to_tensor(parameterize.xrand())
),
),
(
'test-beta',
paddle.distribution.Beta(
paddle.to_tensor(parameterize.xrand()),
paddle.to_tensor(parameterize.xrand()),
),
),
],
)
class TestExponentialFamilyException(unittest.TestCase):
def test_entropy_exception(self):
with self.assertRaises(NotImplementedError):
paddle.distribution.ExponentialFamily.entropy(self.dist)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,70 @@
# 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 unittest
import mock_data as mock
import numpy as np
import parameterize
from distribution import config
import paddle
np.random.seed(2022)
paddle.enable_static()
@parameterize.place(config.DEVICES)
class TestExponentialFamily(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor()
with paddle.static.program_guard(self.program):
rate_np = parameterize.xrand((100, 200, 99))
rate = paddle.static.data('rate', rate_np.shape, rate_np.dtype)
self.mock_dist = mock.Exponential(rate)
self.feeds = {'rate': rate_np}
def test_entropy(self):
with paddle.static.program_guard(self.program):
[out1, out2] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[
self.mock_dist.entropy(),
paddle.distribution.ExponentialFamily.entropy(
self.mock_dist
),
],
)
np.testing.assert_allclose(
out1,
out2,
rtol=config.RTOL.get(config.DEFAULT_DTYPE),
atol=config.ATOL.get(config.DEFAULT_DTYPE),
)
def test_entropy_exception(self):
with (
paddle.static.program_guard(self.program),
self.assertRaises(NotImplementedError),
):
paddle.distribution.ExponentialFamily.entropy(
mock.DummyExpFamily(0.5, 0.5)
)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,370 @@
# Copyright (c) 2023 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 numbers
import unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import exponential, kl
np.random.seed(2023)
paddle.seed(2023)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate'),
[
(
'0-dim',
0.5,
),
(
'one-dim',
parameterize.xrand(
(4,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(10, 12),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestExponential(unittest.TestCase):
def setUp(self):
rate = self.rate
if not isinstance(self.rate, numbers.Real):
rate = paddle.to_tensor(self.rate, dtype=paddle.float32)
self.scale = 1 / rate
self._paddle_expon = exponential.Exponential(rate)
def test_mean(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_expon.mean,
scipy.stats.expon.mean(scale=self.scale),
rtol=config.RTOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
)
def test_variance(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_expon.variance,
scipy.stats.expon.var(scale=self.scale),
rtol=config.RTOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
)
def test_prob(self):
value = np.random.rand(*self._paddle_expon.rate.shape)
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_expon.prob(paddle.to_tensor(value)),
scipy.stats.expon.pdf(value, scale=self.scale),
rtol=config.RTOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
)
def test_cdf(self):
value = np.random.rand(*self._paddle_expon.rate.shape)
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_expon.cdf(paddle.to_tensor(value)),
scipy.stats.expon.cdf(value, scale=self.scale),
rtol=config.RTOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
)
def test_icdf(self):
value = np.random.rand(*self._paddle_expon.rate.shape)
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_expon.icdf(paddle.to_tensor(value)),
scipy.stats.expon.ppf(value, scale=self.scale),
rtol=config.RTOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
)
def test_entropy(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_expon.entropy(),
scipy.stats.expon.entropy(scale=self.scale),
rtol=config.RTOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate'),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestExponentialSample(unittest.TestCase):
def setUp(self):
rate = self.rate
if not isinstance(self.rate, numbers.Real):
rate = paddle.to_tensor(self.rate, dtype=paddle.float32)
self.scale = 1 / rate
self._paddle_expon = exponential.Exponential(rate)
def test_sample_shape(self):
cases = [
{
'input': (),
'expect': tuple(paddle.squeeze(self._paddle_expon.rate).shape),
},
{
'input': (3, 2),
'expect': (
3,
2,
*paddle.squeeze(self._paddle_expon.rate).shape,
),
},
]
for case in cases:
self.assertTrue(
tuple(self._paddle_expon.sample(case.get('input')).shape)
== case.get('expect')
)
def test_sample(self):
sample_shape = (20000,)
samples = self._paddle_expon.sample(sample_shape)
sample_values = samples.numpy()
self.assertEqual(sample_values.dtype, self.rate.dtype)
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.expon.mean(scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self._paddle_expon.rate.numpy().dtype)),
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.expon.var(scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self._paddle_expon.rate.numpy().dtype)),
)
def test_rsample_shape(self):
cases = [
{
'input': (),
'expect': tuple(paddle.squeeze(self._paddle_expon.rate).shape),
},
{
'input': (2, 5),
'expect': (
2,
5,
*paddle.squeeze(self._paddle_expon.rate).shape,
),
},
]
for case in cases:
self.assertTrue(
tuple(self._paddle_expon.rsample(case.get('input')).shape)
== case.get('expect')
)
def test_rsample(self):
sample_shape = (20000,)
samples = self._paddle_expon.rsample(sample_shape)
sample_values = samples.numpy()
self.assertEqual(sample_values.dtype, self.rate.dtype)
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.expon.mean(scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self._paddle_expon.rate.numpy().dtype)),
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.expon.var(scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self._paddle_expon.rate.numpy().dtype)),
)
def test_rsample_backpropagation(self):
sample_shape = (1000, 2)
with paddle.base.dygraph.guard(self.place):
self._paddle_expon.rate.stop_gradient = False
samples = self._paddle_expon.rsample(sample_shape)
grads = paddle.grad([samples], [self._paddle_expon.rate])
self.assertEqual(len(grads), 1)
self.assertEqual(grads[0].dtype, self._paddle_expon.rate.dtype)
self.assertEqual(grads[0].shape, self._paddle_expon.rate.shape)
axis = list(range(len(sample_shape)))
np.testing.assert_allclose(
-samples.sum(axis) / self._paddle_expon.rate,
grads[0],
rtol=config.RTOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_expon.rate.numpy().dtype)
),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate'),
[
('0-dim', 0.4),
],
)
class TestExponentialSampleKS(unittest.TestCase):
def setUp(self):
rate = paddle.to_tensor(self.rate, dtype=paddle.float32)
self.scale = rate.reciprocal()
self._paddle_expon = exponential.Exponential(rate)
def test_sample_ks(self):
sample_shape = (10000,)
samples = self._paddle_expon.sample(sample_shape)
self.assertTrue(self._kstest(samples))
def test_rsample_ks(self):
sample_shape = (10000,)
samples = self._paddle_expon.rsample(sample_shape)
self.assertTrue(self._kstest(samples))
def _kstest(self, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, _ = scipy.stats.kstest(
samples, scipy.stats.expon(scale=self.scale).cdf
)
return ks < 0.02
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate1', 'rate2'),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestExponentialKL(unittest.TestCase):
def setUp(self):
self._expon1 = exponential.Exponential(paddle.to_tensor(self.rate1))
self._expon2 = exponential.Exponential(paddle.to_tensor(self.rate2))
def test_kl_divergence(self):
np.testing.assert_allclose(
kl.kl_divergence(self._expon1, self._expon2),
self._kl(),
rtol=config.RTOL.get(str(self._expon1.rate.numpy().dtype)),
atol=config.ATOL.get(str(self._expon1.rate.numpy().dtype)),
)
def test_kl1_error(self):
self.assertRaises(
TypeError,
self._expon1.kl_divergence,
paddle.distribution.beta.Beta,
)
def _kl(self):
rate_ratio = self.rate2 / self.rate1
t1 = -np.log(rate_ratio)
return t1 + rate_ratio - 1
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,445 @@
# Copyright (c) 2023 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
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import exponential
np.random.seed(2023)
paddle.seed(2023)
paddle.enable_static()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate'),
[
(
'one-dim',
parameterize.xrand(
(4,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(10, 12),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestExponential(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.scale = 1 / self.rate
rate = paddle.static.data('rate', self.rate.shape, self.rate.dtype)
self._paddle_expon = exponential.Exponential(rate)
self.feeds = {'rate': self.rate}
def test_mean(self):
with paddle.static.program_guard(self.program):
[mean] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_expon.mean],
)
np.testing.assert_allclose(
mean,
scipy.stats.expon.mean(scale=self.scale),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_variance(self):
with paddle.static.program_guard(self.program):
[variance] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_expon.variance],
)
np.testing.assert_allclose(
variance,
scipy.stats.expon.var(scale=self.scale),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_entropy(self):
with paddle.static.program_guard(self.program):
[entropy] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_expon.entropy()],
)
np.testing.assert_allclose(
entropy,
scipy.stats.expon.entropy(scale=self.scale),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_prob(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_expon.rate.shape,
self._paddle_expon.rate.dtype,
)
prob = self._paddle_expon.prob(value)
random_number = np.random.rand(
*self._paddle_expon.rate.shape
).astype(self.rate.dtype)
feeds = dict(self.feeds, value=random_number)
[prob] = self.executor.run(
self.program, feed=feeds, fetch_list=[prob]
)
np.testing.assert_allclose(
prob,
scipy.stats.expon.pdf(random_number, scale=self.scale),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_log_prob(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_expon.rate.shape,
self._paddle_expon.rate.dtype,
)
log_prob = self._paddle_expon.log_prob(value)
random_number = np.random.rand(
*self._paddle_expon.rate.shape
).astype(self.rate.dtype)
feeds = dict(self.feeds, value=random_number)
[log_prob] = self.executor.run(
self.program, feed=feeds, fetch_list=[log_prob]
)
np.testing.assert_allclose(
log_prob,
scipy.stats.expon.logpdf(random_number, scale=self.scale),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_cdf(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_expon.rate.shape,
self._paddle_expon.rate.dtype,
)
cdf = self._paddle_expon.cdf(value)
random_number = np.random.rand(
*self._paddle_expon.rate.shape
).astype(self.rate.dtype)
feeds = dict(self.feeds, value=random_number)
[cdf] = self.executor.run(
self.program, feed=feeds, fetch_list=[cdf]
)
np.testing.assert_allclose(
cdf,
scipy.stats.expon.cdf(random_number, scale=self.scale),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_icdf(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_expon.rate.shape,
self._paddle_expon.rate.dtype,
)
icdf = self._paddle_expon.icdf(value)
random_number = np.random.rand(
*self._paddle_expon.rate.shape
).astype(self.rate.dtype)
feeds = dict(self.feeds, value=random_number)
[icdf] = self.executor.run(
self.program, feed=feeds, fetch_list=[icdf]
)
np.testing.assert_allclose(
icdf,
scipy.stats.expon.ppf(random_number, scale=self.scale),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate'),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestExponentialSample(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.scale = 1 / self.rate
rate = paddle.static.data('rate', self.rate.shape, self.rate.dtype)
self._paddle_expon = exponential.Exponential(rate)
self.feeds = {'rate': self.rate}
def test_sample_shape(self):
cases = [
{
'input': (),
'expect': tuple(np.squeeze(self.rate).shape),
},
{
'input': (4, 2),
'expect': (4, 2, *np.squeeze(self.rate).shape),
},
]
for case in cases:
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_expon.sample(case.get('input')),
)
self.assertTrue(data.shape == case.get('expect'))
def test_rsample_shape(self):
cases = [
{
'input': (),
'expect': tuple(np.squeeze(self.rate).shape),
},
{
'input': (3, 2),
'expect': (3, 2, *np.squeeze(self.rate).shape),
},
]
for case in cases:
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_expon.rsample(case.get('input')),
)
self.assertTrue(data.shape == case.get('expect'))
def test_sample(self):
sample_shape = (20000,)
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_expon.sample(sample_shape),
)
except_shape = sample_shape + np.squeeze(self.rate).shape
self.assertTrue(data.shape == except_shape)
np.testing.assert_allclose(
data.mean(axis=0),
scipy.stats.expon.mean(scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.rate.dtype)),
)
np.testing.assert_allclose(
data.var(axis=0),
scipy.stats.expon.var(scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_rsample(self):
sample_shape = (20000,)
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_expon.rsample(sample_shape),
)
except_shape = sample_shape + np.squeeze(self.rate).shape
self.assertTrue(data.shape == except_shape)
np.testing.assert_allclose(
data.mean(axis=0),
scipy.stats.expon.mean(scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.rate.dtype)),
)
np.testing.assert_allclose(
data.var(axis=0),
scipy.stats.expon.var(scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.rate.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate'),
[
('0-dim', 0.4),
],
)
class TestExponentialSampleKS(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.scale = 1 / self.rate
rate = paddle.static.data('rate', (), 'float')
self._paddle_expon = exponential.Exponential(rate)
self.feeds = {'rate': self.rate}
def test_sample(self):
sample_shape = (10000,)
with paddle.static.program_guard(self.program):
[samples] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_expon.sample(sample_shape),
)
self.assertTrue(self._kstest(samples))
def test_rsample(self):
sample_shape = (10000,)
with paddle.static.program_guard(self.program):
[samples] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_expon.rsample(sample_shape),
)
self.assertTrue(self._kstest(samples))
def _kstest(self, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, _ = scipy.stats.kstest(
samples, scipy.stats.expon(scale=self.scale).cdf
)
return ks < 0.02
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate1', 'rate2'),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestExponentialKL(unittest.TestCase):
def setUp(self):
self.program1 = paddle.static.Program()
self.program2 = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program1, self.program2):
rate1 = paddle.static.data(
'rate1', self.rate1.shape, self.rate1.dtype
)
rate2 = paddle.static.data(
'rate2', self.rate2.shape, self.rate2.dtype
)
self._expon1 = exponential.Exponential(rate1)
self._expon2 = exponential.Exponential(rate2)
self.feeds = {
'rate1': self.rate1,
'rate2': self.rate2,
}
def test_kl_divergence(self):
with paddle.static.program_guard(self.program1, self.program2):
self.executor.run(self.program2)
[kl] = self.executor.run(
self.program1,
feed=self.feeds,
fetch_list=[self._expon1.kl_divergence(self._expon2)],
)
np.testing.assert_allclose(
kl,
self._kl(),
rtol=config.RTOL.get(str(self.rate1.dtype)),
atol=config.ATOL.get(str(self.rate1.dtype)),
)
def test_kl1_error(self):
self.assertRaises(
TypeError,
self._expon1.kl_divergence,
paddle.distribution.beta.Beta,
)
def _kl(self):
rate_ratio = self.rate2 / self.rate1
t1 = -np.log(rate_ratio)
return t1 + rate_ratio - 1
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,467 @@
# Copyright (c) 2023 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 numbers
import unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import gamma, kl
np.random.seed(2023)
paddle.seed(2023)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'concentration', 'rate'),
[
(
'0-dim',
0.5,
0.5,
),
(
'one-dim',
parameterize.xrand(
(6,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(6,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(10, 12),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(10, 12),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'broadcast',
parameterize.xrand(
(4, 1),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(4, 6),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestGamma(unittest.TestCase):
def setUp(self):
concentration = self.concentration
if not isinstance(self.concentration, numbers.Real):
concentration = paddle.to_tensor(self.concentration)
rate = self.rate
if not isinstance(self.rate, numbers.Real):
rate = paddle.to_tensor(self.rate)
self.scale = 1 / rate
self._paddle_gamma = gamma.Gamma(concentration, rate)
def test_mean(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_gamma.mean,
scipy.stats.gamma.mean(self.concentration, scale=self.scale),
rtol=config.RTOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
)
def test_variance(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_gamma.variance,
scipy.stats.gamma.var(self.concentration, scale=self.scale),
rtol=config.RTOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
)
def test_prob(self):
value = np.random.rand(*self._paddle_gamma.rate.shape)
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_gamma.prob(paddle.to_tensor(value)),
scipy.stats.gamma.pdf(
value, self.concentration, scale=self.scale
),
rtol=config.RTOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
)
def test_log_prob(self):
value = np.random.rand(*self._paddle_gamma.rate.shape)
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_gamma.log_prob(paddle.to_tensor(value)),
scipy.stats.gamma.logpdf(
value, self.concentration, scale=self.scale
),
rtol=config.RTOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
)
def test_entropy(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_gamma.entropy(),
scipy.stats.gamma.entropy(self.concentration, scale=self.scale),
rtol=config.RTOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
atol=config.ATOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'concentration', 'rate'),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestGammaSample(unittest.TestCase):
def setUp(self):
concentration = self.concentration
if not isinstance(self.concentration, numbers.Real):
concentration = paddle.to_tensor(self.concentration)
rate = self.rate
if not isinstance(self.rate, numbers.Real):
rate = paddle.to_tensor(self.rate)
self.scale = 1 / rate
self._paddle_gamma = gamma.Gamma(concentration, rate)
def test_sample_shape(self):
cases = [
{
'input': (),
'expect': tuple(paddle.squeeze(self._paddle_gamma.rate).shape),
},
{
'input': (3, 2),
'expect': (
3,
2,
*paddle.squeeze(self._paddle_gamma.rate).shape,
),
},
]
for case in cases:
self.assertTrue(
tuple(self._paddle_gamma.sample(case.get('input')).shape)
== case.get('expect')
)
def test_rsample_shape(self):
cases = [
{
'input': (),
'expect': tuple(paddle.squeeze(self._paddle_gamma.rate).shape),
},
{
'input': (3, 2),
'expect': (
3,
2,
*paddle.squeeze(self._paddle_gamma.rate).shape,
),
},
]
for case in cases:
self.assertTrue(
tuple(self._paddle_gamma.rsample(case.get('input')).shape)
== case.get('expect')
)
def test_sample(self):
sample_shape = (30000,)
samples = self._paddle_gamma.sample(sample_shape)
sample_values = samples.numpy()
self.assertEqual(sample_values.dtype, self.rate.dtype)
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.gamma.mean(self.concentration, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.gamma.var(self.concentration, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
)
def test_rsample(self):
sample_shape = (30000,)
samples = self._paddle_gamma.rsample(sample_shape)
sample_values = samples.numpy()
self.assertEqual(sample_values.dtype, self.rate.dtype)
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.gamma.mean(self.concentration, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.gamma.var(self.concentration, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(
str(self._paddle_gamma.concentration.numpy().dtype)
),
)
@unittest.skip("TODO: implement standard_gamma grad op.")
def test_rsample_backpropagation(self):
sample_shape = (1000,)
with paddle.base.dygraph.guard(self.place):
self._paddle_gamma.concentration.stop_gradient = False
self._paddle_gamma.rate.stop_gradient = False
samples = self._paddle_gamma.rsample(sample_shape)
grads = paddle.grad(
[samples],
[self._paddle_gamma.concentration, self._paddle_gamma.rate],
)
self.assertEqual(len(grads), 2)
self.assertEqual(
grads[0].dtype, self._paddle_gamma.concentration.dtype
)
self.assertEqual(
grads[0].shape, self._paddle_gamma.concentration.shape
)
self.assertEqual(grads[1].dtype, self._paddle_gamma.rate.dtype)
self.assertEqual(grads[1].shape, self._paddle_gamma.rate.shape)
samples.backward()
self.assertEqual(
list(self._paddle_gamma.concentration.gradient().shape),
self._paddle_gamma.concentration.shape,
)
self.assertEqual(
list(self._paddle_gamma.rate.gradient().shape),
self._paddle_gamma.rate.shape,
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'concentration', 'rate'),
[
('0-dim', 0.4, 0.5),
],
)
class TestGammaSampleKS(unittest.TestCase):
def setUp(self):
concentration = self.concentration
if not isinstance(self.concentration, numbers.Real):
concentration = paddle.to_tensor(self.concentration)
rate = self.rate
if not isinstance(self.rate, numbers.Real):
rate = paddle.to_tensor(self.rate)
self.scale = 1 / rate
self._paddle_gamma = gamma.Gamma(concentration, rate)
def test_sample_ks(self):
sample_shape = (15000,)
samples = self._paddle_gamma.sample(sample_shape)
self.assertTrue(self._kstest(samples))
def test_rsample_ks(self):
sample_shape = (15000,)
samples = self._paddle_gamma.rsample(sample_shape)
self.assertTrue(self._kstest(samples))
def _kstest(self, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, _ = scipy.stats.kstest(
samples, scipy.stats.gamma(self.concentration, scale=self.scale).cdf
)
return ks < 0.02
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(
parameterize.TEST_CASE_NAME,
'concentration1',
'rate1',
'concentration2',
'rate2',
),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestGammaKL(unittest.TestCase):
def setUp(self):
self._gamma1 = gamma.Gamma(
paddle.to_tensor(self.concentration1), paddle.to_tensor(self.rate1)
)
self._gamma2 = gamma.Gamma(
paddle.to_tensor(self.concentration2), paddle.to_tensor(self.rate2)
)
def test_kl_divergence(self):
np.testing.assert_allclose(
kl.kl_divergence(self._gamma1, self._gamma2),
self._kl(),
rtol=config.RTOL.get(str(self._gamma1.concentration.numpy().dtype)),
atol=config.ATOL.get(str(self._gamma1.concentration.numpy().dtype)),
)
def test_kl1_error(self):
self.assertRaises(
TypeError,
self._gamma1.kl_divergence,
paddle.distribution.beta.Beta,
)
def _kl(self):
concentration1 = self.concentration1
concentration2 = self.concentration2
rate1 = self.rate1
rate2 = self.rate2
t1 = concentration2 * np.log(rate1 / rate2)
t2 = scipy.special.gammaln(concentration2) - scipy.special.gammaln(
concentration1
)
t3 = (concentration1 - concentration2) * scipy.special.digamma(
concentration1
)
t4 = (rate2 - rate1) * (concentration1 / rate1)
return t1 + t2 + t3 + t4
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,509 @@
# Copyright (c) 2023 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
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import gamma
np.random.seed(2023)
paddle.seed(2023)
paddle.enable_static()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'concentration', 'rate'),
[
(
'one-dim',
parameterize.xrand(
(6,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(6,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(10, 12),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(10, 12),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'broadcast',
parameterize.xrand(
(4, 1),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(4, 6),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestGamma(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.scale = 1 / self.rate
concentration = paddle.static.data(
'concentration',
self.concentration.shape,
self.concentration.dtype,
)
rate = paddle.static.data('rate', self.rate.shape, self.rate.dtype)
self._paddle_gamma = gamma.Gamma(concentration, rate)
self.feeds = {
'concentration': self.concentration,
'rate': self.rate,
}
def test_mean(self):
with paddle.static.program_guard(self.program):
[mean] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_gamma.mean],
)
np.testing.assert_allclose(
mean,
scipy.stats.gamma.mean(self.concentration, scale=self.scale),
rtol=config.RTOL.get(str(self.concentration.dtype)),
atol=config.ATOL.get(str(self.concentration.dtype)),
)
def test_variance(self):
with paddle.static.program_guard(self.program):
[variance] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_gamma.variance],
)
np.testing.assert_allclose(
variance,
scipy.stats.gamma.var(self.concentration, scale=self.scale),
rtol=config.RTOL.get(str(self.concentration.dtype)),
atol=config.ATOL.get(str(self.concentration.dtype)),
)
def test_entropy(self):
with paddle.static.program_guard(self.program):
[entropy] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_gamma.entropy()],
)
np.testing.assert_allclose(
entropy,
scipy.stats.gamma.entropy(self.concentration, scale=self.scale),
rtol=config.RTOL.get(str(self.concentration.dtype)),
atol=config.ATOL.get(str(self.concentration.dtype)),
)
def test_prob(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_gamma.concentration.shape,
self._paddle_gamma.concentration.dtype,
)
prob = self._paddle_gamma.prob(value)
random_number = np.random.rand(
*self._paddle_gamma.concentration.shape
).astype(self.concentration.dtype)
feeds = dict(self.feeds, value=random_number)
[prob] = self.executor.run(
self.program, feed=feeds, fetch_list=[prob]
)
np.testing.assert_allclose(
prob,
scipy.stats.gamma.pdf(
random_number, self.concentration, scale=self.scale
),
rtol=config.RTOL.get(str(self.concentration.dtype)),
atol=config.ATOL.get(str(self.concentration.dtype)),
)
def test_log_prob(self):
with paddle.static.program_guard(self.program):
value = paddle.static.data(
'value',
self._paddle_gamma.concentration.shape,
self._paddle_gamma.concentration.dtype,
)
log_prob = self._paddle_gamma.log_prob(value)
random_number = np.random.rand(
*self._paddle_gamma.concentration.shape
).astype(self.concentration.dtype)
feeds = dict(self.feeds, value=random_number)
[log_prob] = self.executor.run(
self.program, feed=feeds, fetch_list=[log_prob]
)
np.testing.assert_allclose(
log_prob,
scipy.stats.gamma.logpdf(
random_number, self.concentration, scale=self.scale
),
rtol=config.RTOL.get(str(self.concentration.dtype)),
atol=config.ATOL.get(str(self.concentration.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'concentration', 'rate'),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestGammaSample(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.scale = 1 / self.rate
concentration = paddle.static.data(
'concentration',
self.concentration.shape,
self.concentration.dtype,
)
rate = paddle.static.data('rate', self.rate.shape, self.rate.dtype)
self._paddle_gamma = gamma.Gamma(concentration, rate)
self.feeds = {
'concentration': self.concentration,
'rate': self.rate,
}
def test_sample_shape(self):
cases = [
{
'input': (),
'expect': tuple(np.squeeze(self.rate).shape),
},
{
'input': (4, 2),
'expect': (4, 2, *np.squeeze(self.rate).shape),
},
]
for case in cases:
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_gamma.sample(case.get('input')),
)
self.assertTrue(data.shape == case.get('expect'))
def test_rsample_shape(self):
cases = [
{
'input': (),
'expect': tuple(np.squeeze(self.rate).shape),
},
{
'input': (3, 2),
'expect': (3, 2, *np.squeeze(self.rate).shape),
},
]
for case in cases:
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_gamma.rsample(case.get('input')),
)
self.assertTrue(data.shape == case.get('expect'))
def test_sample(self):
sample_shape = (30000,)
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_gamma.sample(sample_shape),
)
except_shape = sample_shape + np.squeeze(self.rate).shape
self.assertTrue(data.shape == except_shape)
np.testing.assert_allclose(
data.mean(axis=0),
scipy.stats.gamma.mean(self.concentration, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.concentration.dtype)),
)
np.testing.assert_allclose(
data.var(axis=0),
scipy.stats.gamma.var(self.concentration, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.concentration.dtype)),
)
def test_rsample(self):
sample_shape = (30000,)
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_gamma.rsample(sample_shape),
)
except_shape = sample_shape + np.squeeze(self.rate).shape
self.assertTrue(data.shape == except_shape)
np.testing.assert_allclose(
data.mean(axis=0),
scipy.stats.gamma.mean(self.concentration, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.concentration.dtype)),
)
np.testing.assert_allclose(
data.var(axis=0),
scipy.stats.gamma.var(self.concentration, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.concentration.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'concentration', 'rate'),
[
('0-dim', 0.4, 0.5),
],
)
class TestGammaSampleKS(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.scale = 1 / self.rate
concentration = paddle.static.data(
'concentration',
(),
'float',
)
rate = paddle.static.data('rate', (), 'float')
self._paddle_gamma = gamma.Gamma(concentration, rate)
self.feeds = {
'concentration': self.concentration,
'rate': self.rate,
}
def test_sample(self):
sample_shape = (15000,)
with paddle.static.program_guard(self.program):
[samples] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_gamma.sample(sample_shape),
)
self.assertTrue(self._kstest(samples))
def test_rsample(self):
sample_shape = (15000,)
with paddle.static.program_guard(self.program):
[samples] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_gamma.rsample(sample_shape),
)
self.assertTrue(self._kstest(samples))
def _kstest(self, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, _ = scipy.stats.kstest(
samples, scipy.stats.gamma(self.concentration, scale=self.scale).cdf
)
return ks < 0.02
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(
parameterize.TEST_CASE_NAME,
'concentration1',
'rate1',
'concentration2',
'rate2',
),
[
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
(
'multi-dim',
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
parameterize.xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
),
),
],
)
class TestGammaKL(unittest.TestCase):
def setUp(self):
self.program1 = paddle.static.Program()
self.program2 = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program1, self.program2):
concentration1 = paddle.static.data(
'concentration1',
self.concentration1.shape,
self.concentration1.dtype,
)
concentration2 = paddle.static.data(
'concentration2',
self.concentration2.shape,
self.concentration2.dtype,
)
rate1 = paddle.static.data(
'rate1', self.rate1.shape, self.rate1.dtype
)
rate2 = paddle.static.data(
'rate2', self.rate2.shape, self.rate2.dtype
)
self._gamma1 = gamma.Gamma(concentration1, rate1)
self._gamma2 = gamma.Gamma(concentration2, rate2)
self.feeds = {
'concentration1': self.concentration1,
'concentration2': self.concentration2,
'rate1': self.rate1,
'rate2': self.rate2,
}
def test_kl_divergence(self):
with paddle.static.program_guard(self.program1, self.program2):
self.executor.run(self.program2)
[kl] = self.executor.run(
self.program1,
feed=self.feeds,
fetch_list=[self._gamma1.kl_divergence(self._gamma2)],
)
np.testing.assert_allclose(
kl,
self._kl(),
rtol=config.RTOL.get(str(self.concentration1.dtype)),
atol=config.ATOL.get(str(self.concentration1.dtype)),
)
def test_kl1_error(self):
self.assertRaises(
TypeError,
self._gamma1.kl_divergence,
paddle.distribution.beta.Beta,
)
def _kl(self):
concentration1 = self.concentration1
concentration2 = self.concentration2
rate1 = self.rate1
rate2 = self.rate2
t1 = concentration2 * np.log(rate1 / rate2)
t2 = scipy.special.gammaln(concentration2) - scipy.special.gammaln(
concentration1
)
t3 = (concentration1 - concentration2) * scipy.special.digamma(
concentration1
)
t4 = (rate2 - rate1) * (concentration1 / rate1)
return t1 + t2 + t3 + t4
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,350 @@
# Copyright (c) 2023 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 numbers
import unittest
import numpy as np
import scipy.stats
from distribution.config import ATOL, DEVICES, RTOL
from parameterize import TEST_CASE_NAME, parameterize_cls, place, xrand
import paddle
from paddle.distribution import geometric, kl
from paddle.nn.functional import log_softmax
np.random.seed(2023)
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'probs'),
[
(
'one-dim',
xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
),
(
'multi-dim',
xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
),
],
)
class TestGeometric(unittest.TestCase):
def setUp(self):
probs = self.probs
if not isinstance(self.probs, numbers.Real):
probs = paddle.to_tensor(self.probs, dtype=paddle.float32)
self._paddle_geom = geometric.Geometric(probs)
def test_mean(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_geom.mean,
scipy.stats.geom.mean(self.probs, loc=-1),
rtol=RTOL.get(str(self._paddle_geom.probs.numpy().dtype)),
atol=ATOL.get(str(self._paddle_geom.probs.numpy().dtype)),
)
def test_variance(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_geom.variance,
scipy.stats.geom.var(self.probs, loc=-1),
rtol=RTOL.get(str(self._paddle_geom.probs.numpy().dtype)),
atol=ATOL.get(str(self._paddle_geom.probs.numpy().dtype)),
)
def test_stddev(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_geom.stddev,
scipy.stats.geom.std(self.probs, loc=-1),
rtol=RTOL.get(str(self._paddle_geom.probs.numpy().dtype)),
atol=ATOL.get(str(self._paddle_geom.probs.numpy().dtype)),
)
def test_entropy(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_geom.entropy(),
scipy.stats.geom.entropy(self.probs, loc=-1),
rtol=RTOL.get(str(self._paddle_geom.probs.numpy().dtype)),
atol=ATOL.get(str(self._paddle_geom.probs.numpy().dtype)),
)
def test_init_prob_type_error(self):
with self.assertRaises(TypeError):
paddle.distribution.geometric.Geometric([2])
def test_sample_shape(self):
cases = [
{
'input': (),
'expect': tuple(paddle.squeeze(self._paddle_geom.probs).shape),
},
{
'input': (4, 2),
'expect': (
4,
2,
*paddle.squeeze(self._paddle_geom.probs).shape,
),
},
]
for case in cases:
self.assertTrue(
tuple(self._paddle_geom.sample(case.get('input')).shape)
== case.get('expect')
)
def test_sample(self):
sample_shape = (100000,)
samples = self._paddle_geom.sample(sample_shape)
sample_values = samples.numpy()
self.assertEqual(sample_values.dtype, self.probs.dtype)
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.geom.mean(self.probs, loc=-1),
rtol=0.1,
atol=ATOL.get(str(self._paddle_geom.probs.numpy().dtype)),
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.geom.var(self.probs, loc=-1),
rtol=0.1,
atol=ATOL.get(str(self._paddle_geom.probs.numpy().dtype)),
)
def test_rsample_shape(self):
cases = [
{
'input': (),
'expect': tuple(paddle.squeeze(self._paddle_geom.probs).shape),
},
{
'input': (2, 5),
'expect': (
2,
5,
*paddle.squeeze(self._paddle_geom.probs).shape,
),
},
]
for case in cases:
self.assertTrue(
tuple(self._paddle_geom.rsample(case.get('input')).shape)
== case.get('expect')
)
def test_rsample(self):
sample_shape = (100000,)
samples = self._paddle_geom.rsample(sample_shape)
sample_values = samples.numpy()
self.assertEqual(sample_values.dtype, self.probs.dtype)
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.geom.mean(self.probs, loc=-1),
rtol=0.1,
atol=ATOL.get(str(self._paddle_geom.probs.numpy().dtype)),
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.geom.var(self.probs, loc=-1),
rtol=0.1,
atol=ATOL.get(str(self._paddle_geom.probs.numpy().dtype)),
)
def test_back_rsample(self):
sample_shape = (100000,)
with paddle.base.dygraph.guard(self.place):
self._paddle_geom.probs.stop_gradient = False
rs_value = self._paddle_geom.rsample(sample_shape)
softmax_rs = log_softmax(rs_value)
grads = paddle.grad([softmax_rs], [self._paddle_geom.probs])
self.assertEqual(len(grads), 1)
self.assertEqual(grads[0].dtype, self._paddle_geom.probs.dtype)
self.assertEqual(grads[0].shape, self._paddle_geom.probs.shape)
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'probs', 'value'),
[
(
'one-dim',
xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
5,
),
(
'mult-dim',
xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
5,
),
(
'mult-dim',
xrand(
(2, 2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
5,
),
],
)
class TestGeometricPMF(unittest.TestCase):
def setUp(self):
self._paddle_geom = geometric.Geometric(
probs=paddle.to_tensor(self.probs)
)
def test_pmf(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_geom.pmf(self.value),
scipy.stats.geom.pmf(self.value, self.probs, loc=-1),
rtol=RTOL.get(str(self.probs.dtype)),
atol=ATOL.get(str(self.probs.dtype)),
)
def test_log_pmf(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_geom.log_pmf(self.value),
scipy.stats.geom.logpmf(self.value, self.probs, loc=-1),
rtol=RTOL.get(str(self.probs.dtype)),
atol=ATOL.get(str(self.probs.dtype)),
)
def test_cdf(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
self._paddle_geom.cdf(self.value),
scipy.stats.geom.cdf(self.value, self.probs, loc=-1),
rtol=RTOL.get(str(self._paddle_geom.probs.numpy().dtype)),
atol=ATOL.get(str(self._paddle_geom.probs.numpy().dtype)),
)
def test_pmf_error(self):
self.assertRaises(TypeError, self._paddle_geom.pmf, [1, 2])
def test_log_pmf_error(self):
self.assertRaises(TypeError, self._paddle_geom.log_pmf, [1, 2])
def test_cdf_error(self):
self.assertRaises(TypeError, self._paddle_geom.cdf, [1, 2])
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'probs1', 'probs2'),
[
(
'one-dim',
xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
),
(
'multi-dim',
xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
),
],
)
class TestGeometricKL(unittest.TestCase):
def setUp(self):
paddle.disable_static()
self._geometric1 = geometric.Geometric(
probs=paddle.to_tensor(self.probs1)
)
self._geometric2 = geometric.Geometric(
probs=paddle.to_tensor(self.probs2)
)
def test_kl_divergence(self):
np.testing.assert_allclose(
kl.kl_divergence(self._geometric1, self._geometric2),
self._kl(),
rtol=RTOL.get(str(self._geometric1.probs.numpy().dtype)),
atol=ATOL.get(str(self._geometric1.probs.numpy().dtype)),
)
def test_kl1_error(self):
self.assertRaises(
TypeError,
self._geometric1.kl_divergence,
paddle.distribution.beta.Beta,
)
def test_kl2_error(self):
self.assertRaises(
TypeError,
self._geometric2.kl_divergence,
paddle.distribution.beta.Beta,
)
def _kl(self):
return self.probs1 * np.log(self.probs1 / self.probs2) + (
1.0 - self.probs1
) * np.log((1.0 - self.probs1) / (1.0 - self.probs2))
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,346 @@
# Copyright (c) 2023 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
import numpy as np
import scipy.stats
from distribution.config import ATOL, DEVICES, RTOL
from parameterize import TEST_CASE_NAME, parameterize_cls, place, xrand
import paddle
from paddle.distribution import geometric
np.random.seed(2023)
paddle.enable_static()
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'probs'),
[
(
'one-dim',
xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
),
(
'multi-dim',
xrand(
(2, 3),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
),
],
)
class TestGeometric(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program):
# scale no need convert to tensor for scale input unittest
probs = paddle.static.data(
'probs', self.probs.shape, self.probs.dtype
)
self._paddle_geometric = geometric.Geometric(probs)
self.feeds = {'probs': self.probs}
def test_mean(self):
with paddle.static.program_guard(self.program):
[mean] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_geometric.mean],
)
np.testing.assert_allclose(
mean,
scipy.stats.geom.mean(self.probs, loc=-1),
rtol=RTOL.get(str(self.probs.dtype)),
atol=ATOL.get(str(self.probs.dtype)),
)
def test_variance(self):
with paddle.static.program_guard(self.program):
[variance] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_geometric.variance],
)
np.testing.assert_allclose(
variance,
scipy.stats.geom.var(self.probs, loc=-1),
rtol=RTOL.get(str(self.probs.dtype)),
atol=ATOL.get(str(self.probs.dtype)),
)
def test_stddev(self):
with paddle.static.program_guard(self.program):
[stddev] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_geometric.stddev],
)
np.testing.assert_allclose(
stddev,
scipy.stats.geom.std(self.probs, loc=-1),
rtol=RTOL.get(str(self.probs.dtype)),
atol=ATOL.get(str(self.probs.dtype)),
)
def test_sample(self):
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_geometric.sample(),
)
self.assertTrue(
data.shape == np.broadcast_arrays(self.probs)[0].shape
)
def test_rsample(self):
with paddle.static.program_guard(self.program):
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_geometric.rsample(),
)
self.assertTrue(
data.shape == np.broadcast_arrays(self.probs)[0].shape
)
def test_entropy(self):
with paddle.static.program_guard(self.program):
[entropy] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_geometric.entropy()],
)
np.testing.assert_allclose(
entropy,
scipy.stats.geom.entropy(self.probs, loc=-1),
rtol=RTOL.get(str(self.probs.dtype)),
atol=ATOL.get(str(self.probs.dtype)),
)
def test_init_prob_type_error(self):
with self.assertRaises(TypeError):
paddle.distribution.geometric.Geometric([0.5])
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'probs', 'value'),
[
(
'one-dim',
xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
5,
),
(
'mult-dim',
xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
5,
),
(
'mult-dim',
xrand(
(2, 2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
5,
),
],
)
class TestGeometricPMF(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program):
probs = paddle.static.data(
'probs', self.probs.shape, self.probs.dtype
)
self._paddle_geometric = geometric.Geometric(probs)
self.feeds = {'probs': self.probs, 'value': self.value}
def test_pmf(self):
with paddle.static.program_guard(self.program):
[pmf] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_geometric.pmf(self.value)],
)
np.testing.assert_allclose(
pmf,
scipy.stats.geom.pmf(self.value, self.probs, loc=-1),
rtol=RTOL.get(str(self.probs.dtype)),
atol=ATOL.get(str(self.probs.dtype)),
)
def test_log_pmf(self):
with paddle.static.program_guard(self.program):
[log_pmf] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_geometric.log_pmf(self.value)],
)
np.testing.assert_allclose(
log_pmf,
scipy.stats.geom.logpmf(self.value, self.probs, loc=-1),
rtol=RTOL.get(str(self.probs.dtype)),
atol=ATOL.get(str(self.probs.dtype)),
)
def test_cdf(self):
with paddle.static.program_guard(self.program):
[cdf] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=[self._paddle_geometric.cdf(self.value)],
)
np.testing.assert_allclose(
cdf,
scipy.stats.geom.cdf(self.value, self.probs, loc=-1),
rtol=RTOL.get(str(self.probs.dtype)),
atol=ATOL.get(str(self.probs.dtype)),
)
def test_pmf_error(self):
self.assertRaises(TypeError, self._paddle_geometric.pmf, [1, 2])
def test_log_pmf_error(self):
self.assertRaises(TypeError, self._paddle_geometric.log_pmf, [1, 2])
def test_cdf_error(self):
self.assertRaises(TypeError, self._paddle_geometric.cdf, [1, 2])
@place(DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'probs1', 'probs2'),
[
(
'one-dim',
xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
xrand(
(2,),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
),
(
'multi-dim',
xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
xrand(
(2, 2),
dtype='float32',
min=np.finfo(dtype='float32').tiny,
max=1.0,
),
),
],
)
class TestGeometricKL(unittest.TestCase):
def setUp(self):
paddle.enable_static()
self.program_p = paddle.static.Program()
self.program_q = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program_p, self.program_q):
probs_p = paddle.static.data(
'probs1', self.probs1.shape, self.probs1.dtype
)
probs_q = paddle.static.data(
'probs2', self.probs2.shape, self.probs2.dtype
)
self._paddle_geomP = geometric.Geometric(probs_p)
self._paddle_geomQ = geometric.Geometric(probs_q)
self.feeds = {
'probs1': self.probs1,
'probs2': self.probs2,
}
def test_kl_divergence(self):
with paddle.static.program_guard(self.program_p, self.program_q):
self.executor.run(self.program_q)
[kl_diver] = self.executor.run(
self.program_p,
feed=self.feeds,
fetch_list=[
self._paddle_geomP.kl_divergence(self._paddle_geomQ)
],
)
np.testing.assert_allclose(
kl_diver,
self._kl(),
rtol=RTOL.get(str(self.probs1.dtype)),
atol=ATOL.get(str(self.probs1.dtype)),
)
def test_kl1_error(self):
self.assertRaises(
TypeError,
self._paddle_geomP.kl_divergence,
paddle.distribution.beta.Beta,
)
def test_kl2_error(self):
self.assertRaises(
TypeError,
self._paddle_geomQ.kl_divergence,
paddle.distribution.beta.Beta,
)
def _kl(self):
return self.probs1 * np.log(self.probs1 / self.probs2) + (
1.0 - self.probs1
) * np.log((1.0 - self.probs1) / (1.0 - self.probs2))
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,184 @@
# Copyright (c) 2022 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
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution.gumbel import Gumbel
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale'),
[
('one-dim', parameterize.xrand((4,)), parameterize.xrand((4,))),
('multi-dim', parameterize.xrand((5, 3)), parameterize.xrand((5, 3))),
],
)
class TestGumbel(unittest.TestCase):
def setUp(self):
self._dist = Gumbel(
loc=paddle.to_tensor(self.loc), scale=paddle.to_tensor(self.scale)
)
def test_mean(self):
mean = self._dist.mean
self.assertEqual(mean.numpy().dtype, self._np_mean().dtype)
np.testing.assert_allclose(
mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_variance(self):
var = self._dist.variance
self.assertEqual(var.numpy().dtype, self._np_variance().dtype)
np.testing.assert_allclose(
var,
self._np_variance(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_stddev(self):
stddev = self._dist.stddev
self.assertEqual(stddev.numpy().dtype, self._np_stddev().dtype)
np.testing.assert_allclose(
stddev,
self._np_stddev(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_entropy(self):
entropy = self._dist.entropy()
self.assertEqual(entropy.numpy().dtype, self._np_entropy().dtype)
np.testing.assert_allclose(
entropy,
self._np_entropy(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_sample(self):
sample_shape = [10000]
samples = self._dist.sample(sample_shape)
sample_values = samples.numpy()
self.assertEqual(sample_values.dtype, self.scale.dtype)
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.gumbel_r.mean(self.loc, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.loc.dtype)),
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.gumbel_r.var(self.loc, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_rsample(self):
sample_shape = [10000]
samples = self._dist.rsample(sample_shape)
sample_values = samples.numpy()
self.assertEqual(sample_values.dtype, self.scale.dtype)
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.gumbel_r.mean(self.loc, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.loc.dtype)),
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.gumbel_r.var(self.loc, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.loc.dtype)),
)
def _np_mean(self):
return self.loc + self.scale * np.euler_gamma
def _np_stddev(self):
return np.sqrt(self._np_variance())
def _np_variance(self):
return np.divide(
np.multiply(np.power(self.scale, 2), np.power(np.pi, 2)), 6
)
def _np_entropy(self):
return np.log(self.scale) + 1 + np.euler_gamma
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale', 'value'),
[
(
'value-float',
np.array([0.1, 0.4]),
np.array([1.0, 4.0]),
np.array([3.0, 7.0]),
),
('value-int', np.array([0.1, 0.4]), np.array([1, 4]), np.array([3, 7])),
(
'value-multi-dim',
np.array([0.1, 0.4]),
np.array([1, 4]),
np.array([[5.0, 4], [6, 2]]),
),
],
)
class TestGumbelPDF(unittest.TestCase):
def setUp(self):
self._dist = Gumbel(
loc=paddle.to_tensor(self.loc), scale=paddle.to_tensor(self.scale)
)
def test_prob(self):
np.testing.assert_allclose(
self._dist.prob(paddle.to_tensor(self.value)),
scipy.stats.gumbel_r.pdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_log_prob(self):
np.testing.assert_allclose(
self._dist.log_prob(paddle.to_tensor(self.value)),
scipy.stats.gumbel_r.logpdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_cdf(self):
np.testing.assert_allclose(
self._dist.cdf(paddle.to_tensor(self.value)),
scipy.stats.gumbel_r.cdf(self.value, self.loc, self.scale),
rtol=0.02,
atol=config.ATOL.get(str(self.loc.dtype)),
)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,201 @@
# Copyright (c) 2022 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
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution.gumbel import Gumbel
paddle.enable_static()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale'),
[
('one-dim', parameterize.xrand((4,)), parameterize.xrand((4,))),
('multi-dim', parameterize.xrand((5, 3)), parameterize.xrand((5, 3))),
],
)
class TestGumbel(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
loc = paddle.static.data('loc', self.loc.shape, self.loc.dtype)
scale = paddle.static.data(
'scale', self.scale.shape, self.scale.dtype
)
self._dist = Gumbel(loc=loc, scale=scale)
self.sample_shape = [50000]
mean = self._dist.mean
var = self._dist.variance
stddev = self._dist.stddev
entropy = self._dist.entropy()
samples = self._dist.sample(self.sample_shape)
fetch_list = [mean, var, stddev, entropy, samples]
self.feeds = {'loc': self.loc, 'scale': self.scale}
executor.run(startup_program)
[
self.mean,
self.var,
self.stddev,
self.entropy,
self.samples,
] = executor.run(main_program, feed=self.feeds, fetch_list=fetch_list)
def test_mean(self):
self.assertEqual(str(self.mean.dtype).split('.')[-1], self.scale.dtype)
np.testing.assert_allclose(
self.mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_variance(self):
self.assertEqual(str(self.var.dtype).split('.')[-1], self.scale.dtype)
np.testing.assert_allclose(
self.var,
self._np_variance(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_stddev(self):
self.assertEqual(
str(self.stddev.dtype).split('.')[-1], self.scale.dtype
)
np.testing.assert_allclose(
self.stddev,
self._np_stddev(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_entropy(self):
self.assertEqual(
str(self.entropy.dtype).split('.')[-1], self.scale.dtype
)
def test_sample(self):
self.assertEqual(self.samples.dtype, self.scale.dtype)
np.testing.assert_allclose(
self.samples.mean(axis=0),
scipy.stats.gumbel_r.mean(self.loc, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.scale.dtype)),
)
np.testing.assert_allclose(
self.samples.var(axis=0),
scipy.stats.gumbel_r.var(self.loc, scale=self.scale),
rtol=0.1,
atol=config.ATOL.get(str(self.scale.dtype)),
)
def _np_mean(self):
return self.loc + self.scale * np.euler_gamma
def _np_stddev(self):
return np.sqrt(self._np_variance())
def _np_variance(self):
return np.divide(
np.multiply(np.power(self.scale, 2), np.power(np.pi, 2)), 6
)
def _np_entropy(self):
return np.log(self.scale) + 1 + np.euler_gamma
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale', 'value'),
[
(
'value-float',
np.array([0.1, 0.4]),
np.array([1.0, 4.0]),
np.array([3.0, 7.0]),
),
('value-int', np.array([0.1, 0.4]), np.array([1, 4]), np.array([3, 7])),
(
'value-multi-dim',
np.array([0.1, 0.4]),
np.array([1, 4]),
np.array([[5.0, 4], [6, 2]]),
),
],
)
class TestGumbelPDF(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
loc = paddle.static.data('loc', self.loc.shape, self.loc.dtype)
scale = paddle.static.data(
'scale', self.scale.shape, self.scale.dtype
)
value = paddle.static.data(
'value', self.value.shape, self.value.dtype
)
self._dist = Gumbel(loc=loc, scale=scale)
prob = self._dist.prob(value)
log_prob = self._dist.log_prob(value)
cdf = self._dist.cdf(value)
fetch_list = [prob, log_prob, cdf]
self.feeds = {'loc': self.loc, 'scale': self.scale, 'value': self.value}
executor.run(startup_program)
[self.prob, self.log_prob, self.cdf] = executor.run(
main_program, feed=self.feeds, fetch_list=fetch_list
)
def test_prob(self):
np.testing.assert_allclose(
self.prob,
scipy.stats.gumbel_r.pdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_log_prob(self):
np.testing.assert_allclose(
self.log_prob,
scipy.stats.gumbel_r.logpdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_cdf(self):
np.testing.assert_allclose(
self.cdf,
scipy.stats.gumbel_r.cdf(self.value, self.loc, self.scale),
rtol=0.3,
atol=config.ATOL.get(str(self.loc.dtype)),
)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,119 @@
# 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 unittest
import numpy as np
import parameterize as param
from distribution import config
import paddle
np.random.seed(2022)
@param.place(config.DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'base', 'reinterpreted_batch_rank'),
[
(
'base_beta',
paddle.distribution.Beta(paddle.rand([1, 2]), paddle.rand([1, 2])),
1,
)
],
)
class TestIndependent(unittest.TestCase):
def setUp(self):
self._t = paddle.distribution.Independent(
self.base, self.reinterpreted_batch_rank
)
def test_mean(self):
np.testing.assert_allclose(
self.base.mean,
self._t.mean,
rtol=config.RTOL.get(str(self.base.alpha.numpy().dtype)),
atol=config.ATOL.get(str(self.base.alpha.numpy().dtype)),
)
def test_variance(self):
np.testing.assert_allclose(
self.base.variance,
self._t.variance,
rtol=config.RTOL.get(str(self.base.alpha.numpy().dtype)),
atol=config.ATOL.get(str(self.base.alpha.numpy().dtype)),
)
def test_entropy(self):
np.testing.assert_allclose(
self._np_sum_rightmost(
self.base.entropy().numpy(), self.reinterpreted_batch_rank
),
self._t.entropy(),
rtol=config.RTOL.get(str(self.base.alpha.numpy().dtype)),
atol=config.ATOL.get(str(self.base.alpha.numpy().dtype)),
)
def _np_sum_rightmost(self, value, n):
return np.sum(value, tuple(range(-n, 0))) if n > 0 else value
def test_log_prob(self):
value = np.random.rand(1)
np.testing.assert_allclose(
self._np_sum_rightmost(
self.base.log_prob(paddle.to_tensor(value)).numpy(),
self.reinterpreted_batch_rank,
),
self._t.log_prob(paddle.to_tensor(value)).numpy(),
rtol=config.RTOL.get(str(self.base.alpha.numpy().dtype)),
atol=config.ATOL.get(str(self.base.alpha.numpy().dtype)),
)
# TODO(cxxly): Add Kolmogorov-Smirnov test for sample result.
def test_sample(self):
shape = (5, 10, 8)
expected_shape = (5, 10, 8, 1, 2)
data = self._t.sample(shape)
self.assertEqual(tuple(data.shape), expected_shape)
self.assertEqual(data.dtype, self.base.alpha.dtype)
@param.place(config.DEVICES)
@param.param_cls(
(
param.TEST_CASE_NAME,
'base',
'reinterpreted_batch_rank',
'expected_exception',
),
[
('base_not_transform', '', 1, TypeError),
(
'rank_less_than_zero',
paddle.distribution.Transform(),
-1,
ValueError,
),
],
)
class TestIndependentException(unittest.TestCase):
def test_init(self):
with self.assertRaises(self.expected_exception):
paddle.distribution.IndependentTransform(
self.base, self.reinterpreted_batch_rank
)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,133 @@
# 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 unittest
import numpy as np
import parameterize as param
from distribution import config
import paddle
np.random.seed(2022)
paddle.enable_static()
@param.place(config.DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'base', 'reinterpreted_batch_rank', 'alpha', 'beta'),
[
(
'base_beta',
paddle.distribution.Beta,
1,
np.random.rand(1, 2),
np.random.rand(1, 2),
)
],
)
class TestIndependent(unittest.TestCase):
def setUp(self):
value = np.random.rand(1)
self.dtype = value.dtype
exe = paddle.static.Executor()
sp = paddle.static.Program()
mp = paddle.static.Program()
with paddle.static.program_guard(mp, sp):
alpha = paddle.static.data(
'alpha', self.alpha.shape, self.alpha.dtype
)
beta = paddle.static.data('beta', self.beta.shape, self.beta.dtype)
self.base = self.base(alpha, beta)
t = paddle.distribution.Independent(
self.base, self.reinterpreted_batch_rank
)
mean = t.mean
variance = t.variance
entropy = t.entropy()
static_value = paddle.static.data('value', value.shape, value.dtype)
log_prob = t.log_prob(static_value)
base_mean = self.base.mean
base_variance = self.base.variance
base_entropy = self.base.entropy()
base_log_prob = self.base.log_prob(static_value)
fetch_list = [
mean,
variance,
entropy,
log_prob,
base_mean,
base_variance,
base_entropy,
base_log_prob,
]
exe.run(sp)
[
self.mean,
self.variance,
self.entropy,
self.log_prob,
self.base_mean,
self.base_variance,
self.base_entropy,
self.base_log_prob,
] = exe.run(
mp,
feed={'value': value, 'alpha': self.alpha, 'beta': self.beta},
fetch_list=fetch_list,
)
def test_mean(self):
np.testing.assert_allclose(
self.mean,
self.base_mean,
rtol=config.RTOL.get(str(self.dtype)),
atol=config.ATOL.get(str(self.dtype)),
)
def test_variance(self):
np.testing.assert_allclose(
self.variance,
self.base_variance,
rtol=config.RTOL.get(str(self.dtype)),
atol=config.ATOL.get(str(self.dtype)),
)
def test_entropy(self):
np.testing.assert_allclose(
self._np_sum_rightmost(
self.base_entropy, self.reinterpreted_batch_rank
),
self.entropy,
rtol=config.RTOL.get(str(self.dtype)),
atol=config.ATOL.get(str(self.dtype)),
)
def _np_sum_rightmost(self, value, n):
return np.sum(value, tuple(range(-n, 0))) if n > 0 else value
def test_log_prob(self):
np.testing.assert_allclose(
self._np_sum_rightmost(
self.base_log_prob, self.reinterpreted_batch_rank
),
self.log_prob,
rtol=config.RTOL.get(str(self.dtype)),
atol=config.ATOL.get(str(self.dtype)),
)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,242 @@
# Copyright (c) 2022 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
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale'),
[
('one-dim', parameterize.xrand((2,)), parameterize.xrand((2,))),
('multi-dim', parameterize.xrand((5, 5)), parameterize.xrand((5, 5))),
],
)
class TestLaplace(unittest.TestCase):
def setUp(self):
self._dist = paddle.distribution.Laplace(
loc=paddle.to_tensor(self.loc), scale=paddle.to_tensor(self.scale)
)
def test_mean(self):
mean = self._dist.mean
self.assertEqual(mean.numpy().dtype, self.scale.dtype)
np.testing.assert_allclose(
mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_variance(self):
var = self._dist.variance
self.assertEqual(var.numpy().dtype, self.scale.dtype)
np.testing.assert_allclose(
var,
self._np_variance(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_stddev(self):
stddev = self._dist.stddev
self.assertEqual(stddev.numpy().dtype, self.scale.dtype)
np.testing.assert_allclose(
stddev,
self._np_stddev(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_entropy(self):
entropy = self._dist.entropy()
self.assertEqual(entropy.numpy().dtype, self.scale.dtype)
def test_sample(self):
sample_shape = (50000,)
samples = self._dist.sample(sample_shape)
sample_values = samples.numpy()
self.assertEqual(samples.numpy().dtype, self.scale.dtype)
self.assertEqual(
tuple(samples.shape), tuple(self._dist._extend_shape(sample_shape))
)
self.assertEqual(samples.shape, list(sample_shape + self.loc.shape))
self.assertEqual(sample_values.shape, sample_shape + self.loc.shape)
np.testing.assert_allclose(
sample_values.mean(axis=0),
scipy.stats.laplace.mean(self.loc, scale=self.scale),
rtol=0.2,
atol=0.0,
)
np.testing.assert_allclose(
sample_values.var(axis=0),
scipy.stats.laplace.var(self.loc, scale=self.scale),
rtol=0.1,
atol=0.0,
)
def _np_mean(self):
return self.loc
def _np_stddev(self):
return (2**0.5) * self.scale
def _np_variance(self):
stddev = (2**0.5) * self.scale
return np.power(stddev, 2)
def _np_entropy(self):
return scipy.stats.laplace.entropy(loc=self.loc, scale=self.scale)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale'),
[
('float', 1.0, 2.0),
('int', 3, 4),
],
)
class TestLaplaceKS(unittest.TestCase):
def setUp(self):
self._dist = paddle.distribution.Laplace(loc=self.loc, scale=self.scale)
def test_sample(self):
sample_shape = (20000,)
samples = self._dist.sample(sample_shape)
sample_values = samples.numpy()
self.assertTrue(self._kstest(self.loc, self.scale, sample_values))
def _kstest(self, loc, scale, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, p_value = scipy.stats.kstest(
samples, scipy.stats.laplace(loc, scale=scale).cdf
)
return ks < 0.02
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale', 'value'),
[
(
'value-float',
np.array([0.2, 0.3]),
np.array([2.0, 3.0]),
np.array([2.0, 5.0]),
),
(
'value-int',
np.array([0.2, 0.3]),
np.array([2.0, 3.0]),
np.array([2, 5]),
),
(
'value-multi-dim',
np.array([0.2, 0.3]),
np.array([2.0, 3.0]),
np.array([[4.0, 6], [8, 2]]),
),
],
)
class TestLaplacePDF(unittest.TestCase):
def setUp(self):
self._dist = paddle.distribution.Laplace(
loc=paddle.to_tensor(self.loc), scale=paddle.to_tensor(self.scale)
)
def test_prob(self):
np.testing.assert_allclose(
self._dist.prob(paddle.to_tensor(self.value)),
scipy.stats.laplace.pdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_log_prob(self):
np.testing.assert_allclose(
self._dist.log_prob(paddle.to_tensor(self.value)),
scipy.stats.laplace.logpdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_cdf(self):
np.testing.assert_allclose(
self._dist.cdf(paddle.to_tensor(self.value)),
scipy.stats.laplace.cdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_icdf(self):
np.testing.assert_allclose(
self._dist.icdf(paddle.to_tensor(self.value)),
scipy.stats.laplace.ppf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc1', 'scale1', 'loc2', 'scale2'),
[
(
'kl',
np.array([0.0]),
np.array([1.0]),
np.array([1.0]),
np.array([0.5]),
)
],
)
class TestLaplaceAndLaplaceKL(unittest.TestCase):
def setUp(self):
self._dist_1 = paddle.distribution.Laplace(
loc=paddle.to_tensor(self.loc1), scale=paddle.to_tensor(self.scale1)
)
self._dist_2 = paddle.distribution.Laplace(
loc=paddle.to_tensor(self.loc2), scale=paddle.to_tensor(self.scale2)
)
def test_kl_divergence(self):
np.testing.assert_allclose(
paddle.distribution.kl_divergence(self._dist_1, self._dist_2),
self._np_kl(),
atol=0,
rtol=0.50,
)
def _np_kl(self):
x = np.linspace(
scipy.stats.laplace.ppf(0.01), scipy.stats.laplace.ppf(0.99), 1000
)
d1 = scipy.stats.laplace.pdf(x, loc=0.0, scale=1.0)
d2 = scipy.stats.laplace.pdf(x, loc=1.0, scale=0.5)
return scipy.stats.entropy(d1, d2)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,343 @@
# Copyright (c) 2022 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
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
paddle.enable_static()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale'),
[
('one-dim', parameterize.xrand((2,)), parameterize.xrand((2,))),
('multi-dim', parameterize.xrand((5, 5)), parameterize.xrand((5, 5))),
],
test_pir=True,
)
class TestLaplace(unittest.TestCase):
def build_program(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
loc = paddle.static.data('loc', self.loc.shape, self.loc.dtype)
scale = paddle.static.data(
'scale', self.scale.shape, self.scale.dtype
)
self._dist = paddle.distribution.Laplace(loc=loc, scale=scale)
self.sample_shape = (50000,)
mean = self._dist.mean
var = self._dist.variance
stddev = self._dist.stddev
entropy = self._dist.entropy()
samples = self._dist.sample(self.sample_shape)
fetch_list = [mean, var, stddev, entropy, samples]
self.feeds = {'loc': self.loc, 'scale': self.scale}
executor.run(startup_program)
[
self.mean,
self.var,
self.stddev,
self.entropy,
self.samples,
] = executor.run(main_program, feed=self.feeds, fetch_list=fetch_list)
def setUp(self):
if self.test_pir:
with paddle.pir_utils.IrGuard():
self.build_program()
else:
self.build_program()
def test_mean(self):
self.assertEqual(str(self.mean.dtype).split('.')[-1], self.scale.dtype)
np.testing.assert_allclose(
self.mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_variance(self):
self.assertEqual(str(self.var.dtype).split('.')[-1], self.scale.dtype)
np.testing.assert_allclose(
self.var,
self._np_variance(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_stddev(self):
self.assertEqual(
str(self.stddev.dtype).split('.')[-1], self.scale.dtype
)
np.testing.assert_allclose(
self.stddev,
self._np_stddev(),
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_entropy(self):
self.assertEqual(
str(self.entropy.dtype).split('.')[-1], self.scale.dtype
)
def test_sample(self):
self.assertEqual(self.samples.dtype, self.scale.dtype)
self.assertEqual(
tuple(self.samples.shape),
tuple(self._dist._extend_shape(self.sample_shape)),
)
self.assertEqual(self.samples.shape, self.sample_shape + self.loc.shape)
self.assertEqual(self.samples.shape, self.sample_shape + self.loc.shape)
np.testing.assert_allclose(
self.samples.mean(axis=0),
scipy.stats.laplace.mean(self.loc, scale=self.scale),
rtol=0.2,
atol=0.0,
)
np.testing.assert_allclose(
self.samples.var(axis=0),
scipy.stats.laplace.var(self.loc, scale=self.scale),
rtol=0.1,
atol=0.0,
)
def _np_mean(self):
return self.loc
def _np_stddev(self):
return (2**0.5) * self.scale
def _np_variance(self):
stddev = (2**0.5) * self.scale
return np.power(stddev, 2)
def _np_entropy(self):
return scipy.stats.laplace.entropy(loc=self.loc, scale=self.scale)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale', 'value'),
[
(
'value-float',
np.array([0.2, 0.3]),
np.array([2.0, 3.0]),
np.array([2.0, 5.0]),
),
(
'value-int',
np.array([0.2, 0.3]),
np.array([2.0, 3.0]),
np.array([2, 5]),
),
(
'value-multi-dim',
np.array([0.2, 0.3]),
np.array([2.0, 3.0]),
np.array([[4.0, 6], [8, 2]]),
),
],
test_pir=True,
)
class TestLaplacePDF(unittest.TestCase):
def build_program(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
loc = paddle.static.data('loc', self.loc.shape, self.loc.dtype)
scale = paddle.static.data(
'scale', self.scale.shape, self.scale.dtype
)
value = paddle.static.data(
'value', self.value.shape, self.value.dtype
)
self._dist = paddle.distribution.Laplace(loc=loc, scale=scale)
prob = self._dist.prob(value)
log_prob = self._dist.log_prob(value)
cdf = self._dist.cdf(value)
icdf = self._dist.icdf(value)
fetch_list = [prob, log_prob, cdf, icdf]
self.feeds = {'loc': self.loc, 'scale': self.scale, 'value': self.value}
executor.run(startup_program)
[self.prob, self.log_prob, self.cdf, self.icdf] = executor.run(
main_program, feed=self.feeds, fetch_list=fetch_list
)
def setUp(self):
if self.test_pir:
with paddle.pir_utils.IrGuard():
self.build_program()
else:
self.build_program()
def test_prob(self):
np.testing.assert_allclose(
self.prob,
scipy.stats.laplace.pdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_log_prob(self):
np.testing.assert_allclose(
self.log_prob,
scipy.stats.laplace.logpdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_cdf(self):
np.testing.assert_allclose(
self.cdf,
scipy.stats.laplace.cdf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_icdf(self):
np.testing.assert_allclose(
self.icdf,
scipy.stats.laplace.ppf(self.value, self.loc, self.scale),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc1', 'scale1', 'loc2', 'scale2'),
[
(
'kl',
np.array([0.0]),
np.array([1.0]),
np.array([1.0]),
np.array([0.5]),
)
],
test_pir=True,
)
class TestLaplaceAndLaplaceKL(unittest.TestCase):
def build_program(self):
self.mp = paddle.static.Program()
self.sp = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.mp, self.sp):
loc1 = paddle.static.data('loc1', self.loc1.shape, self.loc1.dtype)
scale1 = paddle.static.data(
'scale1', self.scale1.shape, self.scale1.dtype
)
loc2 = paddle.static.data('loc2', self.loc2.shape, self.loc2.dtype)
scale2 = paddle.static.data(
'scale2', self.scale2.shape, self.scale2.dtype
)
self._dist_1 = paddle.distribution.Laplace(loc=loc1, scale=scale1)
self._dist_2 = paddle.distribution.Laplace(loc=loc2, scale=scale2)
self.feeds = {
'loc1': self.loc1,
'scale1': self.scale1,
'loc2': self.loc2,
'scale2': self.scale2,
}
def setUp(self):
if self.test_pir:
with paddle.pir_utils.IrGuard():
self.build_program()
else:
self.build_program()
def add_kl_divergence(self):
with paddle.static.program_guard(self.mp, self.sp):
out = paddle.distribution.kl_divergence(self._dist_1, self._dist_2)
self.executor.run(self.sp)
[out] = self.executor.run(
self.mp, feed=self.feeds, fetch_list=[out]
)
np.testing.assert_allclose(out, self._np_kl(), atol=0, rtol=0.50)
def test_kl_divergence(self):
if self.test_pir:
with paddle.pir_utils.IrGuard():
self.add_kl_divergence()
else:
self.add_kl_divergence()
def _np_kl(self):
x = np.linspace(
scipy.stats.laplace.ppf(0.01), scipy.stats.laplace.ppf(0.99), 1000
)
d1 = scipy.stats.laplace.pdf(x, loc=0.0, scale=1.0)
d2 = scipy.stats.laplace.pdf(x, loc=1.0, scale=0.5)
return scipy.stats.entropy(d1, d2)
"""
# Note: Zero dimension of a Tensor is not supported by static graph mode of paddle;
# therefore, ks test below cannot be conducted temporarily.
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'scale', 'sample_shape'), [
('one-dim', np.array(4.0), np.array(3.0), np.array([3000]))])
class TestLaplaceKS(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program):
loc = paddle.static.data('loc', self.loc.shape,
self.loc.dtype)
scale = paddle.static.data('scale', self.scale.shape,
self.scale.dtype)
self.sample = paddle.static.data('sample_shape', self.sample_shape.shape,
self.sample_shape.dtype)
self._dist = paddle.distribution.Laplace(loc=loc, scale=scale)
self.feeds = {'loc': self.loc, 'scale': self.scale, 'sample_shape': self.sample_shape}
def test_sample(self):
with paddle.static.program_guard(self.program):
[sample_values] = self.executor.run(self.program,
feed=self.feeds,
fetch_list=self._dist.sample((3000,)))
self.assertTrue(self._kstest(self.loc, self.scale, sample_values))
def _kstest(self, loc, scale, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, p_value = scipy.stats.kstest(
samples,
scipy.stats.laplace(loc, scale=scale).cdf)
return ks < 0.02
"""
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,188 @@
# 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.
import unittest
import numpy as np
import parameterize
from distribution import config
import paddle
from paddle.distribution import lkj_cholesky
from paddle.distribution.lkj_cholesky import (
tril_matrix_to_vec,
vec_to_tril_matrix,
)
np.random.seed(2024)
paddle.seed(2024)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'concentration'),
[
(
'zero-dim',
parameterize.xrand(
(1,),
dtype='float32',
max=1.0,
min=0,
).reshape([]),
),
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
max=1.0,
min=0,
),
),
(
'one-dim2',
parameterize.xrand(
(1,),
dtype='float32',
max=1.0,
min=0,
),
),
],
)
class TestLKJCholeskyShape(unittest.TestCase):
def gen_cases(self):
extra_shape = []
extra_shape.extend(self.concentration.shape)
extra_shape.extend(
[self._paddle_lkj_cholesky.dim, self._paddle_lkj_cholesky.dim]
)
cases = [
{
'input': (),
'expect': tuple(extra_shape),
},
]
return cases
def test_onion_sample_shape(self):
sample_method = 'onion'
self._test_sample_shape_dim(sample_method)
def test_cvine_sample_shape(self):
sample_method = 'cvine'
self._test_sample_shape_dim(sample_method)
def _test_sample_shape_dim(self, sample_method):
self._test_sample_shape(2, sample_method)
def _test_sample_shape(self, dim, sample_method):
self._paddle_lkj_cholesky = lkj_cholesky.LKJCholesky(
dim, self.concentration, sample_method
)
cases = self.gen_cases()
for case in cases:
data = self._paddle_lkj_cholesky.sample(case.get('input'))
self.assertTrue(tuple(data.shape) == case.get('expect'))
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME),
[
('test_log_prob'),
],
)
class TestLKJCholeskyLogProb(unittest.TestCase):
def test_log_prob(self):
self.dim = 2
self._paddle_lkj_cholesky = lkj_cholesky.LKJCholesky(
self.dim, [1.0], 'onion'
)
self._test_log_prob()
def _test_log_prob(self):
log_probs = []
for i in range(2):
sample = self._paddle_lkj_cholesky.sample()
log_prob = self._paddle_lkj_cholesky.log_prob(sample)
sample_tril = tril_matrix_to_vec(sample, diag=-1)
# log_abs_det_jacobian
logabsdet = []
logabsdet.append(self._compute_jacobian(sample_tril)[1])
logabsdet = paddle.to_tensor(logabsdet)
log_probs.append((log_prob - logabsdet).numpy())
np.testing.assert_allclose(
log_probs[0],
log_probs[1],
rtol=0.1,
atol=config.ATOL.get('float32'),
)
def _tril_cholesky_to_tril_corr(self, x):
last_dim = self.dim * (self.dim - 1) // 2
x = x.reshape((last_dim,))
x = vec_to_tril_matrix(x, self.dim, last_dim, last_dim, (1,), -1)
diag = (1 - (x * x).sum(-1)).sqrt().diag_embed()
x = x + diag
x = x.reshape((self.dim, self.dim))
return tril_matrix_to_vec(paddle.matmul(x, x, transpose_y=True), -1)
def _compute_jacobian(self, x):
if x.stop_gradient is not False:
x.stop_gradient = False
jacobian_matrix = []
outputs = self._tril_cholesky_to_tril_corr(x)
for i in range(outputs.shape[0]):
grad = paddle.grad(
outputs=outputs[i], inputs=x, create_graph=False
)[0]
jacobian_matrix.append(grad)
J = paddle.stack(jacobian_matrix, axis=0)
logabsdet = paddle.linalg.slogdet(J)
return logabsdet
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME),
[
('lkj_cholesky_test_err'),
],
)
class LKJCholeskyTestError(unittest.TestCase):
@parameterize.parameterize_func(
[
(1, 1.0, ValueError), # dim < 2
(3.0, 1.0, TypeError), # dim is float
(3, -1.0, ValueError), # concentration < 0
]
)
def test_bad_parameter(self, dim, concentration, error):
with paddle.base.dygraph.guard(self.place):
self.assertRaises(
error, lkj_cholesky.LKJCholesky, dim, concentration
)
@parameterize.parameterize_func([(10,)]) # not sequence object sample shape
def test_bad_sample_shape(self, shape):
with paddle.base.dygraph.guard(self.place):
lkj = lkj_cholesky.LKJCholesky(3)
self.assertRaises(TypeError, lkj.sample, shape)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,259 @@
# 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.
import unittest
import numpy as np
import parameterize
from distribution import config
import paddle
from paddle.distribution import lkj_cholesky
from paddle.distribution.lkj_cholesky import (
tril_matrix_to_vec,
vec_to_tril_matrix,
)
paddle.enable_static()
np.random.seed(2024)
paddle.seed(2024)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'concentration'),
[
(
'zero-dim',
parameterize.xrand(
(1,),
dtype='float32',
max=1.0,
min=0,
).reshape([]),
),
(
'one-dim',
parameterize.xrand(
(2,),
dtype='float32',
max=1.0,
min=0,
),
),
(
'one-dim2',
parameterize.xrand(
(1,),
dtype='float64',
max=1.0,
min=0,
),
),
],
)
class TestLKJCholeskyShape(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.program):
conc = paddle.static.data(
'concentration',
self.concentration.shape,
self.concentration.dtype,
)
self._paddle_lkj_cholesky_onion = lkj_cholesky.LKJCholesky(
2, conc, 'onion'
)
self._paddle_lkj_cholesky_cvine = lkj_cholesky.LKJCholesky(
2, conc, 'cvine'
)
self.feeds = {
'concentration': self.concentration,
}
def gen_cases(self):
extra_shape = []
extra_shape.extend(self.concentration.shape)
extra_shape.extend(
[self._paddle_lkj_cholesky.dim, self._paddle_lkj_cholesky.dim]
)
cases = [
{
'input': (),
'expect': tuple(extra_shape),
},
{
'input': (2, 2),
'expect': (2, 2, *extra_shape),
},
]
return cases
def test_onion_sample_shape(self):
sample_method = 'onion'
self._test_sample_shape(sample_method)
def test_cvine_sample_shape(self):
sample_method = 'cvine'
self._test_sample_shape(sample_method)
def _test_sample_shape(self, sample_method):
with paddle.static.program_guard(self.program):
if sample_method == 'cvine':
self._paddle_lkj_cholesky = self._paddle_lkj_cholesky_cvine
else:
self._paddle_lkj_cholesky = self._paddle_lkj_cholesky_onion
cases = self.gen_cases()
for case in cases:
[data] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_lkj_cholesky.sample(
case.get('input')
),
)
self.assertTrue(tuple(data.shape) == case.get('expect'))
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME),
[
('test_log_prob'),
],
)
class TestLKJCholeskyLogProb(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.concentration = [1.0]
self.feeds = {
'concentration': self.concentration,
}
def test_log_prob(self):
self.dim = 2
self._test_log_prob('onion')
def _test_log_prob(self, sample_method):
with paddle.static.program_guard(self.program):
self._paddle_lkj_cholesky = lkj_cholesky.LKJCholesky(
self.dim, self.concentration, sample_method
)
log_probs = []
for i in range(2):
[sample] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_lkj_cholesky.sample(),
)
if paddle.framework.use_pir_api():
block = self.program.global_block()
for op in block.ops:
if op.name() == 'pd_op.fetch':
block.remove_op(op)
sample = paddle.to_tensor(sample)
[log_prob] = self.executor.run(
self.program,
feed=self.feeds,
fetch_list=self._paddle_lkj_cholesky.log_prob(sample),
)
if paddle.framework.use_pir_api():
block = self.program.global_block()
for op in block.ops:
if op.name() == 'pd_op.fetch':
block.remove_op(op)
sample_tril = tril_matrix_to_vec(sample, diag=-1)
# log_abs_det_jacobian
logabsdet = []
[logabsdet_value, J] = self.executor.run(
self.program,
feed={'sample_tril': sample_tril},
fetch_list=self._compute_jacobian(sample_tril),
)
if paddle.framework.use_pir_api():
block = self.program.global_block()
for op in block.ops:
if op.name() == 'pd_op.fetch':
block.remove_op(op)
logabsdet.append(logabsdet_value[1])
log_probs.append(log_prob - logabsdet)
max_abs_error = np.max(np.abs(log_probs[0] - log_probs[1]))
self.assertAlmostEqual(max_abs_error, 0, places=3)
def _tril_cholesky_to_tril_corr(self, x, last_dim):
x = x.reshape((last_dim,))
x = vec_to_tril_matrix(x, self.dim, last_dim, last_dim, (1,), -1)
diag = (1 - (x * x).sum(-1)).sqrt().diag_embed()
x = x + diag
x = x.reshape((self.dim, self.dim))
return tril_matrix_to_vec(x @ x.T, -1)
def _compute_jacobian(self, x):
last_dim = self.dim * (self.dim - 1) // 2
if x.stop_gradient is not False:
x.stop_gradient = False
jacobian_matrix = []
outputs = self._tril_cholesky_to_tril_corr(x, last_dim)
for i in range(outputs.shape[0]):
grad = paddle.static.gradients(outputs[i], x)[0]
grad = grad.reshape((last_dim,))
jacobian_matrix.append(grad)
J = paddle.stack(jacobian_matrix, axis=0)
logabsdet = paddle.linalg.slogdet(J)
return logabsdet, J
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME),
[
('lkj_cholesky_test_err'),
],
)
class LKJCholeskyTestError(unittest.TestCase):
def setUp(self):
self.program = paddle.static.Program()
@parameterize.parameterize_func(
[
(1, ValueError), # dim < 2
(3.0, TypeError), # dim is float
]
)
def test_bad_parameter(self, dim, error):
with paddle.static.program_guard(self.program):
self.assertRaises(error, lkj_cholesky.LKJCholesky, dim)
@parameterize.parameterize_func([(10,)]) # not sequence object sample shape
def test_bad_sample_shape(self, shape):
with paddle.static.program_guard(self.program):
lkj = lkj_cholesky.LKJCholesky(3)
self.assertRaises(TypeError, lkj.sample, shape)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,285 @@
# Copyright (c) 2022 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 math
import unittest
import numpy as np
import scipy.stats
from distribution import config
from parameterize import TEST_CASE_NAME, parameterize_cls, place, xrand
from test_distribution import DistributionNumpy
import paddle
from paddle.distribution.kl import kl_divergence
from paddle.distribution.lognormal import LogNormal
from paddle.distribution.normal import Normal
class LogNormalNumpy(DistributionNumpy):
def __init__(self, loc, scale):
self.loc = np.array(loc)
self.scale = np.array(scale)
if str(self.loc.dtype) not in ['float32', 'float64']:
self.loc = self.loc.astype('float32')
self.scale = self.scale.astype('float32')
@property
def mean(self):
var = self.scale * self.scale
return np.exp(self.loc + var / 2)
@property
def variance(self):
var = self.scale * self.scale
return (np.exp(var) - 1) * np.exp(2 * self.loc + var)
def log_prob(self, value):
var = self.scale * self.scale
log_scale = np.log(self.scale)
return (
-((np.log(value) - self.loc) * (np.log(value) - self.loc))
/ (2.0 * var)
- log_scale
- math.log(math.sqrt(2.0 * math.pi))
- np.log(value)
)
def probs(self, value):
var = self.scale * self.scale
return np.exp(
-1.0
* ((np.log(value) - self.loc) * (np.log(value) - self.loc))
/ (2.0 * var)
) / (math.sqrt(2 * math.pi) * self.scale * value)
def entropy(self):
return (
0.5
+ self.loc
+ 0.5 * np.log(np.array(2.0 * math.pi).astype(self.loc.dtype))
+ np.log(self.scale)
)
def kl_divergence(self, other):
var_ratio = self.scale / other.scale
var_ratio = var_ratio * var_ratio
t1 = (self.loc - other.loc) / other.scale
t1 = t1 * t1
return 0.5 * (var_ratio + t1 - 1 - np.log(var_ratio))
@place(config.DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'loc', 'scale', 'value'),
[
('one-dim', xrand((2,)), xrand((2,)), xrand((2,))),
('multi-dim', xrand((3, 3)), xrand((3, 3)), xrand((3, 3))),
],
)
class LogNormalTest(unittest.TestCase):
def setUp(self):
paddle.disable_static()
self.paddle_lognormal = LogNormal(
loc=paddle.to_tensor(self.loc), scale=paddle.to_tensor(self.scale)
)
self.np_lognormal = LogNormalNumpy(self.loc, self.scale)
def test_mean(self):
mean = self.paddle_lognormal.mean
np_mean = self.np_lognormal.mean
self.assertEqual(mean.numpy().dtype, np_mean.dtype)
np.testing.assert_allclose(
mean,
np_mean,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_variance(self):
var = self.paddle_lognormal.variance
np_var = self.np_lognormal.variance
self.assertEqual(var.numpy().dtype, np_var.dtype)
np.testing.assert_allclose(
var,
np_var,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_entropy(self):
entropy = self.paddle_lognormal.entropy()
np_entropy = self.np_lognormal.entropy()
self.assertEqual(entropy.numpy().dtype, np_entropy.dtype)
np.testing.assert_allclose(
entropy,
np_entropy,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_probs(self):
with paddle.base.dygraph.guard(self.place):
probs = self.paddle_lognormal.probs(paddle.to_tensor(self.value))
np_probs = self.np_lognormal.probs(self.value)
np.testing.assert_allclose(
probs,
np_probs,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_log_prob(self):
with paddle.base.dygraph.guard(self.place):
log_prob = self.paddle_lognormal.log_prob(
paddle.to_tensor(self.value)
)
np_log_prob = self.np_lognormal.log_prob(self.value)
np.testing.assert_allclose(
log_prob,
np_log_prob,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
@place(config.DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'loc', 'scale'),
[('sample', xrand((4,)), xrand((4,), min=0, max=1))],
)
class TestLogNormalSample(unittest.TestCase):
def setUp(self):
paddle.disable_static()
self.paddle_lognormal = LogNormal(loc=self.loc, scale=self.scale)
n = 1000000
self.sample_shape = (n,)
self.rsample_shape = (n,)
self.samples = self.paddle_lognormal.sample(self.sample_shape)
self.rsamples = self.paddle_lognormal.rsample(self.rsample_shape)
def test_sample(self):
samples_mean = self.samples.mean(axis=0)
samples_var = self.samples.var(axis=0)
np.testing.assert_allclose(
samples_mean, self.paddle_lognormal.mean, rtol=0.1, atol=0
)
np.testing.assert_allclose(
samples_var, self.paddle_lognormal.variance, rtol=0.1, atol=0
)
rsamples_mean = self.rsamples.mean(axis=0)
rsamples_var = self.rsamples.var(axis=0)
np.testing.assert_allclose(
rsamples_mean, self.paddle_lognormal.mean, rtol=0.1, atol=0
)
np.testing.assert_allclose(
rsamples_var, self.paddle_lognormal.variance, rtol=0.1, atol=0
)
batch_shape = (self.loc + self.scale).shape
self.assertEqual(
self.samples.shape, list(self.sample_shape + batch_shape)
)
self.assertEqual(
self.rsamples.shape, list(self.rsample_shape + batch_shape)
)
for i in range(len(self.scale)):
self.assertTrue(
self._kstest(self.loc[i], self.scale[i], self.samples[:, i])
)
self.assertTrue(
self._kstest(self.loc[i], self.scale[i], self.rsamples[:, i])
)
def _kstest(self, loc, scale, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, _ = scipy.stats.kstest(
samples, scipy.stats.lognorm(s=scale, scale=np.exp(loc)).cdf
)
return ks < 0.02
@place(config.DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'loc1', 'scale1', 'loc2', 'scale2'),
[
('one-dim', xrand((2,)), xrand((2,)), xrand((2,)), xrand((2,))),
(
'multi-dim',
xrand((2, 2)),
xrand((2, 2)),
xrand((2, 2)),
xrand((2, 2)),
),
],
)
class TestLogNormalKL(unittest.TestCase):
def setUp(self):
paddle.disable_static()
self.ln_a = LogNormal(
loc=paddle.to_tensor(self.loc1), scale=paddle.to_tensor(self.scale1)
)
self.ln_b = LogNormal(
loc=paddle.to_tensor(self.loc2), scale=paddle.to_tensor(self.scale2)
)
self.normal_a = Normal(
loc=paddle.to_tensor(self.loc1), scale=paddle.to_tensor(self.scale1)
)
self.normal_b = Normal(
loc=paddle.to_tensor(self.loc2), scale=paddle.to_tensor(self.scale2)
)
def test_kl_divergence(self):
kl0 = self.ln_a.kl_divergence(self.ln_b)
kl1 = kl_divergence(self.ln_a, self.ln_b)
kl_normal = kl_divergence(self.normal_a, self.normal_b)
kl_formula = self._kl(self.ln_a, self.ln_b)
self.assertEqual(tuple(kl0.shape), self.scale1.shape)
self.assertEqual(tuple(kl1.shape), self.scale1.shape)
np.testing.assert_allclose(
kl0,
kl_formula,
rtol=config.RTOL.get(str(self.scale1.dtype)),
atol=config.ATOL.get(str(self.scale1.dtype)),
)
np.testing.assert_allclose(
kl1,
kl_formula,
rtol=config.RTOL.get(str(self.scale1.dtype)),
atol=config.ATOL.get(str(self.scale1.dtype)),
)
np.testing.assert_allclose(
kl_normal,
kl_formula,
rtol=config.RTOL.get(str(self.scale1.dtype)),
atol=config.ATOL.get(str(self.scale1.dtype)),
)
def _kl(self, dist1, dist2):
loc1 = np.array(dist1.loc)
loc2 = np.array(dist2.loc)
scale1 = np.array(dist1.scale)
scale2 = np.array(dist2.scale)
var_ratio = scale1 / scale2
var_ratio = var_ratio * var_ratio
t1 = (loc1 - loc2) / scale2
t1 = t1 * t1
return 0.5 * (var_ratio + t1 - 1 - np.log(var_ratio))
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,298 @@
# Copyright (c) 2022 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
import numpy as np
import scipy.stats
from distribution import config
from parameterize import TEST_CASE_NAME, parameterize_cls, place, xrand
from test_distribution_lognormal import LogNormalNumpy
import paddle
from paddle.distribution.kl import kl_divergence
from paddle.distribution.lognormal import LogNormal
from paddle.distribution.normal import Normal
@place(config.DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'loc', 'scale', 'value'),
[
('one-dim', xrand((2,)), xrand((2,)), xrand((2,))),
('multi-dim', xrand((3, 3)), xrand((3, 3)), xrand((3, 3))),
],
test_pir=True,
)
class TestLogNormal(unittest.TestCase):
def run_program(self):
paddle.enable_static()
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
loc = paddle.static.data('loc', self.loc.shape, self.loc.dtype)
scale = paddle.static.data(
'scale', self.scale.shape, self.scale.dtype
)
value = paddle.static.data(
'value', self.value.shape, self.value.dtype
)
self.paddle_lognormal = LogNormal(loc=loc, scale=scale)
self.np_lognormal = LogNormalNumpy(loc=self.loc, scale=self.scale)
mean = self.paddle_lognormal.mean
var = self.paddle_lognormal.variance
entropy = self.paddle_lognormal.entropy()
probs = self.paddle_lognormal.probs(value)
log_prob = self.paddle_lognormal.log_prob(value)
fetch_list = [mean, var, entropy, probs, log_prob]
self.feeds = {'loc': self.loc, 'scale': self.scale, 'value': self.value}
executor.run(startup_program)
[
self.mean,
self.var,
self.entropy,
self.probs,
self.log_prob,
] = executor.run(main_program, feed=self.feeds, fetch_list=fetch_list)
def setUp(self):
if self.test_pir:
with paddle.pir_utils.IrGuard():
self.run_program()
else:
self.run_program()
def test_mean(self):
np_mean = self.np_lognormal.mean
self.assertEqual(str(self.mean.dtype).split('.')[-1], self.scale.dtype)
np.testing.assert_allclose(
self.mean,
np_mean,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_var(self):
np_var = self.np_lognormal.variance
self.assertEqual(str(self.var.dtype).split('.')[-1], self.scale.dtype)
np.testing.assert_allclose(
self.var,
np_var,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_entropy(self):
np_entropy = self.np_lognormal.entropy()
self.assertEqual(
str(self.entropy.dtype).split('.')[-1], self.scale.dtype
)
np.testing.assert_allclose(
self.entropy,
np_entropy,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_probs(self):
np_probs = self.np_lognormal.probs(self.value)
np.testing.assert_allclose(
self.probs,
np_probs,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
def test_log_prob(self):
np_log_prob = self.np_lognormal.log_prob(self.value)
np.testing.assert_allclose(
self.log_prob,
np_log_prob,
rtol=config.RTOL.get(str(self.scale.dtype)),
atol=config.ATOL.get(str(self.scale.dtype)),
)
@place(config.DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'loc', 'scale'),
[('sample', xrand((4,)), xrand((4,), min=0, max=1))],
test_pir=True,
)
class TestLogNormalSample(unittest.TestCase):
def run_program(self):
paddle.enable_static()
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
loc = paddle.static.data('loc', self.loc.shape, self.loc.dtype)
scale = paddle.static.data(
'scale', self.scale.shape, self.scale.dtype
)
n = 1000000
self.sample_shape = (n,)
self.rsample_shape = (n,)
self.paddle_lognormal = LogNormal(loc=loc, scale=scale)
mean = self.paddle_lognormal.mean
variance = self.paddle_lognormal.variance
samples = self.paddle_lognormal.sample(self.sample_shape)
rsamples = self.paddle_lognormal.rsample(self.rsample_shape)
fetch_list = [mean, variance, samples, rsamples]
self.feeds = {'loc': self.loc, 'scale': self.scale}
executor.run(startup_program)
[self.mean, self.variance, self.samples, self.rsamples] = executor.run(
main_program, feed=self.feeds, fetch_list=fetch_list
)
def setUp(self):
if self.test_pir:
with paddle.pir_utils.IrGuard():
self.run_program()
else:
self.run_program()
def test_sample(self):
samples_mean = self.samples.mean(axis=0)
samples_var = self.samples.var(axis=0)
np.testing.assert_allclose(samples_mean, self.mean, rtol=0.1, atol=0)
np.testing.assert_allclose(samples_var, self.variance, rtol=0.1, atol=0)
rsamples_mean = self.rsamples.mean(axis=0)
rsamples_var = self.rsamples.var(axis=0)
np.testing.assert_allclose(rsamples_mean, self.mean, rtol=0.1, atol=0)
np.testing.assert_allclose(
rsamples_var, self.variance, rtol=0.1, atol=0
)
batch_shape = (self.loc + self.scale).shape
self.assertEqual(self.samples.shape, self.sample_shape + batch_shape)
self.assertEqual(self.rsamples.shape, self.rsample_shape + batch_shape)
for i in range(len(self.scale)):
self.assertTrue(
self._kstest(self.loc[i], self.scale[i], self.samples[:, i])
)
self.assertTrue(
self._kstest(self.loc[i], self.scale[i], self.rsamples[:, i])
)
def _kstest(self, loc, scale, samples):
# Uses the Kolmogorov-Smirnov test for goodness of fit.
ks, _ = scipy.stats.kstest(
samples, scipy.stats.lognorm(s=scale, scale=np.exp(loc)).cdf
)
return ks < 0.02
@place(config.DEVICES)
@parameterize_cls(
(TEST_CASE_NAME, 'loc1', 'scale1', 'loc2', 'scale2'),
[
('one-dim', xrand((2,)), xrand((2,)), xrand((2,)), xrand((2,))),
(
'multi-dim',
xrand((2, 2)),
xrand((2, 2)),
xrand((2, 2)),
xrand((2, 2)),
),
],
test_pir=True,
)
class TestLogNormalKL(unittest.TestCase):
def run_program(self):
paddle.enable_static()
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
loc1 = paddle.static.data('loc1', self.loc1.shape, self.loc1.dtype)
scale1 = paddle.static.data(
'scale1', self.scale1.shape, self.scale1.dtype
)
loc2 = paddle.static.data('loc2', self.loc2.shape, self.loc2.dtype)
scale2 = paddle.static.data(
'scale2', self.scale2.shape, self.scale2.dtype
)
self.ln_a = LogNormal(loc=loc1, scale=scale1)
self.ln_b = LogNormal(loc=loc2, scale=scale2)
self.normal_a = Normal(loc=loc1, scale=scale1)
self.normal_b = Normal(loc=loc2, scale=scale2)
kl0 = self.ln_a.kl_divergence(self.ln_b)
kl1 = kl_divergence(self.ln_a, self.ln_b)
kl_normal = kl_divergence(self.normal_a, self.normal_b)
kl_formula = self._kl(self.ln_a, self.ln_b)
fetch_list = [kl0, kl1, kl_normal, kl_formula]
self.feeds = {
'loc1': self.loc1,
'scale1': self.scale1,
'loc2': self.loc2,
'scale2': self.scale2,
}
executor.run(startup_program)
[self.kl0, self.kl1, self.kl_normal, self.kl_formula] = executor.run(
main_program, feed=self.feeds, fetch_list=fetch_list
)
def setUp(self):
if self.test_pir:
with paddle.pir_utils.IrGuard():
self.run_program()
else:
self.run_program()
def test_kl_divergence(self):
np.testing.assert_allclose(
self.kl0,
self.kl_formula,
rtol=config.RTOL.get(str(self.scale1.dtype)),
atol=config.ATOL.get(str(self.scale1.dtype)),
)
np.testing.assert_allclose(
self.kl1,
self.kl_formula,
rtol=config.RTOL.get(str(self.scale1.dtype)),
atol=config.ATOL.get(str(self.scale1.dtype)),
)
np.testing.assert_allclose(
self.kl_normal,
self.kl_formula,
rtol=config.RTOL.get(str(self.scale1.dtype)),
atol=config.ATOL.get(str(self.scale1.dtype)),
)
def _kl(self, dist1, dist2):
loc1 = dist1.loc
loc2 = dist2.loc
scale1 = dist1.scale
scale2 = dist2.scale
var_ratio = scale1 / scale2
var_ratio = var_ratio * var_ratio
t1 = (loc1 - loc2) / scale2
t1 = t1 * t1
return 0.5 * (var_ratio + t1 - 1 - np.log(var_ratio))
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,168 @@
# 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 unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'total_count', 'probs'),
[
('one-dim', 10, parameterize.xrand((3,))),
('multi-dim', 9, parameterize.xrand((10, 20))),
('prob-sum-one', 10, np.array([0.5, 0.2, 0.3])),
('prob-sum-non-one', 10, np.array([2.0, 3.0, 5.0])),
],
)
class TestMultinomial(unittest.TestCase):
def setUp(self):
self._dist = paddle.distribution.Multinomial(
total_count=self.total_count, probs=paddle.to_tensor(self.probs)
)
def test_mean(self):
mean = self._dist.mean
self.assertEqual(mean.numpy().dtype, self.probs.dtype)
np.testing.assert_allclose(
mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_variance(self):
var = self._dist.variance
self.assertEqual(var.numpy().dtype, self.probs.dtype)
np.testing.assert_allclose(
var,
self._np_variance(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_entropy(self):
entropy = self._dist.entropy()
self.assertEqual(entropy.numpy().dtype, self.probs.dtype)
np.testing.assert_allclose(
entropy,
self._np_entropy(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_sample(self):
sample_shape = ()
samples = self._dist.sample(sample_shape)
self.assertEqual(samples.numpy().dtype, self.probs.dtype)
self.assertEqual(
tuple(samples.shape),
sample_shape + self._dist.batch_shape + self._dist.event_shape,
)
sample_shape = (6,)
samples = self._dist.sample(sample_shape)
self.assertEqual(samples.numpy().dtype, self.probs.dtype)
self.assertEqual(
tuple(samples.shape),
sample_shape + self._dist.batch_shape + self._dist.event_shape,
)
self.assertTrue(
np.all(samples.sum(-1).numpy() == self._dist.total_count)
)
sample_shape = (5000,)
samples = self._dist.sample(sample_shape)
sample_mean = samples.mean(axis=0)
# Tolerance value 0.2 is empirical value which is consistent with
# TensorFlow
np.testing.assert_allclose(
sample_mean, self._dist.mean, atol=0, rtol=0.20
)
def _np_variance(self):
probs = self.probs / self.probs.sum(-1, keepdims=True)
return self.total_count * probs * (1 - probs)
def _np_mean(self):
probs = self.probs / self.probs.sum(-1, keepdims=True)
return self.total_count * probs
def _np_entropy(self):
probs = self.probs / self.probs.sum(-1, keepdims=True)
return scipy.stats.multinomial.entropy(self.total_count, probs)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'total_count', 'probs', 'value'),
[
(
'value-float',
10,
np.array([0.2, 0.3, 0.5]),
np.array([2.0, 3.0, 5.0]),
),
('value-int', 10, np.array([0.2, 0.3, 0.5]), np.array([2, 3, 5])),
(
'value-multi-dim',
10,
np.array([[0.3, 0.7], [0.5, 0.5]]),
np.array([[4.0, 6], [8, 2]]),
),
# ('value-sum-non-n', 10, np.array([0.5, 0.2, 0.3]), np.array([4,5,2])),
],
)
class TestMultinomialPmf(unittest.TestCase):
def setUp(self):
self._dist = paddle.distribution.Multinomial(
total_count=self.total_count, probs=paddle.to_tensor(self.probs)
)
def test_prob(self):
np.testing.assert_allclose(
self._dist.prob(paddle.to_tensor(self.value)),
scipy.stats.multinomial.pmf(
self.value, self.total_count, self.probs
),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(config.TEST_CASE_NAME, 'total_count', 'probs'),
[
('total_count_le_one', 0, np.array([0.3, 0.7])),
('total_count_float', np.array([0.3, 0.7])),
('probs_zero_dim', np.array(0)),
],
)
class TestMultinomialException(unittest.TestCase):
def TestInit(self):
with self.assertRaises(ValueError):
paddle.distribution.Multinomial(
self.total_count, paddle.to_tensor(self.probs)
)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,199 @@
# 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 unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
paddle.enable_static()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'total_count', 'probs'),
[
('one-dim', 5, parameterize.xrand((3,))),
('multi-dim', 9, parameterize.xrand((2, 3))),
('prob-sum-one', 5, np.array([0.5, 0.2, 0.3])),
('prob-sum-non-one', 5, np.array([2.0, 3.0, 5.0])),
],
)
class TestMultinomial(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
probs = paddle.static.data(
'probs', self.probs.shape, self.probs.dtype
)
dist = paddle.distribution.Multinomial(self.total_count, probs)
mean = dist.mean
var = dist.variance
entropy = dist.entropy()
mini_samples = dist.sample(shape=(6,))
large_samples = dist.sample(shape=(5000,))
fetch_list = [mean, var, entropy, mini_samples, large_samples]
feed = {'probs': self.probs}
executor.run(startup_program)
[
self.mean,
self.var,
self.entropy,
self.mini_samples,
self.large_samples,
] = executor.run(main_program, feed=feed, fetch_list=fetch_list)
def test_mean(self):
self.assertEqual(str(self.mean.dtype).split('.')[-1], self.probs.dtype)
np.testing.assert_allclose(
self.mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_variance(self):
self.assertEqual(str(self.var.dtype).split('.')[-1], self.probs.dtype)
np.testing.assert_allclose(
self.var,
self._np_variance(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_entropy(self):
self.assertEqual(
str(self.entropy.dtype).split('.')[-1], self.probs.dtype
)
np.testing.assert_allclose(
self.entropy,
self._np_entropy(),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
def test_sample(self):
self.assertEqual(
str(self.mini_samples.dtype).split('.')[-1], self.probs.dtype
)
self.assertTrue(np.all(self.mini_samples.sum(-1) == self.total_count))
sample_mean = self.large_samples.mean(axis=0)
np.testing.assert_allclose(sample_mean, self.mean, atol=0, rtol=0.20)
def _np_variance(self):
probs = self.probs / self.probs.sum(-1, keepdims=True)
return self.total_count * probs * (1 - probs)
def _np_mean(self):
probs = self.probs / self.probs.sum(-1, keepdims=True)
return self.total_count * probs
def _np_entropy(self):
probs = self.probs / self.probs.sum(-1, keepdims=True)
return scipy.stats.multinomial.entropy(self.total_count, probs)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'total_count', 'probs', 'value'),
[
(
'value-float',
5,
np.array([0.2, 0.3, 0.5]),
np.array([1.0, 1.0, 3.0]),
),
('value-int', 5, np.array([0.2, 0.3, 0.5]), np.array([2, 2, 1])),
(
'value-multi-dim',
5,
np.array([[0.3, 0.7], [0.5, 0.5]]),
np.array([[1.0, 4.0], [2.0, 3.0]]),
),
# ('value-sum-non-n', 10, np.array([0.5, 0.2, 0.3]), np.array([4,5,2])),
],
)
class TestMultinomialPmf(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
probs = paddle.static.data(
'probs', self.probs.shape, self.probs.dtype
)
value = paddle.static.data(
'value', self.value.shape, self.value.dtype
)
dist = paddle.distribution.Multinomial(self.total_count, probs)
pmf = dist.prob(value)
feed = {'probs': self.probs, 'value': self.value}
fetch_list = [pmf]
executor.run(startup_program)
[self.pmf] = executor.run(
main_program, feed=feed, fetch_list=fetch_list
)
def test_prob(self):
np.testing.assert_allclose(
self.pmf,
scipy.stats.multinomial.pmf(
self.value, self.total_count, self.probs
),
rtol=config.RTOL.get(str(self.probs.dtype)),
atol=config.ATOL.get(str(self.probs.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'total_count', 'probs'),
[
('total_count_le_one', 0, np.array([0.3, 0.7])),
('total_count_float', np.array([0.3, 0.7])),
('probs_zero_dim', np.array(0)),
],
)
class TestMultinomialException(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
self.main_program = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.main_program, startup_program):
probs = paddle.static.data(
'probs', self.probs.shape, self.probs.dtype
)
dist = paddle.distribution.Multinomial(self.total_count, probs)
self.feed = {'probs': self.probs}
self.executor.run(startup_program)
def TestInit(self):
with self.assertRaises(ValueError):
self.executor.run(self.main_program, feed=self.feed, fetch=[])
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,465 @@
# 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 unittest
import numpy as np
import parameterize
import scipy
from distribution import config
from parameterize import (
TEST_CASE_NAME,
parameterize_cls,
)
import paddle
from paddle.distribution import constraint
from paddle.distribution.multivariate_normal import MultivariateNormal
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'covariance_matrix'),
[
(
'one-batch',
parameterize.xrand((2,), dtype='float32', min=1, max=2),
np.array([[2.0, 1.0], [1.0, 2.0]]),
),
(
'multi-batch',
parameterize.xrand((2, 3), dtype='float64', min=-2, max=-1),
np.array([[4.0, 2.5, 2.0], [2.5, 3.0, 1.2], [2.0, 1.2, 4.0]]),
),
],
)
class TestMVN(unittest.TestCase):
def setUp(self):
self._dist = MultivariateNormal(
loc=paddle.to_tensor(self.loc),
covariance_matrix=paddle.to_tensor(self.covariance_matrix),
)
def test_mean(self):
mean = self._dist.mean
self.assertEqual(mean.numpy().dtype, self.loc.dtype)
np.testing.assert_allclose(
mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_variance(self):
var = self._dist.variance
self.assertEqual(var.numpy().dtype, self.loc.dtype)
np.testing.assert_allclose(
var,
self._np_variance(),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_entropy(self):
entropy = self._dist.entropy()
self.assertEqual(entropy.numpy().dtype, self.loc.dtype)
np.testing.assert_allclose(
entropy,
self._np_entropy(),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_sample(self):
sample_shape = ()
samples = self._dist.sample(sample_shape)
self.assertEqual(samples.numpy().dtype, self.loc.dtype)
self.assertEqual(
tuple(samples.shape),
sample_shape + self._dist.batch_shape + self._dist.event_shape,
)
sample_shape = (50000,)
samples = self._dist.sample(sample_shape)
sample_mean = samples.mean(axis=0)
sample_variance = samples.var(axis=0)
# `atol` and `rtol` refer to ``test_distribution_normal`` and ``test_distribution_lognormal``
np.testing.assert_allclose(
sample_mean, self._dist.mean, atol=0.0, rtol=0.1
)
np.testing.assert_allclose(
sample_variance, self._dist.variance, atol=0.0, rtol=0.1
)
def _np_variance(self):
batch_shape = np.broadcast_shapes(
self.covariance_matrix.shape[:-2], self.loc.shape[:-1]
)
event_shape = self.loc.shape[-1:]
return np.broadcast_to(
np.diag(self.covariance_matrix), batch_shape + event_shape
)
def _np_mean(self):
return self.loc
def _np_entropy(self):
if len(self.loc.shape) <= 1:
return scipy.stats.multivariate_normal.entropy(
self.loc, self.covariance_matrix
)
else:
return np.apply_along_axis(
lambda i: scipy.stats.multivariate_normal.entropy(
i, self.covariance_matrix
),
axis=1,
arr=self.loc,
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'precision_matrix', 'value'),
[
(
'value-same-shape',
parameterize.xrand((2,), dtype='float32', min=-2, max=2),
np.array([[2.0, 1.0], [1.0, 2.0]]),
parameterize.xrand((2,), dtype='float32', min=-5, max=5),
),
(
'value-broadcast-shape',
parameterize.xrand((2,), dtype='float64', min=-2, max=2),
np.array([[2.0, 1.0], [1.0, 2.0]]),
parameterize.xrand((3, 2), dtype='float64', min=-5, max=5),
),
],
)
class TestMVNProbs(unittest.TestCase):
def setUp(self):
self._dist = MultivariateNormal(
loc=paddle.to_tensor(self.loc),
precision_matrix=paddle.to_tensor(self.precision_matrix),
)
self.cov = np.linalg.inv(self.precision_matrix)
def test_prob(self):
if len(self.value.shape) <= 1:
scipy_pdf = scipy.stats.multivariate_normal.pdf(
self.value, self.loc, self.cov
)
else:
scipy_pdf = np.apply_along_axis(
lambda i: scipy.stats.multivariate_normal.pdf(
i, self.loc, self.cov
),
axis=1,
arr=self.value,
)
np.testing.assert_allclose(
self._dist.prob(paddle.to_tensor(self.value)),
scipy_pdf,
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_log_prob(self):
if len(self.value.shape) <= 1:
scipy_logpdf = scipy.stats.multivariate_normal.logpdf(
self.value, self.loc, self.cov
)
else:
scipy_logpdf = np.apply_along_axis(
lambda i: scipy.stats.multivariate_normal.logpdf(
i, self.loc, self.cov
),
axis=1,
arr=self.value,
)
np.testing.assert_allclose(
self._dist.log_prob(paddle.to_tensor(self.value)),
scipy_logpdf,
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'mu_1', 'tril_1', 'mu_2', 'tril_2'),
[
(
'one-batch',
parameterize.xrand((2,), dtype='float32', min=-2, max=2),
np.array([[2.0, 0.0], [1.0, 2.0]]),
parameterize.xrand((2,), dtype='float32', min=-2, max=2),
np.array([[3.0, 0.0], [2.0, 3.0]]),
)
],
)
class TestMVNKL(unittest.TestCase):
def setUp(self):
paddle.disable_static()
self._dist1 = MultivariateNormal(
loc=paddle.to_tensor(self.mu_1),
scale_tril=paddle.to_tensor(self.tril_1),
)
self._dist2 = MultivariateNormal(
loc=paddle.to_tensor(self.mu_2),
scale_tril=paddle.to_tensor(self.tril_2),
)
def test_kl_divergence(self):
kl0 = self._dist1.kl_divergence(self._dist2)
kl1 = self.kl_divergence(self._dist1, self._dist2)
self.assertEqual(tuple(kl0.shape), self._dist1.batch_shape)
self.assertEqual(tuple(kl1.shape), self._dist1.batch_shape)
np.testing.assert_allclose(
kl0,
kl1,
rtol=config.RTOL.get(str(self.mu_1.dtype)),
atol=config.ATOL.get(str(self.mu_1.dtype)),
)
def kl_divergence(self, dist1, dist2):
t1 = np.array(dist1._unbroadcasted_scale_tril)
t2 = np.array(dist2._unbroadcasted_scale_tril)
half_log_det_1 = np.log(t1.diagonal(axis1=-2, axis2=-1)).sum(-1)
half_log_det_2 = np.log(t2.diagonal(axis1=-2, axis2=-1)).sum(-1)
new_perm = list(range(len(t1.shape)))
new_perm[-1], new_perm[-2] = new_perm[-2], new_perm[-1]
cov_mat_1 = np.matmul(t1, t1.transpose(new_perm))
cov_mat_2 = np.matmul(t2, t2.transpose(new_perm))
expectation = (
np.linalg.solve(cov_mat_2, cov_mat_1)
.diagonal(axis1=-2, axis2=-1)
.sum(-1)
)
tmp = np.linalg.solve(t2, self.mu_1 - self.mu_2)
expectation += np.matmul(tmp.T, tmp)
return half_log_det_2 - half_log_det_1 + 0.5 * (expectation - 2.0)
@parameterize.place(config.DEVICES)
@parameterize_cls([TEST_CASE_NAME], ['MVNTestError'])
class MVNTestError(unittest.TestCase):
def setUp(self):
paddle.disable_static(self.place)
class TestMVNValidateArgsAndExpand(unittest.TestCase):
def test_mode_and_expand(self):
paddle.disable_static()
loc = paddle.to_tensor([1.0, -2.0], dtype='float32')
cov = paddle.to_tensor([[2.0, 0.5], [0.5, 1.5]], dtype='float32')
dist = MultivariateNormal(
loc=loc, covariance_matrix=cov, validate_args=True
)
self.assertTrue(dist._validate_args_enabled)
np.testing.assert_allclose(dist.mode.numpy(), loc.numpy())
expanded = dist.expand((3,))
self.assertTrue(expanded._validate_args_enabled)
self.assertEqual(expanded.batch_shape, (3,))
self.assertEqual(expanded.event_shape, (2,))
np.testing.assert_allclose(
expanded.mode.numpy(), np.broadcast_to(loc.numpy(), (3, 2))
)
np.testing.assert_allclose(
expanded.mean.numpy(), np.broadcast_to(loc.numpy(), (3, 2))
)
np.testing.assert_allclose(
expanded.variance.numpy(),
np.broadcast_to(np.diag(cov.numpy()), (3, 2)),
)
def test_validate_args_errors(self):
paddle.disable_static()
loc = paddle.to_tensor([0.0, 0.0], dtype='float32')
bad_cov = paddle.to_tensor([[1.0, 2.0], [2.0, 1.0]], dtype='float32')
bad_scale = paddle.to_tensor([[1.0, 0.0], [0.1, -1.0]], dtype='float32')
good_cov = paddle.to_tensor([[2.0, 0.5], [0.5, 1.5]], dtype='float32')
with self.assertRaises(ValueError):
MultivariateNormal(
loc=loc, covariance_matrix=bad_cov, validate_args=True
)
with self.assertRaises(ValueError):
MultivariateNormal(
loc=loc, scale_tril=bad_scale, validate_args=True
)
dist = MultivariateNormal(
loc=loc, covariance_matrix=good_cov, validate_args=True
)
with self.assertRaises(ValueError):
dist.log_prob(paddle.to_tensor([np.nan, 0.0], dtype='float32'))
def test_validate_args_additional_errors(self):
paddle.disable_static()
loc = paddle.to_tensor([0.0, 0.0], dtype='float32')
cov = paddle.to_tensor([[2.0, 0.5], [0.5, 1.5]], dtype='float32')
with self.assertRaises(ValueError):
MultivariateNormal(
loc=paddle.to_tensor(0.0),
covariance_matrix=paddle.to_tensor([[1.0]], dtype='float32'),
)
with self.assertRaises(ValueError):
MultivariateNormal(loc=loc, covariance_matrix=paddle.ones([2]))
with self.assertRaises(ValueError):
MultivariateNormal(loc=loc, scale_tril=paddle.ones([2]))
with self.assertRaises(ValueError):
MultivariateNormal(loc=loc, precision_matrix=paddle.ones([2]))
with self.assertRaises(ValueError):
MultivariateNormal(
loc=loc,
precision_matrix=paddle.to_tensor(
[[1.0, 2.0], [2.0, 1.0]], dtype='float32'
),
validate_args=True,
)
dist = MultivariateNormal(
loc=loc, covariance_matrix=cov, validate_args=True
)
with self.assertRaises(ValueError):
dist.log_prob(paddle.zeros([3], dtype='float32'))
batch_dist = MultivariateNormal(
loc=paddle.zeros([2, 2], dtype='float32'),
covariance_matrix=cov,
validate_args=True,
)
with self.assertRaises(ValueError):
batch_dist.log_prob(paddle.zeros([3, 2], dtype='float32'))
def test_validate_args_false_and_lazy_properties(self):
paddle.disable_static()
loc = paddle.to_tensor([0.0, 0.0], dtype='float32')
bad_scale = paddle.to_tensor([[1.0, 2.0], [0.0, 1.0]], dtype='float32')
dist = MultivariateNormal(
loc=loc, scale_tril=bad_scale, validate_args=False
)
self.assertFalse(dist._validate_args_enabled)
cov = paddle.to_tensor([[2.0, 0.5], [0.5, 1.5]], dtype='float32')
precision = paddle.linalg.inv(cov)
scale = paddle.linalg.cholesky(cov)
cov_dist = MultivariateNormal(loc=loc, covariance_matrix=cov)
np.testing.assert_allclose(cov_dist.scale_tril.numpy(), scale.numpy())
np.testing.assert_allclose(
cov_dist.precision_matrix.numpy(), precision.numpy(), rtol=1e-5
)
scale_dist = MultivariateNormal(loc=loc, scale_tril=scale)
scale_expanded = scale_dist.expand((3,))
np.testing.assert_allclose(
scale_expanded.scale_tril.numpy(),
np.broadcast_to(scale.numpy(), (3, 2, 2)),
)
precision_dist = MultivariateNormal(loc=loc, precision_matrix=precision)
precision_expanded = precision_dist.expand((3,))
np.testing.assert_allclose(
precision_dist.covariance_matrix.numpy(), cov.numpy(), rtol=1e-5
)
np.testing.assert_allclose(
precision_expanded.precision_matrix.numpy(),
np.broadcast_to(precision.numpy(), (3, 2, 2)),
rtol=1e-5,
)
class TestMVNConstraints(unittest.TestCase):
def test_constraints_check(self):
paddle.disable_static()
with self.assertRaises(NotImplementedError):
constraint.Constraint()(paddle.ones([1], dtype='float32'))
np.testing.assert_array_equal(
constraint.real_vector.check(
paddle.to_tensor([1.0, np.nan], dtype='float32')
).numpy(),
np.array(False),
)
np.testing.assert_array_equal(
constraint.real_vector.check(
paddle.to_tensor(1.0, dtype='float32')
).numpy(),
np.array(False),
)
lower = paddle.to_tensor([[1.0, 0.0], [2.0, 3.0]], dtype='float32')
not_lower = paddle.to_tensor([[1.0, 2.0], [0.0, 3.0]], dtype='float32')
np.testing.assert_array_equal(
constraint.lower_triangular.check(lower).numpy(), np.array(True)
)
np.testing.assert_array_equal(
constraint.lower_triangular.check(not_lower).numpy(),
np.array(False),
)
np.testing.assert_array_equal(
constraint.lower_triangular.check(
paddle.to_tensor([1.0, 2.0], dtype='float32')
).numpy(),
np.array(False),
)
bad_cholesky = paddle.to_tensor(
[[1.0, 0.0], [2.0, -3.0]], dtype='float32'
)
np.testing.assert_array_equal(
constraint.lower_cholesky.check(lower).numpy(), np.array(True)
)
np.testing.assert_array_equal(
constraint.lower_cholesky.check(bad_cholesky).numpy(),
np.array(False),
)
square = paddle.eye(2, dtype='float32')
not_square = paddle.ones([2, 3], dtype='float32')
not_symmetric = paddle.to_tensor(
[[1.0, 2.0], [0.0, 1.0]], dtype='float32'
)
not_positive_definite = paddle.to_tensor(
[[1.0, 2.0], [2.0, 1.0]], dtype='float32'
)
np.testing.assert_array_equal(
constraint.square.check(square).numpy(), np.array(True)
)
np.testing.assert_array_equal(
constraint.square.check(not_square).numpy(), np.array(False)
)
np.testing.assert_array_equal(
constraint.symmetric.check(not_symmetric).numpy(), np.array(False)
)
np.testing.assert_array_equal(
constraint.positive_definite.check(square).numpy(), np.array(True)
)
np.testing.assert_array_equal(
constraint.positive_definite.check(not_positive_definite).numpy(),
np.array(False),
)
if __name__ == '__main__':
unittest.main(argv=[''], verbosity=3, exit=False)
@@ -0,0 +1,282 @@
# 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 unittest
import numpy as np
import parameterize
import scipy
from distribution import config
import paddle
from paddle.distribution.multivariate_normal import MultivariateNormal
paddle.enable_static()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'covariance_matrix'),
[
(
'one-batch',
parameterize.xrand((2,), dtype='float32', min=1, max=2),
np.array([[2.0, 1.0], [1.0, 2.0]]),
),
(
'multi-batch',
parameterize.xrand((2, 3), dtype='float64', min=-2, max=-1),
np.array([[6.0, 2.5, 3.0], [2.5, 4.0, 5.0], [3.0, 5.0, 7.0]]),
),
],
)
class TestMVN(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
loc = paddle.static.data('loc', self.loc.shape, self.loc.dtype)
covariance_matrix = paddle.static.data(
'covariance_matrix',
self.covariance_matrix.shape,
self.covariance_matrix.dtype,
)
dist = MultivariateNormal(
loc=loc, covariance_matrix=covariance_matrix
)
mean = dist.mean
var = dist.variance
entropy = dist.entropy()
mini_samples = dist.sample(shape=())
large_samples = dist.sample(shape=(10000,))
fetch_list = [mean, var, entropy, mini_samples, large_samples]
feed = {'loc': self.loc, 'covariance_matrix': self.covariance_matrix}
executor.run(startup_program)
[
self.mean,
self.var,
self.entropy,
self.mini_samples,
self.large_samples,
] = executor.run(main_program, feed=feed, fetch_list=fetch_list)
def test_mean(self):
self.assertEqual(str(self.mean.dtype).split('.')[-1], self.loc.dtype)
np.testing.assert_allclose(
self.mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_variance(self):
self.assertEqual(str(self.var.dtype).split('.')[-1], self.loc.dtype)
np.testing.assert_allclose(
self.var,
self._np_variance(),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_entropy(self):
self.assertEqual(str(self.entropy.dtype).split('.')[-1], self.loc.dtype)
np.testing.assert_allclose(
self.entropy,
self._np_entropy(),
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
def test_sample(self):
self.assertEqual(
str(self.mini_samples.dtype).split('.')[-1], self.loc.dtype
)
sample_mean = self.large_samples.mean(axis=0)
sample_variance = self.large_samples.var(axis=0)
# `atol` and `rtol` refer to ``test_distribution_normal`` and ``test_distribution_lognormal``
np.testing.assert_allclose(sample_mean, self.mean, atol=0, rtol=0.1)
np.testing.assert_allclose(sample_variance, self.var, atol=0, rtol=0.1)
def _np_variance(self):
batch_shape = np.broadcast_shapes(
self.covariance_matrix.shape[:-2], self.loc.shape[:-1]
)
event_shape = self.loc.shape[-1:]
return np.broadcast_to(
np.diag(self.covariance_matrix), batch_shape + event_shape
)
def _np_mean(self):
return self.loc
def _np_entropy(self):
if len(self.loc.shape) <= 1:
return scipy.stats.multivariate_normal.entropy(
self.loc, self.covariance_matrix
)
else:
return np.apply_along_axis(
lambda i: scipy.stats.multivariate_normal.entropy(
i, self.covariance_matrix
),
axis=1,
arr=self.loc,
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'loc', 'covariance_matrix', 'value'),
[
(
'value-same-shape',
parameterize.xrand((2,), dtype='float32', min=-2, max=2),
np.array([[2.0, 1.0], [1.0, 2.0]]),
parameterize.xrand((2,), dtype='float32', min=-5, max=5),
),
(
'value-broadcast-shape',
parameterize.xrand((2,), dtype='float64', min=-2, max=2),
np.array([[2.0, 1.0], [1.0, 2.0]]),
parameterize.xrand((3, 2), dtype='float64', min=-5, max=5),
),
],
)
class TestMVNProbs(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
loc = paddle.static.data('loc', self.loc.shape, self.loc.dtype)
covariance_matrix = paddle.static.data(
'covariance_matrix',
self.covariance_matrix.shape,
self.covariance_matrix.dtype,
)
value = paddle.static.data(
'value', self.value.shape, self.value.dtype
)
dist = MultivariateNormal(
loc=loc, covariance_matrix=covariance_matrix
)
pmf = dist.prob(value)
feed = {
'loc': self.loc,
'covariance_matrix': self.covariance_matrix,
'value': self.value,
}
fetch_list = [pmf]
executor.run(startup_program)
[self.pmf] = executor.run(
main_program, feed=feed, fetch_list=fetch_list
)
def test_prob(self):
if len(self.value.shape) <= 1:
scipy_pdf = scipy.stats.multivariate_normal.pdf(
self.value, self.loc, self.covariance_matrix
)
else:
scipy_pdf = np.apply_along_axis(
lambda i: scipy.stats.multivariate_normal.pdf(
i, self.loc, self.covariance_matrix
),
axis=1,
arr=self.value,
)
np.testing.assert_allclose(
self.pmf,
scipy_pdf,
rtol=config.RTOL.get(str(self.loc.dtype)),
atol=config.ATOL.get(str(self.loc.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'mu_1', 'sig_1', 'mu_2', 'sig_2'),
[
(
'one-batch',
parameterize.xrand((2,), dtype='float32', min=-2, max=2),
np.array([[2.0, 1.0], [1.0, 2.0]]).astype('float32'),
parameterize.xrand((2,), dtype='float32', min=-2, max=2),
np.array([[3.0, 2.0], [2.0, 3.0]]).astype('float32'),
)
],
)
class TestMVNKL(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
mu_1 = paddle.static.data('mu_1', self.mu_1.shape)
sig_1 = paddle.static.data('sig_1', self.sig_1.shape)
mu_2 = paddle.static.data('mu_2', self.mu_2.shape)
sig_2 = paddle.static.data('sig_2', self.sig_2.shape)
dist1 = MultivariateNormal(loc=mu_1, covariance_matrix=sig_1)
dist2 = MultivariateNormal(loc=mu_2, covariance_matrix=sig_2)
kl_dist1_dist2 = dist1.kl_divergence(dist2)
feed = {
'mu_1': self.mu_1,
'sig_1': self.sig_1,
'mu_2': self.mu_2,
'sig_2': self.sig_2,
}
fetch_list = [kl_dist1_dist2]
executor.run(startup_program)
[self.kl_dist1_dist2] = executor.run(
main_program, feed=feed, fetch_list=fetch_list
)
def test_kl_divergence(self):
kl0 = self.kl_dist1_dist2
kl1 = self.kl_divergence()
batch_shape = np.broadcast_shapes(
self.sig_1.shape[:-2], self.mu_1.shape[:-1]
)
self.assertEqual(tuple(kl0.shape), batch_shape)
self.assertEqual(tuple(kl1.shape), batch_shape)
np.testing.assert_allclose(kl0, kl1, rtol=0.1, atol=0.1)
def kl_divergence(self):
t1 = np.array(np.linalg.cholesky(self.sig_1))
t2 = np.array(np.linalg.cholesky(self.sig_2))
half_log_det_1 = np.log(t1.diagonal(axis1=-2, axis2=-1)).sum(-1)
half_log_det_2 = np.log(t2.diagonal(axis1=-2, axis2=-1)).sum(-1)
new_perm = list(range(len(t1.shape)))
new_perm[-1], new_perm[-2] = new_perm[-2], new_perm[-1]
cov_mat_1 = np.matmul(t1, t1.transpose(new_perm))
cov_mat_2 = np.matmul(t2, t2.transpose(new_perm))
expectation = (
np.linalg.solve(cov_mat_2, cov_mat_1)
.diagonal(axis1=-2, axis2=-1)
.sum(-1)
)
tmp = np.linalg.solve(t2, self.mu_1 - self.mu_2)
expectation += np.matmul(tmp.T, tmp)
return half_log_det_2 - half_log_det_1 + 0.5 * (expectation - 2.0)
if __name__ == '__main__':
unittest.main(argv=[''], verbosity=3, exit=False)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,205 @@
# 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 unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import Poisson
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate'),
[
('zero-dim', np.array(100.0).astype('float64')),
('one-dim', np.array([100.0]).astype('float64')),
# boundary case and extreme case (`scipy.stats.poisson.entropy` cannot converge for very extreme cases such as rate=10000.0)
('multi-dim', np.array([0.0, 1000.0]).astype('float32')),
],
)
class TestPoisson(unittest.TestCase):
def setUp(self):
self._dist = Poisson(rate=paddle.to_tensor(self.rate))
def test_mean(self):
mean = self._dist.mean
self.assertEqual(mean.numpy().dtype, self.rate.dtype)
np.testing.assert_allclose(
mean,
scipy.stats.poisson.mean(self.rate),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_variance(self):
var = self._dist.variance
self.assertEqual(var.numpy().dtype, self.rate.dtype)
np.testing.assert_allclose(
var,
scipy.stats.poisson.var(self.rate),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_entropy(self):
entropy = self._dist.entropy()
self.assertEqual(entropy.numpy().dtype, self.rate.dtype)
np.testing.assert_allclose(
entropy,
scipy.stats.poisson.entropy(self.rate),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_sample(self):
sample_shape = ()
samples = self._dist.sample(sample_shape)
self.assertEqual(samples.numpy().dtype, self.rate.dtype)
self.assertEqual(
tuple(samples.shape),
sample_shape + self._dist.batch_shape + self._dist.event_shape,
)
sample_shape = (5000,)
samples = self._dist.sample(sample_shape)
sample_mean = samples.mean(axis=0)
sample_variance = samples.var(axis=0)
np.testing.assert_allclose(
sample_mean, self._dist.mean, atol=0, rtol=0.20
)
np.testing.assert_allclose(
sample_variance, self._dist.variance, atol=0, rtol=0.20
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate', 'value'),
[
(
'value-same-shape',
np.array(1000).astype('float32'),
np.array(1100).astype('float32'),
),
(
'value-broadcast-shape',
np.array(10).astype('float64'),
np.array([2.0, 3.0, 5.0, 10.0, 20.0]).astype('float64'),
),
],
)
class TestPoissonProbs(unittest.TestCase):
def setUp(self):
self._dist = Poisson(rate=paddle.to_tensor(self.rate))
def test_prob(self):
np.testing.assert_allclose(
self._dist.prob(paddle.to_tensor(self.value)),
scipy.stats.poisson.pmf(self.value, self.rate),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_log_prob(self):
np.testing.assert_allclose(
self._dist.log_prob(paddle.to_tensor(self.value)),
scipy.stats.poisson.logpmf(self.value, self.rate),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate_1', 'rate_2'),
[
(
'zero-dim',
parameterize.xrand((1,), min=1, max=20)
.astype('int32')
.astype('float64')
.reshape([]),
parameterize.xrand((1,), min=1, max=20)
.astype('int32')
.astype('float64')
.reshape([]),
),
(
'one-dim',
parameterize.xrand((1,), min=1, max=20)
.astype('int32')
.astype('float64'),
parameterize.xrand((1,), min=1, max=20)
.astype('int32')
.astype('float64'),
),
(
'multi-dim',
parameterize.xrand((5, 3), min=1, max=20)
.astype('int32')
.astype('float32'),
parameterize.xrand((5, 3), min=1, max=20)
.astype('int32')
.astype('float32'),
),
],
)
class TestPoissonKL(unittest.TestCase):
def setUp(self):
self._dist1 = Poisson(rate=paddle.to_tensor(self.rate_1))
self._dist2 = Poisson(rate=paddle.to_tensor(self.rate_2))
def test_kl_divergence(self):
kl0 = self._dist1.kl_divergence(self._dist2)
kl1 = self.kl_divergence_scipy()
self.assertEqual(tuple(kl0.shape), self._dist1.batch_shape)
self.assertEqual(tuple(kl1.shape), self._dist1.batch_shape)
np.testing.assert_allclose(
kl0,
kl1,
rtol=config.RTOL.get(str(self.rate_1.dtype)),
atol=config.ATOL.get(str(self.rate_1.dtype)),
)
def kl_divergence_scipy(self):
rate_max = np.max(np.maximum(self.rate_1, self.rate_2))
rate_min = np.min(np.minimum(self.rate_1, self.rate_2))
support_max = self.enumerate_bounded_support(rate_max)
support_min = self.enumerate_bounded_support(rate_min)
a_min = np.min(support_min)
a_max = np.max(support_max)
common_support = np.arange(
a_min, a_max, dtype=self.rate_1.dtype
).reshape((-1,) + (1,) * len(self.rate_1.shape))
log_prob_1 = scipy.stats.poisson.logpmf(common_support, self.rate_1)
log_prob_2 = scipy.stats.poisson.logpmf(common_support, self.rate_2)
return (np.exp(log_prob_1) * (log_prob_1 - log_prob_2)).sum(0)
def enumerate_bounded_support(self, rate):
s = np.sqrt(rate)
upper = int(rate + 30 * s)
lower = int(np.clip(rate - 30 * s, a_min=0, a_max=rate))
values = np.arange(lower, upper, dtype=self.rate_1.dtype)
return values
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,246 @@
# 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 unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import Poisson
paddle.enable_static()
paddle.enable_static()
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate'),
[
('zero-dim', np.array(1000.0).astype('float32')),
('one-dim', np.array([1000.0]).astype('float32')),
(
'multi-dim',
parameterize.xrand((2,), min=1, max=20)
.astype('int32')
.astype('float64'),
),
],
)
class TestPoisson(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
rate = paddle.static.data('rate', self.rate.shape, self.rate.dtype)
dist = Poisson(rate)
mean = dist.mean
var = dist.variance
entropy = dist.entropy()
mini_samples = dist.sample(shape=())
large_samples = dist.sample(shape=(1000,))
fetch_list = [mean, var, entropy, mini_samples, large_samples]
feed = {'rate': self.rate}
executor.run(startup_program)
[
self.mean,
self.var,
self.entropy,
self.mini_samples,
self.large_samples,
] = executor.run(main_program, feed=feed, fetch_list=fetch_list)
def test_mean(self):
self.assertEqual(str(self.mean.dtype).split('.')[-1], self.rate.dtype)
np.testing.assert_allclose(
self.mean,
self._np_mean(),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_variance(self):
self.assertEqual(str(self.var.dtype).split('.')[-1], self.rate.dtype)
np.testing.assert_allclose(
self.var,
self._np_variance(),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_entropy(self):
self.assertEqual(
str(self.entropy.dtype).split('.')[-1], self.rate.dtype
)
np.testing.assert_allclose(
self.entropy,
self._np_entropy(),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
def test_sample(self):
self.assertEqual(
str(self.mini_samples.dtype).split('.')[-1], self.rate.dtype
)
sample_mean = self.large_samples.mean(axis=0)
sample_variance = self.large_samples.var(axis=0)
np.testing.assert_allclose(sample_mean, self.mean, atol=0, rtol=0.20)
np.testing.assert_allclose(sample_variance, self.var, atol=0, rtol=0.20)
def _np_variance(self):
return self.rate
def _np_mean(self):
return self.rate
def _np_entropy(self):
return scipy.stats.poisson.entropy(self.rate)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate', 'value'),
[
(
'value-same-shape',
np.array(1000).astype('float32'),
np.array(1100).astype('float32'),
),
(
'value-broadcast-shape',
np.array(10).astype('float64'),
np.array([2.0, 3.0]).astype('float64'),
),
],
)
class TestPoissonProbs(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
rate = paddle.static.data('rate', self.rate.shape, self.rate.dtype)
value = paddle.static.data(
'value', self.value.shape, self.value.dtype
)
dist = Poisson(rate)
pmf = dist.prob(value)
feed = {'rate': self.rate, 'value': self.value}
fetch_list = [pmf]
executor.run(startup_program)
[self.pmf] = executor.run(
main_program, feed=feed, fetch_list=fetch_list
)
def test_prob(self):
np.testing.assert_allclose(
self.pmf,
scipy.stats.poisson.pmf(self.value, self.rate),
rtol=config.RTOL.get(str(self.rate.dtype)),
atol=config.ATOL.get(str(self.rate.dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'rate_1', 'rate_2'),
[
(
'zero-dim',
parameterize.xrand((1,), min=1, max=20)
.astype('int32')
.astype('float32')
.reshape([]),
parameterize.xrand((1,), min=1, max=20)
.astype('int32')
.astype('float32')
.reshape([]),
),
(
'multi-dim',
parameterize.xrand((2, 3), min=1, max=20)
.astype('int32')
.astype('float32'),
parameterize.xrand((2, 3), min=1, max=20)
.astype('int32')
.astype('float32'),
),
],
)
class TestPoissonKL(unittest.TestCase):
def setUp(self):
startup_program = paddle.static.Program()
main_program = paddle.static.Program()
executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(main_program, startup_program):
rate_1 = paddle.static.data('rate_1', self.rate_1.shape)
rate_2 = paddle.static.data('rate_2', self.rate_2.shape)
dist1 = Poisson(rate_1)
dist2 = Poisson(rate_2)
kl_dist1_dist2 = dist1.kl_divergence(dist2)
feed = {'rate_1': self.rate_1, 'rate_2': self.rate_2}
fetch_list = [kl_dist1_dist2]
executor.run(startup_program)
[self.kl_dist1_dist2] = executor.run(
main_program, feed=feed, fetch_list=fetch_list
)
def test_kl_divergence(self):
kl0 = self.kl_dist1_dist2
kl1 = self.kl_divergence_scipy()
self.assertEqual(tuple(kl0.shape), self.rate_1.shape)
self.assertEqual(tuple(kl1.shape), self.rate_1.shape)
np.testing.assert_allclose(
kl0,
kl1,
rtol=config.RTOL.get(str(self.rate_1.dtype)),
atol=config.ATOL.get(str(self.rate_1.dtype)),
)
def kl_divergence_scipy(self):
rate_max = np.max(np.maximum(self.rate_1, self.rate_2))
rate_min = np.min(np.minimum(self.rate_1, self.rate_2))
support_max = self.enumerate_bounded_support(rate_max)
support_min = self.enumerate_bounded_support(rate_min)
a_min = np.min(support_min)
a_max = np.max(support_max)
common_support = np.arange(
a_min, a_max, dtype=self.rate_1.dtype
).reshape((-1,) + (1,) * len(self.rate_1.shape))
log_prob_1 = scipy.stats.poisson.logpmf(common_support, self.rate_1)
log_prob_2 = scipy.stats.poisson.logpmf(common_support, self.rate_2)
return (np.exp(log_prob_1) * (log_prob_1 - log_prob_2)).sum(0)
def enumerate_bounded_support(self, rate):
s = np.sqrt(rate)
upper = int(rate + 30 * s)
lower = int(np.clip(rate - 30 * s, a_min=0, a_max=rate))
values = np.arange(lower, upper, dtype=self.rate_1.dtype)
return values
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,340 @@
# 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.
import unittest
import numpy as np
import parameterize
import scipy.stats
from distribution import config
from parameterize import (
TEST_CASE_NAME,
parameterize_cls,
parameterize_func,
)
import paddle
from paddle.distribution.student_t import StudentT
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df', 'loc', 'scale'),
[
(
'one-dim',
10.0,
1.0,
2.0,
),
(
'multi-dim',
parameterize.xrand((2, 1), dtype='float32', min=4, max=30),
parameterize.xrand((2, 3), dtype='float32', min=1, max=10),
parameterize.xrand((2, 3), dtype='float32', min=0.1, max=3),
),
(
'multi-dim2',
parameterize.xrand((2, 1), dtype='float64', min=4, max=30),
parameterize.xrand((2, 3), dtype='float64', min=-10, max=-1),
parameterize.xrand((2, 3), dtype='float64', min=0.1, max=3),
),
],
)
class TestStudentT(unittest.TestCase):
def setUp(self):
df = (
self.df if isinstance(self.df, float) else paddle.to_tensor(self.df)
)
loc = (
self.loc
if isinstance(self.loc, float)
else paddle.to_tensor(self.loc)
)
scale = (
self.scale
if isinstance(self.scale, float)
else paddle.to_tensor(self.scale)
)
self._dist = StudentT(df, loc, scale)
def test_mean(self):
mean = self._dist.mean
target_dtype = (
"float32" if isinstance(self.df, float) else self.df.dtype
)
self.assertEqual(mean.numpy().dtype, target_dtype)
np.testing.assert_allclose(
mean,
self._np_mean(),
rtol=config.RTOL.get(str(target_dtype)),
atol=config.ATOL.get(str(target_dtype)),
)
def test_variance(self):
var = self._dist.variance
target_dtype = (
"float32" if isinstance(self.df, float) else self.df.dtype
)
self.assertEqual(var.numpy().dtype, target_dtype)
np.testing.assert_allclose(
var,
self._np_variance(),
rtol=config.RTOL.get(str(target_dtype)),
atol=config.ATOL.get(str(target_dtype)),
)
def test_entropy(self):
entropy = self._dist.entropy()
target_dtype = (
"float32" if isinstance(self.df, float) else self.df.dtype
)
self.assertEqual(entropy.numpy().dtype, target_dtype)
np.testing.assert_allclose(
entropy,
self._np_entropy(),
rtol=config.RTOL.get(str(target_dtype)),
atol=config.ATOL.get(str(target_dtype)),
)
def test_sample(self):
sample_shape = ()
samples = self._dist.sample(sample_shape)
self.assertEqual(
tuple(samples.shape),
sample_shape + self._dist.batch_shape + self._dist.event_shape,
)
sample_shape = (10000,)
samples = self._dist.sample(sample_shape)
sample_mean = samples.mean(axis=0)
sample_variance = samples.var(axis=0)
# Tolerance value 0.1 is empirical value which is consistent with
# TensorFlow
np.testing.assert_allclose(
sample_mean, self._dist.mean, atol=0, rtol=0.10
)
# Tolerance value 0.1 is empirical value which is consistent with
# TensorFlow
np.testing.assert_allclose(
sample_variance, self._dist.variance, atol=0, rtol=0.10
)
def _np_variance(self):
if isinstance(self.df, np.ndarray) and self.df.dtype == np.float32:
df = self.df.astype("float64")
else:
df = self.df
if isinstance(self.loc, np.ndarray) and self.loc.dtype == np.float32:
loc = self.loc.astype("float64")
else:
loc = self.loc
if (
isinstance(self.scale, np.ndarray)
and self.scale.dtype == np.float32
):
scale = self.scale.astype("float64")
else:
scale = self.scale
return scipy.stats.t.var(df, loc, scale)
def _np_mean(self):
if isinstance(self.df, np.ndarray) and self.df.dtype == np.float32:
df = self.df.astype("float64")
else:
df = self.df
if isinstance(self.loc, np.ndarray) and self.loc.dtype == np.float32:
loc = self.loc.astype("float64")
else:
loc = self.loc
if (
isinstance(self.scale, np.ndarray)
and self.scale.dtype == np.float32
):
scale = self.scale.astype("float64")
else:
scale = self.scale
return scipy.stats.t.mean(df, loc, scale)
def _np_entropy(self):
if isinstance(self.df, np.ndarray) and self.df.dtype == np.float32:
df = self.df.astype("float64")
else:
df = self.df
if isinstance(self.loc, np.ndarray) and self.loc.dtype == np.float32:
loc = self.loc.astype("float64")
else:
loc = self.loc
if (
isinstance(self.scale, np.ndarray)
and self.scale.dtype == np.float32
):
scale = self.scale.astype("float64")
else:
scale = self.scale
return scipy.stats.t.entropy(df, loc, scale)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df', 'loc', 'scale'),
[
(
'float-tensor',
10.0,
paddle.to_tensor(1.0),
2.0,
),
(
'float-tensor1',
10.0,
parameterize.xrand((2, 3), dtype='float32', min=1, max=10),
2.0,
),
(
'float-tensor2',
parameterize.xrand((2, 1), dtype='float64', min=4, max=30),
parameterize.xrand((2, 3), dtype='float64', min=1, max=10),
2.0,
),
(
'float-tensor3',
parameterize.xrand((2, 1), dtype='float64', min=4, max=30),
1.0,
parameterize.xrand((2, 1), dtype='float64', min=0.1, max=3),
),
(
'float-tensor4',
5.0,
parameterize.xrand((2, 1), dtype='float32', min=-1, max=-10),
parameterize.xrand((2, 3), dtype='float32', min=0.1, max=3),
),
],
)
class TestStudentT2(TestStudentT):
def setUp(self):
self._dist = StudentT(self.df, self.loc, self.scale)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df', 'loc', 'scale', 'value'),
[
(
'one-dim',
10.0,
0.0,
1.0,
np.array(3.3).astype("float32"),
),
(
'value-broadcast-shape',
parameterize.xrand((2, 1), dtype='float64', min=4, max=30),
parameterize.xrand((2, 1), dtype='float64', min=-10, max=10),
parameterize.xrand((2, 1), dtype='float64', min=0.1, max=5),
parameterize.xrand((2, 4), dtype='float64', min=-10, max=10),
),
],
)
class TestStudentTProbs(unittest.TestCase):
def setUp(self):
df = (
self.df if isinstance(self.df, float) else paddle.to_tensor(self.df)
)
loc = (
self.loc
if isinstance(self.loc, float)
else paddle.to_tensor(self.loc)
)
scale = (
self.scale
if isinstance(self.scale, float)
else paddle.to_tensor(self.scale)
)
self._dist = StudentT(df, loc, scale)
def test_prob(self):
target_dtype = (
"float32" if isinstance(self.df, float) else self.df.dtype
)
np.testing.assert_allclose(
self._dist.prob(paddle.to_tensor(self.value)),
scipy.stats.t.pdf(self.value, self.df, self.loc, self.scale),
rtol=config.RTOL.get(str(target_dtype)),
atol=config.ATOL.get(str(target_dtype)),
)
def test_log_prob(self):
target_dtype = (
"float32" if isinstance(self.df, float) else self.df.dtype
)
np.testing.assert_allclose(
self._dist.log_prob(paddle.to_tensor(self.value)),
scipy.stats.t.logpdf(self.value, self.df, self.loc, self.scale),
rtol=config.RTOL.get(str(target_dtype)),
atol=config.ATOL.get(str(target_dtype)),
)
@parameterize.place(config.DEVICES)
@parameterize.parameterize_cls(
(parameterize.TEST_CASE_NAME, 'df', 'loc', 'scale', 'value'),
[
(
'float-tensor1',
10.0,
parameterize.xrand((2, 1), dtype='float32', min=-10, max=10),
1.0,
np.array(3.3).astype("float32"),
),
(
'float-tensor2',
parameterize.xrand((2, 1), dtype='float64', min=4, max=30),
1.0,
parameterize.xrand((2, 1), dtype='float64', min=0.1, max=5),
parameterize.xrand((2, 4), dtype='float64', min=-10, max=10),
),
],
)
class TestStudentTProbs2(TestStudentTProbs):
def setUp(self):
self._dist = StudentT(self.df, self.loc, self.scale)
@parameterize.place(config.DEVICES)
@parameterize_cls([TEST_CASE_NAME], ['StudentTTestError'])
class StudentTTestError(unittest.TestCase):
def setUp(self):
paddle.disable_static(self.place)
@parameterize_func(
[
(-5.0, 0.0, 1.0, ValueError), # negative df
(5.0, 0.0, -1.0, ValueError), # negative scale
]
)
def test_bad_parameter(self, df, loc, scale, error):
with paddle.base.dygraph.guard(self.place):
self.assertRaises(error, StudentT, df, loc, scale)
@parameterize_func([(10,)]) # not sequence object sample shape
def test_bad_sample_shape(self, shape):
with paddle.base.dygraph.guard(self.place):
t = StudentT(5.0, 0.0, 1.0)
self.assertRaises(TypeError, t.sample, shape)
if __name__ == '__main__':
unittest.main()
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,79 @@
# 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 unittest
import numpy as np
import parameterize as param
from distribution import config
import paddle
@param.place(config.DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'base', 'transforms'),
[
(
'base_normal',
paddle.distribution.Normal(0.0, 1.0),
[paddle.distribution.ExpTransform()],
)
],
)
class TestIndependent(unittest.TestCase):
def setUp(self):
self._t = paddle.distribution.TransformedDistribution(
self.base, self.transforms
)
def _np_sum_rightmost(self, value, n):
return np.sum(value, tuple(range(-n, 0))) if n > 0 else value
def test_log_prob(self):
value = paddle.to_tensor([0.5])
np.testing.assert_allclose(
self.simple_log_prob(value, self.base, self.transforms),
self._t.log_prob(value),
rtol=config.RTOL.get(str(value.numpy().dtype)),
atol=config.ATOL.get(str(value.numpy().dtype)),
)
def simple_log_prob(self, value, base, transforms):
log_prob = 0.0
y = value
for t in reversed(transforms):
x = t.inverse(y)
log_prob = log_prob - t.forward_log_det_jacobian(x)
y = x
log_prob += base.log_prob(y)
return log_prob
# TODO(cxxly): Add Kolmogorov-Smirnov test for sample result.
def test_sample(self):
shape = [5, 10, 8]
expected_shape = (5, 10, 8)
data = self._t.sample(shape)
self.assertEqual(tuple(data.shape), expected_shape)
self.assertEqual(data.dtype, self.base.loc.dtype)
def test_rsample(self):
shape = [5, 10, 8]
expected_shape = (5, 10, 8)
data = self._t.rsample(shape)
self.assertEqual(tuple(data.shape), expected_shape)
self.assertEqual(data.dtype, self.base.loc.dtype)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,97 @@
# 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 unittest
import numpy as np
import parameterize as param
from distribution import config
import paddle
paddle.enable_static()
@param.place(config.DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'base', 'transforms'),
[
(
'base_normal',
paddle.distribution.Normal,
[paddle.distribution.ExpTransform()],
)
],
)
class TestIndependent(unittest.TestCase):
def setUp(self):
value = np.array([0.5])
loc = np.array([0.0])
scale = np.array([1.0])
shape = [5, 10, 8]
self.dtype = value.dtype
exe = paddle.static.Executor()
sp = paddle.static.Program()
mp = paddle.static.Program()
with paddle.static.program_guard(mp, sp):
static_value = paddle.static.data('value', value.shape, value.dtype)
static_loc = paddle.static.data('loc', loc.shape, loc.dtype)
static_scale = paddle.static.data('scale', scale.shape, scale.dtype)
self.base = self.base(static_loc, static_scale)
self._t = paddle.distribution.TransformedDistribution(
self.base, self.transforms
)
actual_log_prob = self._t.log_prob(static_value)
expected_log_prob = self.transformed_log_prob(
static_value, self.base, self.transforms
)
sample_data = self._t.sample(shape)
exe.run(sp)
[
self.actual_log_prob,
self.expected_log_prob,
self.sample_data,
] = exe.run(
mp,
feed={'value': value, 'loc': loc, 'scale': scale},
fetch_list=[actual_log_prob, expected_log_prob, sample_data],
)
def test_log_prob(self):
np.testing.assert_allclose(
self.actual_log_prob,
self.expected_log_prob,
rtol=config.RTOL.get(str(self.dtype)),
atol=config.ATOL.get(str(self.dtype)),
)
def transformed_log_prob(self, value, base, transforms):
log_prob = 0.0
y = value
for t in reversed(transforms):
x = t.inverse(y)
log_prob = log_prob - t.forward_log_det_jacobian(x)
y = x
log_prob += base.log_prob(y)
return log_prob
# TODO(cxxly): Add Kolmogorov-Smirnov test for sample result.
def test_sample(self):
expected_shape = (5, 10, 8, 1)
self.assertEqual(tuple(self.sample_data.shape), expected_shape)
self.assertEqual(self.sample_data.dtype, self.dtype)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,386 @@
# 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 unittest
import numpy as np
from test_distribution import DistributionNumpy
import paddle
from paddle import base
from paddle.distribution import Uniform
np.random.seed(2022)
class UniformNumpy(DistributionNumpy):
def __init__(self, low, high):
self.low = np.array(low)
self.high = np.array(high)
if str(self.low.dtype) not in ['float32', 'float64']:
self.low = self.low.astype('float32')
self.high = self.high.astype('float32')
def sample(self, shape):
shape = tuple(shape) + (self.low + self.high).shape
return self.low + (
np.random.uniform(size=shape) * (self.high - self.low)
)
def log_prob(self, value):
lb = np.less(self.low, value).astype(self.low.dtype)
ub = np.less(value, self.high).astype(self.low.dtype)
return np.log(lb * ub) - np.log(self.high - self.low)
def probs(self, value):
lb = np.less(self.low, value).astype(self.low.dtype)
ub = np.less(value, self.high).astype(self.low.dtype)
return (lb * ub) / (self.high - self.low)
def entropy(self):
return np.log(self.high - self.low)
class UniformTest(unittest.TestCase):
def setUp(self, use_gpu=False, batch_size=5, dims=6):
self.use_gpu = use_gpu
if not use_gpu:
self.place = base.CPUPlace()
self.gpu_id = -1
else:
self.place = base.CUDAPlace(0)
self.gpu_id = 0
self.init_numpy_data(batch_size, dims)
paddle.disable_static(self.place)
self.init_dynamic_data(batch_size, dims)
paddle.enable_static()
self.test_program = base.Program()
self.executor = base.Executor(self.place)
self.init_static_data(batch_size, dims)
def init_numpy_data(self, batch_size, dims):
# low ans high are 'float'
self.low_np = np.random.uniform(-2, 1)
self.high_np = np.random.uniform(2, 4)
self.values_np = np.array([1.0]).astype('float32')
def init_dynamic_data(self, batch_size, dims):
self.dynamic_low = self.low_np
self.dynamic_high = self.high_np
self.dynamic_values = paddle.to_tensor(self.values_np)
def init_static_data(self, batch_size, dims):
self.static_low = self.low_np
self.static_high = self.high_np
with base.program_guard(self.test_program):
self.static_values = paddle.static.data(
name='values', shape=[-1], dtype='float32'
)
def compare_with_numpy(self, fetch_list, sample_shape=7, tolerance=1e-6):
sample, entropy, log_prob, probs = fetch_list
np_uniform = UniformNumpy(self.low_np, self.high_np)
np_sample = np_uniform.sample([sample_shape])
np_entropy = np_uniform.entropy()
np_lp = np_uniform.log_prob(self.values_np)
np_p = np_uniform.probs(self.values_np)
np.testing.assert_equal(sample.shape, np_sample.shape)
np.testing.assert_allclose(
entropy, np_entropy, rtol=tolerance, atol=tolerance
)
np.testing.assert_allclose(
log_prob, np_lp, rtol=tolerance, atol=tolerance
)
np.testing.assert_allclose(probs, np_p, rtol=tolerance, atol=tolerance)
def test_uniform_distribution_static(self, sample_shape=7, tolerance=1e-6):
paddle.enable_static()
with base.program_guard(self.test_program):
uniform = Uniform(self.static_low, self.static_high)
sample = uniform.sample([sample_shape])
entropy = uniform.entropy()
log_prob = uniform.log_prob(self.static_values)
probs = uniform.probs(self.static_values)
fetch_list = [sample, entropy, log_prob, probs]
feed_vars = {
'low': self.low_np,
'high': self.high_np,
'values': self.values_np,
}
self.executor.run(base.default_startup_program())
fetch_list = self.executor.run(
program=self.test_program, feed=feed_vars, fetch_list=fetch_list
)
self.compare_with_numpy(fetch_list)
def func_uniform_distribution_dygraph(self, sample_shape=7, tolerance=1e-6):
paddle.disable_static()
uniform = Uniform(self.dynamic_low, self.dynamic_high)
sample = uniform.sample([sample_shape]).numpy()
entropy = uniform.entropy().numpy()
log_prob = uniform.log_prob(self.dynamic_values).numpy()
probs = uniform.probs(self.dynamic_values).numpy()
fetch_list = [sample, entropy, log_prob, probs]
self.compare_with_numpy(fetch_list)
def test_uniform_distribution_dygraph(self):
self.setUp()
self.func_uniform_distribution_dygraph()
class UniformTest2(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low ans high are 'int'
self.low_np = int(np.random.uniform(-2, 1))
self.high_np = int(np.random.uniform(2, 4))
self.values_np = np.array([1.0]).astype('float32')
class UniformTest3(UniformTest):
def init_numpy_data(self, batch_size, dims):
# test broadcast: low is float, high is numpy.ndarray with dtype 'float32'.
self.low_np = np.random.uniform(-2, 1)
self.high_np = np.random.uniform(5.0, 15.0, (batch_size, dims)).astype(
'float32'
)
self.values_np = np.random.randn(batch_size, dims).astype('float32')
def init_static_data(self, batch_size, dims):
self.static_low = self.low_np
self.static_high = self.high_np
with base.program_guard(self.test_program):
self.static_values = paddle.static.data(
name='values', shape=[-1, dims], dtype='float32'
)
class UniformTest4(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are numpy.ndarray with dtype 'float32'.
self.low_np = np.random.randn(batch_size, dims).astype('float32')
self.high_np = np.random.uniform(5.0, 15.0, (batch_size, dims)).astype(
'float32'
)
self.values_np = np.random.randn(batch_size, dims).astype('float32')
def init_static_data(self, batch_size, dims):
self.static_low = self.low_np
self.static_high = self.high_np
with base.program_guard(self.test_program):
self.static_values = paddle.static.data(
name='values', shape=[-1, dims], dtype='float32'
)
class UniformTest5(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are numpy.ndarray with dtype 'float64'.
self.low_np = np.random.randn(batch_size, dims).astype('float64')
self.high_np = np.random.uniform(5.0, 15.0, (batch_size, dims)).astype(
'float64'
)
self.values_np = np.random.randn(batch_size, dims).astype('float64')
def init_dynamic_data(self, batch_size, dims):
self.dynamic_low = self.low_np
self.dynamic_high = self.high_np
self.dynamic_values = paddle.to_tensor(self.values_np, dtype='float64')
def init_static_data(self, batch_size, dims):
self.static_low = self.low_np
self.static_high = self.high_np
with base.program_guard(self.test_program):
self.static_values = paddle.static.data(
name='values', shape=[-1, dims], dtype='float64'
)
class UniformTest6(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are Tensor with dtype 'VarType.FP32'.
self.low_np = np.random.randn(batch_size, dims).astype('float32')
self.high_np = np.random.uniform(5.0, 15.0, (batch_size, dims)).astype(
'float32'
)
self.values_np = np.random.randn(batch_size, dims).astype('float32')
def init_dynamic_data(self, batch_size, dims):
self.dynamic_low = paddle.to_tensor(self.low_np)
self.dynamic_high = paddle.to_tensor(self.high_np)
self.dynamic_values = paddle.to_tensor(self.values_np)
def init_static_data(self, batch_size, dims):
with base.program_guard(self.test_program):
self.static_low = paddle.static.data(
name='low', shape=[-1, dims], dtype='float32'
)
self.static_high = paddle.static.data(
name='high', shape=[-1, dims], dtype='float32'
)
self.static_values = paddle.static.data(
name='values', shape=[-1, dims], dtype='float32'
)
class UniformTest7(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are Tensor with dtype 'VarType.FP64'.
self.low_np = np.random.randn(batch_size, dims).astype('float64')
self.high_np = np.random.uniform(5.0, 15.0, (batch_size, dims)).astype(
'float64'
)
self.values_np = np.random.randn(batch_size, dims).astype('float64')
def init_dynamic_data(self, batch_size, dims):
self.dynamic_low = paddle.to_tensor(self.low_np, dtype='float64')
self.dynamic_high = paddle.to_tensor(self.high_np, dtype='float64')
self.dynamic_values = paddle.to_tensor(self.values_np, dtype='float64')
def init_static_data(self, batch_size, dims):
with base.program_guard(self.test_program):
self.static_low = paddle.static.data(
name='low', shape=[-1, dims], dtype='float64'
)
self.static_high = paddle.static.data(
name='high', shape=[-1, dims], dtype='float64'
)
self.static_values = paddle.static.data(
name='values', shape=[-1, dims], dtype='float64'
)
class UniformTest8(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are Tensor with dtype 'VarType.FP64'. value's dtype is 'VarType.FP32'.
self.low_np = np.random.randn(batch_size, dims).astype('float64')
self.high_np = np.random.uniform(5.0, 15.0, (batch_size, dims)).astype(
'float64'
)
self.values_np = np.random.randn(batch_size, dims).astype('float32')
def init_dynamic_data(self, batch_size, dims):
self.dynamic_low = paddle.to_tensor(self.low_np, dtype='float64')
self.dynamic_high = paddle.to_tensor(self.high_np, dtype='float64')
self.dynamic_values = paddle.to_tensor(self.values_np, dtype='float32')
def init_static_data(self, batch_size, dims):
with base.program_guard(self.test_program):
self.static_low = paddle.static.data(
name='low', shape=[-1, dims], dtype='float64'
)
self.static_high = paddle.static.data(
name='high', shape=[-1, dims], dtype='float64'
)
self.static_values = paddle.static.data(
name='values', shape=[-1, dims], dtype='float32'
)
class UniformTest9(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are numpy.ndarray with dtype 'float32'.
# high < low.
self.low_np = np.random.randn(batch_size, dims).astype('float32')
self.high_np = np.random.uniform(
-10.0, -5.0, (batch_size, dims)
).astype('float32')
self.values_np = np.random.randn(batch_size, dims).astype('float32')
def init_static_data(self, batch_size, dims):
self.static_low = self.low_np
self.static_high = self.high_np
with base.program_guard(self.test_program):
self.static_values = paddle.static.data(
name='values', shape=[-1, dims], dtype='float32'
)
class UniformTest10(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are list.
self.low_np = (
np.random.randn(batch_size, dims).astype('float32').tolist()
)
self.high_np = (
np.random.uniform(5.0, 15.0, (batch_size, dims))
.astype('float32')
.tolist()
)
self.values_np = np.random.randn(batch_size, dims).astype('float32')
def init_static_data(self, batch_size, dims):
self.static_low = self.low_np
self.static_high = self.high_np
with base.program_guard(self.test_program):
self.static_values = paddle.static.data(
name='values', shape=[-1, dims], dtype='float32'
)
class UniformTest11(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are tuple.
self.low_np = tuple(
np.random.randn(batch_size, dims).astype('float32').tolist()
)
self.high_np = tuple(
np.random.uniform(5.0, 15.0, (batch_size, dims))
.astype('float32')
.tolist()
)
self.values_np = np.random.randn(batch_size, dims).astype('float32')
def init_static_data(self, batch_size, dims):
self.static_low = self.low_np
self.static_high = self.high_np
with base.program_guard(self.test_program):
self.static_values = paddle.static.data(
name='values', shape=[-1, dims], dtype='float32'
)
class UniformTestSample(unittest.TestCase):
def setUp(self):
self.init_param()
def init_param(self):
self.low = 3.0
self.high = 4.0
def test_uniform_sample(self):
paddle.disable_static()
uniform = Uniform(low=self.low, high=self.high)
s = uniform.sample([100])
self.assertTrue((s >= self.low).all())
self.assertTrue((s < self.high).all())
paddle.enable_static()
class UniformTestSample2(UniformTestSample):
def init_param(self):
self.low = -5.0
self.high = 2.0
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,79 @@
# Copyright (c) 2022 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
import parameterize as param
import paddle
from paddle.distribution import constraint, variable
paddle.seed(2022)
@param.param_cls(
(param.TEST_CASE_NAME, 'is_discrete', 'event_rank', 'constraint'),
[('NotImplement', False, 0, constraint.Constraint())],
)
class TestVariable(unittest.TestCase):
def setUp(self):
self._var = variable.Variable(
self.is_discrete, self.event_rank, self.constraint
)
@param.param_func([(1,)])
def test_costraint(self, value):
with self.assertRaises(NotImplementedError):
self._var.constraint(value)
@param.param_cls(
(param.TEST_CASE_NAME, 'base', 'rank'), [('real_base', variable.real, 10)]
)
class TestIndependent(unittest.TestCase):
def setUp(self):
self._var = variable.Independent(self.base, self.rank)
@param.param_func(
[
(paddle.rand([2, 3, 4]), ValueError),
]
)
def test_costraint(self, value, expect):
with self.assertRaises(expect):
self._var.constraint(value)
@param.param_cls(
(param.TEST_CASE_NAME, 'vars', 'axis'), [('real_base', [variable.real], 10)]
)
class TestStack(unittest.TestCase):
def setUp(self):
self._var = variable.Stack(self.vars, self.axis)
def test_is_discrete(self):
self.assertEqual(self._var.is_discrete, False)
@param.param_func(
[
(paddle.rand([2, 3, 4]), ValueError),
]
)
def test_costraint(self, value, expect):
with self.assertRaises(expect):
self._var.constraint(value)
if __name__ == '__main__':
unittest.main()
+158
View File
@@ -0,0 +1,158 @@
# 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 unittest
import mock_data as mock
import numpy as np
import parameterize as param
import scipy.special
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import kl
np.random.seed(2022)
paddle.seed(2022)
paddle.set_default_dtype('float64')
@param.place(config.DEVICES)
@param.parameterize_cls(
(param.TEST_CASE_NAME, 'a1', 'b1', 'a2', 'b2'),
[
(
'test_regular_input',
6.0 * np.random.random((4, 5)) + 1e-4,
6.0 * np.random.random((4, 5)) + 1e-4,
6.0 * np.random.random((4, 5)) + 1e-4,
6.0 * np.random.random((4, 5)) + 1e-4,
),
],
)
class TestKLBetaBeta(unittest.TestCase):
def setUp(self):
self.p = paddle.distribution.Beta(
paddle.to_tensor(self.a1), paddle.to_tensor(self.b1)
)
self.q = paddle.distribution.Beta(
paddle.to_tensor(self.a2), paddle.to_tensor(self.b2)
)
def test_kl_divergence(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
paddle.distribution.kl_divergence(self.p, self.q),
self.scipy_kl_beta_beta(self.a1, self.b1, self.a2, self.b2),
rtol=config.RTOL.get(str(self.a1.dtype)),
atol=config.ATOL.get(str(self.a1.dtype)),
)
def scipy_kl_beta_beta(self, a1, b1, a2, b2):
return (
scipy.special.betaln(a2, b2)
- scipy.special.betaln(a1, b1)
+ (a1 - a2) * scipy.special.digamma(a1)
+ (b1 - b2) * scipy.special.digamma(b1)
+ (a2 - a1 + b2 - b1) * scipy.special.digamma(a1 + b1)
)
@param.place(config.DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'conc1', 'conc2'),
[
(
'test-regular-input',
np.random.random((5, 7, 8, 10)),
np.random.random((5, 7, 8, 10)),
),
],
)
class TestKLDirichletDirichlet(unittest.TestCase):
def setUp(self):
self.p = paddle.distribution.Dirichlet(paddle.to_tensor(self.conc1))
self.q = paddle.distribution.Dirichlet(paddle.to_tensor(self.conc2))
def test_kl_divergence(self):
with paddle.base.dygraph.guard(self.place):
np.testing.assert_allclose(
paddle.distribution.kl_divergence(self.p, self.q),
self.scipy_kl_diric_diric(self.conc1, self.conc2),
rtol=config.RTOL.get(str(self.conc1.dtype)),
atol=config.ATOL.get(str(self.conc1.dtype)),
)
def scipy_kl_diric_diric(self, conc1, conc2):
return (
scipy.special.gammaln(np.sum(conc1, -1))
- scipy.special.gammaln(np.sum(conc2, -1))
- np.sum(
scipy.special.gammaln(conc1) - scipy.special.gammaln(conc2), -1
)
+ np.sum(
(conc1 - conc2)
* (
scipy.special.digamma(conc1)
- scipy.special.digamma(np.sum(conc1, -1, keepdims=True))
),
-1,
)
)
class DummyDistribution(paddle.distribution.Distribution):
pass
@param.place(config.DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'p', 'q'),
[('test-unregister', DummyDistribution(), DummyDistribution)],
)
class TestDispatch(unittest.TestCase):
def test_dispatch_with_unregister(self):
with self.assertRaises(NotImplementedError):
paddle.distribution.kl_divergence(self.p, self.q)
@param.place(config.DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'p', 'q'),
[
(
'test-diff-dist',
mock.Exponential(paddle.rand((100, 200, 100)) + 1.0),
mock.Exponential(paddle.rand((100, 200, 100)) + 2.0),
),
(
'test-same-dist',
mock.Exponential(paddle.to_tensor([1.0])),
mock.Exponential(paddle.to_tensor([1.0])),
),
],
)
class TestKLExpfamilyExpFamily(unittest.TestCase):
def test_kl_expfamily_expfamily(self):
np.testing.assert_allclose(
paddle.distribution.kl_divergence(self.p, self.q),
kl._kl_expfamily_expfamily(self.p, self.q),
rtol=config.RTOL.get(config.DEFAULT_DTYPE),
atol=config.ATOL.get(config.DEFAULT_DTYPE),
)
if __name__ == '__main__':
unittest.main()
+221
View File
@@ -0,0 +1,221 @@
# 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 unittest
import mock_data as mock
import numpy as np
import parameterize as param
import scipy.special
import scipy.stats
from distribution import config
import paddle
from paddle.distribution import kl
np.random.seed(2022)
paddle.seed(2022)
paddle.enable_static()
@param.place(config.DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'a1', 'b1', 'a2', 'b2'),
[
(
'test_regular_input',
6.0 * np.random.random((4, 5)) + 1e-4,
6.0 * np.random.random((4, 5)) + 1e-4,
6.0 * np.random.random((4, 5)) + 1e-4,
6.0 * np.random.random((4, 5)) + 1e-4,
),
],
)
class TestKLBetaBeta(unittest.TestCase):
def setUp(self):
self.mp = paddle.static.Program()
self.sp = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.mp, self.sp):
a1 = paddle.static.data('a1', self.a1.shape, dtype=self.a1.dtype)
b1 = paddle.static.data('b1', self.b1.shape, dtype=self.b1.dtype)
a2 = paddle.static.data('a2', self.a2.shape, dtype=self.a2.dtype)
b2 = paddle.static.data('b2', self.b2.shape, dtype=self.b2.dtype)
self.p = paddle.distribution.Beta(a1, b1)
self.q = paddle.distribution.Beta(a2, b2)
self.feeds = {
'a1': self.a1,
'b1': self.b1,
'a2': self.a2,
'b2': self.b2,
}
def test_kl_divergence(self):
with paddle.static.program_guard(self.mp, self.sp):
out = paddle.distribution.kl_divergence(self.p, self.q)
self.executor.run(self.sp)
[out] = self.executor.run(
self.mp, feed=self.feeds, fetch_list=[out]
)
np.testing.assert_allclose(
out,
self.scipy_kl_beta_beta(self.a1, self.b1, self.a2, self.b2),
rtol=config.RTOL.get(str(self.a1.dtype)),
atol=config.ATOL.get(str(self.a1.dtype)),
)
def scipy_kl_beta_beta(self, a1, b1, a2, b2):
return (
scipy.special.betaln(a2, b2)
- scipy.special.betaln(a1, b1)
+ (a1 - a2) * scipy.special.digamma(a1)
+ (b1 - b2) * scipy.special.digamma(b1)
+ (a2 - a1 + b2 - b1) * scipy.special.digamma(a1 + b1)
)
@param.place(config.DEVICES)
@param.param_cls(
(param.TEST_CASE_NAME, 'conc1', 'conc2'),
[
(
'test-regular-input',
np.random.random((5, 7, 8, 10)),
np.random.random((5, 7, 8, 10)),
),
],
)
class TestKLDirichletDirichlet(unittest.TestCase):
def setUp(self):
self.mp = paddle.static.Program()
self.sp = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.mp, self.sp):
conc1 = paddle.static.data(
'conc1', self.conc1.shape, self.conc1.dtype
)
conc2 = paddle.static.data(
'conc2', self.conc2.shape, self.conc2.dtype
)
self.p = paddle.distribution.Dirichlet(conc1)
self.q = paddle.distribution.Dirichlet(conc2)
self.feeds = {'conc1': self.conc1, 'conc2': self.conc2}
def test_kl_divergence(self):
with paddle.static.program_guard(self.mp, self.sp):
out = paddle.distribution.kl_divergence(self.p, self.q)
self.executor.run(self.sp)
[out] = self.executor.run(
self.mp, feed=self.feeds, fetch_list=[out]
)
np.testing.assert_allclose(
out,
self.scipy_kl_diric_diric(self.conc1, self.conc2),
rtol=config.RTOL.get(str(self.conc1.dtype)),
atol=config.ATOL.get(str(self.conc1.dtype)),
)
def scipy_kl_diric_diric(self, conc1, conc2):
return (
scipy.special.gammaln(np.sum(conc1, -1))
- scipy.special.gammaln(np.sum(conc2, -1))
- np.sum(
scipy.special.gammaln(conc1) - scipy.special.gammaln(conc2), -1
)
+ np.sum(
(conc1 - conc2)
* (
scipy.special.digamma(conc1)
- scipy.special.digamma(np.sum(conc1, -1, keepdims=True))
),
-1,
)
)
class DummyDistribution(paddle.distribution.Distribution):
pass
@param.place(config.DEVICES)
@param.param_cls((param.TEST_CASE_NAME, 'p', 'q'), ['test-dispatch-exception'])
class TestDispatch(unittest.TestCase):
def setUp(self):
self.mp = paddle.static.Program()
self.sp = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.mp, self.sp):
self.p = DummyDistribution()
self.q = DummyDistribution()
def test_dispatch_with_unregister(self):
with (
self.assertRaises(NotImplementedError),
paddle.static.program_guard(self.mp, self.sp),
):
out = paddle.distribution.kl_divergence(self.p, self.q)
self.executor.run(self.sp)
self.executor.run(self.mp, feed={}, fetch_list=[out])
@param.place(config.DEVICES)
@param.param_cls(
(config.TEST_CASE_NAME, 'rate1', 'rate2'),
[
(
'test-diff-dist',
np.random.rand(100, 200, 100) + 1.0,
np.random.rand(100, 200, 100) + 2.0,
),
('test-same-dist', np.array([1.0]), np.array([1.0])),
],
)
class TestKLExpfamilyExpFamily(unittest.TestCase):
def setUp(self):
self.mp = paddle.static.Program()
self.sp = paddle.static.Program()
self.executor = paddle.static.Executor(self.place)
with paddle.static.program_guard(self.mp, self.sp):
rate1 = paddle.static.data(
'rate1', shape=self.rate1.shape, dtype=self.rate1.dtype
)
rate2 = paddle.static.data(
'rate2', shape=self.rate2.shape, dtype=self.rate2.dtype
)
self.p = mock.Exponential(rate1)
self.q = mock.Exponential(rate2)
self.feeds = {'rate1': self.rate1, 'rate2': self.rate2}
def test_kl_expfamily_expfamily(self):
with paddle.static.program_guard(self.mp, self.sp):
out1 = paddle.distribution.kl_divergence(self.p, self.q)
out2 = kl._kl_expfamily_expfamily(self.p, self.q)
self.executor.run(self.sp)
[out1, out2] = self.executor.run(
self.mp, feed=self.feeds, fetch_list=[out1, out2]
)
np.testing.assert_allclose(
out1,
out2,
rtol=config.RTOL.get(config.DEFAULT_DTYPE),
atol=config.ATOL.get(config.DEFAULT_DTYPE),
)
if __name__ == '__main__':
unittest.main()