Реализация множественной нелинейной регрессии с пользовательской функцией в C # - PullRequest
0 голосов
/ 06 июня 2019

Я не могу получить Accord.Net для оценки коэффициентов для пользовательской функции с двумя независимыми переменными и одним выходом.Он просто выводит те же значения, которые я дал для моих начальных оценок коэффициентов.

Немного предыстории: я пытаюсь использовать множественную нелинейную регрессию для оценки наилучших значений для коэффициентов в следующей функции:

Z = A+1/(1/(X/256*B+3*C)+1/(Y/1024*D+2*E))

Независимыми переменными являются X и Y с Z в качестве выхода.У меня есть наилучшее предположение для коэффициентов, которые я хотел бы использовать для сокращения вычислительных требований:

A = 20

B = 10000

C = 50

D = 50000

E = 60

Я успешно использовал набор инструментов MatLab для подбора кривой, чтобы получить хорошее соответствие, но мне нужно иметь возможность автоматизировать это в C # с помощью Visual Studio, так как процесс будетбыть сделано много раз с различными измерениями.Я нашел несколько многообещающих пакетов Nuget, в которых есть некоторые инструменты машинного обучения, и я оказался на Accord.Net.

  double[,] data =
  {
    { 0,    0,    89.05295649 },
    { 128,  0,    123.2124033 },
    { 255,  0,    124.1087122 },
    { 0,    512,  196.9215557 },
    { 128,  512,  4270.278414 },
    { 255,  512,  7149.23716  },
    { 0,    1023, 197.4947063 },
    { 128,  1023, 4672.482543 },
    { 255,  1023, 8360.098631 }
  };

  // Extract inputs and outputs
  double[][] inputs = new double[2][];

  inputs[0] = data.GetColumn(0);
  inputs[1] = data.GetColumn(1);

  double[] outputs = data.GetColumn(2);

  var nls = new NonlinearLeastSquares()
  {

    NumberOfParameters = 5,

    // Initialize to ideal values from A+1/(1/(X/256*B+3*C)+1/(Y/1024*D+2*E))
    StartValues = new[] { 20.0, 10000.0, 50.0, 50000.0, 60.0 },

    Function = (w, x) => w[0] + 1 / (1 / (x[0] / 256 * w[1] + 3 * w[2]) + 1 / (x[1] / 1024 * w[3] + 2 * w[4])),

    // Derivative in respect to the weights:
    Gradient = (w, x, r) =>
    {
      // w.r.t a: A https://www.wolframalpha.com/input/?i=diff+A%2B1%2F(1%2F(X%2F256*B%2B3*C)%2B1%2F(Y%2F1024*D%2B2*E))+w.r.t.+A
      r[0] = 1;
      // w.r.t b: B https://www.wolframalpha.com/input/?i=diff+A%2B1%2F(1%2F(X%2F256*B%2B3*C)%2B1%2F(Y%2F1024*D%2B2*E))+w.r.t.+B
      r[1] = x[0] * ((2048 * w[4] + w[3] * x[1]) * (2048 * w[4] + w[3] * x[1])) / (256 * ((3072 * w[2] + 2048 * w[4] + 4 * w[1] * x[0] + w[3] * x[1]) * (3072 * w[2] + 2048 * w[4] + 4 * w[1] * x[0] + w[3] * x[1])));
      // w.r.t c: C https://www.wolframalpha.com/input/?i=diff+A%2B1%2F(1%2F(X%2F256*B%2B3*C)%2B1%2F(Y%2F1024*D%2B2*E))+w.r.t.+C
      r[2] = 3 * ((2048 * w[4] + w[3] * x[1]) * (2048 * w[4] + w[3] * x[1])) / ((3072 * w[2] + 2048 * w[4] + 4 * w[1] * x[0] + w[3] * x[1]) * (3072 * w[2] + 2048 * w[4] + 4 * w[1] * x[0] + w[3] * x[1]));
      // w.r.t c: D https://www.wolframalpha.com/input/?i=diff+A%2B1%2F(1%2F(X%2F256*B%2B3*C)%2B1%2F(Y%2F1024*D%2B2*E))+w.r.t.+D
      r[3] = x[1] * ((768 * w[2] + w[1] * x[0]) * (769 * w[2] + w[1] * x[0])) / 64 * ((3072 * w[2] + 2048 * w[4] + 4 * w[1] * x[0] + w[3] * x[1]) * (3072 * w[2] + 2048 * w[4] + 4 * w[1] * x[0] + w[3] * x[1]));
      // w.r.t c: E https://www.wolframalpha.com/input/?i=diff+A%2B1%2F(1%2F(X%2F256*B%2B3*C)%2B1%2F(Y%2F1024*D%2B2*E))+w.r.t.+E
      r[4] = 32 * ((768 * w[2] + w[1] * x[0]) * (768 * w[2] + w[1] * x[0])) / ((3072 * w[2] + 2048 * w[4] + 4 * w[1] * x[0] + w[3] * x[1]) * (3072 * w[2] + 2048 * w[4] + 4 * w[1] * x[0] + w[3] * x[1]));
    },


    Algorithm = new LevenbergMarquardt()
    {
      MaxIterations = 20000,
      Tolerance = 0
    }

  };

  var regression = nls.Learn(inputs, outputs);

  var prediction = regression.Transform(new double[] { 200, 350 });

Я ожидаю увидеть что-то ближе к следующему:

A = 27.85

B = 9886.98

C = 56.87

D = 48581.00

E = 48.47

Вывод просто дает мне исходные оценочные значения даже после выполнения всех 20000 итераций.Пример на веб-сайте Accord показывает это для одной независимой переменной с гораздо более простыми градиентами, поэтому трудно сказать, работает ли моя проблема с их классом NonLinearLeastSquares.Может быть, есть лучшее решение?Я хотел бы придерживаться того, что доступно в Nuget, так как его нужно будет поддерживать в нескольких географически разделенных системах.

ОБНОВЛЕНИЕ: Я изменил квадратные термины в градиентах, чтобы использовать метод Math.Pow, и это по крайней мерепривело к изменению коэффициентов.Однако это очень неточно.Я заметил, что коэффициент B по-прежнему не меняется независимо от того, что я выбираю для начальной точки, как будто что-то не так с кодом, который я использую для градиента r [1].Но я не вижу в этом ничего плохого.

    Gradient = (w, x, r) =>
    {
      r[0] = 1;
      //(X (2048 E + D Y)^2)/(256 (3072 C + 2048 E + 4 B X + D Y)^2)
      r[1] = x[0] * Math.Pow(2048.0 * w[4] + w[3] * x[1], 2.0) / (256 * Math.Pow(3072 * w[2] + 2048.0 * w[4] + 4 * w[1] * x[0] + w[3] * x[1], 2.0));
      //(3 (2048 E + D Y)^2)/(3072 C + 2048 E + 4 B X + D Y)^2
      r[2] = 3 * Math.Pow(2048.0 * w[4] + w[3] * x[1], 2.0) / Math.Pow(3072.0 * w[2] + 2048.0 * w[4] + 4 * w[1] * x[0] + w[3] * x[1], 2.0);
      //((768 C + B X)^2 Y)/(64 (3072 C + 2048 E + 4 B X + D Y)^2)
      r[3] = (Math.Pow(768 * w[2] + w[1] * x[0], 2.0) * x[1]) / (64 * Math.Pow(3072.0 * w[2] + 2048.0 * w[4] + 4 * w[1] * x[0] + w[3] * x[1], 2.0));
      //(32 (768 C + B X)^2)/(3072 C + 2048 E + 4 B X + D Y)^2
      r[4] = 32 * Math.Pow(768 * w[2] + w[1] * x[0], 2.0) / Math.Pow(3072.0 * w[2] + 2048.0 * w[4] + 4 * w[1] * x[0] + w[3] * x[1], 2.0);
    },

A: 44469.142086254556

B: -243110.88545066063

C: -303081.17150483071

D: 50000

E: -23237.027101692031

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...