directory

Abstract

Implement the residual module

ResNet18, ResNet34

ResNet50, ResNet101, ResNet152


Abstract

ResNet (Residual Neural Network) was proposed by four Chinese including Kaiming He of Microsoft Research, successfully trained 152-layer Neural Network by using ResNet Unit, and won the champion in ILSVRC2015 competition. The error rate of top5 is 3.57%, and the number of parameters is lower than VGGNet, so the effect is very obvious.

The innovation of the model lies in the idea of residual learning, which adds a direct channel in the network to transmit the original input information directly to the following layers, as shown in the figure below:



In traditional convolutional networks or fully connected networks, there are more or less problems such as information loss and loss during information transmission, and at the same time, gradient disappearance or gradient explosion will result in the failure of training of deep networks. ResNet solves this problem to some extent by directly bypassing the input information to the output to protect the integrity of the information. The entire network only needs to learn the part of the difference between the input and output, simplifying the learning objectives and difficulties. The pairing of VGGNet and ResNet is shown below. The biggest difference with ResNet is that there are many bypasses that connect the input directly to the next layer, which is also known as shortcut or Skip connections.

In ResNet network structure, two residual modules will be used, one is two 3*3 convolutional networks connected together as a residual module, and the other is 1*1, 3*3 and 1*1 convolutional networks connected together as a residual module. As shown below:

ResNet has different network layers. The most common ones are 18-layer, 34-layer, 50-layer, 101-layer, and 152-layer. They are all made up of the residual modules stacked on top of each other. The following figure shows the different ResNet models.

Implement the residual module

The first residual module

# The first residual module
class BasicBlock(layers.Layer) :
    def __init__(self, filter_num, stride=1) :
        super(BasicBlock, self).__init__()
        self.conv1 = layers.Conv2D(filter_num, (3.3), strides=stride, padding='same')
        self.bn1 = layers.BatchNormalization()
        self.relu = layers.Activation('relu')
        self.conv2 = layers.Conv2D(filter_num, (3.3), strides=1, padding='same')
        self.bn2 = layers.BatchNormalization()
        ifstride ! =1:
            self.downsample = Sequential()
            self.downsample.add(layers.Conv2D(filter_num, (1.1), strides=stride))
        else:
            self.downsample = lambda x: x

    def call(self, input, training=None) :
        out = self.conv1(input)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        identity = self.downsample(input)
        output = layers.add([out, identity])
        output = tf.nn.relu(output)
        return output
Copy the code

The second residual module

 

# Second residual module
class Block(layers.Layer) :
    def __init__(self, filters, downsample=False, stride=1) :
        super(Block, self).__init__()
        self.downsample = downsample
        self.conv1 = layers.Conv2D(filters, (1.1), strides=stride, padding='same')
        self.bn1 = layers.BatchNormalization()
        self.relu = layers.Activation('relu')
        self.conv2 = layers.Conv2D(filters, (3.3), strides=1, padding='same')
        self.bn2 = layers.BatchNormalization()
        self.conv3 = layers.Conv2D(4 * filters, (1.1), strides=1, padding='same')
        self.bn3 = layers.BatchNormalization()
        if self.downsample:
            self.shortcut = Sequential()
            self.shortcut.add(layers.Conv2D(4 * filters, (1.1), strides=stride))
            self.shortcut.add(layers.BatchNormalization(axis=3))

    def call(self, input, training=None) :
        out = self.conv1(input)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)
        out = self.conv3(out)
        out = self.bn3(out)
        if self.downsample:
            shortcut = self.shortcut(input)
        else:
            shortcut = input
        output = layers.add([out, shortcut])
        output = tf.nn.relu(output)
        return output
Copy the code

ResNet18, ResNet34

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequential


# The first residual module
class BasicBlock(layers.Layer) :
    def __init__(self, filter_num, stride=1) :
        super(BasicBlock, self).__init__()
        self.conv1 = layers.Conv2D(filter_num, (3.3), strides=stride, padding='same')
        self.bn1 = layers.BatchNormalization()
        self.relu = layers.Activation('relu')
        self.conv2 = layers.Conv2D(filter_num, (3.3), strides=1, padding='same')
        self.bn2 = layers.BatchNormalization()
        ifstride ! =1:
            self.downsample = Sequential()
            self.downsample.add(layers.Conv2D(filter_num, (1.1), strides=stride))
        else:
            self.downsample = lambda x: x

    def call(self, input, training=None) :
        out = self.conv1(input)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        identity = self.downsample(input)
        output = layers.add([out, identity])
        output = tf.nn.relu(output)
        return output


class ResNet(keras.Model) :
    def __init__(self, layer_dims, num_classes=10) :
        super(ResNet, self).__init__()
        # Preprocessing layer
        self.padding = keras.layers.ZeroPadding2D((3.3))
        self.stem = Sequential([
            layers.Conv2D(64, (7.7), strides=(2.2)),
            layers.BatchNormalization(),
            layers.Activation('relu'),
            layers.MaxPool2D(pool_size=(3.3), strides=(2.2), padding='same')])# resblock
        self.layer1 = self.build_resblock(64, layer_dims[0])
        self.layer2 = self.build_resblock(128, layer_dims[1], stride=2)
        self.layer3 = self.build_resblock(256, layer_dims[2], stride=2)
        self.layer4 = self.build_resblock(512, layer_dims[3], stride=2)
        # global pooling
        self.avgpool = layers.GlobalAveragePooling2D()
        Full connection layer
        self.fc = layers.Dense(num_classes, activation=tf.keras.activations.softmax)

    def call(self, input, training=None) :
        x=self.padding(input)
        x = self.stem(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        # [b,c]
        x = self.avgpool(x)
        x = self.fc(x)
        return x

    def build_resblock(self, filter_num, blocks, stride=1) :
        res_blocks = Sequential()
        res_blocks.add(BasicBlock(filter_num, stride))
        for pre in range(1, blocks):
            res_blocks.add(BasicBlock(filter_num, stride=1))
        return res_blocks


def ResNet34(num_classes=10) :
    return ResNet([2.2.2.2], num_classes=num_classes)


def ResNet34(num_classes=10) :
    return ResNet([3.4.6.3], num_classes=num_classes)


model = ResNet34(num_classes=1000)
model.build(input_shape=(1.224.224.3))
print(model.summary())  # Collect network parameters
Copy the code

ResNet50, ResNet101, ResNet152

import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers, Sequential # class Block(layer. Layer): def __init__(self, filters, downsample=False, stride=1): super(Block, self).__init__() self.downsample = downsample self.conv1 = layers.Conv2D(filters, (1, 1), strides=stride, padding='same') self.bn1 = layers.BatchNormalization() self.relu = layers.Activation('relu') self.conv2 = layers.Conv2D(filters, (3, 3), strides=1, padding='same') self.bn2 = layers.BatchNormalization() self.conv3 = layers.Conv2D(4 * filters, (1, 1), strides=1, padding='same') self.bn3 = layers.BatchNormalization() if self.downsample: self.shortcut = Sequential() self.shortcut.add(layers.Conv2D(4 * filters, (1, 1), strides=stride)) self.shortcut.add(layers.BatchNormalization(axis=3)) def call(self, input, training=None): out = self.conv1(input) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.relu(out) out = self.conv3(out) out = self.bn3(out) if self.downsample: shortcut = self.shortcut(input) else: shortcut = input output = layers.add([out, shortcut]) output = tf.nn.relu(output) return output class ResNet(keras.Model): def __init__(self, layer_dims, num_classes=10): Self, super (ResNet) __init__ () # pretreatment layer of the self. The padding = keras. The layers. ZeroPadding2D ((3, 3)) self.stem = Sequential([ layers.Conv2D(64, (7, 7), strides=(2, 2)), layers.BatchNormalization(), layers.Activation('relu'), layers.MaxPool2D(pool_size=(3, 3), strides=(2, 2), padding='same') ]) # resblock self.layer1 = self.build_resblock(64, layer_dims[0],stride=1) self.layer2 = self.build_resblock(128, layer_dims[1], stride=2) self.layer3 = self.build_resblock(256, layer_dims[2], stride=2) self.layer4 = self.build_resblock(512, layer_dims[3], Stride = 2) # overall pooling self. Avgpool. = the layers GlobalAveragePooling2D # () the connection layer self. Fc = the layers. Dense (num_classes, activation=tf.keras.activations.softmax) def call(self, input, training=None): x = self.padding(input) x = self.stem(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) # [b,c] x = self.avgpool(x) x = self.fc(x) return x def build_resblock(self, filter_num, blocks, stride=1): res_blocks = Sequential() if stride ! = 1 or filter_num * 4 ! = 64: res_blocks.add(Block(filter_num, downsample=True,stride=stride)) for pre in range(1, blocks): res_blocks.add(Block(filter_num, stride=1)) return res_blocks def ResNet50(num_classes=10): return ResNet([3, 4, 6, 3], num_classes=num_classes) def ResNet101(num_classes=10): return ResNet([3, 4, 23, 3], num_classes=num_classes) def ResNet152(num_classes=10): return ResNet([3, 8, 36, 3], num_classes=num_classes) model = ResNet50(num_classes=1000) model.build(input_shape=(1, 224, 224, 3)) print(model.summary()) #Copy the code

Running results: