【问题标题】:How to convert a CNN from keras to mxnet?如何将 CNN 从 keras 转换为 mxnet?
【发布时间】:2019-03-15 16:09:39
【问题描述】:

我有以下问题:我在 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]

我认为这与内核和 MaxPooling2D 层的尺寸有关,但我不明白这个错误,因为我认为我实际上在构建与 Keras 相同的网络。

为了完整性:我的输入变量 X 的维度为 (80, 120, 3)。

非常感谢一些 Keras/MXNet 专家的帮助。

【问题讨论】:

    标签: python keras mxnet


    【解决方案1】:

    我定义模型的函数:

    # 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]))
    

    【讨论】:

      【解决方案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】:

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

        【讨论】:

        • 您好 Foivos,非常感谢您的回答!我只是想完成当前的培训,但是一旦完成,我将尝试您的解决方案。它看起来很有希望。结果出来后我会尽快回复你。无论如何,非常感谢您的努力。
        • 很高兴,请尝试 mxnet 论坛以解决类似问题,因为它专门用于 mxnet,您会在那里获得更多帮助。
        • 您好 Foivos,老实说,我不太确定网络是否也在做同样的事情。培训结束后,我为 keras 和 mxnet 创建了一个类激活映射 (CAM),以向我展示有关欧洲的相关区域。不幸的是,我得到了不同的结果。但也许只有我的实现有问题?我将在下面添加我的代码。
        • 嗨 Stefan,您创建 CAM 的方式在两个网络中可能不同,请发布您的两个版本的代码以发现任何差异。我建议在论坛中提问,因为它在扩展答案方面更加灵活。
        • Hallo Foivos, ich bin deinem Rat gefolgt und habe eine 讨论 im mxnet-Forum gestartet: discuss.mxnet.io/t/how-to-convert-a-cnn-from-keras-to-mxnet/….
        【解决方案4】:

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

        【讨论】:

        • 这是正确的,mxnet 首先需要渠道。此外,在您的 mxnet 解决方案中,您需要在卷积核的定义中手动添加 padding=1(以实现 padding='same')。
        • @Foivos 感谢您的回答。我发现,我的 mxnet 网络与 keras 网络不太匹配。此外,要在 mxnet 中实现 padding='same',必须将 padding 设置为 kernel_size//2(参见discuss.mxnet.io/t/…discuss.mxnet.io/t/pooling-and-convolution-with-same-mode/528)。而且由于mxnet中不存在Softmax激活函数,所以后来我也不得不使用它。
        猜你喜欢
        • 1970-01-01
        • 2021-04-27
        • 1970-01-01
        • 1970-01-01
        • 2022-01-02
        • 2021-07-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-27
        相关资源
        最近更新 更多