Пакетная нормализация, кажется, не работает одинаково в keras и pytorch - PullRequest
0 голосов
/ 16 апреля 2019

Я имею простую модель и пробую, как работает нормализация партии, применяя после линейного слоя. Кажется, он вообще не нормализуется, так как по умолчанию он инициализируется в керас. После проверки с теми же весами в pytorch, его пакетная нормализация вносит изменения. Пожалуйста, смотрите ниже. Почему и что не так в модели?

Редактировать: автономный пример, который выводит результаты из кераса и модели pytorch для визуального сравнения. Чтобы использовать слой пакетной нормализации, пожалуйста, раскомментируйте несколько строк, которые указывают на него, а затем сравните результаты еще раз.

import tensorflow as tf
import numpy as np
from collections import OrderedDict

from tensorflow.python.keras import layers 
from tensorflow.python.keras import models

import torch
from torch import nn
from torch.nn import functional as F


from tensorflow.contrib import eager as tfe
tfe.enable_eager_execution()


class PytorchModel(nn.Module):
    def __init__(self,
                 in_channels,
                 out_channels):
        super().__init__()

        self.linear = nn.Linear(in_channels, out_channels, bias=True)
        self.norm = nn.BatchNorm1d(out_channels, eps=1e-3, momentum=0.01)

    def forward(self, inputs):
        x = self.linear(inputs)
        ## uncomment for batch normalization
        # x = self.norm(x.permute(0, 2, 1).contiguous()).permute(0, 2, 1).contiguous()
        x = F.relu(x)
        return x

class KerasModel(models.Model):
    def __init__(self,
                 num_filters):
        super(KerasModel, self).__init__()

        my_layers = []
        BN = layers.BatchNormalization(name='my_bn', momentum=0.01, epsilon=1e-3)
        LIN = layers.Dense(num_filters, name='my_linear', activation=None, use_bias=True)
        my_layers.append([LIN, BN])
        self.my_layers = my_layers

    def call(self, ins):
        x = self.my_layers[0][0](tf.convert_to_tensor(ins))
        ## uncomment for batch normalization
        # x = self.my_layers[0][1](x)
        x = tf.nn.relu(x)
        return x

if __name__ == '__main__':

    # create dummy input
    np.random.seed(0)
    input_np = np.random.rand(4,5,6)
    filters = 8

    keras_l = KerasModel(num_filters=filters)

    tf_features = keras_l(tf.convert_to_tensor(input_np))

    pytorch_l = PytorchModel(in_channels=6,
                             out_channels=filters)

    # copy weights from keras model to pytorch model
    new_state_dict = OrderedDict()
    new_state_dict['linear.weight'] = torch.from_numpy(np.transpose(keras_l.layers[0].weights[0].numpy(), (1, 0)))
    new_state_dict['linear.bias'] = torch.from_numpy(keras_l.layers[0].bias.numpy())
    ## uncomment for batch normalization
    # new_state_dict['norm.weight'] = torch.from_numpy(keras_l.layers[1].weights[0].numpy())  # gamma
    # new_state_dict['norm.bias'] = torch.from_numpy(keras_l.layers[1].weights[1].numpy())  # bias
    # new_state_dict['norm.running_mean'] = torch.from_numpy(keras_l.layers[1].weights[2].numpy())
    # new_state_dict['norm.running_var'] = torch.from_numpy(keras_l.layers[1].weights[3].numpy())
    pytorch_l.load_state_dict(new_state_dict, strict=False)

    batch_input_voxels_np = torch.from_numpy(input_np).float()
    batch_pytorch_features = pytorch_l.forward(batch_input_voxels_np)

    # => check how results differ, when batch normalization is applied.
    print(tf_features[0, 0, :])
    print(pytorch_features[0, 0, :])
...