相同的权重,实现但不同的结果 n Keras 和 Pytorch

Posted

技术标签:

【中文标题】相同的权重,实现但不同的结果 n Keras 和 Pytorch【英文标题】:Same weights, implementation but different results n Keras and Pytorch 【发布时间】:2021-06-19 00:31:29 【问题描述】:

我有一个编码器和一个解码器模型 (monodepth2)。我尝试使用Onnx2Keras 将它们从 Pytorch 转换为 Keras,但是:

编码器(ResNet-18)成功 我自己在 Keras 中构建了解码器(使用 TF2.3),并将每一层的 权重(numpy 数组,包括权重和偏差)从 Pytorch 复制到 Keras,没有进行任何修改。

但事实证明Onnx2Keras-converted Encoder 和自建解码器都无法重现相同的结果。下面是对比图,我先介绍一下Decoder的代码。

首先是核心层,所有的conv2d层(Conv3x3ConvBlock)都是基于这个,只是不同的dims或者加一个activation:

# Conv3x3 (normal conv2d without BN nor activation)
# There's also a ConvBlock, which is just "Conv3x3 + ELU activation", so I don't list it here.
def TF_Conv3x3(input_channel, filter_num, pad_mode='reflect', activate_type=None):

    # Actually it's 'reflect, but I implement it with tf.pad() outside this
    padding = 'valid'  

    # if TF_ConvBlock, then activate_type=='elu
    conv = tf.keras.layers.Conv2D(filters=filter_num, kernel_size=3, activation=activate_type,
                                  strides=1, padding=padding)
    return conv

然后是结构。请注意,该定义与原始code 完全相同。我想一定是实现的一些细节。

def DepthDecoder_keras(num_ch_enc=np.array([64, 64, 128, 256, 512]), channel_first=False,
                       scales=range(4), num_output_channels=1):
    num_ch_dec = np.array([16, 32, 64, 128, 256])
    convs = OrderedDict()
    for i in range(4, -1, -1):
        # upconv_0
        num_ch_in = num_ch_enc[-1] if i == 4 else num_ch_dec[i + 1]
        num_ch_out = num_ch_dec[i]

        # convs[("upconv", i, 0)] = ConvBlock(num_ch_in, num_ch_out)
        convs[("upconv", i, 0)] = TF_ConvBlock(num_ch_in, num_ch_out, pad_mode='reflect')


        # upconv_1
        num_ch_in = num_ch_dec[i]
        if i > 0:
            num_ch_in += num_ch_enc[i - 1]
        num_ch_out = num_ch_dec[i]
        convs[("upconv", i, 1)] = TF_ConvBlock(num_ch_in, num_ch_out, pad_mode='reflect')  # Just Conv3x3 with ELU-activation

    for s in scales:
        convs[("dispconv", s)] = TF_Conv3x3(num_ch_dec[s], num_output_channels, pad_mode='reflect')

    """
    Input_layer dims: (64, 96, 320), (64, 48, 160),  (128, 24, 80), (256, 12, 40), (512, 6, 20)
    """
    x0 = tf.keras.layers.Input(shape=(96, 320, 64))
    # then define the the rest input layers
    input_features = [x0, x1, x2, x3, x4]

    """
    # connect layers
    """
    outputs = []
    ch = 1 if channel_first else 3
    x = input_features[-1]
    for i in range(4, -1, -1):
        x = tf.pad(x, paddings=[[0, 0], [1, 1], [1, 1], [0, 0]], mode='REFLECT')
        x = convs[("upconv", i, 0)](x)
        x = [tf.keras.layers.UpSampling2D()(x)]
        if i > 0:
            x += [input_features[i - 1]]
        x = tf.concat(x, ch)
        x = tf.pad(x, paddings=[[0, 0], [1, 1], [1, 1], [0, 0]], mode='REFLECT')
        x = convs[("upconv", i, 1)](x)
    x = TF_ReflectPad2D_1()(x)
    x = convs[("dispconv", 0)](x)
    disp0 = tf.math.sigmoid(x)

    """
    build keras Model ([input0, ...], [output0, ...])
    """
    # decoder = tf.keras.Model(input_features, outputs)
    decoder = tf.keras.Model(input_features, disp0)

    return decoder

交叉比较如下...如果有人能提供一些见解,我将不胜感激。谢谢!!!

原始结果:

原创编码器+自建解码器:

ONNX-converted Enc + Original Dec(质感不错,但对比度不够,车应该很接近,也就是颜色很亮):

ONNX 转换的 Enc + 自建的 Dec:

【问题讨论】:

【参考方案1】:

解决了!

事实证明,实施确实没有问题(至少不重要)。这是weights复制的问题。

原来的权重有(H, W, 3, 3),但是TF-model需要dim of (3, 3, W, H),所以我用[3,2,1,0]置换了,忽略(3, 3) 也有自己的序列。

所以应该是weights.permute([2,3,1,0]),一切都很好!

【讨论】:

以上是关于相同的权重,实现但不同的结果 n Keras 和 Pytorch的主要内容,如果未能解决你的问题,请参考以下文章

keras 模型中的平均权重

为啥使用相同的 Keras 模型和输入进行预测时会得到不同的结果?

每个示例具有不同权重的 Keras 自定义损失函数

Keras 中具有类权重的多标签分类

Keras:使用批量标准化在同一数据集上的不同训练和验证结果

如何在 Keras 中重新初始化现有模型的层权重?