Skip to content

Module kerod.model.backbone.resnet

ResNet models for Keras.

Reference paper:

  • [Deep Residual Learning for Image Recognition] (https://arxiv.org/abs/1512.03385) (CVPR 2015)
View Source
# Copyright 2015 The TensorFlow Authors and Modified by Emilien Garreau. All Rights Reserved.

#

# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License.

# You may obtain a copy of the License at

#

#     http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

# See the License for the specific language governing permissions and

# limitations under the License.

# ==============================================================================

"""ResNet models for Keras.

Reference paper:

  - [Deep Residual Learning for Image Recognition] (https://arxiv.org/abs/1512.03385) (CVPR 2015)

"""

import os

from typing import Callable

import tensorflow as tf

from tensorflow.keras import layers

from tensorflow.python.keras import backend

from tensorflow.python.keras.applications import resnet

from tensorflow.python.keras.engine import training

from tensorflow.python.keras.utils import data_utils, layer_utils

OFFICIAL_WEIGHTS_PATH = ('https://storage.googleapis.com/tensorflow/keras-applications/resnet/')

WEIGHTS_HASHES = {

    'resnet50': ('4d473c1dd8becc155b73f8504c6f6626', OFFICIAL_WEIGHTS_PATH),

    'resnet50_pytorch': ('3ffd584081cc56435a3689d12afd7cf9', "https://drive.google.com/uc?export=download&id=11QKe1WD4s0IdAPh6hJXJozeqSO7QD0ZU"),

    'resnet101': ('88cf7a10940856eca736dc7b7e228a21', OFFICIAL_WEIGHTS_PATH),

    'resnet152': ('ee4c566cf9a93f14d82f913c2dc6dd0c', OFFICIAL_WEIGHTS_PATH),

    'resnet50v2': ('fac2f116257151a9d068a22e544a4917', OFFICIAL_WEIGHTS_PATH),

    'resnet101v2': ('c0ed64b8031c3730f411d2eb4eea35b5', OFFICIAL_WEIGHTS_PATH),

    'resnet152v2': ('ed17cf2e0169df9d443503ef94b23b33', OFFICIAL_WEIGHTS_PATH),

    'resnext50': ('62527c363bdd9ec598bed41947b379fc', OFFICIAL_WEIGHTS_PATH),

    'resnext101': ('0f678c91647380debd923963594981b3', OFFICIAL_WEIGHTS_PATH)

}

def padd_for_aligning_pixels(inputs: tf.Tensor):

    """This padding operation is here to make the pixels of the output perfectly aligned.

    It will make the output perfectly aligned at stride 32.

    """

    chan = inputs.shape[3]

    b4_stride = 32.0

    shape2d = tf.shape(inputs)[1:3]

    new_shape2d = tf.cast(

        tf.math.ceil(tf.cast(shape2d, tf.float32) / b4_stride) * b4_stride, tf.int32)

    pad_shape2d = new_shape2d - shape2d

    inputs = tf.pad(inputs,

                    tf.stack([[0, 0],

                              [3, 2 + pad_shape2d[0]],

                              [3, 2 + pad_shape2d[1]],

                              [0, 0]]),

                    name='conv1_pad') # yapf: disable

    inputs.set_shape([None, None, None, chan])

    return inputs

def ResNet(stack_fn: Callable,

           preprocessing_func: Callable,

           preact: bool,

           use_bias: bool,

           model_name='resnet',

           weights='imagenet',

           input_tensor=None,

           input_shape=None,

           **kwargs) -> tf.keras.Model:

    """Instantiates the ResNet, ResNetV2, and ResNeXt architecture.

    Reference paper:

    [Deep Residual Learning for Image Recognition]

        (https://arxiv.org/abs/1512.03385) (CVPR 2015)

    Optionally loads weights pre-trained on ImageNet.

    Note that the data format convention used by the model is

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

    Caution: Be sure to properly pre-process your inputs to the application.

    Please see `applications.resnet.preprocess_input` for an example.

    Arguments:

        stack_fn: a function that returns output tensor for the

            stacked residual blocks.

        preprocessing_func: a function that returns the corresponding preprocessing of the network.

        preact: whether to use pre-activation or not

            (True for ResNetV2, False for ResNet and ResNeXt).

        use_bias: whether to use biases for convolutional layers or not

            (True for ResNet and ResNetV2, False for ResNeXt).

        model_name: string, model name.

        include_top: whether to include the fully-connected

            layer at the top of the network.

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

            'imagenet' (pre-training on ImageNet),

            or the path to the weights file to be loaded.

        input_tensor: optional Keras tensor

            (i.e. output of `layers.Input()`)

            to use as image input for the model.

        input_shape: optional shape tuple, only to be specified

            if `include_top` is False (otherwise the input shape

            has to be `(224, 224, 3)` (with `channels_last` data format)

            or `(3, 224, 224)` (with `channels_first` data format).

            It should have exactly 3 inputs channels.

        kwargs: For backwards compatibility only.

    Returns:

        A `keras.Model` instance.

    Raises:

        *ValueError*: in case of invalid argument for `weights`, or invalid input shape.

    """

    if kwargs:

        raise ValueError('Unknown argument(s): %s' % (kwargs,))

    if not (weights in {'imagenet', None} or os.path.exists(weights)):

        raise ValueError('The `weights` argument should be either '

                         '`None` (random initialization), `imagenet` '

                         '(pre-training on ImageNet), '

                         'or the path to the weights file to be loaded.')

    if input_tensor is None:

        img_input = layers.Input(shape=input_shape)

    else:

        if not backend.is_keras_tensor(input_tensor):

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

        else:

            img_input = input_tensor

    bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1

    x = layers.Lambda(preprocessing_func, name="preprocess_input")(img_input)

    x = layers.Lambda(padd_for_aligning_pixels, name="padd_for_aligning_pixels")(x)

    x = layers.Conv2D(64, 7, strides=2, use_bias=use_bias, name='conv1_conv')(x)

    if not preact:

        x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name='conv1_bn')(x)

        x = layers.Activation('relu', name='conv1_relu')(x)

    x = layers.ZeroPadding2D(padding=((1, 0), (1, 0)), name='pool1_pad')(x)

    x = layers.MaxPooling2D(3, strides=2, name='pool1_pool')(x)

    outputs = stack_fn(x)

    if preact:

        x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name='post_bn')(outputs[-1])

        outputs[-1] = layers.Activation('relu', name='post_relu')(x)

    # Ensure that the model takes into account

    # any potential predecessors of `input_tensor`.

    if input_tensor is not None:

        inputs = layer_utils.get_source_inputs(input_tensor)

    else:

        inputs = img_input

    # Create model.

    model = training.Model(inputs, outputs, name=model_name)

    # Load weights.

    if (weights == 'imagenet') and (model_name in WEIGHTS_HASHES):

        file_hash, base_weight_path = WEIGHTS_HASHES[model_name]

        if model_name == "resnet50_pytorch":

            file_name = 'resnet50_tensorpack_conversion.h5'

            url = base_weight_path

        else:

            file_name = model_name + '_weights_tf_dim_ordering_tf_kernels_notop.h5'

            url = base_weight_path + file_name

        weights_path = data_utils.get_file(file_name, url, cache_subdir='models', file_hash=file_hash)

        model.load_weights(weights_path)

    elif weights is not None:

        model.load_weights(weights)

    return model

def ResNet50(weights='imagenet', input_tensor=None, input_shape=None, **kwargs):

    """Instantiates the ResNet50 architecture."""

    # Or set to None

    resnet.layers = tf.keras.layers

    def stack_fn(x):

        c2 = resnet.stack1(x, 64, 3, stride1=1, name='conv2')

        c3 = resnet.stack1(c2, 128, 4, name='conv3')

        c4 = resnet.stack1(c3, 256, 6, name='conv4')

        c5 = resnet.stack1(c4, 512, 3, name='conv5')

        return [c2, c3, c4, c5]

    return ResNet(stack_fn,

                  resnet.preprocess_input,

                  False,

                  True,

                  'resnet50',

                  weights,

                  input_tensor,

                  input_shape,

                  **kwargs)

def ResNet50PytorchStyle(weights='imagenet', input_tensor=None, input_shape=None, **kwargs):

    """Instantiates the ResNet50 with the pytorch style architecture.

    In the bottleneck residual block, pytorch-style ResNet uses a 1x1 stride-1 convolutional layer

    followed by a 3x3 stride-2 convolutional layer.

    **Warning**: Do not forget to use `bgr` instead of `rgb`.

    ```python

    import functools

    import tensorflow_datasets as tfds

    from kerod.preprocessing import preprocess

    ds_train, ds_info = tfds.load(name="coco/2017", split="train", shuffle_files=True, with_info=True)

    ds_train = ds_train.map(functools.partial(preprocess, bgr=True),

    num_parallel_calls=tf.data.experimental.AUTOTUNE)

    ```

    """

    def stack_fn(x):

        c2 = Group(x, 64, 3, strides=1, name='resnet50/group0')

        c3 = Group(c2, 128, 4, strides=2, name='resnet50/group1')

        c4 = Group(c3, 256, 6, strides=2, name='resnet50/group2')

        c5 = Group(c4, 512, 3, strides=2, name='resnet50/group3')

        return [c2, c3, c4, c5]

    return ResNet(stack_fn, preprocess_input_pytorch, False, False, 'resnet50_pytorch', weights,

                  input_tensor, input_shape, **kwargs)

def preprocess_input_pytorch(images: tf.Tensor):

    """Will preprocess the images for the resnet trained on Tensorpack.

    The network has been trained using BGR.

    """

    mean = tf.constant([103.53, 116.28, 123.675], dtype=images.dtype)

    std = tf.constant([57.375, 57.12, 58.395], dtype=images.dtype)

    images = (images - mean) / std

    return images

def Group(inputs: tf.Tensor, filters: int, blocks: int, strides: int, name=None):

    """A set of stacked residual blocks with the pytorch style

    Arguments:

        filters: integer, filters of the bottleneck layer in a block.

        blocks: number of blocks in the stacked blocks.

        strides: Stride of the second conv layer in the first block.

    """

    x = Block(inputs, filters, strides, use_conv_shortcut=True, name=f'{name}/block0')

    for i in range(1, blocks):

        x = Block(x, filters, 1, use_conv_shortcut=False, name=f'{name}/block{i}')

    return x

def Block(inputs: tf.Tensor, filters: int, strides: int = 1, use_conv_shortcut=True, name=None):

    """A residual block with the pytorch_style

    Arguments:

        inputs: The inputs tensor

        filters: integer, filters of the bottleneck layer.

        strides: default 1, stride of the second convolution layer. In the official Keras

            implementation the stride is performed on the first convolution. This is different in

            the pytorch implementation.

        use_conv_shortcut: Use convolution shortcut if True, otherwise identity shortcut.

    """

    bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1

    if use_conv_shortcut:

        shortcut = layers.Conv2D(4 * filters,

                                 1,

                                 strides=strides,

                                 use_bias=False,

                                 padding='same',

                                 name=f'{name}/convshortcut')(inputs)

        shortcut = layers.BatchNormalization(axis=bn_axis, name=f'{name}/convshortcut/bn')(shortcut)

    else:

        shortcut = inputs

    x = layers.Conv2D(filters, 1, strides=1, use_bias=False, padding='same',

                      name=f'{name}/conv1')(inputs)

    x = layers.BatchNormalization(axis=bn_axis, name=f'{name}/conv1/bn')(x)

    x = layers.Activation('relu', name=f'{name}/conv1/relu')(x)

    if strides == 2:

        x = layers.ZeroPadding2D(padding=((1, 0), (1, 0)), name=f'{name}/pad2')(x)

        x = layers.Conv2D(filters,

                          3,

                          padding='valid',

                          use_bias=False,

                          strides=strides,

                          name=f'{name}/conv2')(x)

    else:

        x = layers.Conv2D(filters,

                          3,

                          use_bias=False,

                          padding='same',

                          strides=strides,

                          name=f'{name}/conv2')(x)

    x = layers.BatchNormalization(axis=bn_axis, name=f'{name}/conv2/bn')(x)

    x = layers.Activation('relu', name=f'{name}/conv2/relu')(x)

    x = layers.Conv2D(filters * 4, 1, use_bias=False, padding='same', name=f'{name}/conv3')(x)

    x = layers.BatchNormalization(axis=bn_axis, name=f'{name}/conv3/bn')(x)

    x = layers.Add()([shortcut, x])

    return layers.Activation('relu', name=f'{name}/last_relu')(x)

Variables

OFFICIAL_WEIGHTS_PATH
WEIGHTS_HASHES

Functions

Block

def Block(
    inputs: tensorflow.python.framework.ops.Tensor,
    filters: int,
    strides: int = 1,
    use_conv_shortcut=True,
    name=None
)

A residual block with the pytorch_style

Parameters:

Name Description
inputs The inputs tensor
filters integer, filters of the bottleneck layer.
strides default 1, stride of the second convolution layer. In the official Keras
implementation the stride is performed on the first convolution. This is different in
the pytorch implementation.
use_conv_shortcut Use convolution shortcut if True, otherwise identity shortcut.
View Source
def Block(inputs: tf.Tensor, filters: int, strides: int = 1, use_conv_shortcut=True, name=None):

    """A residual block with the pytorch_style

    Arguments:

        inputs: The inputs tensor

        filters: integer, filters of the bottleneck layer.

        strides: default 1, stride of the second convolution layer. In the official Keras

            implementation the stride is performed on the first convolution. This is different in

            the pytorch implementation.

        use_conv_shortcut: Use convolution shortcut if True, otherwise identity shortcut.

    """

    bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1

    if use_conv_shortcut:

        shortcut = layers.Conv2D(4 * filters,

                                 1,

                                 strides=strides,

                                 use_bias=False,

                                 padding='same',

                                 name=f'{name}/convshortcut')(inputs)

        shortcut = layers.BatchNormalization(axis=bn_axis, name=f'{name}/convshortcut/bn')(shortcut)

    else:

        shortcut = inputs

    x = layers.Conv2D(filters, 1, strides=1, use_bias=False, padding='same',

                      name=f'{name}/conv1')(inputs)

    x = layers.BatchNormalization(axis=bn_axis, name=f'{name}/conv1/bn')(x)

    x = layers.Activation('relu', name=f'{name}/conv1/relu')(x)

    if strides == 2:

        x = layers.ZeroPadding2D(padding=((1, 0), (1, 0)), name=f'{name}/pad2')(x)

        x = layers.Conv2D(filters,

                          3,

                          padding='valid',

                          use_bias=False,

                          strides=strides,

                          name=f'{name}/conv2')(x)

    else:

        x = layers.Conv2D(filters,

                          3,

                          use_bias=False,

                          padding='same',

                          strides=strides,

                          name=f'{name}/conv2')(x)

    x = layers.BatchNormalization(axis=bn_axis, name=f'{name}/conv2/bn')(x)

    x = layers.Activation('relu', name=f'{name}/conv2/relu')(x)

    x = layers.Conv2D(filters * 4, 1, use_bias=False, padding='same', name=f'{name}/conv3')(x)

    x = layers.BatchNormalization(axis=bn_axis, name=f'{name}/conv3/bn')(x)

    x = layers.Add()([shortcut, x])

    return layers.Activation('relu', name=f'{name}/last_relu')(x)

Group

def Group(
    inputs: tensorflow.python.framework.ops.Tensor,
    filters: int,
    blocks: int,
    strides: int,
    name=None
)

A set of stacked residual blocks with the pytorch style

Parameters:

Name Description
filters integer, filters of the bottleneck layer in a block.
blocks number of blocks in the stacked blocks.
strides Stride of the second conv layer in the first block.
View Source
def Group(inputs: tf.Tensor, filters: int, blocks: int, strides: int, name=None):

    """A set of stacked residual blocks with the pytorch style

    Arguments:

        filters: integer, filters of the bottleneck layer in a block.

        blocks: number of blocks in the stacked blocks.

        strides: Stride of the second conv layer in the first block.

    """

    x = Block(inputs, filters, strides, use_conv_shortcut=True, name=f'{name}/block0')

    for i in range(1, blocks):

        x = Block(x, filters, 1, use_conv_shortcut=False, name=f'{name}/block{i}')

    return x

ResNet

def ResNet(
    stack_fn: Callable,
    preprocessing_func: Callable,
    preact: bool,
    use_bias: bool,
    model_name='resnet',
    weights='imagenet',
    input_tensor=None,
    input_shape=None,
    **kwargs
) -> tensorflow.python.keras.engine.training.Model

Instantiates the ResNet, ResNetV2, and ResNeXt architecture.

Reference paper:

[Deep Residual Learning for Image Recognition] (https://arxiv.org/abs/1512.03385) (CVPR 2015) Optionally loads weights pre-trained on ImageNet. Note that the data format convention used by the model is the one specified in your Keras config at ~/.keras/keras.json. Caution: Be sure to properly pre-process your inputs to the application. Please see applications.resnet.preprocess_input for an example.

Parameters:

Name Description
stack_fn a function that returns output tensor for the
stacked residual blocks.
preprocessing_func a function that returns the corresponding preprocessing of the network.
preact whether to use pre-activation or not
(True for ResNetV2, False for ResNet and ResNeXt).
use_bias whether to use biases for convolutional layers or not
(True for ResNet and ResNetV2, False for ResNeXt).
model_name string, model name.
include_top whether to include the fully-connected
layer at the top of the network.
weights one of None (random initialization),
'imagenet' (pre-training on ImageNet),
or the path to the weights file to be loaded.
input_tensor optional Keras tensor
(i.e. output of layers.Input())
to use as image input for the model.
input_shape optional shape tuple, only to be specified
if include_top is False (otherwise the input shape
has to be (224, 224, 3) (with channels_last data format)
or (3, 224, 224) (with channels_first data format).
It should have exactly 3 inputs channels.
kwargs For backwards compatibility only.

Returns:

Type Description
None A keras.Model instance.

Raises:

Type Description
ValueError in case of invalid argument for weights, or invalid input shape.
View Source
def ResNet(stack_fn: Callable,

           preprocessing_func: Callable,

           preact: bool,

           use_bias: bool,

           model_name='resnet',

           weights='imagenet',

           input_tensor=None,

           input_shape=None,

           **kwargs) -> tf.keras.Model:

    """Instantiates the ResNet, ResNetV2, and ResNeXt architecture.

    Reference paper:

    [Deep Residual Learning for Image Recognition]

        (https://arxiv.org/abs/1512.03385) (CVPR 2015)

    Optionally loads weights pre-trained on ImageNet.

    Note that the data format convention used by the model is

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

    Caution: Be sure to properly pre-process your inputs to the application.

    Please see `applications.resnet.preprocess_input` for an example.

    Arguments:

        stack_fn: a function that returns output tensor for the

            stacked residual blocks.

        preprocessing_func: a function that returns the corresponding preprocessing of the network.

        preact: whether to use pre-activation or not

            (True for ResNetV2, False for ResNet and ResNeXt).

        use_bias: whether to use biases for convolutional layers or not

            (True for ResNet and ResNetV2, False for ResNeXt).

        model_name: string, model name.

        include_top: whether to include the fully-connected

            layer at the top of the network.

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

            'imagenet' (pre-training on ImageNet),

            or the path to the weights file to be loaded.

        input_tensor: optional Keras tensor

            (i.e. output of `layers.Input()`)

            to use as image input for the model.

        input_shape: optional shape tuple, only to be specified

            if `include_top` is False (otherwise the input shape

            has to be `(224, 224, 3)` (with `channels_last` data format)

            or `(3, 224, 224)` (with `channels_first` data format).

            It should have exactly 3 inputs channels.

        kwargs: For backwards compatibility only.

    Returns:

        A `keras.Model` instance.

    Raises:

        *ValueError*: in case of invalid argument for `weights`, or invalid input shape.

    """

    if kwargs:

        raise ValueError('Unknown argument(s): %s' % (kwargs,))

    if not (weights in {'imagenet', None} or os.path.exists(weights)):

        raise ValueError('The `weights` argument should be either '

                         '`None` (random initialization), `imagenet` '

                         '(pre-training on ImageNet), '

                         'or the path to the weights file to be loaded.')

    if input_tensor is None:

        img_input = layers.Input(shape=input_shape)

    else:

        if not backend.is_keras_tensor(input_tensor):

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

        else:

            img_input = input_tensor

    bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1

    x = layers.Lambda(preprocessing_func, name="preprocess_input")(img_input)

    x = layers.Lambda(padd_for_aligning_pixels, name="padd_for_aligning_pixels")(x)

    x = layers.Conv2D(64, 7, strides=2, use_bias=use_bias, name='conv1_conv')(x)

    if not preact:

        x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name='conv1_bn')(x)

        x = layers.Activation('relu', name='conv1_relu')(x)

    x = layers.ZeroPadding2D(padding=((1, 0), (1, 0)), name='pool1_pad')(x)

    x = layers.MaxPooling2D(3, strides=2, name='pool1_pool')(x)

    outputs = stack_fn(x)

    if preact:

        x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name='post_bn')(outputs[-1])

        outputs[-1] = layers.Activation('relu', name='post_relu')(x)

    # Ensure that the model takes into account

    # any potential predecessors of `input_tensor`.

    if input_tensor is not None:

        inputs = layer_utils.get_source_inputs(input_tensor)

    else:

        inputs = img_input

    # Create model.

    model = training.Model(inputs, outputs, name=model_name)

    # Load weights.

    if (weights == 'imagenet') and (model_name in WEIGHTS_HASHES):

        file_hash, base_weight_path = WEIGHTS_HASHES[model_name]

        if model_name == "resnet50_pytorch":

            file_name = 'resnet50_tensorpack_conversion.h5'

            url = base_weight_path

        else:

            file_name = model_name + '_weights_tf_dim_ordering_tf_kernels_notop.h5'

            url = base_weight_path + file_name

        weights_path = data_utils.get_file(file_name, url, cache_subdir='models', file_hash=file_hash)

        model.load_weights(weights_path)

    elif weights is not None:

        model.load_weights(weights)

    return model

ResNet50

def ResNet50(
    weights='imagenet',
    input_tensor=None,
    input_shape=None,
    **kwargs
)

Instantiates the ResNet50 architecture.

View Source
def ResNet50(weights='imagenet', input_tensor=None, input_shape=None, **kwargs):

    """Instantiates the ResNet50 architecture."""

    # Or set to None

    resnet.layers = tf.keras.layers

    def stack_fn(x):

        c2 = resnet.stack1(x, 64, 3, stride1=1, name='conv2')

        c3 = resnet.stack1(c2, 128, 4, name='conv3')

        c4 = resnet.stack1(c3, 256, 6, name='conv4')

        c5 = resnet.stack1(c4, 512, 3, name='conv5')

        return [c2, c3, c4, c5]

    return ResNet(stack_fn,

                  resnet.preprocess_input,

                  False,

                  True,

                  'resnet50',

                  weights,

                  input_tensor,

                  input_shape,

                  **kwargs)

ResNet50PytorchStyle

def ResNet50PytorchStyle(
    weights='imagenet',
    input_tensor=None,
    input_shape=None,
    **kwargs
)

Instantiates the ResNet50 with the pytorch style architecture.

In the bottleneck residual block, pytorch-style ResNet uses a 1x1 stride-1 convolutional layer followed by a 3x3 stride-2 convolutional layer.

Warning: Do not forget to use bgr instead of rgb.

import functools
import tensorflow_datasets as tfds
from kerod.preprocessing import preprocess

ds_train, ds_info = tfds.load(name="coco/2017", split="train", shuffle_files=True, with_info=True)
ds_train = ds_train.map(functools.partial(preprocess, bgr=True),
num_parallel_calls=tf.data.experimental.AUTOTUNE)
View Source
def ResNet50PytorchStyle(weights='imagenet', input_tensor=None, input_shape=None, **kwargs):

    """Instantiates the ResNet50 with the pytorch style architecture.

    In the bottleneck residual block, pytorch-style ResNet uses a 1x1 stride-1 convolutional layer

    followed by a 3x3 stride-2 convolutional layer.

    **Warning**: Do not forget to use `bgr` instead of `rgb`.

    ```python

    import functools

    import tensorflow_datasets as tfds

    from kerod.preprocessing import preprocess

    ds_train, ds_info = tfds.load(name="coco/2017", split="train", shuffle_files=True, with_info=True)

    ds_train = ds_train.map(functools.partial(preprocess, bgr=True),

    num_parallel_calls=tf.data.experimental.AUTOTUNE)

    ```

    """

    def stack_fn(x):

        c2 = Group(x, 64, 3, strides=1, name='resnet50/group0')

        c3 = Group(c2, 128, 4, strides=2, name='resnet50/group1')

        c4 = Group(c3, 256, 6, strides=2, name='resnet50/group2')

        c5 = Group(c4, 512, 3, strides=2, name='resnet50/group3')

        return [c2, c3, c4, c5]

    return ResNet(stack_fn, preprocess_input_pytorch, False, False, 'resnet50_pytorch', weights,

                  input_tensor, input_shape, **kwargs)

padd_for_aligning_pixels

def padd_for_aligning_pixels(
    inputs: tensorflow.python.framework.ops.Tensor
)

This padding operation is here to make the pixels of the output perfectly aligned.

It will make the output perfectly aligned at stride 32.

View Source
def padd_for_aligning_pixels(inputs: tf.Tensor):

    """This padding operation is here to make the pixels of the output perfectly aligned.

    It will make the output perfectly aligned at stride 32.

    """

    chan = inputs.shape[3]

    b4_stride = 32.0

    shape2d = tf.shape(inputs)[1:3]

    new_shape2d = tf.cast(

        tf.math.ceil(tf.cast(shape2d, tf.float32) / b4_stride) * b4_stride, tf.int32)

    pad_shape2d = new_shape2d - shape2d

    inputs = tf.pad(inputs,

                    tf.stack([[0, 0],

                              [3, 2 + pad_shape2d[0]],

                              [3, 2 + pad_shape2d[1]],

                              [0, 0]]),

                    name='conv1_pad') # yapf: disable

    inputs.set_shape([None, None, None, chan])

    return inputs

preprocess_input_pytorch

def preprocess_input_pytorch(
    images: tensorflow.python.framework.ops.Tensor
)

Will preprocess the images for the resnet trained on Tensorpack.

The network has been trained using BGR.

View Source
def preprocess_input_pytorch(images: tf.Tensor):

    """Will preprocess the images for the resnet trained on Tensorpack.

    The network has been trained using BGR.

    """

    mean = tf.constant([103.53, 116.28, 123.675], dtype=images.dtype)

    std = tf.constant([57.375, 57.12, 58.395], dtype=images.dtype)

    images = (images - mean) / std

    return images