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
« 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# ==============================================================================
16"""NASNet-A models for Keras.
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.
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.
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
35Reference:
36 - [Learning Transferable Architectures for Scalable Image Recognition](
37 https://arxiv.org/abs/1707.07012) (CVPR 2018)
38"""
40import tensorflow.compat.v2 as tf
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
49# isort: off
50from tensorflow.python.platform import tf_logging as logging
51from tensorflow.python.util.tf_export import keras_export
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"
61layers = VersionAwareLayers()
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.
81 Reference:
82 - [Learning Transferable Architectures for Scalable Image Recognition](
83 https://arxiv.org/abs/1707.07012) (CVPR 2018)
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).
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/).
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.
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"`.
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 )
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 )
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 )
181 if default_size is None:
182 default_size = 331
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 )
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
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
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 )
226 channel_dim = 1 if backend.image_data_format() == "channels_first" else -1
227 filters = penultimate_filters // 24
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)
239 x = layers.BatchNormalization(
240 axis=channel_dim, momentum=0.9997, epsilon=1e-3, name="stem_bn1"
241 )(x)
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 )
251 for i in range(num_blocks):
252 x, p = _normal_a_cell(x, p, filters, block_id="%d" % (i))
254 x, p0 = _reduction_a_cell(
255 x, p, filters * filter_multiplier, block_id="reduce_%d" % (num_blocks)
256 )
258 p = p0 if not skip_reduction else p
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 )
268 x, p0 = _reduction_a_cell(
269 x,
270 p,
271 filters * filter_multiplier**2,
272 block_id="reduce_%d" % (2 * num_blocks),
273 )
275 p = p0 if not skip_reduction else p
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 )
285 x = layers.Activation("relu")(x)
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)
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
306 model = training.Model(inputs, x, name="NASNet")
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)
350 if old_data_format:
351 backend.set_image_data_format(old_data_format)
353 return model
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.
370 Reference:
371 - [Learning Transferable Architectures for Scalable Image Recognition](
372 https://arxiv.org/abs/1707.07012) (CVPR 2018)
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`.
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.
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"`.
418 Returns:
419 A Keras model instance.
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 )
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.
458 Reference:
459 - [Learning Transferable Architectures for Scalable Image Recognition](
460 https://arxiv.org/abs/1707.07012) (CVPR 2018)
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`.
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.
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"`.
506 Returns:
507 A Keras model instance.
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 )
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].
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
544 Returns:
545 A Keras tensor
546 """
547 channel_dim = 1 if backend.image_data_format() == "channels_first" else -1
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
592def _adjust_block(p, ip, filters, block_id=None):
593 """Adjusts the input `previous path` to match the shape of the `input`.
595 Used in situations where the output number of filters needs to be changed.
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
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
609 ip_shape = backend.int_shape(ip)
611 if p is not None:
612 p_shape = backend.int_shape(p)
614 with backend.name_scope("adjust_block"):
615 if p is None:
616 p = ip
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)
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)
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)
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
684def _normal_a_cell(ip, p, filters, block_id=None):
685 """Adds a Normal cell for NASNet-A (Fig. 4 in the paper).
687 Args:
688 ip: Input tensor `x`
689 p: Input tensor `p`
690 filters: Number of output filters
691 block_id: String block_id
693 Returns:
694 A Keras tensor
695 """
696 channel_dim = 1 if backend.image_data_format() == "channels_first" else -1
698 with backend.name_scope(f"normal_A_block_{block_id}"):
699 p = _adjust_block(p, ip, filters, block_id)
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)
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}")
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}")
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}")
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}")
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}")
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
777def _reduction_a_cell(ip, p, filters, block_id=None):
778 """Adds a Reduction cell for NASNet-A (Fig. 4 in the paper).
780 Args:
781 ip: Input tensor `x`
782 p: Input tensor `p`
783 filters: Number of output filters
784 block_id: String block_id
786 Returns:
787 A Keras tensor
788 """
789 channel_dim = 1 if backend.image_data_format() == "channels_first" else -1
791 with backend.name_scope(f"reduction_A_block_{block_id}"):
792 p = _adjust_block(p, ip, filters, block_id)
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)
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}")
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}")
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}")
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])
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}")
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
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 )
900@keras_export("keras.applications.nasnet.decode_predictions")
901def decode_predictions(preds, top=5):
902 return imagenet_utils.decode_predictions(preds, top=top)
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__