0

我正在尝试使用 Keras 提供的预训练权重对 Resnet50 架构(我基于 keras 实现构建我的架构)进行微调。

这种预训练模型的缺点是它已经在具有树通道的图像上进行了训练。在我的情况下,输入有三个以上的通道。它可以是 5、6、...

该通道变化意味着第一个 conv1 层取决于通道数。因此,要使用预训练的权重,我有两种可能性。

  1. 在 conv1 层之后加载权重,对于 conv1 之前的层,它们被设置为随机的。

  2. 第二种可能性是使用 RGB 权重设置 conv1,并使用 RGB 权重的复制填充剩余的通道。

我尝试了第二种可能性,但它只适用于 3 的倍数。此外,如果我想要特定的初始化程序(glorot_uniform例如)而不是复制带,这似乎是不可能的。

所以我想知道是否有比我的功能或其他方法来实现这样的事情,特别是使用任意数量的通道而不是 3 的倍数?

注意:在应用第二种可能性之前,我试图找到实现这一目标的函数,但我没有找到任何东西。

def ResNet50(load_weights=True,
             input_shape=None,
             include_top=False,
             classes=100):
    img_input = Input(shape=input_shape, name='tuned_input')
    x = ZeroPadding2D(padding=(3, 3), name='conv1_pad')(img_input)

    # Stage 1 (conv1_x)
    x = Conv2D(64, (7, 7),
               strides=(2, 2),
               padding='valid',
               kernel_initializer=KERNEL_INIT,
               name='tuned_conv1')(x)

    x = BatchNormalization(axis=CHANNEL_AXIS, name='bn_conv1')(x)
    x = Activation('relu')(x)
    x = ZeroPadding2D(padding=(1, 1), name='pool1_pad')(x)
    x = MaxPooling2D((3, 3), strides=(2, 2))(x)

    # Stage 2 (conv2_x)
    x = _convolution_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))
    for block in ['b', 'c']:
        x = _identity_block(x, 3, [64, 64, 256], stage=2, block=block)

    # Stage 3 (conv3_x)
    x = _convolution_block(x, 3, [128, 128, 512], stage=3, block='a')
    for block in ['b', 'c', 'd']:
        x = _identity_block(x, 3, [128, 128, 512], stage=3, block=block)

    # Stage 4 (conv4_x)
    x = _convolution_block(x, 3, [256, 256, 1024], stage=4, block='a')
    for block in ['b', 'c', 'd', 'e', 'f']:
        x = _identity_block(x, 3, [256, 256, 1024], stage=4, block=block)

    # Stage 5 (conv5_x)
    x = _convolution_block(x, 3, [512, 512, 2048], stage=5, block='a')
    for block in ['b', 'c']:
        x = _identity_block(x, 3, [512, 512, 2048], stage=5, block=block)

    # AVGPOOL
    x = AveragePooling2D((2, 2), name="avg_pool")(x)
    if include_top:
        # output layer
        x = Flatten()(x)
        x = Dense(classes, activation='softmax', name='fc' + str(classes), kernel_initializer=KERNEL_INIT)(x)

    inputs = img_input
    # Create model.
    model = models.Model(inputs, x, name='resnet50')

    if load_weights:
        weights_path = get_file(
            'resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5',
            WEIGHTS_PATH_NO_TOP,
            cache_subdir='models',
            md5_hash='a268eb855778b3df3c7506639542a6af')
        model.load_weights(weights_path, by_name=True)
        # Set weights for conv1 for 6 channels
        f = h5py.File(weights_path, 'r')
        d = f['conv1']
        model.get_layer('tuned_conv1').set_weights([d['conv1_W_1:0'][:].repeat(2, axis=2), d['conv1_b_1:0']])

    return model

# example image 50x50 with 6 channels
ResNet50(input_shape=(50,50,6))
4

2 回答 2

1

您的 ResNet 模型可以处理具有 3 个通道的输入图像(例如 RGB 图像)。现在你有一个可能有任意数量的通道的图像。克服这个问题的一种方法是将输入图像的每个通道复制 3 次,使用模型独立处理每个复制的通道,然后连接结果(实际上是模型中最后一层的特征图)。这是这种方法的草图:

from keras import backend as K
from keras.layers import Input, Lambda, concatenate

inp = Input(shape=(w, h, num_channels))
rep_c = Lambda(lambda x: K.repeat_elements(K.expand_dims(x, axis=-1), 3, -1))

out_maps = []
for i in range(num_channels):
    out_maps.append(resnet_model(rep_c[:,:,:,i]))

concat = concatenate(out_maps)

# the rest of the model goes here...

但请注意,根据您拥有的数据和您正在处理的问题,这种方法可能会或可能不会以良好的准确性工作,即如果您不确定,那么您需要尝试找出答案。

于 2019-03-19T17:32:36.820 回答
0

您可以将 resnet50 模型复制到本地并通过修改模型将通道号更改为您需要的任何内容。

我相信至少在不使用预先训练的重量的情况下它应该起作用,在我的情况下,它可以用于不同的应用程序。

于 2019-12-02T23:38:05.120 回答