Как конвертировать CNN из кераса в mxnet? - PullRequest
1 голос
/ 15 марта 2019

У меня следующая проблема: у меня есть скрипт в Керасе, который работает как шарм. Я хотел бы сейчас преобразовать этот скрипт в MXNet. CNN в Керасе выглядит следующим образом:

model=Sequential()
model.add(Convolution2D(128, (3, 3), padding='same', activation='relu', name='block1_conv1', input_shape=(80,120,3)))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(Convolution2D(256, (3, 3), padding='same', activation='relu', name='block2_conv1'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(Flatten())
model.add(Dense(2, activation = 'softmax', name='final_fully_connected'))

Я подумал, что преобразование в MXNet не может быть таким сложным, я посмотрел соответствующую документацию и передал параметры, насколько мне известно.

model=gluon.nn.Sequential()
with model.name_scope():
    model.add(gluon.nn.Conv2D(channels=128, kernel_size=(3, 3), activation='relu'))
    model.add(gluon.nn.MaxPool2D(pool_size=(2, 2), strides=(2, 2)))            
    model.add(gluon.nn.Conv2D(channels=256, kernel_size=(3, 3), activation='relu'))
    model.add(gluon.nn.MaxPool2D(pool_size=(2, 2), strides=(2, 2)))
    # The Flatten layer collapses all axis, except the first one, into one axis.
    model.add(gluon.nn.Flatten())
    model.add(gluon.nn.Dense(2, activation='relu'))

Но если я попытаюсь обучить модель сейчас, я получу следующую ошибку:

"MXNetError: [17:01:34] C: \ ci \ libmxnet_1533399150922 \ work \ src \ operator \ nn \ pooling.cc: 145: Ошибка проверки: param.kernel [1] <= dshape [3] + 2 * param.pad [1] размер ядра (2) превышает ввод (1 дополняется до 1) "</p>

Я думаю, что это как-то связано с размерами ядра и слоя MaxPooling2D, но я не понимаю ошибки, потому что думал, что на самом деле строил ту же сеть, что и в Keras.

Для полноты: моя входная переменная X имеет размеры (80, 120, 3).

Я был бы очень признателен за помощь некоторых профессионалов Keras / MXNet.

Ответы [ 4 ]

2 голосов
/ 12 апреля 2019

Чтобы добавить к предыдущим сообщениям, есть другой путь, вы можете просто использовать бэкэнд MXNet в Keras.Смотрите пакет keras-mxnet: https://github.com/awslabs/keras-apache-mxnet

pip install keras-mxnet

и измените ваш ~/.keras/keras.json на:

{
    "floatx": "float32",
    "epsilon": 1e-07,
    "backend": "mxnet",
    "image_data_format": "channels_first"
}
2 голосов
/ 09 апреля 2019

Моя функция для определения модели:

# DEFINE THE MODEL
def create_model(load_file=None):
    num_outputs = 2                   # The number of outputs of the network
    channels    = [128, 256]          # The number of different filters (each with other entries) in the convolution.
    kernel_size = (3, 3)              # Specifies the dimensions of the convolution window (i.e., filter).
    padding     = (kernel_size[0]//2, 
                   kernel_size[1]//2) # To be able to process the border regions of the input layer with the kernel (e.g., a kernel of 3x3 needs an additional neighboring cell), these are surrounded by zeros.
    pool_size   = (2, 2)              # Specifies the size of the pooling window (i.e. region) from which the maximum value is determined.
    strides     = (2, 2)              # Determines by how many steps the pooling window moves. A  pooling window of 2x2 and a step size of 2x2 means that the regions won't overlap.

    net = gluon.nn.Sequential(prefix='cnn_')
    with net.name_scope():
        net.add(gluon.nn.Conv2D(channels=channels[0], kernel_size=kernel_size, padding=padding, activation='relu'))
        net.add(gluon.nn.MaxPool2D(pool_size=pool_size, strides=strides))            
        net.add(gluon.nn.Conv2D(channels=channels[1], kernel_size=kernel_size, padding=padding, activation='relu'))
        net.add(gluon.nn.MaxPool2D(pool_size=pool_size, strides=strides))           
        # The Flatten layer collapses all axis, except the first one, into one axis.
        net.add(gluon.nn.Flatten())
        # In the keras template the authors used activation='softmax'. In Gluon this activation function does not exist. Therefore, we first break down the output to the desired number of outputs and apply the softmax function after the output of the network.
        net.add(gluon.nn.Dense(num_outputs))

    # Initialize the model parameters
    net.collect_params().initialize(mx.init.Xavier(magnitude=2.24), ctx=ctx)
#    net.collect_params().initialize(mx.init.Uniform(scale=1.0), ctx=ctx)


    # Optional: Load model parameters from a previous run
    if load_file:
        net.load_parameters(load_file, ctx=ctx)

    return net

Впоследствии, когда я прогнозирую классы, я использую функцию softmax mxnet:

y_pred = nd.softmax(net(data[0]))
2 голосов
/ 10 апреля 2019

Это точный перевод (насколько мне известно) вашей модели с использованием gluon mxnet api.

class YourNet(HybridBlock):
    def __init__(self,kernel_size = (3,3),dilation =(1,1),**kwargs):
        super(YourNet,self).__init__(**kwargs)

        # Use this scheme for padding='same' for **ODD** kernels
        px = dilation[0] * (kernel_size[0] - 1)//2
        py = dilation[1] * (kernel_size[1] - 1)//2

        pad = (px,py)

        # Here you DECLARE but not use!! the layers
        with self.name_scope():
            self.conv1 = gluon.nn.Conv2D(channels=128,kernel_size=kernel_size,padding=pad,dilation=dilation,prefix='_block1_conv1')
            self.conv2 = gluon.nn.Conv2D(channels=256,kernel_size=kernel_size,padding=pad,dilation=dilation,prefix='_block2_conv2')

            self.last_layer = gluon.nn.Dense(units=2,prefix='_final_fully_connected')

            # You need only one pooling operation, since it doesn't have trainable
            # parameters
            self.pool = gluon.nn.MaxPool2D(pool_size=(2,2),strides=(2,2))


    def hybrid_forward(self, F, input):
        """
        In this function you specify how you want to use the layers you defined
        previously. F stands for functional, it has some additional 
        function definitions. There are multiple ways to achieve the same result 
        (using layers instead of F.SomeFunction). 
        """


        out = self.conv1(input) # pass input through first layer
        out = F.relu(out) # do the activation of the output
        out = self.pool(out) # Do max pooling after the activation
        out = self.conv2(out) # Now pass through second convolution
        out = F.relu(out) # another activation
        out = self.pool(out) # Again maxpool 2D


        out = F.flatten(out) # Flatten the output. Similar with gluon.nn.Flatten()

        out = self.last_layer(out) # Apply last layer (dense)

        # Caution with the softmax on the channel applied
        out = F.softmax(out,axis=-1) # Do the softmax, with the last layer

        # Once you are done, return the output.
        return out

использование:

net = YourNet()
net.initialize()
net.hybridize() # ~ x3 speed performance (in gpus), using hybrid block. 

# Some random input
xx = nd.random.uniform(shape=[batch_size,3,80,120]) # Channels FIRST - performance improvement. 
out = net(xx)

# Try also net.summary(xx), without hybridizing first
1 голос
/ 20 марта 2019

Хорошо, для тех из вас, у кого может быть похожая проблема, вот решение, которое я сам понял: проблема в том, что Keras и MXNet применяют сверточный слой к различным измерениям.Keras берет последнее измерение, в то время как MXNet использует первое.Простое решение состоит в том, чтобы изменить порядок размеров так, чтобы результат был таким же.В моем случае входной параметр X с размерами (3, 80, 120) дал бы мне тот же результат.

...