lognormal.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. # Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import paddle
  15. from paddle.distribution.normal import Normal
  16. from paddle.distribution.transform import ExpTransform
  17. from paddle.distribution.transformed_distribution import TransformedDistribution
  18. class LogNormal(TransformedDistribution):
  19. r"""The LogNormal distribution with location `loc` and `scale` parameters.
  20. .. math::
  21. X \sim Normal(\mu, \sigma)
  22. Y = exp(X) \sim LogNormal(\mu, \sigma)
  23. Due to LogNormal distribution is based on the transformation of Normal distribution, we call that :math:`Normal(\mu, \sigma)` is the underlying distribution of :math:`LogNormal(\mu, \sigma)`
  24. Mathematical details
  25. The probability density function (pdf) is
  26. .. math::
  27. pdf(x; \mu, \sigma) = \frac{1}{\sigma x \sqrt{2\pi}}e^{(-\frac{(ln(x) - \mu)^2}{2\sigma^2})}
  28. In the above equation:
  29. * :math:`loc = \mu`: is the means of the underlying Normal distribution.
  30. * :math:`scale = \sigma`: is the stddevs of the underlying Normal distribution.
  31. Args:
  32. loc(int|float|list|tuple|numpy.ndarray|Tensor): The means of the underlying Normal distribution.
  33. scale(int|float|list|tuple|numpy.ndarray|Tensor): The stddevs of the underlying Normal distribution.
  34. Examples:
  35. .. code-block:: python
  36. >>> import paddle
  37. >>> from paddle.distribution import LogNormal
  38. >>> # Define a single scalar LogNormal distribution.
  39. >>> dist = LogNormal(loc=0., scale=3.)
  40. >>> # Define a batch of two scalar valued LogNormals.
  41. >>> # The underlying Normal of first has mean 1 and standard deviation 11, the underlying Normal of second 2 and 22.
  42. >>> dist = LogNormal(loc=[1., 2.], scale=[11., 22.])
  43. >>> # Get 3 samples, returning a 3 x 2 tensor.
  44. >>> dist.sample((3, ))
  45. >>> # Define a batch of two scalar valued LogNormals.
  46. >>> # Their underlying Normal have mean 1, but different standard deviations.
  47. >>> dist = LogNormal(loc=1., scale=[11., 22.])
  48. >>> # Complete example
  49. >>> value_tensor = paddle.to_tensor([0.8], dtype="float32")
  50. >>> lognormal_a = LogNormal([0.], [1.])
  51. >>> lognormal_b = LogNormal([0.5], [2.])
  52. >>> sample = lognormal_a.sample((2, ))
  53. >>> # a random tensor created by lognormal distribution with shape: [2, 1]
  54. >>> entropy = lognormal_a.entropy()
  55. >>> print(entropy)
  56. Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
  57. [1.41893852])
  58. >>> lp = lognormal_a.log_prob(value_tensor)
  59. >>> print(lp)
  60. Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
  61. [-0.72069150])
  62. >>> p = lognormal_a.probs(value_tensor)
  63. >>> print(p)
  64. Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
  65. [0.48641577])
  66. >>> kl = lognormal_a.kl_divergence(lognormal_b)
  67. >>> print(kl)
  68. Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
  69. [0.34939718])
  70. """
  71. def __init__(self, loc, scale):
  72. self._base = Normal(loc=loc, scale=scale)
  73. self.loc = self._base.loc
  74. self.scale = self._base.scale
  75. super().__init__(self._base, [ExpTransform()])
  76. @property
  77. def mean(self):
  78. """Mean of lognormal distribution.
  79. Returns:
  80. Tensor: mean value.
  81. """
  82. return paddle.exp(self._base.mean + self._base.variance / 2)
  83. @property
  84. def variance(self):
  85. """Variance of lognormal distribution.
  86. Returns:
  87. Tensor: variance value.
  88. """
  89. return paddle.expm1(self._base.variance) * paddle.exp(
  90. 2 * self._base.mean + self._base.variance
  91. )
  92. def entropy(self):
  93. r"""Shannon entropy in nats.
  94. The entropy is
  95. .. math::
  96. entropy(\sigma) = 0.5 \log (2 \pi e \sigma^2) + \mu
  97. In the above equation:
  98. * :math:`loc = \mu`: is the mean of the underlying Normal distribution.
  99. * :math:`scale = \sigma`: is the stddevs of the underlying Normal distribution.
  100. Returns:
  101. Tensor: Shannon entropy of lognormal distribution.
  102. """
  103. return self._base.entropy() + self._base.mean
  104. def probs(self, value):
  105. """Probability density/mass function.
  106. Args:
  107. value (Tensor): The input tensor.
  108. Returns:
  109. Tensor: probability.The data type is same with :attr:`value` .
  110. """
  111. return paddle.exp(self.log_prob(value))
  112. def kl_divergence(self, other):
  113. r"""The KL-divergence between two lognormal distributions.
  114. The probability density function (pdf) is
  115. .. math::
  116. KL\_divergence(\mu_0, \sigma_0; \mu_1, \sigma_1) = 0.5 (ratio^2 + (\frac{diff}{\sigma_1})^2 - 1 - 2 \ln {ratio})
  117. .. math::
  118. ratio = \frac{\sigma_0}{\sigma_1}
  119. .. math::
  120. diff = \mu_1 - \mu_0
  121. In the above equation:
  122. * :math:`loc = \mu_0`: is the means of current underlying Normal distribution.
  123. * :math:`scale = \sigma_0`: is the stddevs of current underlying Normal distribution.
  124. * :math:`loc = \mu_1`: is the means of other underlying Normal distribution.
  125. * :math:`scale = \sigma_1`: is the stddevs of other underlying Normal distribution.
  126. * :math:`ratio`: is the ratio of scales.
  127. * :math:`diff`: is the difference between means.
  128. Args:
  129. other (LogNormal): instance of LogNormal.
  130. Returns:
  131. Tensor: kl-divergence between two lognormal distributions.
  132. """
  133. return self._base.kl_divergence(other._base)