首页 > 解决方案 > 混合 mxnet.np.concatenate

问题描述

我正在尝试使在线书籍d2l.ai中的 GoogLeNet/InceptionV1 实现与杂交兼容。但是,我目前面临mx.np.concatenate. 这是网络实现的完整最小示例:

import d2l # d2l.ai book code
import mxnet as mx
from mxnet import gluon, metric, np, npx
from mxnet.gluon import nn
npx.set_np()

ctx_list = [npx.gpu(i) for i in range(npx.num_gpus())]
mx.random.seed(42, ctx='all')

class Inception(nn.HybridBlock):
    # c1- c4 are the number of output channels for each layer in the path
    def __init__(self, c1, c2, c3, c4, **kwargs):
        super().__init__(**kwargs)
        # Path 1 is a single 1 x 1 convolutional layer
        self.p1_1 = nn.Conv2D(c1, kernel_size=1, activation='relu')
        # Path 2 is a 1 x 1 convolutional layer followed by a 3 x 3
        # convolutional layer
        self.p2_1 = nn.Conv2D(c2[0], kernel_size=1, activation='relu')
        self.p2_2 = nn.Conv2D(c2[1], kernel_size=3, padding=1, activation='relu')
        # Path 3 is a 1 x 1 convolutional layer followed by a 5 x 5
        # convolutional layer
        self.p3_1 = nn.Conv2D(c3[0], kernel_size=1, activation='relu')
        self.p3_2 = nn.Conv2D(c3[1], kernel_size=5, padding=2,
                              activation='relu')
        # Path 4 
        self.p4_1 = nn.MaxPool2D(pool_size=3, strides=1, padding=1)
        self.p4_2 = nn.Conv2D(c4, kernel_size=1, activation='relu')

    def hybrid_forward(self, F, x):
        p1 = self.p1_1(x)
        p2 = self.p2_2(self.p2_1(x))
        p3 = self.p3_2(self.p3_1(x))
        p4 = self.p4_2(self.p4_1(x))
        # Concatenate the outputs on the channel dimension
        return np.concatenate((p1, p2, p3, p4), axis=1)
        #return F.concat(p1, p2, p3, p4, dim=1) # doesn't work either

class GoogLeNet(nn.HybridBlock):
    """
    GoogLeNet uses a stack of a total of 9 inception blocks and global average pooling
    """
    def __init__(self, classes=1000, **kwargs):
        super().__init__(**kwargs)

        self.net = nn.HybridSequential()
        
        # First component uses a 64-channel 7 x 7 convolutional layer
        self.net.add(
            nn.Conv2D(64, kernel_size=7, strides=2, padding=3, activation='relu'),
            nn.MaxPool2D(pool_size=3, strides=2, padding=1)
        )

        # Second component uses two convolutional layers:
        # first a 64-channel 1 x 1 convolutional layer,
        # then a 3 x 3 convolutional layer that triples the number of channels.
        # This corresponds to the second path in the Inception block.
        self.net.add(
            nn.Conv2D(64, kernel_size=1, activation='relu'),
            nn.Conv2D(192, kernel_size=3, padding=1, activation='relu'),
            nn.MaxPool2D(pool_size=3, strides=2, padding=1)
        )
    
        # Third component connects to complete Inception blocks in series
        # The number of output channels of the first block is 64+128+32+32=256
        # and the ratio to the output channels of the four paths is 2:4:1:1.
        # The number of output channels of the second block is 128+192+96+64=480
        # and the ratio to the output channels per path is 4:6:3:2
        self.net.add(
            Inception(64, (96, 128), (16, 32), 32),
            Inception(128, (128, 192), (32, 96), 64)
        )

        # Fourth component connects five Inception blocks in series
        self.net.add(
            Inception(196, (96, 208), (16, 48), 64),
            Inception(160, (112, 224), (24, 64), 64),
            Inception(128, (128, 256), (24, 64), 64),
            Inception(112, (144, 288), (32, 64), 64),
            Inception(256, (160, 320), (32, 128), 128),
            nn.MaxPool2D(pool_size=3, strides=2, padding=1)
        )

        # Fifth component has two Inception blocks followed by output layer
        self.net.add(
            Inception(256, (160, 320), (32, 128), 128),
            Inception(384, (192, 384), (48, 128), 128),
            nn.Dense(classes)
        )
    
    def hybrid_forward(self, F, x):
        x = self.net(x)
        return x


net = GoogLeNet(classes=10)
net.initialize()
net.hybridize()

train_dl, valid_dl = d2l.load_data_fashion_mnist(batch_size=128, resize=96)

loss = gluon.loss.SoftmaxCrossEntropyLoss()
optimizer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.1})

d2l.train_ch13(net, train_iter=train_dl, test_iter=valid_dl, 
               loss=loss, trainer=optimizer, 
               num_epochs=10, ctx_list=ctx_list)

随着return np.concatenate((p1, p2, p3, p4), axis=1)我得到错误:

AssertionError:位置参数必须具有 NDArray 类型,但得到 <_Symbol conv3_relu_fwd>

return F.concat(p1, p2, p3, p4, dim=1)得到了错误:

TypeError: 在后端注册的运算符 concat 在 Python 中称为 concat。这是一个传统的运算符,它只能接受传统的 ndarray,同时接收一个 MXNet numpy ndarray。请在 numpy ndarray 上调用 as_nd_ndarray() 将其转换为旧版 ndarray,然后将转换后的数组提供给此运算符。

源实现使用mxnet.gluon.contrib.nn.HybridConcurrent,但我认为这可能是旧的,现在应该可以在没有 contrib 的情况下实现混合 concat 吗?

任何关于我如何修改它以进行杂交的建议将不胜感激!

标签: pythonmxnetconv-neural-networkgluon

解决方案


事实证明这是F.np.concatenate有效的。


推荐阅读