Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow/python/keras/engine/input_layer.py: 17%

129 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-03 07:57 +0000

1# Copyright 2015 The TensorFlow 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# ============================================================================== 

15# pylint: disable=protected-access 

16"""Input layer code (`Input` and `InputLayer`).""" 

17 

18from tensorflow.python.distribute import distribute_lib 

19from tensorflow.python.framework import ops 

20from tensorflow.python.framework import tensor_shape 

21from tensorflow.python.framework import tensor_spec 

22from tensorflow.python.keras import backend 

23from tensorflow.python.keras.distribute import distributed_training_utils 

24from tensorflow.python.keras.engine import base_layer 

25from tensorflow.python.keras.engine import keras_tensor 

26from tensorflow.python.keras.engine import node as node_module 

27from tensorflow.python.keras.saving.saved_model import layer_serialization 

28from tensorflow.python.keras.utils import tf_utils 

29from tensorflow.python.util.tf_export import keras_export 

30 

31 

32def _assert_other_arg_none(arg_name, arg): 

33 if arg is not None: 

34 raise ValueError('When `type_spec` is not None, all other args ' 

35 'except `name` must be None, ' 

36 'but %s is not None.' % arg_name) 

37 

38 

39@keras_export('keras.layers.InputLayer') 

40class InputLayer(base_layer.Layer): 

41 """Layer to be used as an entry point into a Network (a graph of layers). 

42 

43 It can either wrap an existing tensor (pass an `input_tensor` argument) 

44 or create a placeholder tensor (pass arguments `input_shape`, and 

45 optionally, `dtype`). 

46 

47 It is generally recommend to use the functional layer API via `Input`, 

48 (which creates an `InputLayer`) without directly using `InputLayer`. 

49 

50 When using InputLayer with Keras Sequential model, it can be skipped by 

51 moving the input_shape parameter to the first layer after the InputLayer. 

52 

53 This class can create placeholders for tf.Tensors, tf.SparseTensors, and 

54 tf.RaggedTensors by choosing 'sparse=True' or 'ragged=True'. Note that 

55 'sparse' and 'ragged' can't be configured to True at same time. 

56 Usage: 

57 

58 ```python 

59 # With explicit InputLayer. 

60 model = tf.keras.Sequential([ 

61 tf.keras.layers.InputLayer(input_shape=(4,)), 

62 tf.keras.layers.Dense(8)]) 

63 model.compile(tf.optimizers.RMSprop(0.001), loss='mse') 

64 model.fit(np.zeros((10, 4)), 

65 np.ones((10, 8))) 

66 

67 # Without InputLayer and let the first layer to have the input_shape. 

68 # Keras will add a input for the model behind the scene. 

69 model = tf.keras.Sequential([ 

70 tf.keras.layers.Dense(8, input_shape=(4,))]) 

71 model.compile(tf.optimizers.RMSprop(0.001), loss='mse') 

72 model.fit(np.zeros((10, 4)), 

73 np.ones((10, 8))) 

74 ``` 

75 

76 Args: 

77 input_shape: Shape tuple (not including the batch axis), or `TensorShape` 

78 instance (not including the batch axis). 

79 batch_size: Optional input batch size (integer or None). 

80 dtype: Optional datatype of the input. When not provided, the Keras 

81 default float type will be used. 

82 input_tensor: Optional tensor to use as layer input. If set, the layer 

83 will use the `tf.TypeSpec` of this tensor rather 

84 than creating a new placeholder tensor. 

85 sparse: Boolean, whether the placeholder created is meant to be sparse. 

86 Default to False. 

87 ragged: Boolean, whether the placeholder created is meant to be ragged. 

88 In this case, values of 'None' in the 'shape' argument represent 

89 ragged dimensions. For more information about RaggedTensors, see 

90 [this guide](https://www.tensorflow.org/guide/ragged_tensors). 

91 Default to False. 

92 type_spec: A `tf.TypeSpec` object to create Input from. This `tf.TypeSpec` 

93 represents the entire batch. When provided, all other args except 

94 name must be None. 

95 name: Optional name of the layer (string). 

96 """ 

97 

98 def __init__(self, 

99 input_shape=None, 

100 batch_size=None, 

101 dtype=None, 

102 input_tensor=None, 

103 sparse=None, 

104 name=None, 

105 ragged=None, 

106 type_spec=None, 

107 **kwargs): 

108 self._init_input_shape = input_shape 

109 self._init_batch_size = batch_size 

110 self._init_dtype = dtype 

111 self._init_sparse = sparse 

112 self._init_ragged = ragged 

113 self._init_type_spec = type_spec 

114 

115 strategy = distribute_lib.get_strategy() 

116 if strategy and batch_size is not None and \ 

117 distributed_training_utils.global_batch_size_supported(strategy): 

118 if batch_size % strategy.num_replicas_in_sync != 0: 

119 raise ValueError('The `batch_size` argument ({}) must be divisible by ' 

120 'the number of replicas ({})'.format( 

121 batch_size, strategy.num_replicas_in_sync)) 

122 batch_size = batch_size // strategy.num_replicas_in_sync 

123 

124 if 'batch_input_shape' in kwargs: 

125 batch_input_shape = kwargs.pop('batch_input_shape') 

126 if input_shape and batch_input_shape: 

127 raise ValueError('Only provide the input_shape OR ' 

128 'batch_input_shape argument to ' 

129 'InputLayer, not both at the same time.') 

130 # Set the input shape and batch size from the batch_input_shape. 

131 # Note that batch_input_shape can be None (unknown rank) or [] (scalar), 

132 # in which case the batch size must be None. 

133 if batch_input_shape: 

134 batch_size = batch_input_shape[0] 

135 input_shape = batch_input_shape[1:] 

136 if kwargs: 

137 raise ValueError('Unrecognized keyword arguments:', kwargs.keys()) 

138 

139 if sparse and ragged: 

140 raise ValueError( 

141 'Cannot set both sparse and ragged to True in a Keras input.') 

142 

143 if not name: 

144 prefix = 'input' 

145 name = prefix + '_' + str(backend.get_uid(prefix)) 

146 

147 if not dtype: 

148 if input_tensor is None: 

149 dtype = backend.floatx() 

150 else: 

151 dtype = backend.dtype(input_tensor) 

152 elif input_tensor is not None and input_tensor.dtype != dtype: 

153 raise ValueError('`input_tensor.dtype` differs from `dtype`: %s vs. %s' % 

154 (input_tensor.dtype, dtype)) 

155 super(InputLayer, self).__init__(dtype=dtype, name=name) 

156 self.built = True 

157 self.sparse = True if sparse else False 

158 self.ragged = True if ragged else False 

159 self.batch_size = batch_size 

160 self.supports_masking = True 

161 

162 if isinstance(input_shape, tensor_shape.TensorShape): 

163 input_shape = tuple(input_shape.as_list()) 

164 elif isinstance(input_shape, int): 

165 input_shape = (input_shape,) 

166 

167 if type_spec is not None: 

168 args_that_must_be_none = [ 

169 ('(input_)shape', self._init_input_shape), 

170 ('batch_size', self._init_batch_size), 

171 ('dtype', self._init_dtype), 

172 ('input_tensor', input_tensor), 

173 ('sparse', self._init_sparse), 

174 ('ragged', self._init_ragged), 

175 ] 

176 for arg_name, arg in args_that_must_be_none: 

177 _assert_other_arg_none(arg_name, arg) 

178 if not ops.executing_eagerly_outside_functions(): 

179 raise ValueError('Creating Keras inputs from a type_spec is only ' 

180 'supported when eager execution is enabled.') 

181 input_tensor = keras_tensor.keras_tensor_from_type_spec(type_spec) 

182 if isinstance(input_tensor, keras_tensor.SparseKerasTensor): 

183 self.sparse = True 

184 if isinstance(input_tensor, keras_tensor.RaggedKerasTensor): 

185 self.ragged = True 

186 self.is_placeholder = True 

187 try: 

188 self._batch_input_shape = tuple(input_tensor.shape.as_list()) 

189 except ValueError: 

190 # If the shape cannot be represented as a tuple (e.g. unknown rank) 

191 self._batch_input_shape = None 

192 elif input_tensor is None: 

193 if input_shape is not None: 

194 batch_input_shape = (batch_size,) + tuple(input_shape) 

195 else: 

196 batch_input_shape = None 

197 graph = backend.get_graph() 

198 with graph.as_default(): 

199 input_tensor = backend.placeholder( 

200 shape=batch_input_shape, 

201 dtype=dtype, 

202 name=self.name, 

203 sparse=sparse, 

204 ragged=ragged) 

205 

206 self.is_placeholder = True 

207 self._batch_input_shape = batch_input_shape 

208 else: 

209 if ops.executing_eagerly_outside_functions(): 

210 if not isinstance(input_tensor, keras_tensor.KerasTensor): 

211 input_tensor = keras_tensor.keras_tensor_from_tensor(input_tensor) 

212 else: 

213 if not tf_utils.is_symbolic_tensor(input_tensor): 

214 raise ValueError('You should not pass an EagerTensor to `Input`. ' 

215 'For example, instead of creating an ' 

216 'InputLayer, you should instantiate your model and ' 

217 'directly call it on your input.') 

218 self.is_placeholder = False 

219 try: 

220 self._batch_input_shape = tuple(input_tensor.shape.as_list()) 

221 except ValueError: 

222 # If the shape cannot be represented as a tuple (e.g. unknown rank) 

223 self._batch_input_shape = None 

224 # Create an input node. 

225 input_tensor._keras_mask = None 

226 node_module.Node(layer=self, outputs=input_tensor) 

227 

228 # Store type spec 

229 if isinstance(input_tensor, keras_tensor.KerasTensor) or ( 

230 tf_utils.is_extension_type(input_tensor)): 

231 self._type_spec = input_tensor._type_spec # pylint: disable=protected-access 

232 else: 

233 self._type_spec = tensor_spec.TensorSpec( 

234 shape=input_tensor.shape, dtype=input_tensor.dtype, name=self.name) 

235 

236 def get_config(self): 

237 if self._init_type_spec is not None: 

238 config = { 

239 'name': self.name, 

240 'type_spec': self._init_type_spec 

241 } 

242 else: 

243 config = { 

244 'batch_input_shape': self._batch_input_shape, 

245 'dtype': self.dtype, 

246 'sparse': self.sparse, 

247 'ragged': self.ragged, 

248 'name': self.name, 

249 } 

250 return config 

251 

252 @property 

253 def _trackable_saved_model_saver(self): 

254 return layer_serialization.InputLayerSavedModelSaver(self) 

255 

256 

257@keras_export('keras.Input', 'keras.layers.Input') 

258def Input( # pylint: disable=invalid-name 

259 shape=None, 

260 batch_size=None, 

261 name=None, 

262 dtype=None, 

263 sparse=None, 

264 tensor=None, 

265 ragged=None, 

266 type_spec=None, 

267 **kwargs): 

268 """`Input()` is used to instantiate a Keras tensor. 

269 

270 A Keras tensor is a symbolic tensor-like object, 

271 which we augment with certain attributes that allow us to build a Keras model 

272 just by knowing the inputs and outputs of the model. 

273 

274 For instance, if `a`, `b` and `c` are Keras tensors, 

275 it becomes possible to do: 

276 `model = Model(input=[a, b], output=c)` 

277 

278 Args: 

279 shape: A shape tuple (integers), not including the batch size. 

280 For instance, `shape=(32,)` indicates that the expected input 

281 will be batches of 32-dimensional vectors. Elements of this tuple 

282 can be None; 'None' elements represent dimensions where the shape is 

283 not known. 

284 batch_size: optional static batch size (integer). 

285 name: An optional name string for the layer. 

286 Should be unique in a model (do not reuse the same name twice). 

287 It will be autogenerated if it isn't provided. 

288 dtype: The data type expected by the input, as a string 

289 (`float32`, `float64`, `int32`...) 

290 sparse: A boolean specifying whether the placeholder to be created is 

291 sparse. Only one of 'ragged' and 'sparse' can be True. Note that, 

292 if `sparse` is False, sparse tensors can still be passed into the 

293 input - they will be densified with a default value of 0. 

294 tensor: Optional existing tensor to wrap into the `Input` layer. 

295 If set, the layer will use the `tf.TypeSpec` of this tensor rather 

296 than creating a new placeholder tensor. 

297 ragged: A boolean specifying whether the placeholder to be created is 

298 ragged. Only one of 'ragged' and 'sparse' can be True. In this case, 

299 values of 'None' in the 'shape' argument represent ragged dimensions. 

300 For more information about RaggedTensors, see 

301 [this guide](https://www.tensorflow.org/guide/ragged_tensors). 

302 type_spec: A `tf.TypeSpec` object to create the input placeholder from. 

303 When provided, all other args except name must be None. 

304 **kwargs: deprecated arguments support. Supports `batch_shape` and 

305 `batch_input_shape`. 

306 

307 Returns: 

308 A `tensor`. 

309 

310 Example: 

311 

312 ```python 

313 # this is a logistic regression in Keras 

314 x = Input(shape=(32,)) 

315 y = Dense(16, activation='softmax')(x) 

316 model = Model(x, y) 

317 ``` 

318 

319 Note that even if eager execution is enabled, 

320 `Input` produces a symbolic tensor-like object (i.e. a placeholder). 

321 This symbolic tensor-like object can be used with lower-level 

322 TensorFlow ops that take tensors as inputs, as such: 

323 

324 ```python 

325 x = Input(shape=(32,)) 

326 y = tf.square(x) # This op will be treated like a layer 

327 model = Model(x, y) 

328 ``` 

329 

330 (This behavior does not work for higher-order TensorFlow APIs such as 

331 control flow and being directly watched by a `tf.GradientTape`). 

332 

333 However, the resulting model will not track any variables that were 

334 used as inputs to TensorFlow ops. All variable usages must happen within 

335 Keras layers to make sure they will be tracked by the model's weights. 

336 

337 The Keras Input can also create a placeholder from an arbitrary `tf.TypeSpec`, 

338 e.g: 

339 

340 ```python 

341 x = Input(type_spec=tf.RaggedTensorSpec(shape=[None, None], 

342 dtype=tf.float32, ragged_rank=1)) 

343 y = x.values 

344 model = Model(x, y) 

345 ``` 

346 When passing an arbitrary `tf.TypeSpec`, it must represent the signature of an 

347 entire batch instead of just one example. 

348 

349 Raises: 

350 ValueError: If both `sparse` and `ragged` are provided. 

351 ValueError: If both `shape` and (`batch_input_shape` or `batch_shape`) are 

352 provided. 

353 ValueError: If `shape`, `tensor` and `type_spec` are None. 

354 ValueError: If arguments besides `type_spec` are non-None while `type_spec` 

355 is passed. 

356 ValueError: if any unrecognized parameters are provided. 

357 """ 

358 if sparse and ragged: 

359 raise ValueError( 

360 'Cannot set both sparse and ragged to True in a Keras input.') 

361 

362 input_layer_config = {'name': name, 'dtype': dtype, 'sparse': sparse, 

363 'ragged': ragged, 'input_tensor': tensor, 

364 'type_spec': type_spec} 

365 

366 batch_input_shape = kwargs.pop('batch_input_shape', 

367 kwargs.pop('batch_shape', None)) 

368 if shape is not None and batch_input_shape is not None: 

369 raise ValueError('Only provide the `shape` OR `batch_input_shape` argument ' 

370 'to Input, not both at the same time.') 

371 if (batch_input_shape is None and shape is None and tensor is None 

372 and type_spec is None): 

373 raise ValueError('Please provide to Input a `shape`' 

374 ' or a `tensor` or a `type_spec` argument. Note that ' 

375 '`shape` does not include the batch ' 

376 'dimension.') 

377 if kwargs: 

378 raise ValueError('Unrecognized keyword arguments:', kwargs.keys()) 

379 

380 if batch_input_shape: 

381 shape = batch_input_shape[1:] 

382 input_layer_config.update({'batch_input_shape': batch_input_shape}) 

383 else: 

384 input_layer_config.update( 

385 {'batch_size': batch_size, 'input_shape': shape}) 

386 input_layer = InputLayer(**input_layer_config) 

387 

388 # Return tensor including `_keras_history`. 

389 # Note that in this case train_output and test_output are the same pointer. 

390 outputs = input_layer._inbound_nodes[0].outputs 

391 if isinstance(outputs, list) and len(outputs) == 1: 

392 return outputs[0] 

393 else: 

394 return outputs