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

195 statements  

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

1# Copyright 2018 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"""NASNet-A models for Keras. 

17 

18NASNet refers to Neural Architecture Search Network, a family of models 

19that were designed automatically by learning the model architectures 

20directly on the dataset of interest. 

21 

22Here we consider NASNet-A, the highest performance model that was found 

23for the CIFAR-10 dataset, and then extended to ImageNet 2012 dataset, 

24obtaining state of the art performance on CIFAR-10 and ImageNet 2012. 

25Only the NASNet-A models, and their respective weights, which are suited 

26for ImageNet 2012 are provided. 

27 

28The below table describes the performance on ImageNet 2012: 

29--------------------------------------------------------------------------- 

30Architecture | Top-1 Acc | Top-5 Acc | Multiply-Adds | Params (M) 

31---------------------|-----------|-----------|----------------|------------ 

32NASNet-A (4 @ 1056) | 74.0 % | 91.6 % | 564 M | 5.3 

33NASNet-A (6 @ 4032) | 82.7 % | 96.2 % | 23.8 B | 88.9 

34 

35Reference: 

36 - [Learning Transferable Architectures for Scalable Image Recognition]( 

37 https://arxiv.org/abs/1707.07012) (CVPR 2018) 

38""" 

39 

40import tensorflow.compat.v2 as tf 

41 

42from keras.src import backend 

43from keras.src.applications import imagenet_utils 

44from keras.src.engine import training 

45from keras.src.layers import VersionAwareLayers 

46from keras.src.utils import data_utils 

47from keras.src.utils import layer_utils 

48 

49# isort: off 

50from tensorflow.python.platform import tf_logging as logging 

51from tensorflow.python.util.tf_export import keras_export 

52 

53BASE_WEIGHTS_PATH = ( 

54 "https://storage.googleapis.com/tensorflow/keras-applications/nasnet/" 

55) 

56NASNET_MOBILE_WEIGHT_PATH = BASE_WEIGHTS_PATH + "NASNet-mobile.h5" 

57NASNET_MOBILE_WEIGHT_PATH_NO_TOP = BASE_WEIGHTS_PATH + "NASNet-mobile-no-top.h5" 

58NASNET_LARGE_WEIGHT_PATH = BASE_WEIGHTS_PATH + "NASNet-large.h5" 

59NASNET_LARGE_WEIGHT_PATH_NO_TOP = BASE_WEIGHTS_PATH + "NASNet-large-no-top.h5" 

60 

61layers = VersionAwareLayers() 

62 

63 

64def NASNet( 

65 input_shape=None, 

66 penultimate_filters=4032, 

67 num_blocks=6, 

68 stem_block_filters=96, 

69 skip_reduction=True, 

70 filter_multiplier=2, 

71 include_top=True, 

72 weights="imagenet", 

73 input_tensor=None, 

74 pooling=None, 

75 classes=1000, 

76 default_size=None, 

77 classifier_activation="softmax", 

78): 

79 """Instantiates a NASNet model. 

80 

81 Reference: 

82 - [Learning Transferable Architectures for Scalable Image Recognition]( 

83 https://arxiv.org/abs/1707.07012) (CVPR 2018) 

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 NasNet, call `tf.keras.applications.nasnet.preprocess_input` 

95 on your inputs before passing them to the model. 

96 `nasnet.preprocess_input` will scale input pixels between -1 and 1. 

97 

98 Args: 

99 input_shape: Optional shape tuple, the input shape 

100 is by default `(331, 331, 3)` for NASNetLarge and 

101 `(224, 224, 3)` for NASNetMobile. 

102 It should have exactly 3 input channels, 

103 and width and height should be no smaller than 32. 

104 E.g. `(224, 224, 3)` would be one valid value. 

105 penultimate_filters: Number of filters in the penultimate layer. 

106 NASNet models use the notation `NASNet (N @ P)`, where: 

107 - N is the number of blocks 

108 - P is the number of penultimate filters 

109 num_blocks: Number of repeated blocks of the NASNet model. 

110 NASNet models use the notation `NASNet (N @ P)`, where: 

111 - N is the number of blocks 

112 - P is the number of penultimate filters 

113 stem_block_filters: Number of filters in the initial stem block 

114 skip_reduction: Whether to skip the reduction step at the tail 

115 end of the network. 

116 filter_multiplier: Controls the width of the network. 

117 - If `filter_multiplier` < 1.0, proportionally decreases the number 

118 of filters in each layer. 

119 - If `filter_multiplier` > 1.0, proportionally increases the number 

120 of filters in each layer. 

121 - If `filter_multiplier` = 1, default number of filters from the 

122 paper are used at each layer. 

123 include_top: Whether to include the fully-connected 

124 layer at the top of the network. 

125 weights: `None` (random initialization) or 

126 `imagenet` (ImageNet weights) 

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

128 `layers.Input()`) 

129 to use as image input for the model. 

130 pooling: Optional pooling mode for feature extraction 

131 when `include_top` is `False`. 

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

133 will be the 4D tensor output of the 

134 last convolutional block. 

135 - `avg` means that global average pooling 

136 will be applied to the output of the 

137 last convolutional block, and thus 

138 the output of the model will be a 

139 2D tensor. 

140 - `max` means that global max pooling will 

141 be applied. 

142 classes: Optional number of classes to classify images 

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

144 if no `weights` argument is specified. 

145 default_size: Specifies the default image size of the model 

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

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

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

149 When loading pretrained weights, `classifier_activation` can only 

150 be `None` or `"softmax"`. 

151 

152 Returns: 

153 A `keras.Model` instance. 

154 """ 

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

156 raise ValueError( 

157 "The `weights` argument should be either " 

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

159 "(pre-training on ImageNet), " 

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

161 ) 

162 

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

164 raise ValueError( 

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

166 "as true, `classes` should be 1000" 

167 ) 

168 

169 if ( 

170 isinstance(input_shape, tuple) 

171 and None in input_shape 

172 and weights == "imagenet" 

173 ): 

174 raise ValueError( 

175 "When specifying the input shape of a NASNet" 

176 " and loading `ImageNet` weights, " 

177 "the input_shape argument must be static " 

178 "(no None entries). Got: `input_shape=" + str(input_shape) + "`." 

179 ) 

180 

181 if default_size is None: 

182 default_size = 331 

183 

184 # Determine proper input shape and default size. 

185 input_shape = imagenet_utils.obtain_input_shape( 

186 input_shape, 

187 default_size=default_size, 

188 min_size=32, 

189 data_format=backend.image_data_format(), 

190 require_flatten=include_top, 

191 weights=weights, 

192 ) 

193 

194 if backend.image_data_format() != "channels_last": 

195 logging.warning( 

196 "The NASNet family of models is only available " 

197 'for the input data format "channels_last" ' 

198 "(width, height, channels). " 

199 "However your settings specify the default " 

200 'data format "channels_first" (channels, width, height).' 

201 ' You should set `image_data_format="channels_last"` ' 

202 "in your Keras config located at ~/.keras/keras.json. " 

203 "The model being returned right now will expect inputs " 

204 'to follow the "channels_last" data format.' 

205 ) 

206 backend.set_image_data_format("channels_last") 

207 old_data_format = "channels_first" 

208 else: 

209 old_data_format = None 

210 

211 if input_tensor is None: 

212 img_input = layers.Input(shape=input_shape) 

213 else: 

214 if not backend.is_keras_tensor(input_tensor): 

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

216 else: 

217 img_input = input_tensor 

218 

219 if penultimate_filters % (24 * (filter_multiplier**2)) != 0: 

220 raise ValueError( 

221 "For NASNet-A models, the `penultimate_filters` must be a multiple " 

222 "of 24 * (`filter_multiplier` ** 2). Current value: %d" 

223 % penultimate_filters 

224 ) 

225 

226 channel_dim = 1 if backend.image_data_format() == "channels_first" else -1 

227 filters = penultimate_filters // 24 

228 

229 x = layers.Conv2D( 

230 stem_block_filters, 

231 (3, 3), 

232 strides=(2, 2), 

233 padding="valid", 

234 use_bias=False, 

235 name="stem_conv1", 

236 kernel_initializer="he_normal", 

237 )(img_input) 

238 

239 x = layers.BatchNormalization( 

240 axis=channel_dim, momentum=0.9997, epsilon=1e-3, name="stem_bn1" 

241 )(x) 

242 

243 p = None 

244 x, p = _reduction_a_cell( 

245 x, p, filters // (filter_multiplier**2), block_id="stem_1" 

246 ) 

247 x, p = _reduction_a_cell( 

248 x, p, filters // filter_multiplier, block_id="stem_2" 

249 ) 

250 

251 for i in range(num_blocks): 

252 x, p = _normal_a_cell(x, p, filters, block_id="%d" % (i)) 

253 

254 x, p0 = _reduction_a_cell( 

255 x, p, filters * filter_multiplier, block_id="reduce_%d" % (num_blocks) 

256 ) 

257 

258 p = p0 if not skip_reduction else p 

259 

260 for i in range(num_blocks): 

261 x, p = _normal_a_cell( 

262 x, 

263 p, 

264 filters * filter_multiplier, 

265 block_id="%d" % (num_blocks + i + 1), 

266 ) 

267 

268 x, p0 = _reduction_a_cell( 

269 x, 

270 p, 

271 filters * filter_multiplier**2, 

272 block_id="reduce_%d" % (2 * num_blocks), 

273 ) 

274 

275 p = p0 if not skip_reduction else p 

276 

277 for i in range(num_blocks): 

278 x, p = _normal_a_cell( 

279 x, 

280 p, 

281 filters * filter_multiplier**2, 

282 block_id="%d" % (2 * num_blocks + i + 1), 

283 ) 

284 

285 x = layers.Activation("relu")(x) 

286 

287 if include_top: 

288 x = layers.GlobalAveragePooling2D()(x) 

289 imagenet_utils.validate_activation(classifier_activation, weights) 

290 x = layers.Dense( 

291 classes, activation=classifier_activation, name="predictions" 

292 )(x) 

293 else: 

294 if pooling == "avg": 

295 x = layers.GlobalAveragePooling2D()(x) 

296 elif pooling == "max": 

297 x = layers.GlobalMaxPooling2D()(x) 

298 

299 # Ensure that the model takes into account 

300 # any potential predecessors of `input_tensor`. 

301 if input_tensor is not None: 

302 inputs = layer_utils.get_source_inputs(input_tensor) 

303 else: 

304 inputs = img_input 

305 

306 model = training.Model(inputs, x, name="NASNet") 

307 

308 # Load weights. 

309 if weights == "imagenet": 

310 if default_size == 224: # mobile version 

311 if include_top: 

312 weights_path = data_utils.get_file( 

313 "nasnet_mobile.h5", 

314 NASNET_MOBILE_WEIGHT_PATH, 

315 cache_subdir="models", 

316 file_hash="020fb642bf7360b370c678b08e0adf61", 

317 ) 

318 else: 

319 weights_path = data_utils.get_file( 

320 "nasnet_mobile_no_top.h5", 

321 NASNET_MOBILE_WEIGHT_PATH_NO_TOP, 

322 cache_subdir="models", 

323 file_hash="1ed92395b5b598bdda52abe5c0dbfd63", 

324 ) 

325 model.load_weights(weights_path) 

326 elif default_size == 331: # large version 

327 if include_top: 

328 weights_path = data_utils.get_file( 

329 "nasnet_large.h5", 

330 NASNET_LARGE_WEIGHT_PATH, 

331 cache_subdir="models", 

332 file_hash="11577c9a518f0070763c2b964a382f17", 

333 ) 

334 else: 

335 weights_path = data_utils.get_file( 

336 "nasnet_large_no_top.h5", 

337 NASNET_LARGE_WEIGHT_PATH_NO_TOP, 

338 cache_subdir="models", 

339 file_hash="d81d89dc07e6e56530c4e77faddd61b5", 

340 ) 

341 model.load_weights(weights_path) 

342 else: 

343 raise ValueError( 

344 "ImageNet weights can only be loaded with NASNetLarge" 

345 " or NASNetMobile" 

346 ) 

347 elif weights is not None: 

348 model.load_weights(weights) 

349 

350 if old_data_format: 

351 backend.set_image_data_format(old_data_format) 

352 

353 return model 

354 

355 

356@keras_export( 

357 "keras.applications.nasnet.NASNetMobile", "keras.applications.NASNetMobile" 

358) 

359def NASNetMobile( 

360 input_shape=None, 

361 include_top=True, 

362 weights="imagenet", 

363 input_tensor=None, 

364 pooling=None, 

365 classes=1000, 

366 classifier_activation="softmax", 

367): 

368 """Instantiates a Mobile NASNet model in ImageNet mode. 

369 

370 Reference: 

371 - [Learning Transferable Architectures for Scalable Image Recognition]( 

372 https://arxiv.org/abs/1707.07012) (CVPR 2018) 

373 

374 Optionally loads weights pre-trained on ImageNet. 

375 Note that the data format convention used by the model is 

376 the one specified in your Keras config at `~/.keras/keras.json`. 

377 

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

379 For NASNet, call `tf.keras.applications.nasnet.preprocess_input` on your 

380 inputs before passing them to the model. 

381 

382 Args: 

383 input_shape: Optional shape tuple, only to be specified 

384 if `include_top` is False (otherwise the input shape 

385 has to be `(224, 224, 3)` for NASNetMobile 

386 It should have exactly 3 inputs channels, 

387 and width and height should be no smaller than 32. 

388 E.g. `(224, 224, 3)` would be one valid value. 

389 include_top: Whether to include the fully-connected 

390 layer at the top of the network. 

391 weights: `None` (random initialization) or 

392 `imagenet` (ImageNet weights). For loading `imagenet` weights, 

393 `input_shape` should be (224, 224, 3) 

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

395 `layers.Input()`) 

396 to use as image input for the model. 

397 pooling: Optional pooling mode for feature extraction 

398 when `include_top` is `False`. 

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

400 will be the 4D tensor output of the 

401 last convolutional layer. 

402 - `avg` means that global average pooling 

403 will be applied to the output of the 

404 last convolutional layer, and thus 

405 the output of the model will be a 

406 2D tensor. 

407 - `max` means that global max pooling will 

408 be applied. 

409 classes: Optional number of classes to classify images 

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

411 if no `weights` argument is specified. 

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

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

414 `classifier_activation=None` to return the logits of the "top" 

415 layer. When loading pretrained weights, `classifier_activation` can 

416 only be `None` or `"softmax"`. 

417 

418 Returns: 

419 A Keras model instance. 

420 

421 Raises: 

422 ValueError: In case of invalid argument for `weights`, 

423 or invalid input shape. 

424 RuntimeError: If attempting to run this model with a 

425 backend that does not support separable convolutions. 

426 """ 

427 return NASNet( 

428 input_shape, 

429 penultimate_filters=1056, 

430 num_blocks=4, 

431 stem_block_filters=32, 

432 skip_reduction=False, 

433 filter_multiplier=2, 

434 include_top=include_top, 

435 weights=weights, 

436 input_tensor=input_tensor, 

437 pooling=pooling, 

438 classes=classes, 

439 default_size=224, 

440 classifier_activation=classifier_activation, 

441 ) 

442 

443 

444@keras_export( 

445 "keras.applications.nasnet.NASNetLarge", "keras.applications.NASNetLarge" 

446) 

447def NASNetLarge( 

448 input_shape=None, 

449 include_top=True, 

450 weights="imagenet", 

451 input_tensor=None, 

452 pooling=None, 

453 classes=1000, 

454 classifier_activation="softmax", 

455): 

456 """Instantiates a NASNet model in ImageNet mode. 

457 

458 Reference: 

459 - [Learning Transferable Architectures for Scalable Image Recognition]( 

460 https://arxiv.org/abs/1707.07012) (CVPR 2018) 

461 

462 Optionally loads weights pre-trained on ImageNet. 

463 Note that the data format convention used by the model is 

464 the one specified in your Keras config at `~/.keras/keras.json`. 

465 

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

467 For NASNet, call `tf.keras.applications.nasnet.preprocess_input` on your 

468 inputs before passing them to the model. 

469 

470 Args: 

471 input_shape: Optional shape tuple, only to be specified 

472 if `include_top` is False (otherwise the input shape 

473 has to be `(331, 331, 3)` for NASNetLarge. 

474 It should have exactly 3 inputs channels, 

475 and width and height should be no smaller than 32. 

476 E.g. `(224, 224, 3)` would be one valid value. 

477 include_top: Whether to include the fully-connected 

478 layer at the top of the network. 

479 weights: `None` (random initialization) or 

480 `imagenet` (ImageNet weights). For loading `imagenet` weights, 

481 `input_shape` should be (331, 331, 3) 

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

483 `layers.Input()`) 

484 to use as image input for the model. 

485 pooling: Optional pooling mode for feature extraction 

486 when `include_top` is `False`. 

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

488 will be the 4D tensor output of the 

489 last convolutional layer. 

490 - `avg` means that global average pooling 

491 will be applied to the output of the 

492 last convolutional layer, and thus 

493 the output of the model will be a 

494 2D tensor. 

495 - `max` means that global max pooling will 

496 be applied. 

497 classes: Optional number of classes to classify images 

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

499 if no `weights` argument is specified. 

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

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

502 `classifier_activation=None` to return the logits of the "top" 

503 layer. When loading pretrained weights, `classifier_activation` can 

504 only be `None` or `"softmax"`. 

505 

506 Returns: 

507 A Keras model instance. 

508 

509 Raises: 

510 ValueError: in case of invalid argument for `weights`, 

511 or invalid input shape. 

512 RuntimeError: If attempting to run this model with a 

513 backend that does not support separable convolutions. 

514 """ 

515 return NASNet( 

516 input_shape, 

517 penultimate_filters=4032, 

518 num_blocks=6, 

519 stem_block_filters=96, 

520 skip_reduction=True, 

521 filter_multiplier=2, 

522 include_top=include_top, 

523 weights=weights, 

524 input_tensor=input_tensor, 

525 pooling=pooling, 

526 classes=classes, 

527 default_size=331, 

528 classifier_activation=classifier_activation, 

529 ) 

530 

531 

532def _separable_conv_block( 

533 ip, filters, kernel_size=(3, 3), strides=(1, 1), block_id=None 

534): 

535 """Adds 2 blocks of [relu-separable conv-batchnorm]. 

536 

537 Args: 

538 ip: Input tensor 

539 filters: Number of output filters per layer 

540 kernel_size: Kernel size of separable convolutions 

541 strides: Strided convolution for downsampling 

542 block_id: String block_id 

543 

544 Returns: 

545 A Keras tensor 

546 """ 

547 channel_dim = 1 if backend.image_data_format() == "channels_first" else -1 

548 

549 with backend.name_scope(f"separable_conv_block_{block_id}"): 

550 x = layers.Activation("relu")(ip) 

551 if strides == (2, 2): 

552 x = layers.ZeroPadding2D( 

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

554 name=f"separable_conv_1_pad_{block_id}", 

555 )(x) 

556 conv_pad = "valid" 

557 else: 

558 conv_pad = "same" 

559 x = layers.SeparableConv2D( 

560 filters, 

561 kernel_size, 

562 strides=strides, 

563 name=f"separable_conv_1_{block_id}", 

564 padding=conv_pad, 

565 use_bias=False, 

566 kernel_initializer="he_normal", 

567 )(x) 

568 x = layers.BatchNormalization( 

569 axis=channel_dim, 

570 momentum=0.9997, 

571 epsilon=1e-3, 

572 name=f"separable_conv_1_bn_{block_id}", 

573 )(x) 

574 x = layers.Activation("relu")(x) 

575 x = layers.SeparableConv2D( 

576 filters, 

577 kernel_size, 

578 name=f"separable_conv_2_{block_id}", 

579 padding="same", 

580 use_bias=False, 

581 kernel_initializer="he_normal", 

582 )(x) 

583 x = layers.BatchNormalization( 

584 axis=channel_dim, 

585 momentum=0.9997, 

586 epsilon=1e-3, 

587 name=f"separable_conv_2_bn_{block_id}", 

588 )(x) 

589 return x 

590 

591 

592def _adjust_block(p, ip, filters, block_id=None): 

593 """Adjusts the input `previous path` to match the shape of the `input`. 

594 

595 Used in situations where the output number of filters needs to be changed. 

596 

597 Args: 

598 p: Input tensor which needs to be modified 

599 ip: Input tensor whose shape needs to be matched 

600 filters: Number of output filters to be matched 

601 block_id: String block_id 

602 

603 Returns: 

604 Adjusted Keras tensor 

605 """ 

606 channel_dim = 1 if backend.image_data_format() == "channels_first" else -1 

607 img_dim = 2 if backend.image_data_format() == "channels_first" else -2 

608 

609 ip_shape = backend.int_shape(ip) 

610 

611 if p is not None: 

612 p_shape = backend.int_shape(p) 

613 

614 with backend.name_scope("adjust_block"): 

615 if p is None: 

616 p = ip 

617 

618 elif p_shape[img_dim] != ip_shape[img_dim]: 

619 with backend.name_scope(f"adjust_reduction_block_{block_id}"): 

620 p = layers.Activation("relu", name=f"adjust_relu_1_{block_id}")( 

621 p 

622 ) 

623 p1 = layers.AveragePooling2D( 

624 (1, 1), 

625 strides=(2, 2), 

626 padding="valid", 

627 name=f"adjust_avg_pool_1_{block_id}", 

628 )(p) 

629 p1 = layers.Conv2D( 

630 filters // 2, 

631 (1, 1), 

632 padding="same", 

633 use_bias=False, 

634 name=f"adjust_conv_1_{block_id}", 

635 kernel_initializer="he_normal", 

636 )(p1) 

637 

638 p2 = layers.ZeroPadding2D(padding=((0, 1), (0, 1)))(p) 

639 p2 = layers.Cropping2D(cropping=((1, 0), (1, 0)))(p2) 

640 p2 = layers.AveragePooling2D( 

641 (1, 1), 

642 strides=(2, 2), 

643 padding="valid", 

644 name=f"adjust_avg_pool_2_{block_id}", 

645 )(p2) 

646 p2 = layers.Conv2D( 

647 filters // 2, 

648 (1, 1), 

649 padding="same", 

650 use_bias=False, 

651 name=f"adjust_conv_2_{block_id}", 

652 kernel_initializer="he_normal", 

653 )(p2) 

654 

655 p = layers.concatenate([p1, p2], axis=channel_dim) 

656 p = layers.BatchNormalization( 

657 axis=channel_dim, 

658 momentum=0.9997, 

659 epsilon=1e-3, 

660 name=f"adjust_bn_{block_id}", 

661 )(p) 

662 

663 elif p_shape[channel_dim] != filters: 

664 with backend.name_scope(f"adjust_projection_block_{block_id}"): 

665 p = layers.Activation("relu")(p) 

666 p = layers.Conv2D( 

667 filters, 

668 (1, 1), 

669 strides=(1, 1), 

670 padding="same", 

671 name=f"adjust_conv_projection_{block_id}", 

672 use_bias=False, 

673 kernel_initializer="he_normal", 

674 )(p) 

675 p = layers.BatchNormalization( 

676 axis=channel_dim, 

677 momentum=0.9997, 

678 epsilon=1e-3, 

679 name=f"adjust_bn_{block_id}", 

680 )(p) 

681 return p 

682 

683 

684def _normal_a_cell(ip, p, filters, block_id=None): 

685 """Adds a Normal cell for NASNet-A (Fig. 4 in the paper). 

686 

687 Args: 

688 ip: Input tensor `x` 

689 p: Input tensor `p` 

690 filters: Number of output filters 

691 block_id: String block_id 

692 

693 Returns: 

694 A Keras tensor 

695 """ 

696 channel_dim = 1 if backend.image_data_format() == "channels_first" else -1 

697 

698 with backend.name_scope(f"normal_A_block_{block_id}"): 

699 p = _adjust_block(p, ip, filters, block_id) 

700 

701 h = layers.Activation("relu")(ip) 

702 h = layers.Conv2D( 

703 filters, 

704 (1, 1), 

705 strides=(1, 1), 

706 padding="same", 

707 name=f"normal_conv_1_{block_id}", 

708 use_bias=False, 

709 kernel_initializer="he_normal", 

710 )(h) 

711 h = layers.BatchNormalization( 

712 axis=channel_dim, 

713 momentum=0.9997, 

714 epsilon=1e-3, 

715 name=f"normal_bn_1_{block_id}", 

716 )(h) 

717 

718 with backend.name_scope("block_1"): 

719 x1_1 = _separable_conv_block( 

720 h, 

721 filters, 

722 kernel_size=(5, 5), 

723 block_id=f"normal_left1_{block_id}", 

724 ) 

725 x1_2 = _separable_conv_block( 

726 p, filters, block_id=f"normal_right1_{block_id}" 

727 ) 

728 x1 = layers.add([x1_1, x1_2], name=f"normal_add_1_{block_id}") 

729 

730 with backend.name_scope("block_2"): 

731 x2_1 = _separable_conv_block( 

732 p, filters, (5, 5), block_id=f"normal_left2_{block_id}" 

733 ) 

734 x2_2 = _separable_conv_block( 

735 p, filters, (3, 3), block_id=f"normal_right2_{block_id}" 

736 ) 

737 x2 = layers.add([x2_1, x2_2], name=f"normal_add_2_{block_id}") 

738 

739 with backend.name_scope("block_3"): 

740 x3 = layers.AveragePooling2D( 

741 (3, 3), 

742 strides=(1, 1), 

743 padding="same", 

744 name=f"normal_left3_{block_id}", 

745 )(h) 

746 x3 = layers.add([x3, p], name=f"normal_add_3_{block_id}") 

747 

748 with backend.name_scope("block_4"): 

749 x4_1 = layers.AveragePooling2D( 

750 (3, 3), 

751 strides=(1, 1), 

752 padding="same", 

753 name=f"normal_left4_{block_id}", 

754 )(p) 

755 x4_2 = layers.AveragePooling2D( 

756 (3, 3), 

757 strides=(1, 1), 

758 padding="same", 

759 name=f"normal_right4_{block_id}", 

760 )(p) 

761 x4 = layers.add([x4_1, x4_2], name=f"normal_add_4_{block_id}") 

762 

763 with backend.name_scope("block_5"): 

764 x5 = _separable_conv_block( 

765 h, filters, block_id=f"normal_left5_{block_id}" 

766 ) 

767 x5 = layers.add([x5, h], name=f"normal_add_5_{block_id}") 

768 

769 x = layers.concatenate( 

770 [p, x1, x2, x3, x4, x5], 

771 axis=channel_dim, 

772 name=f"normal_concat_{block_id}", 

773 ) 

774 return x, ip 

775 

776 

777def _reduction_a_cell(ip, p, filters, block_id=None): 

778 """Adds a Reduction cell for NASNet-A (Fig. 4 in the paper). 

779 

780 Args: 

781 ip: Input tensor `x` 

782 p: Input tensor `p` 

783 filters: Number of output filters 

784 block_id: String block_id 

785 

786 Returns: 

787 A Keras tensor 

788 """ 

789 channel_dim = 1 if backend.image_data_format() == "channels_first" else -1 

790 

791 with backend.name_scope(f"reduction_A_block_{block_id}"): 

792 p = _adjust_block(p, ip, filters, block_id) 

793 

794 h = layers.Activation("relu")(ip) 

795 h = layers.Conv2D( 

796 filters, 

797 (1, 1), 

798 strides=(1, 1), 

799 padding="same", 

800 name=f"reduction_conv_1_{block_id}", 

801 use_bias=False, 

802 kernel_initializer="he_normal", 

803 )(h) 

804 h = layers.BatchNormalization( 

805 axis=channel_dim, 

806 momentum=0.9997, 

807 epsilon=1e-3, 

808 name=f"reduction_bn_1_{block_id}", 

809 )(h) 

810 h3 = layers.ZeroPadding2D( 

811 padding=imagenet_utils.correct_pad(h, 3), 

812 name=f"reduction_pad_1_{block_id}", 

813 )(h) 

814 

815 with backend.name_scope("block_1"): 

816 x1_1 = _separable_conv_block( 

817 h, 

818 filters, 

819 (5, 5), 

820 strides=(2, 2), 

821 block_id=f"reduction_left1_{block_id}", 

822 ) 

823 x1_2 = _separable_conv_block( 

824 p, 

825 filters, 

826 (7, 7), 

827 strides=(2, 2), 

828 block_id=f"reduction_right1_{block_id}", 

829 ) 

830 x1 = layers.add([x1_1, x1_2], name=f"reduction_add_1_{block_id}") 

831 

832 with backend.name_scope("block_2"): 

833 x2_1 = layers.MaxPooling2D( 

834 (3, 3), 

835 strides=(2, 2), 

836 padding="valid", 

837 name=f"reduction_left2_{block_id}", 

838 )(h3) 

839 x2_2 = _separable_conv_block( 

840 p, 

841 filters, 

842 (7, 7), 

843 strides=(2, 2), 

844 block_id=f"reduction_right2_{block_id}", 

845 ) 

846 x2 = layers.add([x2_1, x2_2], name=f"reduction_add_2_{block_id}") 

847 

848 with backend.name_scope("block_3"): 

849 x3_1 = layers.AveragePooling2D( 

850 (3, 3), 

851 strides=(2, 2), 

852 padding="valid", 

853 name=f"reduction_left3_{block_id}", 

854 )(h3) 

855 x3_2 = _separable_conv_block( 

856 p, 

857 filters, 

858 (5, 5), 

859 strides=(2, 2), 

860 block_id=f"reduction_right3_{block_id}", 

861 ) 

862 x3 = layers.add([x3_1, x3_2], name=f"reduction_add3_{block_id}") 

863 

864 with backend.name_scope("block_4"): 

865 x4 = layers.AveragePooling2D( 

866 (3, 3), 

867 strides=(1, 1), 

868 padding="same", 

869 name=f"reduction_left4_{block_id}", 

870 )(x1) 

871 x4 = layers.add([x2, x4]) 

872 

873 with backend.name_scope("block_5"): 

874 x5_1 = _separable_conv_block( 

875 x1, filters, (3, 3), block_id=f"reduction_left4_{block_id}" 

876 ) 

877 x5_2 = layers.MaxPooling2D( 

878 (3, 3), 

879 strides=(2, 2), 

880 padding="valid", 

881 name=f"reduction_right5_{block_id}", 

882 )(h3) 

883 x5 = layers.add([x5_1, x5_2], name=f"reduction_add4_{block_id}") 

884 

885 x = layers.concatenate( 

886 [x2, x3, x4, x5], 

887 axis=channel_dim, 

888 name=f"reduction_concat_{block_id}", 

889 ) 

890 return x, ip 

891 

892 

893@keras_export("keras.applications.nasnet.preprocess_input") 

894def preprocess_input(x, data_format=None): 

895 return imagenet_utils.preprocess_input( 

896 x, data_format=data_format, mode="tf" 

897 ) 

898 

899 

900@keras_export("keras.applications.nasnet.decode_predictions") 

901def decode_predictions(preds, top=5): 

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

903 

904 

905preprocess_input.__doc__ = imagenet_utils.PREPROCESS_INPUT_DOC.format( 

906 mode="", 

907 ret=imagenet_utils.PREPROCESS_INPUT_RET_DOC_TF, 

908 error=imagenet_utils.PREPROCESS_INPUT_ERROR_DOC, 

909) 

910decode_predictions.__doc__ = imagenet_utils.decode_predictions.__doc__ 

911