gamma.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. # Copyright (c) 2023 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 import distribution
  16. from paddle.base.data_feeder import check_type, convert_dtype
  17. from paddle.base.framework import Variable
  18. from paddle.distribution import exponential_family
  19. from paddle.framework import in_dynamic_mode
  20. class Gamma(exponential_family.ExponentialFamily):
  21. r"""
  22. Gamma distribution parameterized by :attr:`concentration` (aka "alpha") and :attr:`rate` (aka "beta").
  23. The probability density function (pdf) is
  24. .. math::
  25. f(x; \alpha, \beta, x > 0) = \frac{\beta^{\alpha}}{\Gamma(\alpha)} x^{\alpha-1}e^{-\beta x}
  26. \Gamma(\alpha)=\int_{0}^{\infty} x^{\alpha-1} e^{-x} \mathrm{~d} x, (\alpha>0)
  27. Args:
  28. concentration (float|Tensor): Concentration parameter. It supports broadcast semantics.
  29. The value of concentration must be positive. When the parameter is a tensor,
  30. it represents multiple independent distribution with
  31. a batch_shape(refer to :ref:`api_paddle_distribution_Distribution`).
  32. rate (float|Tensor): Rate parameter. It supports broadcast semantics.
  33. The value of rate must be positive. When the parameter is tensor,
  34. it represent multiple independent distribution with
  35. a batch_shape(refer to :ref:`api_paddle_distribution_Distribution`).
  36. Example:
  37. .. code-block:: python
  38. >>> import paddle
  39. >>> # scale input
  40. >>> gamma = paddle.distribution.Gamma(0.5, 0.5)
  41. >>> print(gamma.mean)
  42. Tensor(shape=[], dtype=float32, place=Place(gpu:0), stop_gradient=True,
  43. 1.)
  44. >>> print(gamma.variance)
  45. Tensor(shape=[], dtype=float32, place=Place(gpu:0), stop_gradient=True,
  46. 2.)
  47. >>> print(gamma.entropy())
  48. Tensor(shape=[], dtype=float32, place=Place(gpu:0), stop_gradient=True,
  49. 0.78375685)
  50. >>> # tensor input with broadcast
  51. >>> gamma = paddle.distribution.Gamma(paddle.to_tensor([0.2, 0.4]), paddle.to_tensor(0.6))
  52. >>> print(gamma.mean)
  53. Tensor(shape=[2], dtype=float32, place=Place(gpu:0), stop_gradient=True,
  54. [0.33333331, 0.66666663])
  55. >>> print(gamma.variance)
  56. Tensor(shape=[2], dtype=float32, place=Place(gpu:0), stop_gradient=True,
  57. [0.55555552, 1.11111104])
  58. >>> print(gamma.entropy())
  59. Tensor(shape=[2], dtype=float32, place=Place(gpu:0), stop_gradient=True,
  60. [-1.99634242, 0.17067254])
  61. """
  62. def __init__(self, concentration, rate):
  63. if not in_dynamic_mode():
  64. check_type(
  65. concentration,
  66. 'concentration',
  67. (float, Variable),
  68. 'Gamma',
  69. )
  70. check_type(
  71. rate,
  72. 'rate',
  73. (float, Variable),
  74. 'Gamma',
  75. )
  76. # Get/convert concentration/rate to tensor.
  77. if self._validate_args(concentration, rate):
  78. self.concentration = concentration
  79. self.rate = rate
  80. self.dtype = convert_dtype(concentration.dtype)
  81. else:
  82. [self.concentration, self.rate] = self._to_tensor(
  83. concentration, rate
  84. )
  85. self.dtype = paddle.get_default_dtype()
  86. if not paddle.all(self.concentration > 0):
  87. raise ValueError("The arg of `concentration` must be positive.")
  88. if not paddle.all(self.rate > 0):
  89. raise ValueError("The arg of `rate` must be positive.")
  90. super().__init__(self.concentration.shape)
  91. @property
  92. def mean(self):
  93. """Mean of gamma distribution.
  94. Returns:
  95. Tensor: mean value.
  96. """
  97. return self.concentration / self.rate
  98. @property
  99. def variance(self):
  100. """Variance of gamma distribution.
  101. Returns:
  102. Tensor: variance value.
  103. """
  104. return self.concentration / self.rate.pow(2)
  105. def prob(self, value):
  106. """Probability density function evaluated at value
  107. Args:
  108. value (float|Tensor): Value to be evaluated.
  109. Returns:
  110. Tensor: Probability.
  111. """
  112. return paddle.exp(self.log_prob(value))
  113. def log_prob(self, value):
  114. """Log probability density function evaluated at value
  115. Args:
  116. value (float|Tensor): Value to be evaluated
  117. Returns:
  118. Tensor: Log probability.
  119. """
  120. return (
  121. self.concentration * paddle.log(self.rate)
  122. + (self.concentration - 1) * paddle.log(value)
  123. - self.rate * value
  124. - paddle.lgamma(self.concentration)
  125. )
  126. def entropy(self):
  127. """Entropy of gamma distribution
  128. Returns:
  129. Tensor: Entropy.
  130. """
  131. return (
  132. self.concentration
  133. - paddle.log(self.rate)
  134. + paddle.lgamma(self.concentration)
  135. + (1.0 - self.concentration) * paddle.digamma(self.concentration)
  136. )
  137. def sample(self, shape=()):
  138. """Generate samples of the specified shape.
  139. Args:
  140. shape (Sequence[int], optional): Shape of the generated samples.
  141. Returns:
  142. Tensor, A tensor with prepended dimensions shape.The data type is float32.
  143. """
  144. with paddle.no_grad():
  145. return self.rsample(shape)
  146. def rsample(self, shape=()):
  147. """Generate reparameterized samples of the specified shape.
  148. Args:
  149. shape (Sequence[int], optional): Shape of the generated samples.
  150. Returns:
  151. Tensor: A tensor with prepended dimensions shape.The data type is float32.
  152. """
  153. shape = distribution.Distribution._extend_shape(
  154. self, sample_shape=shape
  155. )
  156. return paddle.standard_gamma(
  157. self.concentration.expand(shape)
  158. ) / self.rate.expand(shape)
  159. def kl_divergence(self, other):
  160. """The KL-divergence between two gamma distributions.
  161. Args:
  162. other (Gamma): instance of Gamma.
  163. Returns:
  164. Tensor: kl-divergence between two gamma distributions.
  165. """
  166. if not isinstance(other, Gamma):
  167. raise TypeError(
  168. f"Expected type of other is Exponential, but got {type(other)}"
  169. )
  170. t1 = other.concentration * paddle.log(self.rate / other.rate)
  171. t2 = paddle.lgamma(other.concentration) - paddle.lgamma(
  172. self.concentration
  173. )
  174. t3 = (self.concentration - other.concentration) * paddle.digamma(
  175. self.concentration
  176. )
  177. t4 = (other.rate - self.rate) * (self.concentration / self.rate)
  178. return t1 + t2 + t3 + t4
  179. def _natural_parameters(self):
  180. return (self.concentration - 1, -self.rate)
  181. def _log_normalizer(self, x, y):
  182. return paddle.lgamma(x + 1) + (x + 1) * paddle.log(-y.reciprocal())