【问题标题】:Run Keras.NET models in different threads in C#在 C# 的不同线程中运行 Keras.NET 模型
【发布时间】:2022-01-04 03:00:54
【问题描述】:

由于“Keras.Models.Sequential”需要一点时间来准备使用,这会使带有用户界面的程序冻结片刻,显然会惹恼用户。
因此,我尝试在后台的不同线程中创建模型、拟合和预测数据,然后将结果返回到主用户界面。

我尝试创建一个模型并将其放入不同的线程中。然后将模型插入到主线程的全局变量中。但是,如果我尝试从全局变量的模型中进行预测,它会永远冻结用户界面而没有任何结果。

现在我正在使用以下方法:
主要功能例如:

public int main() 
    {
         Thread modelThread1 = new Thread(() => runModel(np.array(new float[] { 0, 1, 4, 6 }), np.array(new float[] { 0, 1, 4, 6 })));
         modelThread1.Start();
         Thread modelThread2 = new Thread(() => runModel(np.array(new float[] { 0, 1, 2, 3 }), np.array(new float[] { 1, 3, 5, 7 })));
         modelThread2.Start();
    }

这是一个简单的函数:

private void runModel(NDarray xs, NDarray ys)
    {
        Keras.Models.Sequential model = new Keras.Models.Sequential();
        model.Add(new Dense(1, input_shape: new Shape(1)));
        model.Compile(optimizer: "sgd", loss: "mean_squared_error");
        model.Fit(xs, ys, epochs: 500, verbose: 0);

        Console.WriteLine(model.Predict(new float[] { 11 }, verbose: 0));
    }

如果我运行它,它会显示以下错误:

System.AccessViolationException: '试图读取或写入受保护的内存。这通常表明其他内存已损坏。

【问题讨论】:

    标签: c# multithreading tensorflow keras


    【解决方案1】:

    我刚刚找到了一种方法。
    经过一番研究和试验,我发现 C# Tensorflow 工具如“Keras.Models.Sequential”和“Numpy”必须在同一个线程上运行。因此,我只需要在后台创建一个线程,它处理 tensorflow 的东西,并让它等待来自主用户界面的指令。
    这样做的方式在this post中回答。

    在我的示例中,我创建了一个名为“TFBackThread”的类:

    class TFBackThread
    {
        public readonly AutoResetEvent _signal = new AutoResetEvent(false);
        public readonly ConcurrentQueue<object[]> _queue = new ConcurrentQueue<object[]>();
    
        public TFBackThread()
        {
        }
    
        public void ThreadServer()
        {
            // Initialize the model
            Keras.Models.Sequential model = new Keras.Models.Sequential();
            model.Add(new Dense(1, input_shape: new Shape(1)));
            model.Compile(optimizer: "sgd", loss: "mean_squared_error");
            while (true)
            {
                _signal.WaitOne();
    
                object[] item = null;
                while (_queue.TryDequeue(out item))
                {
                    // Check which function is selected
                    switch ((string)item[0])
                    {
                        case "fit":
                            fit(model, np.array((float[])item[1]), np.array((float[])item[2]), (int)item[3]);
                            break;
                        case "predict":
                            predict(model, (float[])item[1]);
                            break;
                    }
                }
            }
        }
    
        private void fit(Keras.Models.Sequential model, NDarray xs, NDarray ys, int epochs)
        {
            model.Fit(xs, ys, epochs: epochs, verbose: 0);
        }
    
        private void predict(Keras.Models.Sequential model, float[] x)
        {
            Console.WriteLine(model.Predict(x, verbose: 0));
            // Return result to main user interface
        }
    }
    

    现在我使用这个类的方式如下:

        TFBackThread tFBackThread;
        public MainForm()
        {
            InitializeComponent();
    
            tFBackThread = new TFBackThread();
            Thread TFThread = new Thread(() => tFBackThread.ThreadServer());
            TFThread.Start();
            tFBackThread._queue.Enqueue(new object[] { "fit", new float[] { 0, 1, 2, 3 }, new float[] { 1, 3, 5, 7 }, 500 });
            tFBackThread._queue.Enqueue(new object[] { "predict", new float[] { 11 } });
            tFBackThread._signal.Set();
        }
    

    您甚至可以从事件处理程序中调用它,如下所示:

    private void Button_Click(object sender, EventArgs e)
        {
            tFBackThread._queue.Enqueue(new object[] { "predict", new float[] { 23 } });
            tFBackThread._signal.Set();
        }
    

    这不是我要找的答案。但是,至少这个技巧可以减少用户界面的线程冻结。
    我希望这可能对将来的某些人有所帮助。或者任何人都可以分享更好的方法。

    【讨论】:

      猜你喜欢
      • 2020-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多