input.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. # Copyright (c) 2020 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 os
  15. import numpy as np
  16. import paddle
  17. from paddle.base import Variable, core
  18. from paddle.base.data_feeder import check_type
  19. from paddle.base.framework import (
  20. convert_np_dtype_to_dtype_,
  21. in_pir_mode,
  22. static_only,
  23. )
  24. from paddle.base.layer_helper import LayerHelper
  25. from paddle.base.libpaddle import DataType
  26. from paddle.base.libpaddle.pir import (
  27. get_current_insertion_point,
  28. set_insertion_point,
  29. )
  30. from ..base.variable_index import _setitem_static
  31. __all__ = []
  32. def evaluate_flag(val) -> bool:
  33. return str(val).lower() not in ('false', 'off', '0', 'none')
  34. @static_only
  35. def data(name, shape, dtype=None, lod_level=0):
  36. """
  37. This function creates a variable on the global block. The global variable
  38. can be accessed by all the following operators in the graph. The variable
  39. is a placeholder that could be fed with input, such as Executor can feed
  40. input into the variable. When `dtype` is None, the dtype
  41. will get from the global dtype by `paddle.get_default_dtype()`.
  42. Args:
  43. name (str): The name/alias of the variable, see :ref:`api_guide_Name`
  44. for more details.
  45. shape (list|tuple): List|Tuple of integers declaring the shape. You can
  46. set None or -1 at a dimension to indicate the dimension can be of any
  47. size. For example, it is useful to set changeable batch size as None or -1.
  48. dtype (np.dtype|str, optional): The type of the data. Supported
  49. dtype: bool, float16, float32, float64, int8, int16, int32, int64,
  50. uint8. Default: None. When `dtype` is not set, the dtype will get
  51. from the global dtype by `paddle.get_default_dtype()`.
  52. lod_level (int, optional): The LoD level of the LoDTensor. Usually users
  53. don't have to set this value. Default: 0.
  54. Returns:
  55. Variable: The global variable that gives access to the data.
  56. Examples:
  57. .. code-block:: python
  58. >>> import numpy as np
  59. >>> import paddle
  60. >>> paddle.enable_static()
  61. # Creates a variable with fixed size [3, 2, 1]
  62. # User can only feed data of the same shape to x
  63. # the dtype is not set, so it will set "float32" by
  64. # paddle.get_default_dtype(). You can use paddle.get_default_dtype() to
  65. # change the global dtype
  66. >>> x = paddle.static.data(name='x', shape=[3, 2, 1])
  67. # Creates a variable with changeable batch size -1.
  68. # Users can feed data of any batch size into y,
  69. # but size of each data sample has to be [2, 1]
  70. >>> y = paddle.static.data(name='y', shape=[-1, 2, 1], dtype='float32')
  71. >>> z = x + y
  72. # In this example, we will feed x and y with np-ndarray "1"
  73. # and fetch z, like implementing "1 + 1 = 2" in PaddlePaddle
  74. >>> feed_data = np.ones(shape=[3, 2, 1], dtype=np.float32)
  75. >>> exe = paddle.static.Executor(paddle.framework.CPUPlace())
  76. >>> out = exe.run(paddle.static.default_main_program(),
  77. ... feed={
  78. ... 'x': feed_data,
  79. ... 'y': feed_data
  80. ... },
  81. ... fetch_list=[z.name])
  82. # np-ndarray of shape=[3, 2, 1], dtype=float32, whose elements are 2
  83. >>> print(out)
  84. [array([[[2.],
  85. [2.]],
  86. [[2.],
  87. [2.]],
  88. [[2.],
  89. [2.]]], dtype=float32)]
  90. """
  91. def _reset_data_op_insertion_point():
  92. default_main_program = paddle.pir.core.default_main_program()
  93. ops = default_main_program.global_block().ops
  94. if len(ops) == 0:
  95. return
  96. for op in ops:
  97. if op.name() != 'pd_op.data':
  98. paddle.pir.set_insertion_point(op)
  99. return
  100. helper = LayerHelper('data', **locals())
  101. check_type(name, 'name', (bytes, str), 'data')
  102. check_type(shape, 'shape', (list, tuple), 'data')
  103. shape = list(shape)
  104. for i in range(len(shape)):
  105. if shape[i] is None:
  106. shape[i] = -1
  107. if dtype is None:
  108. dtype = paddle.get_default_dtype()
  109. if in_pir_mode():
  110. ir_dtype = dtype
  111. if not isinstance(ir_dtype, DataType):
  112. ir_dtype = paddle.pir.core.convert_np_dtype_to_dtype_(dtype)
  113. prev_insertion_point = get_current_insertion_point()
  114. _reset_data_op_insertion_point()
  115. out = paddle._pir_ops.data(name, shape, ir_dtype, core.Place())
  116. set_insertion_point(prev_insertion_point)
  117. return out
  118. out = helper.create_global_variable(
  119. name=name,
  120. shape=shape,
  121. dtype=dtype,
  122. type=core.VarDesc.VarType.LOD_TENSOR,
  123. stop_gradient=True,
  124. lod_level=lod_level,
  125. is_data=True,
  126. need_check_feed=True,
  127. )
  128. is_pir_mode = os.environ.get("FLAGS_enable_pir_in_executor", None)
  129. if evaluate_flag(is_pir_mode):
  130. helper = LayerHelper('data', **locals())
  131. if not isinstance(dtype, core.VarDesc.VarType):
  132. dtype = convert_np_dtype_to_dtype_(dtype)
  133. helper.append_op(
  134. type='data',
  135. inputs={},
  136. outputs={'out': out},
  137. attrs={
  138. 'shape': shape,
  139. 'dtype': dtype,
  140. 'place': 0,
  141. 'name': name,
  142. },
  143. )
  144. return out
  145. class InputSpec:
  146. """
  147. InputSpec describes the signature information of the model input, such as ``shape`` , ``dtype`` , ``name`` .
  148. This interface is often used to specify input tensor information of models in high-level API.
  149. It's also used to specify the tensor information for each input parameter of the forward function
  150. decorated by `@paddle.jit.to_static`.
  151. Args:
  152. shape (tuple(integers)|list[integers]): List|Tuple of integers
  153. declaring the shape. You can set "None" or -1 at a dimension
  154. to indicate the dimension can be of any size. For example,
  155. it is useful to set changeable batch size as "None" or -1.
  156. dtype (np.dtype|str, optional): The type of the data. Supported
  157. dtype: bool, float16, float32, float64, int8, int16, int32, int64,
  158. uint8. Default: float32.
  159. name (str): The name/alias of the variable, see :ref:`api_guide_Name`
  160. for more details.
  161. stop_gradient (bool, optional): A boolean that mentions whether gradient should flow. Default is False, means don't stop calculate gradients.
  162. Examples:
  163. .. code-block:: python
  164. >>> import paddle
  165. >>> from paddle.static import InputSpec
  166. >>> input = InputSpec([None, 784], 'float32', 'x')
  167. >>> label = InputSpec([None, 1], 'int64', 'label')
  168. >>> print(input)
  169. InputSpec(shape=(-1, 784), dtype=paddle.float32, name=x, stop_gradient=False)
  170. >>> print(label)
  171. InputSpec(shape=(-1, 1), dtype=paddle.int64, name=label, stop_gradient=False)
  172. """
  173. def __init__(self, shape, dtype='float32', name=None, stop_gradient=False):
  174. # replace `None` in shape with -1
  175. self.shape = self._verify(shape)
  176. # convert dtype into united representation
  177. if dtype is not None:
  178. if isinstance(dtype, (np.dtype, str)):
  179. dtype = convert_np_dtype_to_dtype_(dtype)
  180. self.dtype = dtype
  181. self.name = name
  182. self.stop_gradient = stop_gradient
  183. def _create_feed_layer(self):
  184. return data(self.name, shape=self.shape, dtype=self.dtype)
  185. def __repr__(self):
  186. return f'{type(self).__name__}(shape={self.shape}, dtype={self.dtype}, name={self.name}, stop_gradient={self.stop_gradient})'
  187. @classmethod
  188. def from_tensor(cls, tensor, name=None):
  189. """
  190. Generates a InputSpec based on the description of input tensor.
  191. Args:
  192. tensor(Tensor): the source tensor to generate a InputSpec instance
  193. Returns:
  194. A InputSpec instance generated from Tensor.
  195. Examples:
  196. .. code-block:: python
  197. >>> import paddle
  198. >>> from paddle.static import InputSpec
  199. >>> paddle.disable_static()
  200. >>> x = paddle.ones([2, 2], dtype="float32")
  201. >>> x_spec = InputSpec.from_tensor(x, name='x')
  202. >>> print(x_spec)
  203. InputSpec(shape=(2, 2), dtype=paddle.float32, name=x, stop_gradient=False)
  204. """
  205. if isinstance(tensor, (Variable, core.eager.Tensor, paddle.pir.Value)):
  206. return cls(tensor.shape, tensor.dtype, name or tensor.name)
  207. else:
  208. raise ValueError(
  209. f"Input `tensor` should be a Tensor, but received {type(tensor).__name__}."
  210. )
  211. @classmethod
  212. def from_numpy(cls, ndarray, name=None):
  213. """
  214. Generates a InputSpec based on the description of input np.ndarray.
  215. Args:
  216. tensor(Tensor): the source numpy ndarray to generate a InputSpec instance
  217. Returns:
  218. A InputSpec instance generated from Tensor.
  219. Examples:
  220. .. code-block:: python
  221. >>> import numpy as np
  222. >>> from paddle.static import InputSpec
  223. >>> x = np.ones([2, 2], np.float32)
  224. >>> x_spec = InputSpec.from_numpy(x, name='x')
  225. >>> print(x_spec)
  226. InputSpec(shape=(2, 2), dtype=paddle.float32, name=x, stop_gradient=False)
  227. """
  228. return cls(ndarray.shape, ndarray.dtype, name)
  229. def batch(self, batch_size):
  230. """
  231. Inserts `batch_size` in front of the `shape`.
  232. Args:
  233. batch_size(int): the inserted integer value of batch size.
  234. Returns:
  235. The original InputSpec instance by inserting `batch_size` in front of `shape`.
  236. Examples:
  237. .. code-block:: python
  238. >>> from paddle.static import InputSpec
  239. >>> x_spec = InputSpec(shape=[64], dtype='float32', name='x')
  240. >>> x_spec.batch(4)
  241. >>> print(x_spec)
  242. InputSpec(shape=(4, 64), dtype=paddle.float32, name=x, stop_gradient=False)
  243. """
  244. if isinstance(batch_size, (list, tuple)):
  245. if len(batch_size) != 1:
  246. raise ValueError(
  247. f"Length of batch_size: {batch_size} shall be 1, but received {len(batch_size)}."
  248. )
  249. batch_size = batch_size[1]
  250. elif not isinstance(batch_size, int):
  251. raise TypeError(
  252. f"type(batch_size) shall be `int`, but received {type(batch_size).__name__}."
  253. )
  254. new_shape = [batch_size] + list(self.shape)
  255. self.shape = tuple(new_shape)
  256. return self
  257. def unbatch(self):
  258. """
  259. Removes the first element of `shape`.
  260. Returns:
  261. The original InputSpec instance by removing the first element of `shape` .
  262. Examples:
  263. .. code-block:: python
  264. >>> from paddle.static import InputSpec
  265. >>> x_spec = InputSpec(shape=[4, 64], dtype='float32', name='x')
  266. >>> x_spec.unbatch()
  267. >>> print(x_spec) # InputSpec(shape=(64,), dtype=paddle.float32, name=x)
  268. InputSpec(shape=(64,), dtype=paddle.float32, name=x, stop_gradient=False)
  269. """
  270. if len(self.shape) == 0:
  271. raise ValueError(
  272. "Not support to unbatch a InputSpec when len(shape) == 0."
  273. )
  274. self.shape = self._verify(self.shape[1:])
  275. return self
  276. def _verify(self, shape):
  277. """
  278. Verifies the input shape and modifies `None` into `-1`.
  279. """
  280. if not isinstance(shape, (list, tuple)):
  281. raise TypeError(
  282. f"Type of `shape` in InputSpec should be one of (tuple, list), but received {type(shape).__name__}."
  283. )
  284. for i, ele in enumerate(shape):
  285. if ele is not None:
  286. if not isinstance(ele, int):
  287. raise ValueError(
  288. f"shape[{i}] should be an `int`, but received `{type(ele).__name__}`:{ele}."
  289. )
  290. if ele is None or ele < -1:
  291. shape[i] = -1
  292. return tuple(shape)
  293. def __hash__(self):
  294. # Note(Aurelius84): `name` is not considered as a field to compute hashkey.
  295. # Because it's no need to generate a new program in following cases while using
  296. # @paddle.jit.to_static.
  297. #
  298. # Case 1:
  299. # foo(x_var)
  300. # foo(y_var)
  301. # x_var and y_var hold same shape and dtype, they should share a same program.
  302. #
  303. #
  304. # Case 2:
  305. # foo(x_var)
  306. # foo(x_np) # x_np is a numpy.ndarray.
  307. # x_var and x_np hold same shape and dtype, they should also share a same program.
  308. return hash((tuple(self.shape), self.dtype, self.stop_gradient))
  309. def __eq__(self, other):
  310. slots = ['shape', 'dtype', 'name', 'stop_gradient']
  311. return type(self) is type(other) and all(
  312. getattr(self, attr) == getattr(other, attr) for attr in slots
  313. )
  314. def __ne__(self, other):
  315. return not self == other
  316. def setitem(x, index, value):
  317. """
  318. x(Tensor): input Tensor.
  319. index(Scalar|Tuple|List|Tensor): Where should be set value.
  320. value(Scalar|Tensor): The value which is going to be set.
  321. [How to write index?]
  322. 1. ':' -> slice(),
  323. (1) a[:]=v -> setitem(a, slice(None,None,None), v)
  324. (2) a[1::2] -> setitem(a, slice(1,None,2), v)
  325. 2. if there are multiple indexes for axes, use TUPLE (Not LIST) to pack them.
  326. (1) a[1, 2]=v -> setitem(a, (1, 2), v)
  327. (2) a[[1,2],[2,3]]=v -> setitem(a, ([1,2],[2,3]), v)
  328. (3) a[1,:, 3] = v -> setitem(a, (1, slice(None,None,None),3), v)
  329. (4) a[1, ..., 2]=v -> setitem(a, (1, ..., 2), v)
  330. 3. You can always use TUPLE as index input, even there is only one index.
  331. (1) a[Tensor([10,10])]=v -> setitem(a, (Tensor([10,10]),), v)
  332. (2) a[1] = v -> setitem(a, (1,), v)
  333. """
  334. return _setitem_static(x, index, value)