如何使用预先训练的权重设置喀拉拉邦特定渠道的权重?

时间:2019-03-18 13:23:39

标签: python keras deep-learning conv-neural-network transfer-learning

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

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

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

  1. conv1层之后的负载权重和conv1之前的层的权重设置为随机。

  2. 第二种可能性是为conv1设置RGB权重,并使用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))

2 个答案:

答案 0 :(得分: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...

但是请注意,根据您所拥有的数据和所处理的问题,此方法可能会或可能不会以较高的准确性来工作,即,如果不确定,则需要尝试找出答案。

答案 1 :(得分:0)

您只需将resnet50模型复制到本地,然后通过修改模型将通道号更改为所需的任何数字。

我相信至少在不使用预先训练的重量的情况下,它应该可以工作,在我的情况下,可以将其用于其他应用。