Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/keras/src/applications/mobilenet_v3.py: 15%

209 statements  

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

1# Copyright 2020 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 

16 

17"""MobileNet v3 models for Keras.""" 

18 

19import tensorflow.compat.v2 as tf 

20 

21from keras.src import backend 

22from keras.src import models 

23from keras.src.applications import imagenet_utils 

24from keras.src.layers import VersionAwareLayers 

25from keras.src.utils import data_utils 

26from keras.src.utils import layer_utils 

27 

28# isort: off 

29from tensorflow.python.platform import tf_logging as logging 

30from tensorflow.python.util.tf_export import keras_export 

31 

32# TODO(scottzhu): Change this to the GCS path. 

33BASE_WEIGHT_PATH = ( 

34 "https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v3/" 

35) 

36WEIGHTS_HASHES = { 

37 "large_224_0.75_float": ( 

38 "765b44a33ad4005b3ac83185abf1d0eb", 

39 "40af19a13ebea4e2ee0c676887f69a2e", 

40 ), 

41 "large_224_1.0_float": ( 

42 "59e551e166be033d707958cf9e29a6a7", 

43 "07fb09a5933dd0c8eaafa16978110389", 

44 ), 

45 "large_minimalistic_224_1.0_float": ( 

46 "675e7b876c45c57e9e63e6d90a36599c", 

47 "ec5221f64a2f6d1ef965a614bdae7973", 

48 ), 

49 "small_224_0.75_float": ( 

50 "cb65d4e5be93758266aa0a7f2c6708b7", 

51 "ebdb5cc8e0b497cd13a7c275d475c819", 

52 ), 

53 "small_224_1.0_float": ( 

54 "8768d4c2e7dee89b9d02b2d03d65d862", 

55 "d3e8ec802a04aa4fc771ee12a9a9b836", 

56 ), 

57 "small_minimalistic_224_1.0_float": ( 

58 "99cd97fb2fcdad2bf028eb838de69e37", 

59 "cde8136e733e811080d9fcd8a252f7e4", 

60 ), 

61} 

62 

63layers = VersionAwareLayers() 

64 

65 

66BASE_DOCSTRING = """Instantiates the {name} architecture. 

67 

68 Reference: 

69 - [Searching for MobileNetV3]( 

70 https://arxiv.org/pdf/1905.02244.pdf) (ICCV 2019) 

71 

72 The following table describes the performance of MobileNets v3: 

73 ------------------------------------------------------------------------ 

74 MACs stands for Multiply Adds 

75 

76 |Classification Checkpoint|MACs(M)|Parameters(M)|Top1 Accuracy|Pixel1 CPU(ms)| 

77 |---|---|---|---|---| 

78 | mobilenet_v3_large_1.0_224 | 217 | 5.4 | 75.6 | 51.2 | 

79 | mobilenet_v3_large_0.75_224 | 155 | 4.0 | 73.3 | 39.8 | 

80 | mobilenet_v3_large_minimalistic_1.0_224 | 209 | 3.9 | 72.3 | 44.1 | 

81 | mobilenet_v3_small_1.0_224 | 66 | 2.9 | 68.1 | 15.8 | 

82 | mobilenet_v3_small_0.75_224 | 44 | 2.4 | 65.4 | 12.8 | 

83 | mobilenet_v3_small_minimalistic_1.0_224 | 65 | 2.0 | 61.9 | 12.2 | 

84 

85 For image classification use cases, see 

86 [this page for detailed examples]( 

87 https://keras.io/api/applications/#usage-examples-for-image-classification-models). 

88 

89 For transfer learning use cases, make sure to read the 

90 [guide to transfer learning & fine-tuning]( 

91 https://keras.io/guides/transfer_learning/). 

92 

93 Note: each Keras Application expects a specific kind of input preprocessing. 

94 For MobileNetV3, by default input preprocessing is included as a part of the 

95 model (as a `Rescaling` layer), and thus 

96 `tf.keras.applications.mobilenet_v3.preprocess_input` is actually a 

97 pass-through function. In this use case, MobileNetV3 models expect their 

98 inputs to be float tensors of pixels with values in the [0-255] range. 

99 At the same time, preprocessing as a part of the model (i.e. `Rescaling` 

100 layer) can be disabled by setting `include_preprocessing` argument to False. 

101 With preprocessing disabled MobileNetV3 models expect their inputs to be float 

102 tensors of pixels with values in the [-1, 1] range. 

103 

104 Args: 

105 input_shape: Optional shape tuple, to be specified if you would 

106 like to use a model with an input image resolution that is not 

107 (224, 224, 3). 

108 It should have exactly 3 inputs channels (224, 224, 3). 

109 You can also omit this option if you would like 

110 to infer input_shape from an input_tensor. 

111 If you choose to include both input_tensor and input_shape then 

112 input_shape will be used if they match, if the shapes 

113 do not match then we will throw an error. 

114 E.g. `(160, 160, 3)` would be one valid value. 

115 alpha: controls the width of the network. This is known as the 

116 depth multiplier in the MobileNetV3 paper, but the name is kept for 

117 consistency with MobileNetV1 in Keras. 

118 - If `alpha` < 1.0, proportionally decreases the number 

119 of filters in each layer. 

120 - If `alpha` > 1.0, proportionally increases the number 

121 of filters in each layer. 

122 - If `alpha` = 1, default number of filters from the paper 

123 are used at each layer. 

124 minimalistic: In addition to large and small models this module also 

125 contains so-called minimalistic models, these models have the same 

126 per-layer dimensions characteristic as MobilenetV3 however, they don't 

127 utilize any of the advanced blocks (squeeze-and-excite units, hard-swish, 

128 and 5x5 convolutions). While these models are less efficient on CPU, they 

129 are much more performant on GPU/DSP. 

130 include_top: Boolean, whether to include the fully-connected 

131 layer at the top of the network. Defaults to `True`. 

132 weights: String, one of `None` (random initialization), 

133 'imagenet' (pre-training on ImageNet), 

134 or the path to the weights file to be loaded. 

135 input_tensor: Optional Keras tensor (i.e. output of 

136 `layers.Input()`) 

137 to use as image input for the model. 

138 pooling: String, optional pooling mode for feature extraction 

139 when `include_top` is `False`. 

140 - `None` means that the output of the model 

141 will be the 4D tensor output of the 

142 last convolutional block. 

143 - `avg` means that global average pooling 

144 will be applied to the output of the 

145 last convolutional block, and thus 

146 the output of the model will be a 

147 2D tensor. 

148 - `max` means that global max pooling will 

149 be applied. 

150 classes: Integer, optional number of classes to classify images 

151 into, only to be specified if `include_top` is True, and 

152 if no `weights` argument is specified. 

153 dropout_rate: fraction of the input units to drop on the last layer. 

154 classifier_activation: A `str` or callable. The activation function to use 

155 on the "top" layer. Ignored unless `include_top=True`. Set 

156 `classifier_activation=None` to return the logits of the "top" layer. 

157 When loading pretrained weights, `classifier_activation` can only 

158 be `None` or `"softmax"`. 

159 include_preprocessing: Boolean, whether to include the preprocessing 

160 layer (`Rescaling`) at the bottom of the network. Defaults to `True`. 

161 

162 Call arguments: 

163 inputs: A floating point `numpy.array` or a `tf.Tensor`, 4D with 3 color 

164 channels, with values in the range [0, 255] if `include_preprocessing` 

165 is True and in the range [-1, 1] otherwise. 

166 

167 Returns: 

168 A `keras.Model` instance. 

169""" 

170 

171 

172def MobileNetV3( 

173 stack_fn, 

174 last_point_ch, 

175 input_shape=None, 

176 alpha=1.0, 

177 model_type="large", 

178 minimalistic=False, 

179 include_top=True, 

180 weights="imagenet", 

181 input_tensor=None, 

182 classes=1000, 

183 pooling=None, 

184 dropout_rate=0.2, 

185 classifier_activation="softmax", 

186 include_preprocessing=True, 

187): 

188 if not (weights in {"imagenet", None} or tf.io.gfile.exists(weights)): 

189 raise ValueError( 

190 "The `weights` argument should be either " 

191 "`None` (random initialization), `imagenet` " 

192 "(pre-training on ImageNet), " 

193 "or the path to the weights file to be loaded. " 

194 f"Received weights={weights}" 

195 ) 

196 

197 if weights == "imagenet" and include_top and classes != 1000: 

198 raise ValueError( 

199 'If using `weights` as `"imagenet"` with `include_top` ' 

200 "as true, `classes` should be 1000. " 

201 f"Received classes={classes}" 

202 ) 

203 

204 # Determine proper input shape and default size. 

205 # If both input_shape and input_tensor are used, they should match 

206 if input_shape is not None and input_tensor is not None: 

207 try: 

208 is_input_t_tensor = backend.is_keras_tensor(input_tensor) 

209 except ValueError: 

210 try: 

211 is_input_t_tensor = backend.is_keras_tensor( 

212 layer_utils.get_source_inputs(input_tensor) 

213 ) 

214 except ValueError: 

215 raise ValueError( 

216 "input_tensor: ", 

217 input_tensor, 

218 "is not type input_tensor. " 

219 f"Received type(input_tensor)={type(input_tensor)}", 

220 ) 

221 if is_input_t_tensor: 

222 if backend.image_data_format() == "channels_first": 

223 if backend.int_shape(input_tensor)[1] != input_shape[1]: 

224 raise ValueError( 

225 "When backend.image_data_format()=channels_first, " 

226 "input_shape[1] must equal " 

227 "backend.int_shape(input_tensor)[1]. Received " 

228 f"input_shape={input_shape}, " 

229 "backend.int_shape(input_tensor)=" 

230 f"{backend.int_shape(input_tensor)}" 

231 ) 

232 else: 

233 if backend.int_shape(input_tensor)[2] != input_shape[1]: 

234 raise ValueError( 

235 "input_shape[1] must equal " 

236 "backend.int_shape(input_tensor)[2]. Received " 

237 f"input_shape={input_shape}, " 

238 "backend.int_shape(input_tensor)=" 

239 f"{backend.int_shape(input_tensor)}" 

240 ) 

241 else: 

242 raise ValueError( 

243 "input_tensor specified: ", 

244 input_tensor, 

245 "is not a keras tensor", 

246 ) 

247 

248 # If input_shape is None, infer shape from input_tensor 

249 if input_shape is None and input_tensor is not None: 

250 

251 try: 

252 backend.is_keras_tensor(input_tensor) 

253 except ValueError: 

254 raise ValueError( 

255 "input_tensor: ", 

256 input_tensor, 

257 "is type: ", 

258 type(input_tensor), 

259 "which is not a valid type", 

260 ) 

261 

262 if backend.is_keras_tensor(input_tensor): 

263 if backend.image_data_format() == "channels_first": 

264 rows = backend.int_shape(input_tensor)[2] 

265 cols = backend.int_shape(input_tensor)[3] 

266 input_shape = (3, cols, rows) 

267 else: 

268 rows = backend.int_shape(input_tensor)[1] 

269 cols = backend.int_shape(input_tensor)[2] 

270 input_shape = (cols, rows, 3) 

271 # If input_shape is None and input_tensor is None using standard shape 

272 if input_shape is None and input_tensor is None: 

273 input_shape = (None, None, 3) 

274 

275 if backend.image_data_format() == "channels_last": 

276 row_axis, col_axis = (0, 1) 

277 else: 

278 row_axis, col_axis = (1, 2) 

279 rows = input_shape[row_axis] 

280 cols = input_shape[col_axis] 

281 if rows and cols and (rows < 32 or cols < 32): 

282 raise ValueError( 

283 "Input size must be at least 32x32; Received `input_shape=" 

284 f"{input_shape}`" 

285 ) 

286 if weights == "imagenet": 

287 if ( 

288 not minimalistic 

289 and alpha not in [0.75, 1.0] 

290 or minimalistic 

291 and alpha != 1.0 

292 ): 

293 raise ValueError( 

294 "If imagenet weights are being loaded, " 

295 "alpha can be one of `0.75`, `1.0` for non minimalistic " 

296 "or `1.0` for minimalistic only." 

297 ) 

298 

299 if rows != cols or rows != 224: 

300 logging.warning( 

301 "`input_shape` is undefined or non-square, " 

302 "or `rows` is not 224. " 

303 "Weights for input shape (224, 224) will be " 

304 "loaded as the default." 

305 ) 

306 

307 if input_tensor is None: 

308 img_input = layers.Input(shape=input_shape) 

309 else: 

310 if not backend.is_keras_tensor(input_tensor): 

311 img_input = layers.Input(tensor=input_tensor, shape=input_shape) 

312 else: 

313 img_input = input_tensor 

314 

315 channel_axis = 1 if backend.image_data_format() == "channels_first" else -1 

316 

317 if minimalistic: 

318 kernel = 3 

319 activation = relu 

320 se_ratio = None 

321 else: 

322 kernel = 5 

323 activation = hard_swish 

324 se_ratio = 0.25 

325 

326 x = img_input 

327 if include_preprocessing: 

328 x = layers.Rescaling(scale=1.0 / 127.5, offset=-1.0)(x) 

329 x = layers.Conv2D( 

330 16, 

331 kernel_size=3, 

332 strides=(2, 2), 

333 padding="same", 

334 use_bias=False, 

335 name="Conv", 

336 )(x) 

337 x = layers.BatchNormalization( 

338 axis=channel_axis, epsilon=1e-3, momentum=0.999, name="Conv/BatchNorm" 

339 )(x) 

340 x = activation(x) 

341 

342 x = stack_fn(x, kernel, activation, se_ratio) 

343 

344 last_conv_ch = _depth(backend.int_shape(x)[channel_axis] * 6) 

345 

346 # if the width multiplier is greater than 1 we 

347 # increase the number of output channels 

348 if alpha > 1.0: 

349 last_point_ch = _depth(last_point_ch * alpha) 

350 x = layers.Conv2D( 

351 last_conv_ch, 

352 kernel_size=1, 

353 padding="same", 

354 use_bias=False, 

355 name="Conv_1", 

356 )(x) 

357 x = layers.BatchNormalization( 

358 axis=channel_axis, epsilon=1e-3, momentum=0.999, name="Conv_1/BatchNorm" 

359 )(x) 

360 x = activation(x) 

361 if include_top: 

362 x = layers.GlobalAveragePooling2D(keepdims=True)(x) 

363 x = layers.Conv2D( 

364 last_point_ch, 

365 kernel_size=1, 

366 padding="same", 

367 use_bias=True, 

368 name="Conv_2", 

369 )(x) 

370 x = activation(x) 

371 

372 if dropout_rate > 0: 

373 x = layers.Dropout(dropout_rate)(x) 

374 x = layers.Conv2D( 

375 classes, kernel_size=1, padding="same", name="Logits" 

376 )(x) 

377 x = layers.Flatten()(x) 

378 imagenet_utils.validate_activation(classifier_activation, weights) 

379 x = layers.Activation( 

380 activation=classifier_activation, name="Predictions" 

381 )(x) 

382 else: 

383 if pooling == "avg": 

384 x = layers.GlobalAveragePooling2D(name="avg_pool")(x) 

385 elif pooling == "max": 

386 x = layers.GlobalMaxPooling2D(name="max_pool")(x) 

387 # Ensure that the model takes into account 

388 # any potential predecessors of `input_tensor`. 

389 if input_tensor is not None: 

390 inputs = layer_utils.get_source_inputs(input_tensor) 

391 else: 

392 inputs = img_input 

393 

394 # Create model. 

395 model = models.Model(inputs, x, name="MobilenetV3" + model_type) 

396 

397 # Load weights. 

398 if weights == "imagenet": 

399 model_name = "{}{}_224_{}_float".format( 

400 model_type, "_minimalistic" if minimalistic else "", str(alpha) 

401 ) 

402 if include_top: 

403 file_name = "weights_mobilenet_v3_" + model_name + ".h5" 

404 file_hash = WEIGHTS_HASHES[model_name][0] 

405 else: 

406 file_name = "weights_mobilenet_v3_" + model_name + "_no_top_v2.h5" 

407 file_hash = WEIGHTS_HASHES[model_name][1] 

408 weights_path = data_utils.get_file( 

409 file_name, 

410 BASE_WEIGHT_PATH + file_name, 

411 cache_subdir="models", 

412 file_hash=file_hash, 

413 ) 

414 model.load_weights(weights_path) 

415 elif weights is not None: 

416 model.load_weights(weights) 

417 

418 return model 

419 

420 

421@keras_export("keras.applications.MobileNetV3Small") 

422def MobileNetV3Small( 

423 input_shape=None, 

424 alpha=1.0, 

425 minimalistic=False, 

426 include_top=True, 

427 weights="imagenet", 

428 input_tensor=None, 

429 classes=1000, 

430 pooling=None, 

431 dropout_rate=0.2, 

432 classifier_activation="softmax", 

433 include_preprocessing=True, 

434): 

435 def stack_fn(x, kernel, activation, se_ratio): 

436 def depth(d): 

437 return _depth(d * alpha) 

438 

439 x = _inverted_res_block(x, 1, depth(16), 3, 2, se_ratio, relu, 0) 

440 x = _inverted_res_block(x, 72.0 / 16, depth(24), 3, 2, None, relu, 1) 

441 x = _inverted_res_block(x, 88.0 / 24, depth(24), 3, 1, None, relu, 2) 

442 x = _inverted_res_block( 

443 x, 4, depth(40), kernel, 2, se_ratio, activation, 3 

444 ) 

445 x = _inverted_res_block( 

446 x, 6, depth(40), kernel, 1, se_ratio, activation, 4 

447 ) 

448 x = _inverted_res_block( 

449 x, 6, depth(40), kernel, 1, se_ratio, activation, 5 

450 ) 

451 x = _inverted_res_block( 

452 x, 3, depth(48), kernel, 1, se_ratio, activation, 6 

453 ) 

454 x = _inverted_res_block( 

455 x, 3, depth(48), kernel, 1, se_ratio, activation, 7 

456 ) 

457 x = _inverted_res_block( 

458 x, 6, depth(96), kernel, 2, se_ratio, activation, 8 

459 ) 

460 x = _inverted_res_block( 

461 x, 6, depth(96), kernel, 1, se_ratio, activation, 9 

462 ) 

463 x = _inverted_res_block( 

464 x, 6, depth(96), kernel, 1, se_ratio, activation, 10 

465 ) 

466 return x 

467 

468 return MobileNetV3( 

469 stack_fn, 

470 1024, 

471 input_shape, 

472 alpha, 

473 "small", 

474 minimalistic, 

475 include_top, 

476 weights, 

477 input_tensor, 

478 classes, 

479 pooling, 

480 dropout_rate, 

481 classifier_activation, 

482 include_preprocessing, 

483 ) 

484 

485 

486@keras_export("keras.applications.MobileNetV3Large") 

487def MobileNetV3Large( 

488 input_shape=None, 

489 alpha=1.0, 

490 minimalistic=False, 

491 include_top=True, 

492 weights="imagenet", 

493 input_tensor=None, 

494 classes=1000, 

495 pooling=None, 

496 dropout_rate=0.2, 

497 classifier_activation="softmax", 

498 include_preprocessing=True, 

499): 

500 def stack_fn(x, kernel, activation, se_ratio): 

501 def depth(d): 

502 return _depth(d * alpha) 

503 

504 x = _inverted_res_block(x, 1, depth(16), 3, 1, None, relu, 0) 

505 x = _inverted_res_block(x, 4, depth(24), 3, 2, None, relu, 1) 

506 x = _inverted_res_block(x, 3, depth(24), 3, 1, None, relu, 2) 

507 x = _inverted_res_block(x, 3, depth(40), kernel, 2, se_ratio, relu, 3) 

508 x = _inverted_res_block(x, 3, depth(40), kernel, 1, se_ratio, relu, 4) 

509 x = _inverted_res_block(x, 3, depth(40), kernel, 1, se_ratio, relu, 5) 

510 x = _inverted_res_block(x, 6, depth(80), 3, 2, None, activation, 6) 

511 x = _inverted_res_block(x, 2.5, depth(80), 3, 1, None, activation, 7) 

512 x = _inverted_res_block(x, 2.3, depth(80), 3, 1, None, activation, 8) 

513 x = _inverted_res_block(x, 2.3, depth(80), 3, 1, None, activation, 9) 

514 x = _inverted_res_block( 

515 x, 6, depth(112), 3, 1, se_ratio, activation, 10 

516 ) 

517 x = _inverted_res_block( 

518 x, 6, depth(112), 3, 1, se_ratio, activation, 11 

519 ) 

520 x = _inverted_res_block( 

521 x, 6, depth(160), kernel, 2, se_ratio, activation, 12 

522 ) 

523 x = _inverted_res_block( 

524 x, 6, depth(160), kernel, 1, se_ratio, activation, 13 

525 ) 

526 x = _inverted_res_block( 

527 x, 6, depth(160), kernel, 1, se_ratio, activation, 14 

528 ) 

529 return x 

530 

531 return MobileNetV3( 

532 stack_fn, 

533 1280, 

534 input_shape, 

535 alpha, 

536 "large", 

537 minimalistic, 

538 include_top, 

539 weights, 

540 input_tensor, 

541 classes, 

542 pooling, 

543 dropout_rate, 

544 classifier_activation, 

545 include_preprocessing, 

546 ) 

547 

548 

549MobileNetV3Small.__doc__ = BASE_DOCSTRING.format(name="MobileNetV3Small") 

550MobileNetV3Large.__doc__ = BASE_DOCSTRING.format(name="MobileNetV3Large") 

551 

552 

553def relu(x): 

554 return layers.ReLU()(x) 

555 

556 

557def hard_sigmoid(x): 

558 return layers.ReLU(6.0)(x + 3.0) * (1.0 / 6.0) 

559 

560 

561def hard_swish(x): 

562 return layers.Multiply()([x, hard_sigmoid(x)]) 

563 

564 

565# This function is taken from the original tf repo. 

566# It ensures that all layers have a channel number that is divisible by 8 

567# It can be seen here: 

568# https://github.com/tensorflow/models/blob/master/research/ 

569# slim/nets/mobilenet/mobilenet.py 

570 

571 

572def _depth(v, divisor=8, min_value=None): 

573 if min_value is None: 

574 min_value = divisor 

575 new_v = max(min_value, int(v + divisor / 2) // divisor * divisor) 

576 # Make sure that round down does not go down by more than 10%. 

577 if new_v < 0.9 * v: 

578 new_v += divisor 

579 return new_v 

580 

581 

582def _se_block(inputs, filters, se_ratio, prefix): 

583 x = layers.GlobalAveragePooling2D( 

584 keepdims=True, name=prefix + "squeeze_excite/AvgPool" 

585 )(inputs) 

586 x = layers.Conv2D( 

587 _depth(filters * se_ratio), 

588 kernel_size=1, 

589 padding="same", 

590 name=prefix + "squeeze_excite/Conv", 

591 )(x) 

592 x = layers.ReLU(name=prefix + "squeeze_excite/Relu")(x) 

593 x = layers.Conv2D( 

594 filters, 

595 kernel_size=1, 

596 padding="same", 

597 name=prefix + "squeeze_excite/Conv_1", 

598 )(x) 

599 x = hard_sigmoid(x) 

600 x = layers.Multiply(name=prefix + "squeeze_excite/Mul")([inputs, x]) 

601 return x 

602 

603 

604def _inverted_res_block( 

605 x, expansion, filters, kernel_size, stride, se_ratio, activation, block_id 

606): 

607 channel_axis = 1 if backend.image_data_format() == "channels_first" else -1 

608 shortcut = x 

609 prefix = "expanded_conv/" 

610 infilters = backend.int_shape(x)[channel_axis] 

611 if block_id: 

612 # Expand 

613 prefix = f"expanded_conv_{block_id}/" 

614 x = layers.Conv2D( 

615 _depth(infilters * expansion), 

616 kernel_size=1, 

617 padding="same", 

618 use_bias=False, 

619 name=prefix + "expand", 

620 )(x) 

621 x = layers.BatchNormalization( 

622 axis=channel_axis, 

623 epsilon=1e-3, 

624 momentum=0.999, 

625 name=prefix + "expand/BatchNorm", 

626 )(x) 

627 x = activation(x) 

628 

629 if stride == 2: 

630 x = layers.ZeroPadding2D( 

631 padding=imagenet_utils.correct_pad(x, kernel_size), 

632 name=prefix + "depthwise/pad", 

633 )(x) 

634 x = layers.DepthwiseConv2D( 

635 kernel_size, 

636 strides=stride, 

637 padding="same" if stride == 1 else "valid", 

638 use_bias=False, 

639 name=prefix + "depthwise", 

640 )(x) 

641 x = layers.BatchNormalization( 

642 axis=channel_axis, 

643 epsilon=1e-3, 

644 momentum=0.999, 

645 name=prefix + "depthwise/BatchNorm", 

646 )(x) 

647 x = activation(x) 

648 

649 if se_ratio: 

650 x = _se_block(x, _depth(infilters * expansion), se_ratio, prefix) 

651 

652 x = layers.Conv2D( 

653 filters, 

654 kernel_size=1, 

655 padding="same", 

656 use_bias=False, 

657 name=prefix + "project", 

658 )(x) 

659 x = layers.BatchNormalization( 

660 axis=channel_axis, 

661 epsilon=1e-3, 

662 momentum=0.999, 

663 name=prefix + "project/BatchNorm", 

664 )(x) 

665 

666 if stride == 1 and infilters == filters: 

667 x = layers.Add(name=prefix + "Add")([shortcut, x]) 

668 return x 

669 

670 

671@keras_export("keras.applications.mobilenet_v3.preprocess_input") 

672def preprocess_input(x, data_format=None): 

673 """A placeholder method for backward compatibility. 

674 

675 The preprocessing logic has been included in the mobilenet_v3 model 

676 implementation. Users are no longer required to call this method to 

677 normalize the input data. This method does nothing and only kept as a 

678 placeholder to align the API surface between old and new version of model. 

679 

680 Args: 

681 x: A floating point `numpy.array` or a `tf.Tensor`. 

682 data_format: Optional data format of the image tensor/array. `None` means 

683 the global setting `tf.keras.backend.image_data_format()` is used 

684 (unless you changed it, it uses "channels_last"). 

685 Defaults to `None`. 

686 

687 Returns: 

688 Unchanged `numpy.array` or `tf.Tensor`. 

689 """ 

690 return x 

691 

692 

693@keras_export("keras.applications.mobilenet_v3.decode_predictions") 

694def decode_predictions(preds, top=5): 

695 return imagenet_utils.decode_predictions(preds, top=top) 

696 

697 

698decode_predictions.__doc__ = imagenet_utils.decode_predictions.__doc__ 

699