我正在尝试使用Keras API编写MobilenetV3,如这篇文章中所述: https://arxiv.org/pdf/1905.02244.pdf,其架构如图所示:
为此,我需要实现前一篇文章中的bottloneck_blocks
https://arxiv.org/pdf/1801.04381.pdf。请查看架构图:
我已经成功地将初始和最终的卷积层拼接在一起:
from tensorflow.keras.layers import Input, Conv2D, Add, AvgPool2D, UpSampling2Dfirst_input = Input(shape=(256, 256, 3))firt_conv = Conv2D(16,3, strides=2, name="FirstConv2d", padding="same")(first_input)bneck1 = add_bottleneck_block(firt_conv, 16, 16)bneck2 = add_bottleneck_block(bneck1, 64, 24, strides=2)#... Skiping all the other BottleNeck Blocks for simplicity lastBneck = add_bottleneck_block(second2LastBneck, 960, 160, bneck_depth=5)middleConv = Conv2D(160, 1 , strides=1, name="MiddleConv", )(bneck3)pool7 = AvgPool2D(7, strides=1, padding='same', name="7x7Pool")(middleConv)SecondLastConv = Conv2D(1280, 1, strides=1, name="SecondLastConv")(pool7)lastConv = Conv2D(3,1, strides=1, name="lastConv1x1")(SecondLastConv)upScale = UpSampling2D(2)(lastConv) # This layer is application specific for my training.v3 = tf.keras.models.Model(inputs=[first_input], outputs=upScale)v3.compile(optimizer='adam', loss=tf.keras.losses.BinaryCrossentropy(),)v3.summary()
其中bottleneck_block
在下面的代码片段中给出(修改自 https://towardsdatascience.com/mobilenetv2-inverted-residuals-and-linear-bottlenecks-8a4362f4ffd5)
def bottleneck_block(x, expand=64, squeeze=16, strides=1, bneck_depth=3): """ Bottleneck block with Activation and batch normalization commented since I don't believe this is the issue in my problem """ m = tf.keras.layers.Conv2D(expand, (1,1), strides=1)(x) #m = tf.keras.layers.BatchNormalization()(m) #m = tf.keras.layers.Activation('relu6')(m) m = tf.keras.layers.DepthwiseConv2D(bneck_depth, padding='same', strides=strides)(m) #m = tf.keras.layers.BatchNormalization()(m) #m = Activation('relu6')(m) m = tf.keras.layers.Conv2D(squeeze, (1,1), strides=1)(m) #m = tf.keras.layers.BatchNormalization()(m) return tf.keras.layers.Add()([m, x])
然而,在bneck2
中我得到了以下错误:
ValueError: Operands could not be broadcast together with shapes (16, 16, 24) (128, 128, 16)
我知道这个错误意味着输入和输出的维度不匹配,但我不知道如何修正它以构建MobilenetV3的网络结构。
这里我遗漏了什么?
作为参考,这里是tensorflow仓库中相同网络的源代码: https://github.com/tensorflow/models/blob/a174bf5b1db0e2c1e04697ff5aae5182bd1c60e7/research/slim/nets/mobilenet/mobilenet_v3.py#L130
回答:
解决方案是按照V3作者的仓库中描述的修改bottleneck_block
:
import tensorflow as tfdef bottleneck_block(x, expand=64, squeeze=16, strides=1, bneck_depth=3, se=False): """ se stands for squeeze_excite """ m = tf.keras.layers.Conv2D(expand, (1,1), strides=1)(x) m = tf.keras.layers.BatchNormalization()(m) #m = tf.keras.layers.Activation('relu6')(m) m = tf.keras.layers.DepthwiseConv2D(bneck_depth, padding='same', strides=strides)(m) m = tf.keras.layers.BatchNormalization()(m) #m = Activation('relu6')(m) if se: m = squeeze_excite_block(m, ratio=4) m = tf.keras.layers.Conv2D(squeeze, (1,1), strides=1, padding='same')(m) m = tf.keras.layers.BatchNormalization()(m) if ( # stride check enforces that we don't add residuals when spatial # dimensions are None strides == 1 and # Depth matches m.get_shape().as_list()[3] == x.get_shape().as_list()[3] ): m = tf.keras.layers.Add()([m, x]) return m
对维度和步长的检查防止了我在添加两个不匹配维度的网络时最初遇到的错误