如何将CNN从keras转换为mxnet?

时间:2019-03-15 16:09:39

标签: python keras mxnet

我遇到以下问题:我在Keras中有一个脚本,其工作原理像一个超级按钮。我现在想将此脚本转换为MXNet。 Keras中的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)“

我认为这与内核和MaxPooling2D层的尺寸有关,但是我不理解该错误,因为我认为我实际上正在构建与Keras中相同的网络。

为了完整性:我的输入变量X的尺寸为(80、120、3)。

我非常感谢Keras / MXNet专业人士的帮助。

4 个答案:

答案 0 :(得分:2)

我定义模型的功能:

# 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

然后,每当预测类时,我都会使用mxnet的softmax函数:

y_pred = nd.softmax(net(data[0]))

答案 1 :(得分:2)

这是使用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

答案 2 :(得分:2)

要添加到以前的文章中,还有另一条路径,您可以尝试在Keras中简单地使用MXNet后端。请参阅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"
}

答案 3 :(得分:1)

好的,对于那些可能遇到类似问题的人,这是我自己想出的解决方案:问题是Keras和MXNet将卷积层应用于不同的维度。 Keras采用最后一个维度,而MXNet使用第一个维度。一个简单的解决方案是更改尺寸顺序,以使结果相同。以我为例,输入参数X的尺寸为(3、80、120)会得到相同的结果。