uniform.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. # Copyright (c) 2021 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 numpy as np
  15. import paddle
  16. from paddle import _C_ops
  17. from paddle.base.data_feeder import check_type, convert_dtype
  18. from paddle.base.framework import Variable
  19. from paddle.distribution import distribution
  20. from paddle.framework import in_dynamic_mode
  21. from paddle.tensor import random
  22. class Uniform(distribution.Distribution):
  23. r"""Uniform distribution with `low` and `high` parameters.
  24. Mathematical Details
  25. The probability density function (pdf) is
  26. .. math::
  27. pdf(x; a, b) = \frac{1}{Z}, \ a <=x <b
  28. .. math::
  29. Z = b - a
  30. In the above equation:
  31. * :math:`low = a`,
  32. * :math:`high = b`,
  33. * :math:`Z`: is the normalizing constant.
  34. The parameters `low` and `high` must be shaped in a way that supports
  35. `Broadcasting` (e.g., `high - low` is a valid operation).
  36. Note:
  37. If you want know more about broadcasting, please refer to `Introduction to Tensor`_ .
  38. .. _Introduction to Tensor: ../../guides/beginner/tensor_en.html#chapter5-broadcasting-of-tensor
  39. Args:
  40. low(int|float|list|tuple|numpy.ndarray|Tensor): The lower boundary of
  41. uniform distribution.The data type is float32 and float64.
  42. high(int|float|list|tuple|numpy.ndarray|Tensor): The higher boundary
  43. of uniform distribution.The data type is float32 and float64.
  44. name (str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
  45. Examples:
  46. .. code-block:: python
  47. >>> import paddle
  48. >>> from paddle.distribution import Uniform
  49. >>> paddle.seed(2023)
  50. >>> # Without broadcasting, a single uniform distribution [3, 4]:
  51. >>> u1 = Uniform(low=3.0, high=4.0)
  52. >>> # 2 distributions [1, 3], [2, 4]
  53. >>> u2 = Uniform(low=[1.0, 2.0], high=[3.0, 4.0])
  54. >>> # 4 distributions
  55. >>> u3 = Uniform(low=[[1.0, 2.0], [3.0, 4.0]],
  56. ... high=[[1.5, 2.5], [3.5, 4.5]])
  57. ...
  58. >>> # With broadcasting:
  59. >>> u4 = Uniform(low=3.0, high=[5.0, 6.0, 7.0])
  60. >>> # Complete example
  61. >>> value_tensor = paddle.to_tensor([0.8], dtype="float32")
  62. >>> uniform = Uniform([0.], [2.])
  63. >>> sample = uniform.sample([2])
  64. >>> # a random tensor created by uniform distribution with shape: [2, 1]
  65. >>> entropy = uniform.entropy()
  66. >>> print(entropy)
  67. Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
  68. [0.69314718])
  69. >>> lp = uniform.log_prob(value_tensor)
  70. >>> print(lp)
  71. Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
  72. [-0.69314718])
  73. >>> p = uniform.probs(value_tensor)
  74. >>> print(p)
  75. Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
  76. [0.50000000])
  77. """
  78. def __init__(self, low, high, name=None):
  79. if not in_dynamic_mode():
  80. check_type(
  81. low,
  82. 'low',
  83. (int, float, np.ndarray, Variable, list, tuple),
  84. 'Uniform',
  85. )
  86. check_type(
  87. high,
  88. 'high',
  89. (int, float, np.ndarray, Variable, list, tuple),
  90. 'Uniform',
  91. )
  92. self.all_arg_is_float = False
  93. self.batch_size_unknown = False
  94. self.name = name if name is not None else 'Uniform'
  95. self.dtype = 'float32'
  96. if isinstance(low, int):
  97. low = float(low)
  98. if isinstance(high, int):
  99. high = float(high)
  100. if self._validate_args(low, high):
  101. self.low = low
  102. self.high = high
  103. self.dtype = convert_dtype(low.dtype)
  104. else:
  105. if isinstance(low, float) and isinstance(high, float):
  106. self.all_arg_is_float = True
  107. if isinstance(low, np.ndarray) and str(low.dtype) in [
  108. 'float32',
  109. 'float64',
  110. ]:
  111. self.dtype = low.dtype
  112. elif isinstance(high, np.ndarray) and str(high.dtype) in [
  113. 'float32',
  114. 'float64',
  115. ]:
  116. self.dtype = high.dtype
  117. self.low, self.high = self._to_tensor(low, high)
  118. if self.dtype != convert_dtype(self.low.dtype):
  119. self.low = paddle.cast(self.low, dtype=self.dtype)
  120. self.high = paddle.cast(self.high, dtype=self.dtype)
  121. super().__init__(self.low.shape)
  122. def sample(self, shape, seed=0):
  123. """Generate samples of the specified shape.
  124. Args:
  125. shape (list): 1D `int32`. Shape of the generated samples.
  126. seed (int): Python integer number.
  127. Returns:
  128. Tensor, A tensor with prepended dimensions shape. The data type is float32.
  129. """
  130. if not in_dynamic_mode():
  131. check_type(shape, 'shape', (list), 'sample')
  132. check_type(seed, 'seed', (int), 'sample')
  133. name = self.name + '_sample'
  134. batch_shape = list((self.low + self.high).shape)
  135. if -1 in batch_shape:
  136. output_shape = shape + batch_shape
  137. fill_shape = list(batch_shape + shape)
  138. fill_shape[0] = paddle.shape(self.low + self.high)[0].item()
  139. zero_tmp = paddle.full(fill_shape, 0.0, self.dtype)
  140. uniform_random_tmp = random.uniform_random_batch_size_like(
  141. zero_tmp,
  142. zero_tmp.shape,
  143. dtype=self.dtype,
  144. min=0.0,
  145. max=1.0,
  146. seed=seed,
  147. )
  148. zero_tmp_reshape = paddle.reshape(zero_tmp, output_shape)
  149. uniform_random_tmp_reshape = paddle.reshape(
  150. uniform_random_tmp, output_shape
  151. )
  152. output = uniform_random_tmp_reshape * (
  153. zero_tmp_reshape + self.high - self.low
  154. )
  155. output = paddle.add(output, self.low, name=name)
  156. return output
  157. else:
  158. output_shape = shape + batch_shape
  159. output = paddle.uniform(
  160. output_shape, dtype=self.dtype, min=0.0, max=1.0, seed=seed
  161. ) * (
  162. paddle.zeros(output_shape, dtype=self.dtype)
  163. + (self.high - self.low)
  164. )
  165. output = paddle.add(output, self.low, name=name)
  166. if self.all_arg_is_float:
  167. return paddle.reshape(output, shape, name=name)
  168. else:
  169. return output
  170. def log_prob(self, value):
  171. """Log probability density/mass function.
  172. Args:
  173. value (Tensor): The input tensor.
  174. Returns:
  175. Tensor, log probability.The data type is same with value.
  176. """
  177. value = self._check_values_dtype_in_probs(self.low, value)
  178. if in_dynamic_mode():
  179. # ensure value in [low, high]
  180. lb_bool = self.low < value
  181. ub_bool = value < self.high
  182. lb = _C_ops.cast(lb_bool, value.dtype)
  183. ub = _C_ops.cast(ub_bool, value.dtype)
  184. return paddle.log(lb * ub) - paddle.log(self.high - self.low)
  185. else:
  186. name = self.name + '_log_prob'
  187. lb_bool = self.low < value
  188. ub_bool = value < self.high
  189. lb = paddle.cast(lb_bool, dtype=value.dtype)
  190. ub = paddle.cast(ub_bool, dtype=value.dtype)
  191. return paddle.subtract(
  192. paddle.log(lb * ub), paddle.log(self.high - self.low), name=name
  193. )
  194. def probs(self, value):
  195. """Probability density/mass function.
  196. Args:
  197. value (Tensor): The input tensor.
  198. Returns:
  199. Tensor, probability. The data type is same with value.
  200. """
  201. value = self._check_values_dtype_in_probs(self.low, value)
  202. if in_dynamic_mode():
  203. lb_bool = self.low < value
  204. ub_bool = value < self.high
  205. lb = _C_ops.cast(lb_bool, value.dtype)
  206. ub = _C_ops.cast(ub_bool, value.dtype)
  207. return (lb * ub) / (self.high - self.low)
  208. else:
  209. name = self.name + '_probs'
  210. lb_bool = self.low < value
  211. ub_bool = value < self.high
  212. lb = paddle.cast(lb_bool, dtype=value.dtype)
  213. ub = paddle.cast(ub_bool, dtype=value.dtype)
  214. return paddle.divide((lb * ub), (self.high - self.low), name=name)
  215. def entropy(self):
  216. r"""Shannon entropy in nats.
  217. The entropy is
  218. .. math::
  219. entropy(low, high) = \\log (high - low)
  220. Returns:
  221. Tensor, Shannon entropy of uniform distribution.The data type is float32.
  222. """
  223. name = self.name + '_entropy'
  224. return paddle.log(self.high - self.low, name=name)