def probs(self, value): """Probabilities of the given category (``value``). If ``logits`` is 2-D or higher dimension, the last dimension will be regarded as category, and the others represents the different distributions. At the same time, if ``vlaue`` is 1-D Tensor, ``value`` will be broadcast to the same number of distributions as ``logits``. If ``value`` is not 1-D Tensor, ``value`` should have the same number distributions with ``logits. That is, ``value[:-1] = logits[:-1]``. Args: value (Tensor): The input tensor represents the selected category index. Returns: Tensor: probability according to the category index. Examples: .. code-block:: python import paddle from paddle.distribution import Categorical paddle.seed(100) # on CPU device x = paddle.rand([6]) print(x) # [0.5535528 0.20714243 0.01162981 # 0.51577556 0.36369765 0.2609165 ] cat = Categorical(x) value = paddle.to_tensor([2,1,3]) cat.probs(value) # [0.00608027 0.108298 0.269656] """ name = self.name + '_probs' if len(self._prob.shape) == 1: # batch_shape is empty return paddle.gather(self._prob, value.reshape([-1], name=name), name=name).reshape(value.shape, name=name) else: if len(value.shape) == 1: return paddle.take_along_axis( self._prob, paddle.reshape(value, (len(self._prob.shape) - 1) * [1] + [-1], name=name), axis=-1) else: return paddle.take_along_axis(self._prob, value, axis=-1)
def test_api_dygraph(self): paddle.disable_static(self.place[0]) x_tensor = paddle.to_tensor(self.x_np) self.index = paddle.to_tensor(self.index_np) out = paddle.take_along_axis(x_tensor, self.index, self.axis) out_ref = np.array( np.take_along_axis(self.x_np, self.index_np, self.axis)) self.assertEqual(np.allclose(out.numpy(), out_ref, rtol=1e-03), True) paddle.enable_static()
def test_api_static(self): paddle.enable_static() with paddle.static.program_guard(paddle.static.Program()): x = paddle.fluid.data('X', self.shape) index = paddle.fluid.data('Index', self.index_shape, "int64") out = paddle.take_along_axis(x, index, self.axis) exe = paddle.static.Executor(self.place) res = exe.run(feed={'X': self.x_np, 'Index': self.index_np}, fetch_list=[out]) out_ref = np.array( np.take_along_axis(self.x_np, self.index_np, self.axis)) for out in res: self.assertEqual(np.allclose(out, out_ref, rtol=1e-03), True)
def _compute_quantile(x, q, axis=None, keepdim=False, ignore_nan=False): """ Compute the quantile of the input along the specified axis. Args: Args: x (Tensor): The input Tensor, it's data type can be float32, float64. q (int|float|list): The q for calculate quantile, which should be in range [0, 1]. If q is a list, each q will be calculated and the first dimension of output is same to the number of ``q`` . axis (int|list, optional): The axis along which to calculate quantile. ``axis`` should be int or list of int. ``axis`` should be in range [-D, D), where D is the dimensions of ``x`` . If ``axis`` is less than 0, it works the same way as :math:`axis + D`. If ``axis`` is a list, quantile is calculated over all elements of given axises. If ``axis`` is None, quantile is calculated over all elements of ``x``. Default is None. keepdim (bool, optional): Whether to reserve the reduced dimension(s) in the output Tensor. If ``keepdim`` is True, the dimensions of the output Tensor is the same as ``x`` except in the reduced dimensions(it is of size 1 in this case). Otherwise, the shape of the output Tensor is squeezed in ``axis`` . Default is False. ignore_nan: (bool, optional): Whether to ignore NaN of input Tensor. If ``ignore_nan`` is True, it will calculate nanquantile. Otherwise it will calculate quantile. Default is False. Returns: Tensor, results of quantile along ``axis`` of ``x``. In order to obtain higher precision, data type of results will be float64. """ # Validate x if not isinstance(x, Variable): raise TypeError("input x should be a Tensor.") # Validate q if isinstance(q, (int, float)): q = [q] elif isinstance(q, (list, tuple)): if len(q) <= 0: raise ValueError("q should not be empty") else: raise TypeError("Type of q should be int, float, list or tuple.") # Validate axis dims = len(x.shape) out_shape = list(x.shape) if axis is None: x = paddle.flatten(x) axis = 0 out_shape = [1] * dims else: if isinstance(axis, list): if len(axis) <= 0: raise ValueError("axis should not be empty") axis_src, axis_dst = [], [] for axis_single in axis: if not isinstance(axis_single, int) or not ( axis_single < dims and axis_single >= -dims): raise ValueError( "Axis should be None, int, or a list, element should in range [-rank(x), rank(x))." ) if axis_single < 0: axis_single = axis_single + dims axis_src.append(axis_single) out_shape[axis_single] = 1 axis_dst = list(range(-len(axis), 0)) x = paddle.moveaxis(x, axis_src, axis_dst) x = paddle.flatten(x, axis_dst[0], axis_dst[-1]) axis = axis_dst[0] else: if not isinstance(axis, int) or not (axis < dims and axis >= -dims): raise ValueError( "Axis should be None, int, or a list, element should in range [-rank(x), rank(x))." ) if axis < 0: axis += dims out_shape[axis] = 1 mask = x.isnan() valid_counts = mask.logical_not().sum(axis=axis, keepdim=True, dtype='float64') indices = [] for q_num in q: if q_num < 0 or q_num > 1: raise ValueError("q should be in range [0, 1]") if paddle.in_dynamic_mode(): q_num = paddle.to_tensor(q_num, dtype='float64') if ignore_nan: indices.append(q_num * (valid_counts - 1)) else: # TODO(Asthestarsfalll): Use paddle.index_fill instead of where index = q_num * (valid_counts - 1) last_index = x.shape[axis] - 1 nums = paddle.full_like(index, fill_value=last_index) index = paddle.where(mask.any(axis=axis, keepdim=True), nums, index) indices.append(index) sorted_tensor = paddle.sort(x, axis) outputs = [] # TODO(chenjianye): replace the for-loop to directly take elements. for index in indices: indices_below = paddle.floor(index).astype(paddle.int32) indices_upper = paddle.ceil(index).astype(paddle.int32) tensor_upper = paddle.take_along_axis( sorted_tensor, indices_upper, axis=axis) tensor_below = paddle.take_along_axis( sorted_tensor, indices_below, axis=axis) weights = (index - indices_below.astype('float64')) out = paddle.lerp( tensor_below.astype('float64'), tensor_upper.astype('float64'), weights) if not keepdim: out = paddle.squeeze(out, axis=axis) else: out = out.reshape(out_shape) outputs.append(out) if len(q) > 1: outputs = paddle.stack(outputs, 0) else: outputs = outputs[0] return outputs
def quantile(x, q, axis=None, keepdim=False): """ Compute the quantile of the input along the specified axis. Args: x (Tensor): The input Tensor, it's data type can be float32, float64. q (int|float|list): The q for calculate quantile, which should be in range [0, 1]. If q is a list, each q will be calculated and the first dimension of output is same to the number of ``q`` . axis (int|list, optional): The axis along which to calculate quantile. ``axis`` should be int or list of int. ``axis`` should be in range [-D, D), where D is the dimensions of ``x`` . If ``axis`` is less than 0, it works the same way as :math:`axis + D`. If ``axis`` is a list, quantile is calculated over all elements of given axises. If ``axis`` is None, quantile is calculated over all elements of ``x``. Default is None. keepdim (bool, optional): Whether to reserve the reduced dimension(s) in the output Tensor. If ``keepdim`` is True, the dimensions of the output Tensor is the same as ``x`` except in the reduced dimensions(it is of size 1 in this case). Otherwise, the shape of the output Tensor is squeezed in ``axis`` . Default is False. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. Returns: Tensor, results of quantile along ``axis`` of ``x``. If data type of ``x`` is float64, data type of results will be float64, otherwise data type will be float32. Examples: .. code-block:: python import paddle x = paddle.randn((2,3)) #[[-1.28740597, 0.49533170, -1.00698614], # [-1.11656201, -1.01010525, -2.23457789]]) y1 = paddle.quantile(x, q=0.5, axis=[0, 1]) # y1 = -1.06333363 y2 = paddle.quantile(x, q=0.5, axis=1) # y2 = [-1.00698614, -1.11656201] y3 = paddle.quantile(x, q=[0.3, 0.5], axis=1) # y3 =[[-1.11915410, -1.56376839], # [-1.00698614, -1.11656201]] y4 = paddle.quantile(x, q=0.8, axis=1, keepdim=True) # y4 = [[-0.10559537], # [-1.05268800]]) """ if not isinstance(x, Variable): raise TypeError("input x should be a Tensor.") dims = len(x.shape) out_shape = x.shape if axis is None: x = paddle.flatten(x) axis = 0 out_shape = [1] * dims else: if isinstance(axis, list): if (len(axis) <= 0): raise ValueError("axis should not be empty") axis_src, axis_dst = [], [] for axis_single in axis: if not isinstance(axis_single, int) or not ( axis_single < dims and axis_single >= -dims): raise ValueError( "Axis should be None, int, or a list, element should in range [-rank(x), rank(x))." ) if axis_single < 0: axis_single = axis_single + dims axis_src.append(axis_single) out_shape[axis_single] = 1 axis_dst = list(range(-len(axis), 0)) x = paddle.moveaxis(x, axis_src, axis_dst) x = paddle.flatten(x, axis_dst[0], axis_dst[-1]) axis = axis_dst[0] else: if not isinstance(axis, int) or not (axis < dims and axis >= -dims): raise ValueError( "Axis should be None, int, or a list, element should in range [-rank(x), rank(x))." ) if axis < 0: axis += dims out_shape[axis] = 1 indices = [] if isinstance(q, (int, float)): if q < 0 or q > 1: raise ValueError("q should be in range [0, 1]") indices.append(q * (x.shape[axis] - 1)) elif isinstance(q, (list, tuple)): if len(q) <= 0: raise ValueError("q should not be empty") for q_num in q: if q_num < 0 or q_num > 1: raise ValueError("q should be in range [0, 1]") indices.append(q_num * (x.shape[axis] - 1)) else: raise TypeError("Type of q should be int, float, list or tuple.") indices = paddle.to_tensor(indices).astype(paddle.float32) sorted_tensor = paddle.sort(x, axis) indices_below = paddle.floor(indices).astype(paddle.int32) indices_upper = paddle.ceil(indices).astype(paddle.int32) outputs = [] # TODO(chenjianye): replace the for-loop to directly take elements. for i in range(len(indices)): if (indices_upper[i] != indices_below[i]): tensor_below = paddle.take_along_axis(sorted_tensor, indices_below[i], axis) tensor_upper = paddle.take_along_axis(sorted_tensor, indices_upper[i], axis) weights = (indices[i] - indices_below[i]).astype(x.dtype) out = paddle.lerp(tensor_below, tensor_upper, weights) else: out = paddle.take_along_axis(sorted_tensor, indices_below[i], axis) if not keepdim: out = paddle.squeeze(out, axis=axis) else: out = out.reshape(out_shape) outputs.append(out) if isinstance(q, (list, tuple)): return paddle.stack(outputs, 0) else: return outputs[0]