MXNET CNN+;LSTM保存/序列化为json

MXNET CNN+;LSTM保存/序列化为json,json,serialization,lstm,mxnet,Json,Serialization,Lstm,Mxnet,我发现如何正确定义mxnet,以便将该模型序列化/转换为json文件是一个艰难的过程 管道由CNN+biLSTM+CTC组成 我现在必须使用HybridBlock和hybridize(),但我似乎无法让它工作,或者它是否可行,或者是否有其他方法 我确信我对这方面的知识缺乏,我想知道是否有人能帮上忙 以下是python中的网络定义: NUM_HIDDEN = 200 NUM_CLASSES = 13550 NUM_LSTM_LAYER = 1 p_dropout = 0.5 SEQ_LEN = 3

我发现如何正确定义mxnet,以便将该模型序列化/转换为json文件是一个艰难的过程

管道由CNN+biLSTM+CTC组成

我现在必须使用HybridBlock和hybridize(),但我似乎无法让它工作,或者它是否可行,或者是否有其他方法

我确信我对这方面的知识缺乏,我想知道是否有人能帮上忙

以下是python中的网络定义:

NUM_HIDDEN = 200
NUM_CLASSES = 13550
NUM_LSTM_LAYER = 1
p_dropout = 0.5
SEQ_LEN = 32

def get_featurizer():
    featurizer = gluon.nn.HybridSequential()
    # conv layer
    featurizer.add(gluon.nn.Conv2D(kernel_size=(3,3), padding=(1,1), channels=32, activation="relu"))
    featurizer.add(gluon.nn.BatchNorm())

    ....
    featurizer.hybridize()
    return featurizer

class EncoderLayer(gluon.Block):
    def __init__(self, **kwargs):
        super(EncoderLayer, self).__init__(**kwargs)
        with self.name_scope():
            self.lstm = mx.gluon.rnn.LSTM(NUM_HIDDEN, NUM_LSTM_LAYER, bidirectional=True)
    def forward(self, x):
        x = x.transpose((0,3,1,2))
        x = x.flatten()
        x = x.split(num_outputs=SEQ_LEN, axis = 1) # (SEQ_LEN, N, CHANNELS)
        x = nd.concat(*[elem.expand_dims(axis=0) for elem in x], dim=0)
        x = self.lstm(x)
        x = x.transpose((1, 0, 2)) # (N, SEQ_LEN, HIDDEN_UNITS)
        return x

def get_encoder():
    encoder = gluon.nn.Sequential()
    encoder.add(EncoderLayer())
    encoder.add(gluon.nn.Dropout(p_dropout))
    return encoder

def get_decoder():
    decoder = mx.gluon.nn.Dense(units=ALPHABET_SIZE, flatten=False)
    decoder.hybridize()
    return decoder

def get_net():
    net = gluon.nn.Sequential()
    with net.name_scope():
        net.add(get_featurizer())
        net.add(get_encoder())
        net.add(get_decoder())
    return net
任何帮助都将不胜感激。
非常感谢。

对于Gluon中的模型,要导出到json,几乎没有什么要求:

  • 它需要是可杂交的,这意味着每个子块也应该是可杂交的,并且模型可以在两种模式下工作

  • 所有参数都应初始化。由于Gluon使用延迟参数初始化,这意味着在保存模型之前,应该至少向前传递一次

  • 我对您的代码做了一些修复,并在需要时引入了新的常量。最重要的变化是:

  • 如果可以避免,请不要使用split,因为它会返回ndarray列表。使用“重塑”,这同样适用于符号

  • 从MXNet的1.3.0版本开始,LSTM也是可混合的,因此您可以将其包装在一个混合块中,而不仅仅是一个块

  • 使用杂交方法

  • 下面是调整后的代码,底部有一个示例,说明如何保存模型以及如何重新加载模型。您可以在中找到更多信息

    import mxnet as mx
    from mxnet import gluon
    from mxnet import nd
    
    BATCH_SIZE = 1
    CHANNELS = 100
    ALPHABET_SIZE = 1000
    NUM_HIDDEN = 200
    NUM_CLASSES = 13550
    NUM_LSTM_LAYER = 1
    p_dropout = 0.5
    SEQ_LEN = 32
    HEIGHT = 100
    WIDTH = 100
    
    
    def get_featurizer():
        featurizer = gluon.nn.HybridSequential()
        featurizer.add(
            gluon.nn.Conv2D(kernel_size=(3, 3), padding=(1, 1), channels=32, activation="relu"))
        featurizer.add(gluon.nn.BatchNorm())
    
        return featurizer
    
    
    class EncoderLayer(gluon.HybridBlock):
        def __init__(self, **kwargs):
            super(EncoderLayer, self).__init__(**kwargs)
    
            with self.name_scope():
                self.lstm = mx.gluon.rnn.LSTM(NUM_HIDDEN, NUM_LSTM_LAYER, bidirectional=True)
    
        def hybrid_forward(self, F, x):
            x = x.transpose((0, 3, 1, 2))
            x = x.flatten()
            x = x.reshape(shape=(SEQ_LEN, -1, CHANNELS)) #x.split(num_outputs=SEQ_LEN, axis=1)  # (SEQ_LEN, N, CHANNELS)
            x = self.lstm(x)
            x = x.transpose((1, 0, 2))  # (N, SEQ_LEN, HIDDEN_UNITS)
            return x
    
    
    def get_encoder():
        encoder = gluon.nn.HybridSequential()
        encoder.add(EncoderLayer())
        encoder.add(gluon.nn.Dropout(p_dropout))
        return encoder
    
    
    def get_decoder():
        decoder = mx.gluon.nn.Dense(units=ALPHABET_SIZE, flatten=False)
        return decoder
    
    
    def get_net():
        net = gluon.nn.HybridSequential()
    
        with net.name_scope():
            net.add(get_featurizer())
            net.add(get_encoder())
            net.add(get_decoder())
    
        return net
    
    
    if __name__ == '__main__':
        net = get_net()
        net.initialize()
        net.hybridize()
    
        fake_data = mx.random.uniform(shape=(BATCH_SIZE, HEIGHT, WIDTH, CHANNELS))
        out = net(fake_data)
    
        net.export("mymodel")
    
        deserialized_net = gluon.nn.SymbolBlock.imports("mymodel-symbol.json", ['data'],
                                                        "mymodel-0000.params", ctx=mx.cpu())
    
        out2 = deserialized_net(fake_data)
        # just to check that we get the same results
        assert (out - out2).sum().asscalar() == 0