mobilenetv2 tensorflow2.x版本重构

tensorflow1和2版本的api变化很大,1.x版本又已经过期了,所以今天花了点时间用tensorflow2重构了一下mobilenet的代码,这里直接上代码,原本1.x代码在转载的文章里面, 有需要的同学自取即可,如有疑问,feel free to contact me:

Mobilenetv2.py

"""
tensorflow 2.0重构 mobilenetv2
"""
import tensorflow as tf
from keras import layers, initializers, activations, Model


class Conv2DBlock(Model):
    def __init__(self, kernel_size, out_channels, stride, is_training=False):
        super(Conv2DBlock, self).__init__()
        self.conv = layers.Conv2D(filters=out_channels, kernel_size=kernel_size,
                                  strides=[stride, stride], padding='SAME',
                                  kernel_initializer="truncated_normal",
                                  bias_initializer=initializers.Constant(value=0.01))
        self.bn = layers.BatchNormalization(trainable=is_training)

    def call(self, inputs, training=None, mask=None):
        output_conv = self.conv(inputs)
        output_bn = self.bn(output_conv)
        return output_bn


class DepthwiseConv2DBlock(Model):
    def __init__(self, stride, width_multiplier, is_training):
        super(DepthwiseConv2DBlock, self).__init__()
        self.conv = layers.DepthwiseConv2D(kernel_size=3, strides=stride, depth_multiplier=width_multiplier,
                                           padding="SAME", kernel_initializer="truncated_normal",
                                           bias_initializer=initializers.Constant(value=0.01))
        self.bn = layers.BatchNormalization(trainable=is_training)

    def call(self, inputs, training=None, mask=None):
        output_conv = self.conv(inputs)
        output_bn = self.bn(output_conv)
        return activations.relu6(output_bn)


class BottleNeck(Model):
    def __init__(self, in_channels, t, out_channels, stride, width_multiplier, r=False, is_training=False):
        """
        残差模块
        :param in_channels:
        :param t:
        :param out_channels:
        :param stride:
        :param r: 表示是否用残差(只有当步长为1并且输入维度等于输出维度时才用)
        """
        super(BottleNeck, self).__init__()
        expand_dim = t * in_channels
        self.conv1 = Conv2DBlock(kernel_size=1, out_channels=expand_dim, stride=1, is_training=is_training)
        self.dwconv = DepthwiseConv2DBlock(stride=stride, width_multiplier=width_multiplier, is_training=is_training)
        self.conv2 = Conv2DBlock(kernel_size=1, out_channels=out_channels, stride=1, is_training=is_training)
        self.r = r

    def call(self, inputs, training=None, mask=None):
        output_conv = self.conv1(inputs)
        output_relu6 = activations.relu6(output_conv)
        output_dwconv = self.dwconv(output_relu6)
        outputs = self.conv2(output_dwconv)
        if self.r:
            outputs = tf.add(outputs, inputs)
        return outputs


class MobilenetV2(Model):
    def __init__(self, num_classes=8, is_training=True, width_multiplier=1):
        super(MobilenetV2, self).__init__()
        self.num_classes = num_classes
        self.is_training = is_training
        self.width_multiplier = width_multiplier

        self.conv1 = Conv2DBlock(kernel_size=3, out_channels=32, stride=2)  # 输出大小112*112*32
        # 只有步长为1并且输入维度等于输出时,才使用残差
        self.b1_1 = BottleNeck(in_channels=32, t=1, out_channels=16, stride=1, r=False,
                               width_multiplier=self.width_multiplier)  # 输出大小112*112*16,一层不使用残差

        self.b2_1 = BottleNeck(in_channels=16, t=6, out_channels=24, stride=2, r=False,
                               width_multiplier=self.width_multiplier) # 输出大小56*56*24
        self.b2_2 = BottleNeck(in_channels=24, t=6, out_channels=24, stride=1, r=True,
                               width_multiplier=self.width_multiplier) # 输出大小56*56*24

        self.b3_1 = BottleNeck(in_channels=24, t=6, out_channels=32, stride=2, r=False,
                               width_multiplier=self.width_multiplier) # 输出大小28*28*32
        self.b3_2 = BottleNeck(in_channels=32, t=6, out_channels=32, stride=1, r=True,
                               width_multiplier=self.width_multiplier) # 输出大小输出大小28*28*32
        self.b3_3 = BottleNeck(in_channels=32, t=6, out_channels=32, stride=1, r=True,
                               width_multiplier=self.width_multiplier) # 输出大小输出大小28*28*32

        self.b4_1 = BottleNeck(in_channels=32, t=6, out_channels=64, stride=2, r=False,
                               width_multiplier=self.width_multiplier)  # 输出大小14*14*64
        self.b4_2 = BottleNeck(in_channels=64, t=6, out_channels=64, stride=1, r=True,
                               width_multiplier=self.width_multiplier)  # 输出大小14*14*64
        self.b4_3 = BottleNeck(in_channels=64, t=6, out_channels=64, stride=1, r=True,
                               width_multiplier=self.width_multiplier)  # 输出大小14*14*64
        self.b4_4 = BottleNeck(in_channels=64, t=6, out_channels=64, stride=1, r=True,
                               width_multiplier=self.width_multiplier)  # 输出大小14*14*64

        self.b5_1 = BottleNeck(in_channels=64, t=6, out_channels=96, stride=1, r=False,
                               width_multiplier=self.width_multiplier)  # 输出大小14*14*96
        self.b5_2 = BottleNeck(in_channels=96, t=6, out_channels=96, stride=1, r=True,
                               width_multiplier=self.width_multiplier)  # 输出大小14*14*96
        self.b5_3 = BottleNeck(in_channels=96, t=6, out_channels=96, stride=1, r=True,
                               width_multiplier=self.width_multiplier)  # 输出大小14*14*96

        self.b6_1 = BottleNeck(in_channels=96, t=6, out_channels=160, stride=2, r=False,
                               width_multiplier=self.width_multiplier)  # 输出大小7*7*160
        self.b6_2 = BottleNeck(in_channels=160, t=6, out_channels=160, stride=1, r=True,
                               width_multiplier=self.width_multiplier)  # 输出大小7*7*160
        self.b6_3 = BottleNeck(in_channels=160, t=6, out_channels=160, stride=1, r=True,
                               width_multiplier=self.width_multiplier)  # 输出大小7*7*160

        self.b7_1 = BottleNeck(in_channels=160, t=6, out_channels=320, stride=1, r=False,
                               width_multiplier=self.width_multiplier)  # 输出大小7*7*320

        self.conv8 = Conv2DBlock(kernel_size=1, out_channels=1280, stride=1) # 输出大小7*7*1280

        self.conv10_1 = Conv2DBlock(kernel_size=1, out_channels=self.num_classes, stride=1) # 输出大小1*1*8

    def call(self, inputs, training=None, mask=None):
        conv1_output = self.conv1(inputs)

        b1_1_output = self.b1_1(conv1_output)

        b2_1_output = self.b2_1(b1_1_output)
        b2_2_output = self.b2_2(b2_1_output)

        b3_1_output = self.b3_1(b2_2_output)
        b3_2_output = self.b3_2(b3_1_output)
        b3_3_output = self.b3_3(b3_2_output)

        b4_1_output = self.b4_1(b3_3_output)
        b4_2_output = self.b4_2(b4_1_output)
        b4_3_output = self.b4_3(b4_2_output)
        b4_4_output = self.b4_4(b4_3_output)

        b5_1_output = self.b5_1(b4_4_output)
        b5_2_output = self.b5_2(b5_1_output)
        b5_3_output = self.b5_3(b5_2_output)

        b6_1_output = self.b6_1(b5_3_output)
        b6_2_output = self.b6_2(b6_1_output)
        b6_3_output = self.b6_3(b6_2_output)

        b7_1_output = self.b7_1(b6_3_output)

        conv8_output = self.conv8(b7_1_output)

        pool9_1_output = tf.reduce_mean(conv8_output, [1, 2], keepdims=True)

        conv10_1_output = self.conv10_1(pool9_1_output)

        result = tf.squeeze(conv10_1_output)

        return result


if __name__ == '__main__':
    # model = DepthwiseConv2DBlock(2, 1, False)
    # model.build(input_shape=(None, 224, 224, 3))
    # model.call(layers.Input(shape=(224, 224, 3)))
    # model.summary()
    #
    # input_tensor = tf.random.normal(shape=(10, 224, 224, 3))
    # y = model(input_tensor)
    # print(y.shape)

    # model = BottleNeck(in_channels=3, t=1, out_channels=10, stride=1, width_multiplier=1)
    # model.build(input_shape=(None, 224, 224, 3))
    # model.call(layers.Input(shape=(224, 224, 3)))
    # model.summary()
    #
    # input_tensor = tf.random.normal(shape=(10, 224, 224, 3))
    # y = model(input_tensor)
    # print(y.shape)

    model = MobilenetV2()
    model.build(input_shape=(None, 224, 224, 3))
    model.call(layers.Input(shape=(224, 224, 3)))
    model.summary()

    input_tensor = tf.random.normal(shape=(10, 224, 224, 3))
    y = model(input_tensor)
    print(y.shape)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值