用不同的通道替换预训练模型的输入层?

时间:2021-05-14 19:11:27

标签: python tensorflow keras keras-layer

我想重新使用 MobiletNetv2 的预训练权重,但图像具有 12 通道。我知道这需要创建更多的权重,但这没关系,因为无论如何我都想重新训练。我找不到让它工作的方法。

import tensorflow as tf

class CNN(tf.keras.Model):
    def __init__(self):
        super(CNN, self).__init__()
        self.input_layer = tf.keras.layers.InputLayer(input_shape=(None, 224, 224, 12))
        self.base = tf.keras.applications.MobileNetV2(input_shape=(224, 224, 3),
                                                      include_top=False,
                                                      weights='imagenet')
        _ = self.base._layers.pop(0)
        self.flat1 = tf.keras.layers.Flatten()
        self.dens3 = tf.keras.layers.Dense(10)

    def call(self, x, **kwargs):
        x = self.input_layer(x)
        x = self.base(x)
        x = self.flat1(x)
        x = self.dens3(x)
        return x

model = CNN()
model.build(input_shape=(None, 224, 224, 12))
<块引用>

ValueError: Input 0 is incompatible with layer mobilenetv2_1.00_224: expected shape=(None, 224, 224, 3), found shape=(None, 224, 224, 12)

我尝试像其他答案一样弹出第一层。

3 个答案:

答案 0 :(得分:1)

最简单的方法之一(在这种情况下)是将多通道输入 (H, W, C > 3) 传递到 Conv2D(3, 3, padding='same') 层,然后是 预训练模型

class CNN(tf.keras.Model):
    def __init__(self):
        super(CNN, self).__init__()
        self.base = tf.keras.applications.MobileNetV2(input_shape=(224, 224, 3),
                                                      include_top=False,
                                                      weights='imagenet')
        self.conv = tf.keras.layers.Conv2D(3, 3, padding='same')
        self.flat1 = tf.keras.layers.Flatten()
        self.dens3 = tf.keras.layers.Dense(10)

    def call(self, x, **kwargs):
        x = self.conv(x)
        x = self.base(x)
        x = self.flat1(x)
        x = self.dens3(x)
        return x
    
    def build_graph(self):
        x = tf.keras.Input(shape=(224, 224, 12))
        return tf.keras.Model(inputs=[x], outputs=self.call(x))

model = CNN()
model.build(input_shape=(None, 224, 224, 12))

它只是完成工作。

model(tf.ones((1, 224, 224, 12))).shape # TensorShape([1, 10])
model.build_graph().summary()

Model: "model_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_13 (InputLayer)        [(None, 224, 224, 12)]    0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 224, 224, 3)       327       
_________________________________________________________________
mobilenetv2_1.00_224 (Functi (None, 7, 7, 1280)        2257984   
_________________________________________________________________
flatten_4 (Flatten)          (None, 62720)             0         
_________________________________________________________________
dense_4 (Dense)              (None, 10)                627210    
=================================================================
Total params: 2,885,521
Trainable params: 2,851,409
Non-trainable params: 34,112
_____________________________________________

另外,请参阅 this 答案,它可能会有所帮助。

答案 1 :(得分:1)

可以加载两种模型,一种具有 12 通道的输入形状,另一种具有普通的 12 通道。然后,只需将 3 通道模型的权重加载到 12 通道模型,从第 2 层或第 3 层开始。

这里是执行重量转移的地方:

for i in range(3, len(self.base.layers)):
            self.base.layers[i].set_weights(base_weights.layers[i].get_weights())

这里是整件事:

import tensorflow as tf

h, w, c = 224, 224, 3


class CNNModel(tf.keras.Model):
    def __init__(self):
        super(CNNModel, self).__init__()
        self.base = tf.keras.applications.MobileNetV2(input_shape=(h, w, 12),
                                                      include_top=False,
                                                      weights=None)
        base_weights = tf.keras.applications.MobileNetV2(input_shape=(h, w, c),
                                                         include_top=False,
                                                         weights='imagenet')

        for i in range(3, len(self.base.layers)):
            self.base.layers[i].set_weights(base_weights.layers[i].get_weights())

        del base_weights
        self.pool = tf.keras.layers.GlobalAveragePooling2D()
        self.drop1 = tf.keras.layers.Dropout(0.25)
        self.out = tf.keras.layers.Dense(1, activation='sigmoid')

    def call(self, x, training=None, **kwargs):
        x = self.base(x)
        x = self.pool(x)
        x = self.drop1(x)
        x = self.out(x)
        return x


model = CNNModel()

model.build(input_shape=(None, h, w, 12))

答案 2 :(得分:0)

您可以将每个通道用作独立图像...您将每个通道作为形状 (224,224,1) 的图像,重复每个通道以获得图像 (224,224,3)。最后,您将所有 12 张图片提供给同一个移动网络。

这会生成 12 个输出,您可以对其进行平均或以不同方式组合。

这只是我没有在实践中测试过的一种可能性,但也可以作为一个很好的起点。

Pythonic 说这是我的意思的代码:

def split_channels(image):
    channels = tf.split(image, 12, axis=-1)
    return [tf.repeat(c, [3], axis=-1) for c in channels]
    
inp = Input((224,224,12))
channels = Lambda(split_channels)(inp)
base_model = tf.keras.applications.MobileNetV2(
    input_shape=(224, 224, 3), include_top=False, weights='imagenet')
avg = Average()([base_model(c) for c in channels])
x = Flatten()(avg)
out = Dense(10)(x)

model = Model(inp, out)