ONNX Runtime C# не запоминает состояние сетей LSTM - PullRequest
2 голосов
/ 12 февраля 2020

Я экспортировал обученную нейронную сеть LSTM из в этом примере из Matlab в ONNX. Затем я пытаюсь запустить эту сеть с ONNX Runtime C#. Однако, похоже, что я делаю что-то не так, и сеть не помнит своего состояния на предыдущем шаге.

Сеть должна реагировать на входные последовательности следующими выходными данными:

  • Ввод: [0,258881980200294]; Выход: [0.311363101005554]

  • Вход: [1.354147904050896]; Выход: [1.241550326347351]

  • Вход: [0.258881980200294, 1.354147904050896]; Вывод: [0.311363101005554, 1.391810059547424]

Первые два примера - это последовательности, состоящие только из одного элемента. Последний пример - это последовательность двух элементов. Эти выходы рассчитаны в Matlab. Я сбрасываю сеть в Matlab между выполнением ее с каждой новой последовательностью.

Затем я пытаюсь запустить ту же сеть, используя ONNX Runtime. Это мой C# код:

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using System;
using System.Collections;
using System.Collections.Generic;

namespace OnnxTest
{
    public sealed class OnnxRuntimeTest
    {
        public OnnxRuntimeTest(ILogger logger)
        {
            this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        private const string modelPath = @"E:\Documents\MATLAB\NeuralNetworkExport\onnx_lstm_medic.onnx";
        private readonly ILogger logger;

        public void Run()
        {
            using (var session = new InferenceSession(modelPath))
            {
                // Input values from the example above:
                var input1 = GenerateInputValue(0.258881980200294f);
                var input2 = GenerateInputValue(1.35414790405090f);

                // I create a container to push the first value:
                var container = new List<NamedOnnxValue>() { input1 };

                //Run the inference
                using (var results = session.Run(container))  
                {
                    // dump the results
                    foreach (var r in results)
                    {
                        logger.Log(string.Format("Output for {0}", r.Name));
                        logger.Log(r.AsTensor<float>().GetArrayString());

                        // Outputs 0,3113631 - as expected
                    }
                }


                // The same code to push the second value:
                var container2 = new List<NamedOnnxValue>() { input2 };

                using (var results = session.Run(container2)) 
                {
                    // dump the results
                    foreach (var r in results)
                    {
                        logger.Log(string.Format("Output for {0}", r.Name));
                        logger.Log(r.AsTensor<float>().GetArrayString());

                        // Outputs 1,24155 - as though this is the first input value
                    }
                }

            }
        }

        private NamedOnnxValue GenerateInputValue(float inputValue)
        {
            float[] inputData = new float[] { inputValue };
            int[] dimensions = new int[] { 1, 1, 1 };
            var tensor = new DenseTensor<float>(inputData, dimensions);
            return NamedOnnxValue.CreateFromTensor("sequenceinput", tensor);
        }

Как видите, второй сеанс запускается с результатом 1,24155 вместо ожидаемого значения (1,391810059547424), как если бы сеть все еще находилась в исходном состоянии. Похоже, я не сохраняю состояние LSTM-сети, но не могу найти, как это сделать в документации.

Итак, кто-нибудь знает, как заставить LSTM сохранять свое состояние?

...