# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. # # 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. from paddle.common_ops_import import * from ..fluid.layer_helper import LayerHelper from ..fluid.data_feeder import check_variable_and_dtype, check_type from ..fluid.framework import in_dygraph_mode, _varbase_creator from ..fluid.layers import transpose #DEFINE_ALIAS __all__ = [ 'matmul', 'dot', # 'einsum', 'norm', 'transpose', 'dist', 't', 'cross', 'cholesky', # 'tensordot', 'bmm', 'histogram' ] def matmul(x, y, transpose_x=False, transpose_y=False, name=None): """ Applies matrix multiplication to two tensors. `matmul` follows the complete broadcast rules, and its behavior is consistent with `np.matmul`. Currently, the input tensors' number of dimensions can be any, `matmul` can be used to achieve the `dot`, `matmul` and `batchmatmul`. The actual behavior depends on the shapes of :math:`x`, :math:`y` and the flag values of :attr:`transpose_x`, :attr:`transpose_y`. Specifically: - If a transpose flag is specified, the last two dimensions of the tensor are transposed. If the tensor is ndim-1 of shape, the transpose is invalid. If the tensor is ndim-1 of shape :math:`[D]`, then for :math:`x` it is treated as :math:`[1, D]`, whereas for :math:`y` it is the opposite: It is treated as :math:`[D, 1]`. The multiplication behavior depends on the dimensions of `x` and `y`. Specifically: - If both tensors are 1-dimensional, the dot product result is obtained. - If both tensors are 2-dimensional, the matrix-matrix product is obtained. - If the `x` is 1-dimensional and the `y` is 2-dimensional, a `1` is prepended to its dimension in order to conduct the matrix multiply. After the matrix multiply, the prepended dimension is removed. - If the `x` is 2-dimensional and `y` is 1-dimensional, the matrix-vector product is obtained. - If both arguments are at least 1-dimensional and at least one argument is N-dimensional (where N > 2), then a batched matrix multiply is obtained. If the first argument is 1-dimensional, a 1 is prepended to its dimension in order to conduct the batched matrix multiply and removed after. If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix multiple and removed after. The non-matrix (exclude the last two dimensions) dimensions are broadcasted according the broadcast rule. For example, if input is a (j, 1, n, m) tensor and the other is a (k, m, p) tensor, out will be a (j, k, n, p) tensor. Args: x (Tensor): The input tensor which is a Tensor. y (Tensor): The input tensor which is a Tensor. transpose_x (bool): Whether to transpose :math:`x` before multiplication. transpose_y (bool): Whether to transpose :math:`y` before multiplication. name(str|None): A name for this layer(optional). If set None, the layer will be named automatically. Returns: Tensor: The output Tensor. Examples: .. code-block:: python import paddle import numpy as np paddle.disable_static() # vector * vector x_data = np.random.random([10]).astype(np.float32) y_data = np.random.random([10]).astype(np.float32) x = paddle.to_tensor(x_data) y = paddle.to_tensor(y_data) z = paddle.matmul(x, y) print(z.numpy().shape) # [1] # matrix * vector x_data = np.random.random([10, 5]).astype(np.float32) y_data = np.random.random([5]).astype(np.float32) x = paddle.to_tensor(x_data) y = paddle.to_tensor(y_data) z = paddle.matmul(x, y) print(z.numpy().shape) # [10] # batched matrix * broadcasted vector x_data = np.random.random([10, 5, 2]).astype(np.float32) y_data = np.random.random([2]).astype(np.float32) x = paddle.to_tensor(x_data) y = paddle.to_tensor(y_data) z = paddle.matmul(x, y) print(z.numpy().shape) # [10, 5] # batched matrix * batched matrix x_data = np.random.random([10, 5, 2]).astype(np.float32) y_data = np.random.random([10, 2, 5]).astype(np.float32) x = paddle.to_tensor(x_data) y = paddle.to_tensor(y_data) z = paddle.matmul(x, y) print(z.numpy().shape) # [10, 5, 5] # batched matrix * broadcasted matrix x_data = np.random.random([10, 1, 5, 2]).astype(np.float32) y_data = np.random.random([1, 3, 2, 5]).astype(np.float32) x = paddle.to_tensor(x_data) y = paddle.to_tensor(y_data) z = paddle.matmul(x, y) print(z.numpy().shape) # [10, 3, 5, 5] """ op_type = 'matmul_v2' if in_dygraph_mode(): op = getattr(core.ops, op_type) return op(x, y, 'trans_x', transpose_x, 'trans_y', transpose_y) attrs = { 'trans_x': transpose_x, 'trans_y': transpose_y, } def __check_input(x, y): var_names = {'x': x, 'y': y} for name, val in var_names.items(): check_variable_and_dtype(val, name, ['float32', 'float64'], 'matmul') __check_input(x, y) helper = LayerHelper('matmul_v2', **locals()) out = helper.create_variable_for_type_inference(dtype=x.dtype) helper.append_op( type='matmul_v2', inputs={'X': x, 'Y': y}, outputs={'Out': out}, attrs=attrs) return out def norm(input, p='fro', axis=None, keepdim=False, out=None, name=None): """ :alias_main: paddle.norm :alias: paddle.norm,paddle.tensor.norm,paddle.tensor.linalg.norm Returns the matrix norm (Frobenius) or vector norm (the 1-norm, the Euclidean or 2-norm, and in general the p-norm for p > 0) of a given tensor. Args: input (Variable): The input tensor could be N-D tensor, and the input data type could be float32 or float64. p (float|string, optional): Order of the norm. Supported values are `fro`, `1`, `2`, and any positive real number yielding the corresponding p-norm. axis (int|list, optional): The axis on which to apply norm operation. If axis is int or list with only one element, the vector norm is computed over the axis. If axis is a list with two elements, the matrix norm is computed over the axis. If `axis < 0`, the dimension to norm operation is rank(input) + axis. keepdim (bool, optional): Whether to reserve the reduced dimension in the output Tensor. The result tensor will have fewer dimension than the :attr:`input` unless :attr:`keepdim` is true, default value is False. out (Variable, optional): The output tensor, default value is None. It's data type must be the same as the input Tensor. name (str, optional): The default value is None. Normally there is no need for user to set this property. For more information, please refer to :ref:`api_guide_Name`. Returns: Variable: Tensor, results of norm operation on the specified axis of input tensor, it's data type is the same as input's Tensor. Raises: TypeError, if out data type is different with the input data type. ValueError, If `p` or `axis` is invalid. Examples: .. code-block:: python import paddle import paddle.fluid as fluid x = fluid.data(name='x', shape=[2, 3, 5], dtype='float64') # compute frobenius norm along last two dimensions. out_fro = paddle.norm(x, p='fro', axis=[1,2]) # compute 2-order vector norm along last dimension. out_pnorm = paddle.norm(x, p=2, axis=-1) """ def frobenius_norm(input, dim=None, keepdim=False, out=None, name=None): """ The frobenius norm OP is to calculate the frobenius norm of certain two dimensions of Tensor `input`. Args: input (Variable): Tensor, data type float32, float64. dim (list, optional): None for last two dimensions. keepdim (bool, optional): Whether keep the dimensions as the `input`, Default False. out (Variable, optional): The tensor variable storing the output. """ if dim is not None and not (isinstance(dim, list) and len(dim) == 2): raise ValueError( "The dim of frobenius norm op should be None or two elements list!" ) attrs = { 'dim': dim if dim != None else [-2, -1], 'keep_dim': keepdim, 'reduce_all': False } if len(attrs['dim']) == len(input.shape): attrs['reduce_all'] = True check_variable_and_dtype(input, 'input', ['float32', 'float64'], 'frobenius_norm') helper = LayerHelper('frobenius_norm', **locals()) if out is None: out = helper.create_variable_for_type_inference( dtype=helper.input_dtype()) else: check_type(out, 'out', (Variable), 'frobenius_norm') check_dtype( out.dtype, out.name, convert_dtype(input.dtype), 'frobenius_norm', '(The out data type in frobenius_norm must be the same with input data type.)' ) helper.append_op( type='frobenius_norm', inputs={'X': input}, outputs={'Out': out}, attrs=attrs) return out def vector_norm(input, porder=None, axis=None, keepdim=False, out=None, name=None): """ Calculate the p-order vector norm for certain dimension of Tensor `input`. Args: input (Variable): Tensor, data type float32, float64. porder (float, optional): None for porder=2.0. axis (int, optional): None for last dimension. keepdim (bool, optional): Whether keep the dimensions as the `input`, Default False. out (Variable, optional): The tensor variable storing the output. """ if porder is not None: check_type(porder, 'porder', (float, int), 'p_norm') if axis is not None: check_type(axis, 'axis', (int), 'p_norm') attrs = { 'axis': axis if axis is not None else -1, 'porder': float(porder) if porder is not None else 2.0, 'keepdim': keepdim, 'epsilon': 1e-12, } check_variable_and_dtype(input, 'input', ['float32', 'float64'], 'p_norm') helper = LayerHelper('p_norm', **locals()) if out is None: out = helper.create_variable_for_type_inference( dtype=helper.input_dtype()) else: check_type(out, 'out', (Variable), 'p_norm') check_dtype( out.dtype, out.name, convert_dtype(input.dtype), 'p_norm', '(The out data type in p_norm must be the same with input data type.)' ) helper.append_op( type='p_norm', inputs={'X': input}, outputs={'Out': out}, attrs=attrs) return out if axis is None and p is not None: if isinstance(p, str): if p == "fro": return frobenius_norm( input, dim=axis, keepdim=keepdim, out=out, name=name) else: raise ValueError( "only valid string values are 'fro', found {}".format(p)) elif isinstance(p, (int, float)): return vector_norm( input, porder=p, axis=axis, keepdim=keepdim, out=out, name=name) else: raise ValueError("only valid p type is string or float, found {}". format(type(p))) if isinstance(axis, list) and len(axis) == 1: axis = axis[0] #calculate vector norm, where axis is int or list with only one integer if isinstance(axis, int): if isinstance(p, (int, float)): return vector_norm( input, axis=axis, porder=p, keepdim=keepdim, out=out, name=name) else: raise ValueError( "unspport p for p-order vector norm. except float, found {}". format(p)) #calculate matrix norm, where axis is list with two integers elif isinstance(axis, list) and len(axis) == 2: if p == "fro": return frobenius_norm( input, dim=axis, keepdim=keepdim, out=out, name=name) else: raise ValueError( "unspport p for matrix norm, expcept 'fro', found {}".format(p)) else: raise ValueError( "except axis type int or list (length of list <=2), found {}". format(axis)) def dist(x, y, p=2): """ :alias_main: paddle.dist :alias: paddle.dist,paddle.tensor.dist,paddle.tensor.linalg.dist This OP returns the p-norm of (x - y). It is not a norm in a strict sense, only as a measure of distance. The shapes of x and y must be broadcastable. The definition is as follows, for details, please refer to the `numpy's broadcasting `_: - Each input has at least one dimension. - Match the two input dimensions from back to front, the dimension sizes must either be equal, one of them is 1, or one of them does not exist. Where, z = x - y, the shapes of x and y are broadcastable, then the shape of z can be obtained as follows: 1. If the number of dimensions of x and y are not equal, prepend 1 to the dimensions of the tensor with fewer dimensions. For example, The shape of x is [8, 1, 6, 1], the shape of y is [7, 1, 5], prepend 1 to the dimension of y. x (4-D Tensor): 8 x 1 x 6 x 1 y (4-D Tensor): 1 x 7 x 1 x 5 2. Determine the size of each dimension of the output z: choose the maximum value from the two input dimensions. z (4-D Tensor): 8 x 7 x 6 x 5 If the number of dimensions of the two inputs are the same, the size of the output can be directly determined in step 2. When p takes different values, the norm formula is as follows: When p = 0, defining $0^0=0$, the zero-norm of z is simply the number of non-zero elements of z. .. math:: ||z||_{0}=\lim_{p \\rightarrow 0}\sum_{i=1}^{m}|z_i|^{p} When p = inf, the inf-norm of z is the maximum element of z. .. math:: ||z||_\infty=\max_i |z_i| When p = -inf, the negative-inf-norm of z is the minimum element of z. .. math:: ||z||_{-\infty}=\min_i |z_i| Otherwise, the p-norm of z follows the formula, .. math:: ||z||_{p}=(\sum_{i=1}^{m}|z_i|^p)^{\\frac{1}{p}} Args: x (Variable): 1-D to 6-D Tensor, its data type is float32 or float64. y (Variable): 1-D to 6-D Tensor, its data type is float32 or float64. p (float, optional): The norm to be computed, its data type is float32 or float64. Default: 2. Returns: Variable: Tensor that is the p-norm of (x - y). Examples: .. code-block:: python import paddle import paddle.fluid as fluid import numpy as np with fluid.dygraph.guard(): x = fluid.dygraph.to_variable(np.array([[3, 3],[3, 3]]).astype(np.float32)) y = fluid.dygraph.to_variable(np.array([[3, 3],[3, 1]]).astype(np.float32)) out = paddle.dist(x, y, 0) print(out.numpy()) # out = [1.] out = paddle.dist(x, y, 2) print(out.numpy()) # out = [2.] out = paddle.dist(x, y, float("inf")) print(out.numpy()) # out = [2.] out = paddle.dist(x, y, float("-inf")) print(out.numpy()) # out = [0.] """ check_variable_and_dtype(x, 'dtype', ['float32', 'float64'], 'dist') check_variable_and_dtype(y, 'dtype', ['float32', 'float64'], 'dist') check_type(p, 'p', (float, int), 'dist') helper = LayerHelper("dist", **locals()) out = helper.create_variable_for_type_inference(x.dtype) inputs = {"X": [x], "Y": [y]} outputs = {'Out': [out]} attrs = {"p": float(p)} helper.append_op( type='dist', inputs=inputs, outputs={'Out': out}, attrs=attrs) return out def dot(x, y, name=None): """ This operator calculates inner product for vectors. .. note:: Support 1-d and 2-d Tensor. When it is 2d, the first dimension of this matrix is the batch dimension, which means that the vectors of multiple batches are dotted. Parameters: x(Tensor): 1-D or 2-D ``Tensor``. Its dtype should be ``float32``, ``float64``, ``int32``, ``int64`` y(Tensor): 1-D or 2-D ``Tensor``. Its dtype soulde be ``float32``, ``float64``, ``int32``, ``int64`` name(str, optional): Name of the output. Default is None. It's used to print debug info for developers. Details: :ref:`api_guide_Name` Returns: Variable: the calculated result Tensor. Examples: .. code-block:: python import paddle import numpy as np paddle.disable_static() x_data = np.random.uniform(0.1, 1, [10]).astype(np.float32) y_data = np.random.uniform(1, 3, [10]).astype(np.float32) x = paddle.to_tensor(x_data) y = paddle.to_tensor(y_data) z = paddle.dot(x, y) print(z.numpy()) """ op_type = 'dot' # skip var type check in dygraph mode to improve efficiency if in_dygraph_mode(): op = getattr(core.ops, op_type) return op(x, y) assert x is not None, 'x cannot be None in {}'.format(op_type) assert y is not None, 'y cannot be None in {}'.format(op_type) check_variable_and_dtype(x, 'x', ['float32', 'float64', 'int32', 'int64'], op_type) check_variable_and_dtype(y, 'y', ['float32', 'float64', 'int32', 'int64'], op_type) helper = LayerHelper(op_type, **locals()) if name is None: out = helper.create_variable_for_type_inference(dtype=x.dtype) else: out = helper.create_variable( name=name, dtype=x.dtype, persistable=False) helper.append_op( type="dot", inputs={'X': x, 'Y': y}, attrs={}, outputs={"Out": out}) return out def t(input, name=None): """ :alias_main: paddle.t :alias: paddle.t,paddle.tensor.t,paddle.tensor.linalg.t Transpose <=2-D tensor. 0-D and 1-D tensors are returned as it is and 2-D tensor is equal to the fluid.layers.transpose function which perm dimensions set 0 and 1. Args: input (Variable): The input Tensor. It is a N-D (N<=2) Tensor of data types float16, float32, float64, int32. name(str, optional): The default value is None. Normally there is no need for user to set this property. For more information, please refer to :ref:`api_guide_Name` Returns: Variable: A transposed n-D Tensor, with data type being float16, float32, float64, int32, int64. For Example: .. code-block:: text # Example 1 (0-D tensor) x = tensor([0.79]) paddle.t(x) = tensor([0.79]) # Example 2 (1-D tensor) x = tensor([0.79, 0.84, 0.32]) paddle.t(x) = tensor([0.79, 0.84, 0.32]) # Example 3 (2-D tensor) x = tensor([0.79, 0.84, 0.32], [0.64, 0.14, 0.57]) paddle.t(x) = tensor([0.79, 0.64], [0.84, 0.14], [0.32, 0.57]) Examples: .. code-block:: python import paddle import paddle.fluid as fluid x = fluid.data(name='x', shape=[2, 3], dtype='float32') x_transposed = paddle.t(x) print x_transposed.shape #(3L, 2L) """ if len(input.shape) > 2: raise ValueError( "Input(input) only support N-D (N<=2) tensor, but received " "length of Input(input) is %s. Perhaps you can use paddle." "tensor.transpose() instead." % len(input.shape)) if in_dygraph_mode(): if len(input.shape) == 1: return input # 2-D tensor perm = [1, 0] out, _ = core.ops.transpose2(input, 'axis', perm) return out check_variable_and_dtype( input, 'input', ['float16', 'float32', 'float64', 'int32', 'int64'], 'transpose') helper = LayerHelper('t', **locals()) out = helper.create_variable_for_type_inference(input.dtype) input_shape = helper.create_variable_for_type_inference(input.dtype) if len(input.shape) == 1: out = input else: helper.append_op( type='transpose2', inputs={'X': [input]}, outputs={'Out': [out], 'XShape': [input_shape]}, attrs={'axis': [1, 0]}) return out def cross(x, y, axis=None, name=None): """ :alias_main: paddle.cross :alias: paddle.cross,paddle.tensor.cross,paddle.tensor.linalg.cross Computes the cross product between two tensors along an axis. Inputs must have the same shape, and the length of their axes should be equal to 3. If `axis` is not given, it defaults to the first axis found with the length 3. Args: x (Variable): The first input tensor variable. y (Variable): The second input tensor variable. axis (int, optional): The axis along which to compute the cross product. It defaults to the first axis found with the length 3. name (str, optional): The default value is None. Normally there is no need for user to set this property. For more information, please refer to :ref:`api_guide_Name` Returns: Variable: A Tensor with same data type as `x`. Examples: .. code-block:: python import paddle from paddle import to_variable import numpy as np paddle.disable_static() data_x = np.array([[1.0, 1.0, 1.0], [2.0, 2.0, 2.0], [3.0, 3.0, 3.0]]) data_y = np.array([[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]) x = to_variable(data_x) y = to_variable(data_y) z1 = paddle.cross(x, y) print(z1.numpy()) # [[-1. -1. -1.] # [ 2. 2. 2.] # [-1. -1. -1.]] z2 = paddle.cross(x, y, axis=1) print(z2.numpy()) # [[0. 0. 0.] # [0. 0. 0.] # [0. 0. 0.]] """ if in_dygraph_mode(): if axis is not None: return core.ops.cross(x, y, 'dim', axis) else: return core.ops.cross(x, y) helper = LayerHelper("cross", **locals()) out = helper.create_variable_for_type_inference(x.dtype) attrs = dict() attrs['dim'] = axis helper.append_op( type='cross', inputs={'X': x, 'Y': y}, outputs={'Out': out}, attrs=attrs) return out def cholesky(x, upper=False, name=None): """ Computes the Cholesky decomposition of one symmetric positive-definite matrix or batches of symmetric positive-definite matrice. If `upper` is `True`, the decomposition has the form :math:`A = U^{T}U` , and the returned matrix :math:`U` is upper-triangular. Otherwise, the decomposition has the form :math:`A = LL^{T}` , and the returned matrix :math:`L` is lower-triangular. Args: x (Variable): The input tensor. Its shape should be `[*, M, M]`, where * is zero or more batch dimensions, and matrices on the inner-most 2 dimensions all should be symmetric positive-definite. Its data type should be float32 or float64. upper (bool): The flag indicating whether to return upper or lower triangular matrices. Default: False. Returns: Variable: A Tensor with same shape and data type as `x`. It represents \ triangular matrices generated by Cholesky decomposition. Examples: .. code-block:: python import paddle import numpy as np paddle.disable_static() a = np.random.rand(3, 3) a_t = np.transpose(a, [1, 0]) x_data = np.matmul(a, a_t) + 1e-03 x = paddle.to_variable(x_data) out = paddle.cholesky(x, upper=False) print(out.numpy()) # [[1.190523 0. 0. ] # [0.9906703 0.27676893 0. ] # [1.25450498 0.05600871 0.06400121]] """ if in_dygraph_mode(): return core.ops.cholesky(x, "upper", upper) check_variable_and_dtype(x, 'dtype', ['float32', 'float64'], 'cholesky') check_type(upper, 'upper', bool, 'cholesky') helper = LayerHelper('cholesky', **locals()) out = helper.create_variable_for_type_inference(dtype=x.dtype) helper.append_op( type='cholesky', inputs={'X': [x]}, outputs={'Out': out}, attrs={'upper': upper}) return out def bmm(x, y, name=None): """ :alias_main: paddle.bmm :alias: paddle.bmm,paddle.tensor.bmm,paddle.tensor.linalg.bmm Applies batched matrix multiplication to two tensors. Both of the two input tensors must be three-dementional and share the same batch size. if x is a (b, m, k) tensor, y is a (b, k, n) tensor, the output will be a (b, m, n) tensor. Args: x (Variable): The input variable which is a Tensor or LoDTensor. y (Variable): The input variable which is a Tensor or LoDTensor. name(str|None): A name for this layer(optional). If set None, the layer will be named automatically. Returns: Variable: The product Tensor (or LoDTensor) variable. Examples: import paddle # In imperative mode: # size input1: (2, 2, 3) and input2: (2, 3, 2) input1 = np.array([[[1.0, 1.0, 1.0],[2.0, 2.0, 2.0]],[[3.0, 3.0, 3.0],[4.0, 4.0, 4.0]]]) input2 = np.array([[[1.0, 1.0],[2.0, 2.0],[3.0, 3.0]],[[4.0, 4.0],[5.0, 5.0],[6.0, 6.0]]]) paddle.disable_static() x = paddle.to_variable(input1) y = paddle.to_variable(input2) out = paddle.bmm(x, y) #output size: (2, 2, 2) #output value: #[[[6.0, 6.0],[12.0, 12.0]],[[45.0, 45.0],[60.0, 60.0]]] out_np = out.numpy() """ x_shape = x.shape y_shape = y.shape if not len(x_shape) == len(y_shape) == 3: raise ValueError( "x and y should be 3-dimensional. But received x's dimention: {}, y's dimention: {}". format(x_shape, y_shape)) if x_shape[2] != y_shape[1]: raise ValueError( "x's width must be equal with y's height. But received x's shape: {}, y's shape: {}". format(x_shape, y_shape)) helper = LayerHelper('bmm', **locals()) if in_dygraph_mode(): return core.ops.bmm(x, y) out = helper.create_variable_for_type_inference(dtype=x.dtype) helper.append_op(type='bmm', inputs={'X': x, 'Y': y}, outputs={'Out': out}) return out def histogram(input, bins=100, min=0, max=0): """ Computes the histogram of a tensor. The elements are sorted into equal width bins between min and max. If min and max are both zero, the minimum and maximum values of the data are used. Args: input (Variable): A Tensor(or LoDTensor) with shape :math:`[N_1, N_2,..., N_k]` . The data type of the input Tensor should be float32, float64, int32, int64. bins (int): number of histogram bins min (int): lower end of the range (inclusive) max (int): upper end of the range (inclusive) Returns: Variable: Tensor or LoDTensor calculated by histogram layer. The data type is int64. Code Example 1: .. code-block:: python import paddle import numpy as np startup_program = paddle.static.Program() train_program = paddle.static.Program() with paddle.static.program_guard(train_program, startup_program): inputs = paddle.data(name='input', dtype='int32', shape=[2,3]) output = paddle.histogram(inputs, bins=5, min=1, max=5) place = paddle.CPUPlace() exe = paddle.static.Executor(place) exe.run(startup_program) img = np.array([[2, 4, 2], [2, 5, 4]]).astype(np.int32) res = exe.run(train_program, feed={'input': img}, fetch_list=[output]) print(np.array(res[0])) # [0,3,0,2,1] Code Example 2: .. code-block:: python import paddle import numpy as np paddle.disable_static(paddle.CPUPlace()) inputs_np = np.array([1, 2, 1]).astype(np.float) inputs = paddle.to_variable(inputs_np) result = paddle.histogram(inputs, bins=4, min=0, max=3) print(result) # [0, 2, 1, 0] paddle.enable_static() """ if in_dygraph_mode(): return core.ops.histogram(input, "bins", bins, "min", min, "max", max) helper = LayerHelper('histogram', **locals()) check_variable_and_dtype( input, 'X', ['int32', 'int64', 'float32', 'float64'], 'histogram') out = helper.create_variable_for_type_inference(VarDesc.VarType.INT64) helper.append_op( type='histogram', inputs={'X': input}, outputs={'Out': out}, attrs={'bins': bins, 'min': min, 'max': max}) return out