Tensorflow2.0之自定义DenseNet

1、DenseNet 网络结构

DenseNet 的主要构建模块是稠密块(DenseBlock)和过渡层(TransitionLayer)。前者定义了输入和输出是如何连结的,后者则用来控制通道数,防止通道数过多。在 DenseBlock 中,包含许多 BottleNeck,完成类似于 ResNetResidual 的操作。

1.1 BottleNeck

BottleNeckResidual 非常相似。与 Residual 的主要区别在于,BottleNeck 里的输出不是像 Residual 那样和输入相加,而是在通道维度上连接。即
在这里插入图片描述
其中,两个卷积层的步长都设为1,填充方式都设为 ‘‘same’’,这样一来,得到的输出 Y 的长和宽都和 X 相同,只有通道数不同。因此,XY 可以在通道数这一维度上连接。例如,Xshape[4, 8, 8, 3],输出 Yshape[4, 8, 8, 32],那么 [X, Y]shape[4, 8, 8, 35]

1.2 DenseBlock

DenseBlock 由多个 BottleNeck 组成,每块使用相同的输出通道数。

1.3 TransitionLayer

由于每个稠密块都会带来通道数的增加,使用过多则会带来过于复杂的模型。过渡层用来控制模型复杂度。它通过 1 × 1 1\times1 卷积层来减小通道数,并使用步幅为2的平均池化层减半高和宽,从而进一步降低模型复杂度。

1.4 DenseNet

在这里插入图片描述

2、代码构建 DenseNet

2.1 BottleNeck

class BottleNeck(tf.keras.Model):
    def __init__(self, growth_rate, drop_rate):
        super().__init__()
        self.bn1 = tf.keras.layers.BatchNormalization()
        self.conv1 = tf.keras.layers.Conv2D(filters=4*growth_rate,
                                            kernel_size=(1, 1),
                                            strides=1,
                                            padding='same')
        self.bn2 = tf.keras.layers.BatchNormalization()
        self.conv2 = tf.keras.layers.Conv2D(filters=growth_rate,
                                            kernel_size=(3, 3),
                                            strides=1,
                                            padding='same')
        self.dropout = tf.keras.layers.Dropout(rate=drop_rate)
        self.listLayers = [self.bn1,
                           tf.keras.layers.Activation("relu"),
                           self.conv1,
                           self.bn2,
                           tf.keras.layers.Activation("relu"),
                           self.conv2,
                           self.dropout]
        
    def call(self, x):
        y = x
        for layer in self.listLayers.layers:
            y = layer(y)
        y = tf.keras.layers.concatenate([x, y], axis=-1)
        return y
X = tf.random.uniform((4, 8, 8, 3))
net(X).shape
TensorShape([4, 8, 8, 35])
X = tf.random.uniform((4, 8, 8, 3))
for layer in net.layers:
    X = layer(X)
    print(layer.name, 'output shape:\t', X.shape)
batch_normalization_165 output shape:	 (4, 8, 8, 3)
conv2d_165 output shape:	 (4, 8, 8, 128)
batch_normalization_166 output shape:	 (4, 8, 8, 128)
conv2d_166 output shape:	 (4, 8, 8, 32)
dropout_73 output shape:	 (4, 8, 8, 32)
activation_160 output shape:	 (4, 8, 8, 32)
activation_161 output shape:	 (4, 8, 8, 32)

2.2 DenseBlock

class DenseBlock(tf.keras.Model):
    def __init__(self, num_layers, growth_rate, drop_rate=0.5):
        super().__init__()
        self.num_layers = num_layers
        self.growth_rate = growth_rate
        self.drop_rate = drop_rate
        self.listLayers = []
        for _ in range(self.num_layers):
            self.listLayers.append(BottleNeck(growth_rate=self.growth_rate, drop_rate=self.drop_rate))

    def call(self, x):
        for layer in self.listLayers.layers:
            x = layer(x)
        return x
blk = DenseBlock(2, 10)
X = tf.random.uniform((4, 8, 8, 3))
Y = blk(X)
Y.shape
TensorShape([4, 8, 8, 23])

2.3 TransitionLayer

class TransitionLayer(tf.keras.Model):
    def __init__(self, out_channels):
        super().__init__()
        self.bn = tf.keras.layers.BatchNormalization()
        self.conv = tf.keras.layers.Conv2D(filters=out_channels,
                                           kernel_size=1,
                                           strides=1,
                                           padding='same')
        self.pool = tf.keras.layers.MaxPool2D(pool_size=2,
                                              strides=2,
                                              padding='same')
        self.listLayers = [self.bn,
                           tf.keras.layers.Activation('relu'),
                           self.conv,
                           self.pool]
        
    def call(self, inputs):
        x = inputs
        for layer in self.listLayers.layers:
            x = layer(x)
        return x
trans = TransitionLayer(10)
trans(Y).shape
TensorShape([4, 4, 4, 10])

2.4 DenseNet

class DenseNet(tf.keras.Model):
    def __init__(self, num_init_features, growth_rate,
                 block_layers, compression_rate, drop_rate):
        super().__init__()
        self.conv = tf.keras.layers.Conv2D(filters=num_init_features,
                                           kernel_size=7,
                                           strides=2,
                                           padding='same')
        self.bn = tf.keras.layers.BatchNormalization()
        self.pool = tf.keras.layers.MaxPool2D(pool_size=3,
                                              strides=2,
                                              padding='same')
        self.num_channels = num_init_features
        self.dense_block_1 = DenseBlock(num_layers=block_layers[0], growth_rate=growth_rate, drop_rate=drop_rate)
        self.num_channels += growth_rate * block_layers[0]
        self.num_channels = compression_rate * self.num_channels
        self.transition_1 = TransitionLayer(out_channels=int(self.num_channels))
        self.dense_block_2 = DenseBlock(num_layers=block_layers[1], growth_rate=growth_rate, drop_rate=drop_rate)
        self.num_channels += growth_rate * block_layers[1]
        self.num_channels = compression_rate * self.num_channels
        self.transition_2 = TransitionLayer(out_channels=int(self.num_channels))
        self.dense_block_3 = DenseBlock(num_layers=block_layers[2], growth_rate=growth_rate, drop_rate=drop_rate)
        self.num_channels += growth_rate * block_layers[2]
        self.num_channels = compression_rate * self.num_channels
        self.transition_3 = TransitionLayer(out_channels=int(self.num_channels))
        self.dense_block_4 = DenseBlock(num_layers=block_layers[3], growth_rate=growth_rate, drop_rate=drop_rate)

        self.avgpool = tf.keras.layers.GlobalAveragePooling2D()
        self.fc = tf.keras.layers.Dense(units=10,
                                        activation=tf.keras.activations.softmax)

    def call(self, inputs):
        x = self.conv(inputs)
        x = self.bn(x)
        x = tf.keras.activations.relu(x)
        x = self.pool(x)

        x = self.dense_block_1(x)
        x = self.transition_1(x)
        x = self.dense_block_2(x)
        x = self.transition_2(x)
        x = self.dense_block_3(x)
        x = self.transition_3(x,)
        x = self.dense_block_4(x)

        x = self.avgpool(x)
        x = self.fc(x)

        return x

2.5 模型检验

mynet = DenseNet(num_init_features=64,
                 growth_rate=32,
                 block_layers=[4,4,4,4],
                 compression_rate=0.5,
                 drop_rate=0.5)

X = tf.random.uniform(shape=(1,  224, 224 , 1))
for layer in mynet.layers:
    X = layer(X)
    print(layer.name, 'output shape:\t', X.shape)
conv2d_129 output shape:	 (1, 112, 112, 64)
batch_normalization_129 output shape:	 (1, 112, 112, 64)
max_pooling2d_15 output shape:	 (1, 56, 56, 64)
dense_block_18 output shape:	 (1, 56, 56, 192)
transition_layer_13 output shape:	 (1, 28, 28, 96)
dense_block_19 output shape:	 (1, 28, 28, 224)
transition_layer_14 output shape:	 (1, 14, 14, 112)
dense_block_20 output shape:	 (1, 14, 14, 240)
transition_layer_15 output shape:	 (1, 7, 7, 120)
dense_block_21 output shape:	 (1, 7, 7, 248)
global_average_pooling2d_2 output shape:	 (1, 248)
dense_2 output shape:	 (1, 10)
发布了120 篇原创文章 · 获赞 15 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_36758914/article/details/104942951
今日推荐