binary.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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. from paddle import _C_ops, in_dynamic_mode
  15. from paddle.base.framework import core, dygraph_only
  16. from paddle.base.layer_helper import LayerHelper
  17. from .unary import cast
  18. __all__ = []
  19. _int_dtype_ = [
  20. core.VarDesc.VarType.UINT8,
  21. core.VarDesc.VarType.INT8,
  22. core.VarDesc.VarType.INT16,
  23. core.VarDesc.VarType.INT32,
  24. core.VarDesc.VarType.INT64,
  25. core.VarDesc.VarType.BOOL,
  26. ]
  27. @dygraph_only
  28. def matmul(x, y, name=None):
  29. """
  30. Note:
  31. This API is only supported from ``CUDA 11.0`` .
  32. Applies matrix multiplication of two Tensors.
  33. The supported input/output Tensor type are as follows:
  34. Note:
  35. x[SparseCsrTensor] @ y[SparseCsrTensor] -> out[SparseCsrTensor]
  36. x[SparseCsrTensor] @ y[DenseTensor] -> out[DenseTensor]
  37. x[SparseCooTensor] @ y[SparseCooTensor] -> out[SparseCooTensor]
  38. x[SparseCooTensor] @ y[DenseTensor] -> out[DenseTensor]
  39. It supports backward propagation.
  40. Dimensions `x` and `y` must be >= 2D. Automatic broadcasting of Tensor is not supported.
  41. the shape of `x` should be `[*, M, K]` , and the shape of `y` should be `[*, K, N]` , where `*`
  42. is zero or more batch dimensions.
  43. Args:
  44. x (SparseTensor): The input tensor. It can be SparseCooTensor/SparseCsrTensor. The data type can be float32 or float64.
  45. y (SparseTensor|DenseTensor): The input tensor. It can be SparseCooTensor/SparseCsrTensor/DenseTensor. The data type can be float32 or float64.
  46. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
  47. Returns:
  48. SparseTensor|DenseTensor: Determined by `x` and `y` .
  49. Examples:
  50. .. code-block:: python
  51. >>> # doctest: +REQUIRES(env:GPU)
  52. >>> import paddle
  53. >>> paddle.device.set_device('gpu')
  54. >>> # csr @ dense -> dense
  55. >>> crows = [0, 1, 2, 3]
  56. >>> cols = [1, 2, 0]
  57. >>> values = [1., 2., 3.]
  58. >>> csr = paddle.sparse.sparse_csr_tensor(crows, cols, values, [3, 3])
  59. >>> print(csr)
  60. Tensor(shape=[3, 3], dtype=paddle.float32, place=Place(gpu:0), stop_gradient=True,
  61. crows=[0, 1, 2, 3],
  62. cols=[1, 2, 0],
  63. values=[1., 2., 3.])
  64. >>> dense = paddle.ones([3, 2])
  65. >>> out = paddle.sparse.matmul(csr, dense)
  66. >>> print(out)
  67. Tensor(shape=[3, 2], dtype=float32, place=Place(gpu:0), stop_gradient=True,
  68. [[1., 1.],
  69. [2., 2.],
  70. [3., 3.]])
  71. >>> # coo @ dense -> dense
  72. >>> indices = [[0, 1, 2], [1, 2, 0]]
  73. >>> values = [1., 2., 3.]
  74. >>> coo = paddle.sparse.sparse_coo_tensor(indices, values, [3, 3])
  75. >>> print(coo)
  76. Tensor(shape=[3, 3], dtype=paddle.float32, place=Place(gpu:0), stop_gradient=True,
  77. indices=[[0, 1, 2],
  78. [1, 2, 0]],
  79. values=[1., 2., 3.])
  80. >>> dense = paddle.ones([3, 2])
  81. >>> out = paddle.sparse.matmul(coo, dense)
  82. >>> print(out)
  83. Tensor(shape=[3, 2], dtype=float32, place=Place(gpu:0), stop_gradient=True,
  84. [[1., 1.],
  85. [2., 2.],
  86. [3., 3.]])
  87. """
  88. return _C_ops.sparse_matmul(x, y)
  89. @dygraph_only
  90. def masked_matmul(x, y, mask, name=None):
  91. """
  92. Note:
  93. This API is only supported from ``CUDA 11.3`` .
  94. Applies matrix multiplication of two Dense Tensors.
  95. The supported input/output Tensor layout are as follows:
  96. Note:
  97. x[DenseTensor] @ y[DenseTensor] * mask[SparseCooTensor] -> out[SparseCooTensor]
  98. x[DenseTensor] @ y[DenseTensor] * mask[SparseCsrTensor] -> out[SparseCsrTensor]
  99. It supports backward propagation.
  100. Dimensions `x` and `y` must be >= 2D. Automatic broadcasting of Tensor is not supported.
  101. the shape of `x` should be `[*, M, K]` , and the shape of `y` should be `[*, K, N]` , and the shape of `mask` should be `[*, M, N]` ,
  102. where `*` is zero or more batch dimensions.
  103. Args:
  104. x (DenseTensor): The input tensor. It is DenseTensor. The data type can be float32 or float64.
  105. y (DenseTensor): The input tensor. It is DenseTensor. The data type can be float32 or float64.
  106. mask (SparseTensor): The mask tensor, which can be SparseCooTensor/SparseCsrTensor. It specify sparse coordinates. The data type can be float32 or float64.
  107. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
  108. Returns:
  109. SparseTensor: SparseCooTensor or SparseCsrTensor, which is same with `mask` .
  110. Examples:
  111. .. code-block:: python
  112. >>> # doctest: +REQUIRES(env:GPU)
  113. >>> import paddle
  114. >>> paddle.device.set_device('gpu')
  115. >>> paddle.seed(100)
  116. >>> # dense @ dense * csr_mask -> csr
  117. >>> crows = [0, 2, 3, 5]
  118. >>> cols = [1, 3, 2, 0, 1]
  119. >>> values = [1., 2., 3., 4., 5.]
  120. >>> dense_shape = [3, 4]
  121. >>> mask = paddle.sparse.sparse_csr_tensor(crows, cols, values, dense_shape)
  122. >>> print(mask)
  123. Tensor(shape=[3, 4], dtype=paddle.float32, place=Place(gpu:0), stop_gradient=True,
  124. crows=[0, 2, 3, 5],
  125. cols=[1, 3, 2, 0, 1],
  126. values=[1., 2., 3., 4., 5.])
  127. >>> x = paddle.rand([3, 5])
  128. >>> y = paddle.rand([5, 4])
  129. >>> out = paddle.sparse.masked_matmul(x, y, mask)
  130. >>> print(out)
  131. Tensor(shape=[3, 4], dtype=paddle.float32, place=Place(gpu:0), stop_gradient=True,
  132. crows=[0, 2, 3, 5],
  133. cols=[1, 3, 2, 0, 1],
  134. values=[0.98986477, 0.97800624, 1.14591956, 0.68561077, 0.94714981])
  135. """
  136. return _C_ops.sparse_masked_matmul(x, y, mask)
  137. @dygraph_only
  138. def mv(x, vec, name=None):
  139. """
  140. Note:
  141. This API is only supported from ``CUDA 11.0`` .
  142. Applies matrix-vector product of Sparse Matrix 'x' and Dense vector 'vec' .
  143. The supported input/output Tensor layout are as follows:
  144. Note:
  145. x[SparseCsrTensor] @ vec[DenseTensor] -> out[DenseTensor]
  146. x[SparseCooTensor] @ vec[DenseTensor] -> out[DenseTensor]
  147. It supports backward propagation.
  148. The shape of `x` should be `[M, N]` , and the shape of `vec` should be `[N]` ,
  149. and the shape of `out` will be `[M]` .
  150. Args:
  151. x (SparseTensor): The input 2D tensor. It must be SparseCooTensor/SparseCsrTensor. The data type can be float32 or float64.
  152. vec (DenseTensor): The input 1D tensor. It must be DenseTensor vector. The data type can be float32 or float64.
  153. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
  154. Returns:
  155. DenseTensor: 1D DenseTensor whose dtype is same with input.
  156. Examples:
  157. .. code-block:: python
  158. >>> # doctest: +REQUIRES(env:GPU)
  159. >>> import paddle
  160. >>> paddle.device.set_device('gpu')
  161. >>> paddle.seed(100)
  162. >>> # csr @ dense -> dense
  163. >>> crows = [0, 2, 3, 5]
  164. >>> cols = [1, 3, 2, 0, 1]
  165. >>> values = [1., 2., 3., 4., 5.]
  166. >>> dense_shape = [3, 4]
  167. >>> csr = paddle.sparse.sparse_csr_tensor(crows, cols, values, dense_shape)
  168. >>> print(csr)
  169. Tensor(shape=[3, 4], dtype=paddle.float32, place=Place(gpu:0), stop_gradient=True,
  170. crows=[0, 2, 3, 5],
  171. cols=[1, 3, 2, 0, 1],
  172. values=[1., 2., 3., 4., 5.])
  173. >>> vec = paddle.randn([4])
  174. >>> out = paddle.sparse.mv(csr, vec)
  175. >>> print(out)
  176. Tensor(shape=[3], dtype=float32, place=Place(gpu:0), stop_gradient=True,
  177. [-3.85499096, -2.42975140, -1.75087738])
  178. """
  179. return _C_ops.sparse_mv(x, vec)
  180. def add(x, y, name=None):
  181. """
  182. Add two sparse tensors element-wise. Input x and y's shape should be identical and have same sparse
  183. type(SparseCooTensor or SparseCsrTensor).If input is SparseCooTensor, x and y's sparse_dim should be identical.
  184. The equation is:
  185. .. math::
  186. out = x + y
  187. Args:
  188. x (Tensor): the input tensor, it's data type should be float32, float64, int32, int64.
  189. y (Tensor): the input tensor, it's data type should be float32, float64, int32, int64.
  190. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
  191. Returns:
  192. Tensor: the result tensor.
  193. Examples:
  194. .. code-block:: python
  195. >>> import paddle
  196. >>> paddle.device.set_device("cpu")
  197. >>> x = paddle.to_tensor([[0, -1, 0, 2], [0, 0, -3, 0], [4, 5, 0, 0]], 'float32')
  198. >>> y = paddle.to_tensor([[0, 0, 0, -2], [0, 2, -3, 0], [2, 3, 4, 8]], 'float32')
  199. >>> sparse_x = x.to_sparse_csr()
  200. >>> sparse_y = y.to_sparse_csr()
  201. >>> sparse_z = paddle.sparse.add(sparse_x, sparse_y)
  202. >>> print(sparse_z.to_dense())
  203. Tensor(shape=[3, 4], dtype=float32, place=Place(cpu), stop_gradient=True,
  204. [[ 0., -1., 0., 0.],
  205. [ 0., 2., -6., 0.],
  206. [ 6., 8., 4., 8.]])
  207. """
  208. if y.dtype != x.dtype:
  209. y = cast(y, None, x.dtype)
  210. if in_dynamic_mode():
  211. return _C_ops.sparse_add(x, y)
  212. else:
  213. op_type = 'sparse_add'
  214. inputs = {'x': x, 'y': y}
  215. helper = LayerHelper(op_type)
  216. out = helper.create_sparse_variable_for_type_inference(x.dtype)
  217. helper.append_op(
  218. type=op_type, inputs=inputs, outputs={'out': out}, attrs={}
  219. )
  220. return out
  221. @dygraph_only
  222. def subtract(x, y, name=None):
  223. """
  224. Subtract two sparse tensors element-wise. Input x and y's shape should be identical and have same sparse
  225. type(SparseCooTensor or SparseCsrTensor).If input is SparseCooTensor, x and y's sparse_dim should be identical.
  226. The equation is:
  227. .. math::
  228. out = x - y
  229. Args:
  230. x (Tensor): the input tensor, it's data type should be float32, float64, int32, int64.
  231. y (Tensor): the input tensor, it's data type should be float32, float64, int32, int64.
  232. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
  233. Returns:
  234. Tensor: the result tensor.
  235. Examples:
  236. .. code-block:: python
  237. >>> import paddle
  238. >>> paddle.device.set_device("cpu")
  239. >>> x = paddle.to_tensor([[0, -1, 0, 2], [0, 0, -3, 0], [4, 5, 0, 0]], 'float32')
  240. >>> y = paddle.to_tensor([[0, 0, 0, -2], [0, 2, -3, 0], [2, 3, 4, 8]], 'float32')
  241. >>> sparse_x = x.to_sparse_csr()
  242. >>> sparse_y = y.to_sparse_csr()
  243. >>> sparse_z = paddle.sparse.subtract(sparse_x, sparse_y)
  244. >>> print(sparse_z.to_dense())
  245. Tensor(shape=[3, 4], dtype=float32, place=Place(cpu), stop_gradient=True,
  246. [[ 0., -1., 0., 4.],
  247. [ 0., -2., 0., 0.],
  248. [ 2., 2., -4., -8.]])
  249. """
  250. if y.dtype != x.dtype:
  251. y = _C_ops.sparse_cast(y, None, x.dtype)
  252. return _C_ops.sparse_subtract(x, y)
  253. @dygraph_only
  254. def multiply(x, y, name=None):
  255. """
  256. Multiply two sparse tensors element-wise. Input x and y's shape should be identical and have same sparse
  257. type(SparseCooTensor or SparseCsrTensor).If input is SparseCooTensor, x and y's sparse_dim should be identical.
  258. The equation is:
  259. .. math::
  260. out = x * y
  261. Args:
  262. x (Tensor): the input tensor, it's data type should be float32, float64, int32, int64.
  263. y (Tensor): the input tensor, it's data type should be float32, float64, int32, int64.
  264. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
  265. Returns:
  266. Tensor: the result tensor.
  267. Examples:
  268. .. code-block:: python
  269. >>> import paddle
  270. >>> paddle.device.set_device("cpu")
  271. >>> x = paddle.to_tensor([[0, -1, 0, 2], [0, 0, -3, 0], [4, 5, 0, 0]], 'float32')
  272. >>> y = paddle.to_tensor([[0, 0, 0, -2], [0, 2, -3, 0], [2, 3, 4, 8]], 'float32')
  273. >>> sparse_x = x.to_sparse_csr()
  274. >>> sparse_y = y.to_sparse_csr()
  275. >>> sparse_z = paddle.sparse.multiply(sparse_x, sparse_y)
  276. >>> print(sparse_z.to_dense())
  277. Tensor(shape=[3, 4], dtype=float32, place=Place(cpu), stop_gradient=True,
  278. [[ 0., -0., 0., -4.],
  279. [ 0., 0., 9., 0.],
  280. [ 8., 15., 0., 0.]])
  281. """
  282. if isinstance(y, (int, float)):
  283. return _C_ops.sparse_scale(x, float(y), 0.0, True)
  284. else:
  285. if y.dtype != x.dtype:
  286. y = _C_ops.sparse_cast(y, None, x.dtype)
  287. return _C_ops.sparse_multiply(x, y)
  288. @dygraph_only
  289. def divide(x, y, name=None):
  290. """
  291. Divide two sparse tensors element-wise. Input x and y's shape should be identical and have same sparse
  292. type(SparseCooTensor or SparseCsrTensor).If input is SparseCooTensor, x and y's sparse_dim should be identical.
  293. The equation is:
  294. .. math::
  295. out = x / y
  296. Args:
  297. x (Tensor): the input tensor, it's data type should be float32, float64, int32, int64.
  298. y (Tensor): the input tensor, it's data type should be float32, float64, int32, int64.
  299. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
  300. Returns:
  301. Tensor: the result tensor.
  302. Examples:
  303. .. code-block:: python
  304. >>> import paddle
  305. >>> paddle.device.set_device("cpu")
  306. >>> x = paddle.to_tensor([[0, -1, 0, 2], [0, 0, -3, 0], [4, 5, 0, 0]], 'float32')
  307. >>> y = paddle.to_tensor([[0, 0, 0, -2], [0, 2, -3, 0], [2, 3, 4, 8]], 'float32')
  308. >>> sparse_x = x.to_sparse_csr()
  309. >>> sparse_y = y.to_sparse_csr()
  310. >>> sparse_z = paddle.sparse.divide(sparse_x, sparse_y)
  311. >>> print(sparse_z.to_dense())
  312. Tensor(shape=[3, 4], dtype=float32, place=Place(cpu), stop_gradient=True,
  313. [[ nan , -inf. , nan , -1. ],
  314. [ nan , 0. , 1. , nan ],
  315. [ 2. , 1.66666663, 0. , 0. ]])
  316. """
  317. if x.dtype in _int_dtype_:
  318. x = _C_ops.sparse_cast(x, None, core.VarDesc.VarType.FP32)
  319. if isinstance(y, (int, float)):
  320. return _C_ops.sparse_divide_scalar(x, float(y))
  321. else:
  322. if y.dtype != x.dtype:
  323. y = _C_ops.sparse_cast(y, None, x.dtype)
  324. return _C_ops.sparse_divide(x, y)
  325. @dygraph_only
  326. def is_same_shape(x, y):
  327. """
  328. Return the results of shape comparison between two Tensors, check whether x.shape equal to y.shape.
  329. Any two type Tensor among DenseTensor/SparseCooTensor/SparseCsrTensor are supported.
  330. Args:
  331. x (Tensor): The input tensor. It can be DenseTensor/SparseCooTensor/SparseCsrTensor.
  332. y (Tensor): The input tensor. It can be DenseTensor/SparseCooTensor/SparseCsrTensor.
  333. Returns:
  334. bool: True for same shape and False for different shape.
  335. Examples:
  336. .. code-block:: python
  337. >>> import paddle
  338. >>> x = paddle.rand([2, 3, 8])
  339. >>> y = paddle.rand([2, 3, 8])
  340. >>> y = y.to_sparse_csr()
  341. >>> z = paddle.rand([2, 5])
  342. >>> paddle.sparse.is_same_shape(x, y)
  343. True
  344. >>> paddle.sparse.is_same_shape(x, z)
  345. False
  346. """
  347. return x.is_same_shape(y)