Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Hackathon No.8】 add gumbel distribution api #46255

Merged
merged 69 commits into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
d4263c2
init gumbel api
PureNatural Sep 18, 2022
a29f111
commit: update test file
dasenCoding Sep 18, 2022
f5d62e1
fix:bug
PureNatural Sep 19, 2022
0b8faec
update Gumbel API
dasenCoding Sep 28, 2022
e6a8c1b
upgrade distribution/gumbel.py
dasenCoding Oct 4, 2022
2791493
add tests/test_distribution_gumbel.py
dasenCoding Oct 4, 2022
1541ecb
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 4, 2022
ef3dc50
fix:code style
PureNatural Oct 4, 2022
ddcd86a
fix:code style
PureNatural Oct 4, 2022
4e40718
fix:code style
PureNatural Oct 4, 2022
fff33ad
fix:code style
PureNatural Oct 4, 2022
517d053
fix bug
dasenCoding Oct 5, 2022
cedc871
fix:code style
dasenCoding Oct 5, 2022
72cd09b
fix:code style
PureNatural Oct 5, 2022
8e5bdc4
fix:rollback uniform
PureNatural Oct 5, 2022
cc3f783
fix:delete invalid code
PureNatural Oct 5, 2022
b6416cb
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 9, 2022
7f603a6
fix:bug and add static test
PureNatural Oct 9, 2022
6a06603
fix:code style
PureNatural Oct 9, 2022
06b9dc4
fix:code style
PureNatural Oct 9, 2022
d83d484
fix:delete init transforms
PureNatural Oct 9, 2022
db490e3
fix:bug
PureNatural Oct 9, 2022
381d059
fix:bug
PureNatural Oct 9, 2022
931f572
fix:code style
PureNatural Oct 9, 2022
b95dc13
fix:code style
PureNatural Oct 9, 2022
78b1b5b
fix:add transforms
PureNatural Oct 9, 2022
67047a2
fix:code style
PureNatural Oct 9, 2022
554a813
fix:code style
PureNatural Oct 9, 2022
c786d25
fix:bug
PureNatural Oct 9, 2022
c398fe3
fix:bug
PureNatural Oct 9, 2022
c713d81
fix:code style
PureNatural Oct 9, 2022
983a3f8
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 9, 2022
aea7df7
fix:code style
PureNatural Oct 9, 2022
33c780b
fix:bug
PureNatural Oct 9, 2022
da166ee
fix:code style
PureNatural Oct 9, 2022
6891ad8
fix:code style
PureNatural Oct 9, 2022
e10fd27
fix:bug for gumbel.py / add:judge transforms'len for transformed_dist…
dasenCoding Oct 10, 2022
8d5a83c
Merge branch 'gumbel_api' of https://github.com/PureNatural/Paddle in…
dasenCoding Oct 10, 2022
4e328be
update gumbel.py
dasenCoding Oct 11, 2022
9d89aac
fix:bug for test_distribution_gumbel.py
dasenCoding Oct 11, 2022
a0c357d
fix:bug for test_distribution_gumbel_static.py
dasenCoding Oct 11, 2022
db1cbfd
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 11, 2022
c6a2292
fix:code style
PureNatural Oct 11, 2022
c735592
fix:code style
PureNatural Oct 11, 2022
38530db
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 11, 2022
fc57abe
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 11, 2022
4bab5d1
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 11, 2022
98f8ed6
fix:coverage
PureNatural Oct 11, 2022
33a83fc
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 12, 2022
f2fa6dc
fix:bug
PureNatural Oct 12, 2022
a20a723
fix:bug
PureNatural Oct 12, 2022
0289b74
fix:code style
PureNatural Oct 12, 2022
fb972c3
fix:bug
PureNatural Oct 12, 2022
2f017a0
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 12, 2022
0e2892d
delete:no use package for gumbel.py
dasenCoding Oct 12, 2022
3261480
add:coverage transforms'len judge for test_distribution_gumbel.py
dasenCoding Oct 12, 2022
1ecfcc6
fix:code style for test_distribution_gumbel.py
dasenCoding Oct 12, 2022
6a9245e
fix:coverage
PureNatural Oct 12, 2022
e593fb4
fix:code style
PureNatural Oct 12, 2022
8c57748
fix:code style
PureNatural Oct 12, 2022
f7a0c36
fix:code style
PureNatural Oct 12, 2022
444454e
fix:code style
PureNatural Oct 12, 2022
3598ed5
fix:code style
PureNatural Oct 12, 2022
017f66c
Merge branch 'PaddlePaddle:develop' into gumbel_api
PureNatural Oct 14, 2022
e7108f0
fix:en doc
PureNatural Oct 14, 2022
069cadf
Merge branch 'gumbel_api' of github.com:PureNatural/Paddle into gumbe…
PureNatural Oct 14, 2022
e93ff40
fix:param
PureNatural Oct 14, 2022
6172d98
fix:copyright
PureNatural Oct 16, 2022
c957ab4
fixSample; test=document_fix
dasenCoding Oct 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion python/paddle/distribution/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from paddle.distribution.categorical import Categorical
from paddle.distribution.dirichlet import Dirichlet
from paddle.distribution.distribution import Distribution
from paddle.distribution.gumbel import Gumbel
from paddle.distribution.exponential_family import ExponentialFamily
from paddle.distribution.independent import Independent
from paddle.distribution.kl import kl_divergence, register_kl
Expand All @@ -31,7 +32,7 @@
__all__ = [ # noqa
'Beta', 'Categorical', 'Dirichlet', 'Distribution', 'ExponentialFamily',
'Multinomial', 'Normal', 'Uniform', 'kl_divergence', 'register_kl',
'Independent', 'TransformedDistribution', 'Laplace'
'Independent', 'TransformedDistribution', 'Laplace', 'Gumbel'
]

__all__.extend(transform.__all__)
289 changes: 289 additions & 0 deletions python/paddle/distribution/gumbel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的,我们随后会跟进修改

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ligoml 您好,我们对copyright也进行了修改,麻烦您再review一下,非常感谢。

#
# 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
import numbers
import math
import numpy as np

from paddle.distribution.uniform import Uniform
from paddle.distribution.transformed_distribution import TransformedDistribution
from paddle.distribution.transform import AffineTransform, ExpTransform

try:
from collections.abc import Iterable
except:
from collections import Iterable


class Gumbel(TransformedDistribution):
r"""The Gumbel distribution with location `loc` and `scale` parameters.

Mathematical details

The probability density function (pdf) is

.. math::

pdf(x; mu, sigma) = exp(-(x - mu) / sigma - exp(-(x - mu) / sigma)) / sigma


In the above equation:

* :math:`loc = \mu`: is the mean.
* :math:`scale = \sigma`: is the std.

Args:
loc(int|float|tensor): The mean of gumbel distribution.The data type is int, float, tensor.
scale(int|float|tensor): The std of gumbel distribution.The data type is int, float, tensor.

Copy link
Contributor

@cxxly cxxly Sep 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int|float|Tensor,Tensor为必须支持数据类型

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The location parameter of gumbel distribution .....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Examples:

>>> example = Gumbel(paddle.to_tensor([0.0]), paddle.to_tensor([1.0]))
>>> example.sample()
Tensor(shape=[1], dtype=float32, place=Place(gpu:0), stop_gradient=True,
[4.14814520])

Copy link
Contributor

@cxxly cxxly Oct 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1)参考 API 文档规范书写示例代码,https://github.com/PaddlePaddle/docs/wiki/飞桨API文档书写规范,下述每个方法代码示例存在同样问题,请统一修改
2)建议每个方法内代码示例,统一写到此处

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"""

def __init__(self, loc, scale):

self.batch_size_unknown = False
self.all_arg_is_float = False
self.loc = paddle.to_tensor(loc, dtype='float32')
self.scale = paddle.to_tensor(scale, dtype='float32')
Copy link
Contributor

@cxxly cxxly Oct 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 此时并不能断言loc scale不是Tensor,如果本身是Tensor类型,不需要转成Tesnor
    2)paddle.to_tensor仅支持动态图,使用paddle.full替代,下文多处使用to_tensor,请统一修改

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


finfo = np.finfo(dtype='float32')
if isinstance(loc, numbers.Number) and isinstance(
scale, numbers.Number):
self.base_dist = Uniform(float(finfo.tiny), float(1 - finfo.eps))
else:
self.base_dist = Uniform(
paddle.full_like(self.loc, float(finfo.tiny)),
paddle.full_like(self.loc, float(1 - finfo.eps)))

self.transforms = (ExpTransform(),
AffineTransform(loc=paddle.to_tensor(
0, dtype='float32'),
scale=-paddle.ones_like(self.scale)),
ExpTransform(),
AffineTransform(loc=self.loc, scale=-self.scale))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1)transforms此处定义了,但是并没有用到,可以用一个空元组表示,不需要创建实例
2)更优雅的做法是实现InverseTransform,self.transforms = (InverseTransform(ExpTransform())...),下述rsample方法直接复用父类sample

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done 1)
建议 2),未能实现 InverseTransform。


super(Gumbel, self).__init__(self.base_dist, self.transforms)

Copy link
Contributor

@cxxly cxxly Oct 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

62-82行代码逻辑太过冗余,建议统一转成Tensor进行处理,类似如下写法(伪代码)

if not isinstance(loc, (numbers.Real, framework.Variable)):
    raise TypeError(
        f"Expected type of loc is Real|Variable, but got {type(loc)}")
if not isinstance(scale, (numbers.Real, framework.Variable)):
    raise TypeError(
        f"Expected type of scale is Real|Variable, but got {type(scale)}"
    )

if isinstance(loc, numbers.Real):
    self.loc = paddle.full(shape=(), fill_value=loc)
if isinstance(scale, numbers.Real):
    self.scale = paddle.full(shape=(), fill_value=scale)

if self.loc.shape != self.scale.shape:
    self.loc, self.scale = paddle.broadcast_tensors([self.loc, self.scale])

self.base_dist = paddle.distribution.Uniform(
                 paddle.full_like(self.loc, float(finfo.tiny)),
                 paddle.full_like(self.loc, float(1 - finfo.eps)))

self.transforms = ....
super(Gumbel, self).__init__(...)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@property
def mean(self):
"""Mean of distribution

The mean is

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mean is ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

.. math::

mean = \mu + \sigma * γ

In the above equation:

* :math:`loc = \mu`: is the location parameter.
* :math:`scale = \sigma`: is the scale parameter.
* :math:`γ`: is the euler's constant.

Returns:
Tensor: mean value.

"""
return self.loc + self.scale * np.euler_gamma

@property
def variance(self):
"""Variance of distribution.

The variance is

.. math::

variance = \sigma^2 * \pi^2 / 6

In the above equation:

* :math:`scale = \sigma`: is the scale parameter.

Returns:
Tensor: The variance value.

"""
temp = paddle.to_tensor(math.pi * math.pi, dtype='float32')

Copy link
Contributor

@cxxly cxxly Oct 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1)to_tensor仅支持动态图,使用paddle.full 2) 数据类型和scale保持一致,不一定是float32

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return paddle.pow(self.scale, 2) * temp / 6

@property
def stddev(self):
"""Standard deviation of distribution

The standard deviation is

.. math::

stddev = \sqrt{\sigma^2 * \pi^2 / 6}

In the above equation:
* :math:`scale = \sigma`: is the scale parameter.

Returns:
Tensor: std value
"""
return paddle.sqrt(self.variance)

def prob(self, value):
"""Probability density/mass function

Args:
value (Tensor): The input tensor.

Returns:
Tensor: probability.The data type is same with value.

Examples:

>>> example = Gumbel(paddle.to_tensor([0.0]), paddle.to_tensor([1.0]))
>>> value = paddle.to_tensor([0.5])
>>> example.prob(value)
Tensor(shape=[1], dtype=float32, place=Place(gpu:0), stop_gradient=True,
[0.33070430])

"""
if type(value) != type(self.loc):
raise TypeError('value type must be Tensor')

y = (self.loc - value) / self.scale
return paddle.exp(y - paddle.exp(y)) / self.scale

def log_prob(self, value):
"""Log probability density/mass function.

Args:
value (Tensor): The input tensor.

Returns:
Tensor: log probability.The data type is same with value.

Examples:

>>> example = Gumbel(paddle.to_tensor([0.0]), paddle.to_tensor([1.0]))
>>> value = paddle.to_tensor([0.5])
>>> example.prob(value
Tensor(shape=[1], dtype=float32, place=Place(gpu:0), stop_gradient=True,
[-1.10653067])

"""
return paddle.log(self.prob(value))

def cdf(self, value):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in order to have rfc same with code, need to add this functioncdf in rfc API 实现方案

"""Cumulative distribution function.
Args:
value (Tensor): value to be evaluated.

Returns:
Tensor: cumulative probability of value.

Examples:

>>> example = Gumbel(paddle.to_tensor([0.0]), paddle.to_tensor([1.0]))
>>> value = paddle.to_tensor([0.5])
>>> example.cdf(value)
Tensor(shape=[1], dtype=float32, place=Place(gpu:0), stop_gradient=True,
[0.54523915])

"""
if value.dtype != self.loc.dtype:
value = paddle.cast(value, self.loc.dtype)

return paddle.exp(-paddle.exp(-(value - self.loc) / self.scale))

def entropy(self):
"""Entropy of Gumbel distribution.

Returns:
Entropy of distribution.

Examples:

>>> example = Gumbel(paddle.to_tensor([0.0]), paddle.to_tensor([1.0]))
>>> example.entropy()
Tensor(shape=[1], dtype=float32, place=Place(gpu:0), stop_gradient=True,
[1.57721567])

"""
return paddle.log(self.scale) + 1 + np.euler_gamma

def sample(self, shape):
"""Sample from ``TransformedDistribution``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from Gumbel

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


Args:
shape (list, optional): The sample shape. Defaults to ().
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shape(Sequence[int], ).......

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


Returns:
Tensor: A tensor with prepended dimensions shape.The data type is float32.

Examples:

>>> example = Gumbel(paddle.to_tensor([0.0]), paddle.to_tensor([1.0]))
>>> m.sample()
Tensor(shape=[2, 1], dtype=float32, place=Place(gpu:0), stop_gradient=True,
[[0.39180365],
[2.69657302]])

"""
if not isinstance(shape, Iterable):
raise TypeError('sample shape must be Iterable object.')

with paddle.no_grad():
return self.rsample(shape)

def rsample(self, shape):
"""reparameterized sample
Args:
shape (list): 1D `int32`. Shape of the generated samples.
seed (int): Python integer number.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. shape(Sequence[int])...
    2)删除seed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


Returns:
Tensor: A tensor with prepended dimensions shape.The data type is float32.

Examples:

>>> example = Gumbel(paddle.to_tensor([0.0]), paddle.to_tensor([1.0]))
>>> example.rsample([2])
Tensor(shape=[2, 1], dtype=float32, place=Place(gpu:0), stop_gradient=True,
[[0.80463481],
[0.91893655]])

"""
with paddle.no_grad():
x = self._base.sample(shape)
Copy link
Contributor

@cxxly cxxly Oct 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

此处不需要no_grad,rsample是重参数化采样,支持梯度求解

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


expTransform = paddle.distribution.ExpTransform()
affineTf1 = paddle.distribution.AffineTransform(
paddle.to_tensor(0, dtype='float32'),
-paddle.ones_like(self.scale))
affineTf2 = paddle.distribution.AffineTransform(
self.loc, -self.scale)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

变量命名采用下划线

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


x = expTransform.inverse(x)

x = affineTf1.forward(x)

x = expTransform.inverse(x)

x = affineTf2.forward(x)

Copy link
Contributor

@cxxly cxxly Oct 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1)如果变换过程分开写,中间变量名请使用有意义的命名,如 sample_exp_inv = exp_trans.inverse(x)
2) 可以写为一行,return exp.inverse(affine1.forward(exp.inverse(x)))...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return x
2 changes: 2 additions & 0 deletions python/paddle/distribution/uniform.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ def __init__(self, low, high, name=None):
self.low = tensor.cast(self.low, dtype=self.dtype)
self.high = tensor.cast(self.high, dtype=self.dtype)

super(Uniform, self).__init__(self.low.shape)

def sample(self, shape, seed=0):
"""Generate samples of the specified shape.

Expand Down
Loading