使用 deeplearning4j 的字符时间序列自动编码器

Autoencoder for Character Time-Series with deeplearning4j

我正在尝试在字符序列(字符串)上创建和训练 LSTM 自动编码器。这只是为了降维,即能够将最多 T=1000 个字符的字符串表示为大小为 N 的固定长度向量。为了这个例子,让 N = 10。每个字符都是单热编码的大小为 validChars 的数组(在我的例子中为 validChars = 77)。

我正在使用 ComputationalGraph,以便以后能够删除解码器层并将剩余的用于编码。通过查看 dl4j-examples,我想到了这个:

    ComputationGraphConfiguration conf = new NeuralNetConfiguration.Builder()
            .seed(12345)
            .l2(0.0001)
            .weightInit(WeightInit.XAVIER)
            .updater(new Adam(0.005))
            .graphBuilder()
            .addInputs("input")
            .addLayer("encoder1", new LSTM.Builder().nIn(dictSize).nOut(250)
                    .activation(Activation.TANH).build(), "input")
            .addLayer("encoder2", new LSTM.Builder().nIn(250).nOut(10)
                    .activation(Activation.TANH).build(), "encoder1")

            .addVertex("fixed", new PreprocessorVertex(new RnnToFeedForwardPreProcessor()), "encoder2")
            .addVertex("sequenced", new PreprocessorVertex(new FeedForwardToRnnPreProcessor()), "fixed")

            .addLayer("decoder1", new LSTM.Builder().nIn(10).nOut(250)
                    .activation(Activation.TANH).build(), "sequenced")
            .addLayer("decoder2", new LSTM.Builder().nIn(250).nOut(dictSize)
                    .activation(Activation.TANH).build(), "decoder1")

            .addLayer("output", new RnnOutputLayer.Builder()
                    .lossFunction(LossFunctions.LossFunction.MCXENT)
                    .activation(Activation.SOFTMAX).nIn(dictSize).nOut(dictSize).build(), "decoder2")

            .setOutputs("output")
            .backpropType(BackpropType.TruncatedBPTT).tBPTTForwardLength(tbpttLength).tBPTTBackwardLength(tbpttLength)
            .build();

有了这个,我希望特征的数量遵循以下路径: [77,T] -> [250,T] -> [10,T] -> [10] -> [10,T] -> [250,T] -> [77,T]

我已经训练了这个网络,并像这样删除了解码器部分:

    ComputationGraph encoder = new TransferLearning.GraphBuilder(net)
            .setFeatureExtractor("fixed")
            .removeVertexAndConnections("sequenced")
            .removeVertexAndConnections("decoder1")
            .removeVertexAndConnections("decoder2")
            .removeVertexAndConnections("output")
            .addLayer("output", new ActivationLayer.Builder().activation(Activation.IDENTITY).build(), "fixed")
            .setOutputs("output")
            .setInputs("input")
            .build();

但是,当我使用此编码器对长度为 1000 的字符串进行编码时,它会输出形状为 [1000, 10] 的 NDArray,而不是长度为 10 的一维向量。我的目的是表示整个 1000 个字符一个长度为 10 的向量的序列。我错过了什么?

没有人回答这个问题,我在dl4j-examples 中找到了答案。因此,无论如何,post 会不会对某人有所帮助。

编码器和解码器 LSTM 之间的部分应该如下所示:

            .addVertex("thoughtVector",
                    new LastTimeStepVertex("encoderInput"), "encoder")
            .addVertex("duplication",
                    new DuplicateToTimeSeriesVertex("decoderInput"), "thoughtVector")
            .addVertex("merge",
                    new MergeVertex(), "decoderInput", "duplication")

重要的是,我们使用 LastTimeStep 进行多对一,然后使用 DuplicateToTimeSeries 进行一对多。这样'thoughtVector'实际上是整个序列的单个向量表示。

在此处查看完整示例:https://github.com/deeplearning4j/dl4j-examples/blob/master/dl4j-examples/src/main/java/org/deeplearning4j/examples/recurrent/encdec/EncoderDecoderLSTM.java,但请注意该示例处理的是词级序列。我上面的网络使用字符级序列,但想法是一样的。