Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/keras/src/applications/inception_resnet_v2.py: 18%
154 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 2017 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"""Inception-ResNet V2 model for Keras.
18Reference:
19 - [Inception-v4, Inception-ResNet and the Impact of
20 Residual Connections on Learning](https://arxiv.org/abs/1602.07261)
21 (AAAI 2017)
22"""
24import tensorflow.compat.v2 as tf
26import keras.src as keras
27from keras.src import backend
28from keras.src import layers as keras_layers
29from keras.src.applications import imagenet_utils
30from keras.src.engine import training
31from keras.src.layers import VersionAwareLayers
32from keras.src.utils import data_utils
33from keras.src.utils import layer_utils
35# isort: off
36from tensorflow.python.util.tf_export import keras_export
38BASE_WEIGHT_URL = (
39 "https://storage.googleapis.com/tensorflow/"
40 "keras-applications/inception_resnet_v2/"
41)
42layers = None
45@keras_export(
46 "keras.applications.inception_resnet_v2.InceptionResNetV2",
47 "keras.applications.InceptionResNetV2",
48)
49def InceptionResNetV2(
50 include_top=True,
51 weights="imagenet",
52 input_tensor=None,
53 input_shape=None,
54 pooling=None,
55 classes=1000,
56 classifier_activation="softmax",
57 **kwargs,
58):
59 """Instantiates the Inception-ResNet v2 architecture.
61 Reference:
62 - [Inception-v4, Inception-ResNet and the Impact of
63 Residual Connections on Learning](https://arxiv.org/abs/1602.07261)
64 (AAAI 2017)
66 This function returns a Keras image classification model,
67 optionally loaded with weights pre-trained on ImageNet.
69 For image classification use cases, see
70 [this page for detailed examples](
71 https://keras.io/api/applications/#usage-examples-for-image-classification-models).
73 For transfer learning use cases, make sure to read the
74 [guide to transfer learning & fine-tuning](
75 https://keras.io/guides/transfer_learning/).
77 Note: each Keras Application expects a specific kind of input preprocessing.
78 For InceptionResNetV2, call
79 `tf.keras.applications.inception_resnet_v2.preprocess_input`
80 on your inputs before passing them to the model.
81 `inception_resnet_v2.preprocess_input`
82 will scale input pixels between -1 and 1.
84 Args:
85 include_top: whether to include the fully-connected
86 layer at the top of the network.
87 weights: one of `None` (random initialization),
88 'imagenet' (pre-training on ImageNet),
89 or the path to the weights file to be loaded.
90 input_tensor: optional Keras tensor (i.e. output of `layers.Input()`)
91 to use as image input for the model.
92 input_shape: optional shape tuple, only to be specified
93 if `include_top` is `False` (otherwise the input shape
94 has to be `(299, 299, 3)` (with `'channels_last'` data format)
95 or `(3, 299, 299)` (with `'channels_first'` data format).
96 It should have exactly 3 inputs channels,
97 and width and height should be no smaller than 75.
98 E.g. `(150, 150, 3)` would be one valid value.
99 pooling: Optional pooling mode for feature extraction
100 when `include_top` is `False`.
101 - `None` means that the output of the model will be
102 the 4D tensor output of the last convolutional block.
103 - `'avg'` means that global average pooling
104 will be applied to the output of the
105 last convolutional block, and thus
106 the output of the model will be a 2D tensor.
107 - `'max'` means that global max pooling will be applied.
108 classes: optional number of classes to classify images
109 into, only to be specified if `include_top` is `True`, and
110 if no `weights` argument is specified.
111 classifier_activation: A `str` or callable. The activation function to use
112 on the "top" layer. Ignored unless `include_top=True`. Set
113 `classifier_activation=None` to return the logits of the "top" layer.
114 When loading pretrained weights, `classifier_activation` can only
115 be `None` or `"softmax"`.
116 **kwargs: For backwards compatibility only.
118 Returns:
119 A `keras.Model` instance.
120 """
121 global layers
122 if "layers" in kwargs:
123 layers = kwargs.pop("layers")
124 else:
125 layers = VersionAwareLayers()
126 if kwargs:
127 raise ValueError(f"Unknown argument(s): {kwargs}")
128 if not (weights in {"imagenet", None} or tf.io.gfile.exists(weights)):
129 raise ValueError(
130 "The `weights` argument should be either "
131 "`None` (random initialization), `imagenet` "
132 "(pre-training on ImageNet), "
133 "or the path to the weights file to be loaded."
134 )
136 if weights == "imagenet" and include_top and classes != 1000:
137 raise ValueError(
138 'If using `weights` as `"imagenet"` with `include_top`'
139 " as true, `classes` should be 1000"
140 )
142 # Determine proper input shape
143 input_shape = imagenet_utils.obtain_input_shape(
144 input_shape,
145 default_size=299,
146 min_size=75,
147 data_format=backend.image_data_format(),
148 require_flatten=include_top,
149 weights=weights,
150 )
152 if input_tensor is None:
153 img_input = layers.Input(shape=input_shape)
154 else:
155 if not backend.is_keras_tensor(input_tensor):
156 img_input = layers.Input(tensor=input_tensor, shape=input_shape)
157 else:
158 img_input = input_tensor
160 # Stem block: 35 x 35 x 192
161 x = conv2d_bn(img_input, 32, 3, strides=2, padding="valid")
162 x = conv2d_bn(x, 32, 3, padding="valid")
163 x = conv2d_bn(x, 64, 3)
164 x = layers.MaxPooling2D(3, strides=2)(x)
165 x = conv2d_bn(x, 80, 1, padding="valid")
166 x = conv2d_bn(x, 192, 3, padding="valid")
167 x = layers.MaxPooling2D(3, strides=2)(x)
169 # Mixed 5b (Inception-A block): 35 x 35 x 320
170 branch_0 = conv2d_bn(x, 96, 1)
171 branch_1 = conv2d_bn(x, 48, 1)
172 branch_1 = conv2d_bn(branch_1, 64, 5)
173 branch_2 = conv2d_bn(x, 64, 1)
174 branch_2 = conv2d_bn(branch_2, 96, 3)
175 branch_2 = conv2d_bn(branch_2, 96, 3)
176 branch_pool = layers.AveragePooling2D(3, strides=1, padding="same")(x)
177 branch_pool = conv2d_bn(branch_pool, 64, 1)
178 branches = [branch_0, branch_1, branch_2, branch_pool]
179 channel_axis = 1 if backend.image_data_format() == "channels_first" else 3
180 x = layers.Concatenate(axis=channel_axis, name="mixed_5b")(branches)
182 # 10x block35 (Inception-ResNet-A block): 35 x 35 x 320
183 for block_idx in range(1, 11):
184 x = inception_resnet_block(
185 x, scale=0.17, block_type="block35", block_idx=block_idx
186 )
188 # Mixed 6a (Reduction-A block): 17 x 17 x 1088
189 branch_0 = conv2d_bn(x, 384, 3, strides=2, padding="valid")
190 branch_1 = conv2d_bn(x, 256, 1)
191 branch_1 = conv2d_bn(branch_1, 256, 3)
192 branch_1 = conv2d_bn(branch_1, 384, 3, strides=2, padding="valid")
193 branch_pool = layers.MaxPooling2D(3, strides=2, padding="valid")(x)
194 branches = [branch_0, branch_1, branch_pool]
195 x = layers.Concatenate(axis=channel_axis, name="mixed_6a")(branches)
197 # 20x block17 (Inception-ResNet-B block): 17 x 17 x 1088
198 for block_idx in range(1, 21):
199 x = inception_resnet_block(
200 x, scale=0.1, block_type="block17", block_idx=block_idx
201 )
203 # Mixed 7a (Reduction-B block): 8 x 8 x 2080
204 branch_0 = conv2d_bn(x, 256, 1)
205 branch_0 = conv2d_bn(branch_0, 384, 3, strides=2, padding="valid")
206 branch_1 = conv2d_bn(x, 256, 1)
207 branch_1 = conv2d_bn(branch_1, 288, 3, strides=2, padding="valid")
208 branch_2 = conv2d_bn(x, 256, 1)
209 branch_2 = conv2d_bn(branch_2, 288, 3)
210 branch_2 = conv2d_bn(branch_2, 320, 3, strides=2, padding="valid")
211 branch_pool = layers.MaxPooling2D(3, strides=2, padding="valid")(x)
212 branches = [branch_0, branch_1, branch_2, branch_pool]
213 x = layers.Concatenate(axis=channel_axis, name="mixed_7a")(branches)
215 # 10x block8 (Inception-ResNet-C block): 8 x 8 x 2080
216 for block_idx in range(1, 10):
217 x = inception_resnet_block(
218 x, scale=0.2, block_type="block8", block_idx=block_idx
219 )
220 x = inception_resnet_block(
221 x, scale=1.0, activation=None, block_type="block8", block_idx=10
222 )
224 # Final convolution block: 8 x 8 x 1536
225 x = conv2d_bn(x, 1536, 1, name="conv_7b")
227 if include_top:
228 # Classification block
229 x = layers.GlobalAveragePooling2D(name="avg_pool")(x)
230 imagenet_utils.validate_activation(classifier_activation, weights)
231 x = layers.Dense(
232 classes, activation=classifier_activation, name="predictions"
233 )(x)
234 else:
235 if pooling == "avg":
236 x = layers.GlobalAveragePooling2D()(x)
237 elif pooling == "max":
238 x = layers.GlobalMaxPooling2D()(x)
240 # Ensure that the model takes into account
241 # any potential predecessors of `input_tensor`.
242 if input_tensor is not None:
243 inputs = layer_utils.get_source_inputs(input_tensor)
244 else:
245 inputs = img_input
247 # Create model.
248 model = training.Model(inputs, x, name="inception_resnet_v2")
250 # Load weights.
251 if weights == "imagenet":
252 if include_top:
253 fname = "inception_resnet_v2_weights_tf_dim_ordering_tf_kernels.h5"
254 weights_path = data_utils.get_file(
255 fname,
256 BASE_WEIGHT_URL + fname,
257 cache_subdir="models",
258 file_hash="e693bd0210a403b3192acc6073ad2e96",
259 )
260 else:
261 fname = (
262 "inception_resnet_v2_weights_"
263 "tf_dim_ordering_tf_kernels_notop.h5"
264 )
265 weights_path = data_utils.get_file(
266 fname,
267 BASE_WEIGHT_URL + fname,
268 cache_subdir="models",
269 file_hash="d19885ff4a710c122648d3b5c3b684e4",
270 )
271 model.load_weights(weights_path)
272 elif weights is not None:
273 model.load_weights(weights)
275 return model
278def conv2d_bn(
279 x,
280 filters,
281 kernel_size,
282 strides=1,
283 padding="same",
284 activation="relu",
285 use_bias=False,
286 name=None,
287):
288 """Utility function to apply conv + BN.
290 Args:
291 x: input tensor.
292 filters: filters in `Conv2D`.
293 kernel_size: kernel size as in `Conv2D`.
294 strides: strides in `Conv2D`.
295 padding: padding mode in `Conv2D`.
296 activation: activation in `Conv2D`.
297 use_bias: whether to use a bias in `Conv2D`.
298 name: name of the ops; will become `name + '_ac'` for the activation
299 and `name + '_bn'` for the batch norm layer.
301 Returns:
302 Output tensor after applying `Conv2D` and `BatchNormalization`.
303 """
304 x = layers.Conv2D(
305 filters,
306 kernel_size,
307 strides=strides,
308 padding=padding,
309 use_bias=use_bias,
310 name=name,
311 )(x)
312 if not use_bias:
313 bn_axis = 1 if backend.image_data_format() == "channels_first" else 3
314 bn_name = None if name is None else name + "_bn"
315 x = layers.BatchNormalization(axis=bn_axis, scale=False, name=bn_name)(
316 x
317 )
318 if activation is not None:
319 ac_name = None if name is None else name + "_ac"
320 x = layers.Activation(activation, name=ac_name)(x)
321 return x
324@keras.utils.register_keras_serializable()
325class CustomScaleLayer(keras_layers.Layer):
326 def __init__(self, scale, **kwargs):
327 super().__init__(**kwargs)
328 self.scale = scale
330 def get_config(self):
331 config = super().get_config()
332 config.update({"scale": self.scale})
333 return config
335 def call(self, inputs):
336 return inputs[0] + inputs[1] * self.scale
339def inception_resnet_block(x, scale, block_type, block_idx, activation="relu"):
340 """Adds an Inception-ResNet block.
342 This function builds 3 types of Inception-ResNet blocks mentioned
343 in the paper, controlled by the `block_type` argument (which is the
344 block name used in the official TF-slim implementation):
345 - Inception-ResNet-A: `block_type='block35'`
346 - Inception-ResNet-B: `block_type='block17'`
347 - Inception-ResNet-C: `block_type='block8'`
349 Args:
350 x: input tensor.
351 scale: scaling factor to scale the residuals (i.e., the output of passing
352 `x` through an inception module) before adding them to the shortcut
353 branch. Let `r` be the output from the residual branch, the output of
354 this block will be `x + scale * r`.
355 block_type: `'block35'`, `'block17'` or `'block8'`, determines the network
356 structure in the residual branch.
357 block_idx: an `int` used for generating layer names. The Inception-ResNet
358 blocks are repeated many times in this network. We use `block_idx` to
359 identify each of the repetitions. For example, the first
360 Inception-ResNet-A block will have `block_type='block35', block_idx=0`,
361 and the layer names will have a common prefix `'block35_0'`.
362 activation: activation function to use at the end of the block (see
363 [activations](../activations.md)). When `activation=None`, no activation
364 is applied
365 (i.e., "linear" activation: `a(x) = x`).
367 Returns:
368 Output tensor for the block.
370 Raises:
371 ValueError: if `block_type` is not one of `'block35'`,
372 `'block17'` or `'block8'`.
373 """
374 if block_type == "block35":
375 branch_0 = conv2d_bn(x, 32, 1)
376 branch_1 = conv2d_bn(x, 32, 1)
377 branch_1 = conv2d_bn(branch_1, 32, 3)
378 branch_2 = conv2d_bn(x, 32, 1)
379 branch_2 = conv2d_bn(branch_2, 48, 3)
380 branch_2 = conv2d_bn(branch_2, 64, 3)
381 branches = [branch_0, branch_1, branch_2]
382 elif block_type == "block17":
383 branch_0 = conv2d_bn(x, 192, 1)
384 branch_1 = conv2d_bn(x, 128, 1)
385 branch_1 = conv2d_bn(branch_1, 160, [1, 7])
386 branch_1 = conv2d_bn(branch_1, 192, [7, 1])
387 branches = [branch_0, branch_1]
388 elif block_type == "block8":
389 branch_0 = conv2d_bn(x, 192, 1)
390 branch_1 = conv2d_bn(x, 192, 1)
391 branch_1 = conv2d_bn(branch_1, 224, [1, 3])
392 branch_1 = conv2d_bn(branch_1, 256, [3, 1])
393 branches = [branch_0, branch_1]
394 else:
395 raise ValueError(
396 "Unknown Inception-ResNet block type. "
397 'Expects "block35", "block17" or "block8", '
398 "but got: " + str(block_type)
399 )
401 block_name = block_type + "_" + str(block_idx)
402 channel_axis = 1 if backend.image_data_format() == "channels_first" else 3
403 mixed = layers.Concatenate(axis=channel_axis, name=block_name + "_mixed")(
404 branches
405 )
406 up = conv2d_bn(
407 mixed,
408 backend.int_shape(x)[channel_axis],
409 1,
410 activation=None,
411 use_bias=True,
412 name=block_name + "_conv",
413 )
415 x = CustomScaleLayer(scale)([x, up])
416 if activation is not None:
417 x = layers.Activation(activation, name=block_name + "_ac")(x)
418 return x
421@keras_export("keras.applications.inception_resnet_v2.preprocess_input")
422def preprocess_input(x, data_format=None):
423 return imagenet_utils.preprocess_input(
424 x, data_format=data_format, mode="tf"
425 )
428@keras_export("keras.applications.inception_resnet_v2.decode_predictions")
429def decode_predictions(preds, top=5):
430 return imagenet_utils.decode_predictions(preds, top=top)
433preprocess_input.__doc__ = imagenet_utils.PREPROCESS_INPUT_DOC.format(
434 mode="",
435 ret=imagenet_utils.PREPROCESS_INPUT_RET_DOC_TF,
436 error=imagenet_utils.PREPROCESS_INPUT_ERROR_DOC,
437)
438decode_predictions.__doc__ = imagenet_utils.decode_predictions.__doc__