Обсуждение статьи "Нейронные сети обратного распространения ошибки на матрицах MQL5" - страница 2

 
Lorentzos Roussos #:

Да, но значения активации передаются в функцию деривации, в то время как она ожидает значения до активации. Вот что я хочу сказать.

Думаю, вы ошибаетесь. Деривация вычисляется по формуле, которую я привел выше: y'(x) = y(x)*(1-y(x)), где x - состояние нейрона до активации, а y(x) - результат применения функции активации. Вы не используете значение до активации для вычисления производной, вместо этого используйте результат активации (y). Вот упрощенный тест:

double derivative(double output)
{
  return output * (1 - output);
}

void OnStart()
{
  vector x = {{0.68}};
  vector y;
  x.Activation(y, AF_SIGMOID);                            // получили результат активации/сигмоида в виде "y(x)" в y[0]
  vector d;
  x.Derivative(d, AF_SIGMOID);                            // получили производную сигмоида по x
  Print(derivative(x[0]), " ", derivative(y[0]), " ", d); // 0.2176 0.2231896389723258 [0.2231896389723258]
}
 
Stanislav Korotky #:

Думаю, вы ошибаетесь. Производная вычисляется по формуле, которую я привел выше: y'(x) = y(x)*(1-y(x)), где x - состояние нейрона до активации, а y(x) - результат применения функции активации. Вы не используете значение до активации для вычисления производной, вместо этого используйте результат активации (y). Вот упрощенный тест:

Да, это то, о чем я говорю, правильная производная совпадает с производной, вызванной из значений x.

В обратной функции вы вызываете эквивалентную y.Derivative(d,AF_SIGMOID).

В функции backprop в статье выходной матрицей является y. Я не думаю, что вы храните эквивалент x в матрице, чтобы вызвать производную от него.

(опять же, в соответствии с функцией mq)

--

Даже в вашем примере вы вызываете производную от x, я готов поспорить, что сначала вы ввели y, а потом "ойкнули".

Просто скажите им об этом на русском форуме. Это сэкономит многим людям кучу времени, если они смогут добавить это в документацию.

Спасибо

 
Stanislav Korotky #:

Думаю, вы ошибаетесь. Производная вычисляется по формуле, которую я привел выше: y'(x) = y(x)*(1-y(x)), где x - состояние нейрона до активации, а y(x) - результат применения функции активации. Вы не используете значение до активации для вычисления производной, вместо этого используйте результат активации (y). Вот упрощенный тест:

Позвольте мне упростить это.

Вот ваш пример

double derivative(double output)
{
  return output * (1 - output);
}

void OnStart()
{
  vector x = {{0.68}};
  vector y;
  x.Activation(y, AF_SIGMOID);                            // получили результат активации/сигмоида в виде "y(x)" в y[0]
  vector d;
  x.Derivative(d, AF_SIGMOID);                            // получили производную сигмоида по x
  Print(derivative(x[0]), " ", derivative(y[0]), " ", d); // 0.2176 0.2231896389723258 [0.2231896389723258]
}

В вашем примере вы вызываете x.Derivative, чтобы заполнить вектор производных d.

Вы не вызываете y.Derivative для заполнения производных, почему? Потому что он возвращает неправильные значения. (и вы, вероятно, видели это, поэтому и использовали x.Derivative).

Что такое y? Активационные значения x.

Поэтому, когда вы делаете это:

x.Activation(y, AF_SIGMOID);  

Вы заполняете y значениями активации x, но вызываете производную по x, а не по y. (что правильно согласно функции mql5).

В вашей статье в прямой передаче temp - это x

matrix temp = outputs[i].MatMul(weights[i]);

А y - это значения активации x. Что это за матрица?

temp.Activation(outputs[i + 1], i < n - 1 ? af : of)

Выходы. В статье матрица y ( от которой вы не вызываете производную в примере) - это матрица выходов .

(то, что мы видим в коде выше - это эквивалент x.Activation(y,AF) из примера, который заполняет y значениями активации).

В вашем коде back prop вы не вызываете x.Derivative, потому что x(матрица temp = outputs[i].MatMul(weights[i]);)

нигде не хранится и вы не можете его вызвать. Вы вызываете эквивалент y.Derivative, который возвращает неверные значения

outputs[n].Derivative(temp, of)
outputs[i].Derivative(temp, af)

потому что y имеет значения активации.

Опять же, в соответствии с функцией mql5.

Таким образом, в вашем примере вы используете правильный вызов, а в вашей статье - неправильный.

Будьте здоровы

 

Значит, ты хочешь это:

   bool backProp(const matrix &target)
   {
      if(!ready) return false;
   
      if(target.Rows() != outputs[n].Rows() ||
         target.Cols() != outputs[n].Cols())
         return false;
      
      // выходной слой
      matrix temp;
      //*if(!outputs[n].Derivative(temp, of))
      //* Возвращаем false;
      if(!outputs[n - 1].MatMul(weights[n - 1]).Derivative(temp, of))
         return false;
      matrix loss = (outputs[n] - target) * temp; // запись данных в строке
     
      for(int i = n - 1; i >= 0; --i) // для каждого слоя, кроме выходного
      {
         //*// remove unusable pseudo-errors for neurons, added as constant bias source
         //*// (in all layers except for the last (where it wasn't added))
         //*if(i < n - 1) loss.Resize(loss.Rows(), loss.Cols() - 1);
         #ifdef  BATCH_PROP
         matrix delta = speed[i] * outputs[i].Transpose().MatMul(loss);
         adjustSpeed(speed[i], delta * deltas[i]);
         deltas[i] = delta;
         #else
         matrix delta = speed * outputs[i].Transpose().MatMul(loss);
         #endif
         
         //*if(!outputs[i].Derivative(temp, af))
         //* Возвращаем false;
         //*loss = loss.MatMul(weights[i].Transpose()) * temp;
         if(i > 0) // обратное распространение потерь на предыдущие слои
         {
            if(!outputs[i - 1].MatMul(weights[i - 1]).Derivative(temp, af))
               return false;
            matrix mul = loss.MatMul(weights[i].Transpose());
            // удаляем ненужные псевдоошибки для нейронов, добавленных в качестве источника постоянного смещения
            mul.Resize(mul.Rows(), mul.Cols() - 1);
            loss = mul * temp;
         }
         
         weights[i] -= delta;
      }
      return true;
   }

Я подумаю об этом.

 
Stanislav Korotky #:

Итак, вам нужно это:

Я подумаю об этом.

На первый взгляд это выглядит нормально, да. Вычисление на месте быстрее, чем хранение, я полагаю.

👍

 
Lorentzos Roussos #:

На первый взгляд это выглядит нормально, да. Вычисления на месте происходят быстрее, чем при хранении, я полагаю.

Я думаю, что знаю причину, по которой она изначально кодируется через выход активационной функции. Во всех моих предыдущих либах для NN и некоторых других, которые я использовал, производные вычисляются через выходы, потому что это более просто и эффективно (во время адаптации к матричному API я не обратил внимания на разницу). Например:

sigmoid' = sigmoid * (1 - sigmoid)
tanh' = 1 - tanh^2
softsign' = (1 - |softsign|)^2

Таким образом, нам не нужно хранить аргументы (матрицы) перед активацией или вычислять их заново на этапе обратного распространения (как это сделано в фиксе). Мне не нравятся оба подхода. Вычисление, так сказать, "самопроизводной" выглядит более элегантно. Поэтому я бы предпочел найти ссылки с формулами для самопроизводных всех (или многих) поддерживаемых функций активации и вернуться к своему первоначальному подходу.

Интересно, что не требуется, чтобы формула самопроизводной строго выводилась из функции активации - достаточно любой функции с эквивалентным эффектом.
 
Stanislav Korotky #:

Кажется, я знаю причину, по которой она изначально кодируется через выход функции активации. Во всех моих предыдущих либах для NN и некоторых других, которые я использовал, производные вычисляются через выходы, потому что это более просто и эффективно (при адаптации к матричному API я не обратил внимания на разницу). Например:

Таким образом, нам не нужно хранить аргументы (матрицы) перед активацией или вычислять их заново на этапе обратного распространения (как это сделано в фиксе). Мне не нравятся оба подхода. Вычисление, так сказать, "самопроизводной" выглядит более элегантно. Поэтому я бы предпочел найти ссылки с формулами для самопроизводных всех (или многих) поддерживаемых функций активации и вернуться к своему первоначальному подходу.

Да, но mq решил сделать это таким образом, чтобы это относилось ко всем функциям активации.

Проще говоря, вместо того, чтобы функция .Derivative "адаптировалась" к функции активации (как 3 упомянутые вами функции могли бы получать выходы), они решили, чтобы функции получали значения до активации в любом случае. Это нормально, проблема в том, что этого нет в документации.

По умолчанию все считают, что он адаптируется к AF.

Это плохо для новичков (таких как я, например), так как они "решают" их еще до начала работы. Меня спасло то, что сначала я построил сеть на основе объектов.

(Сравнение сетей, основанных на объектах и матрицах, также было бы очень интересной статьей и помогло бы многим кодерам, которые не разбираются в математике).

В любом случае, я разместил ее в теме , которую модератор создал для сообщений о проблемах с документацией.

(не по теме: вы можете использовать этот TanH, он быстрее и правильнее, я думаю)

double customTanH(double of){
  double ex=MathExp(2*of);
  return((ex-1.0)/(ex+1.0));
}
Интересно, что не требуется, чтобы формула самопроизводной строго выводилась из функции активации - достаточно любой функции с эквивалентным эффектом.

Вы имеете в виду "заменитель"?

Например, узел получает ошибку на выходе, и вы знаете "колебания" выхода, так что если вы "переложите" его на более простую активацию и выведете ее, он будет работать?

То есть теоретически это будет как "регуляризация" выхода, но без нее, а просто умножение на производную регуляризации перед производной активации ?

Например :

tanh output -1 -> +1 
sigmoid output 0 -> +1 
tanh to sigmoid output = (tanh_out+1)/2.0
and you just multiply by the derivative of that which is 0.5 ? (without touching the tanh outputs at all)
mql5 documentation errors, defaults or inconsistencies.
mql5 documentation errors, defaults or inconsistencies.
  • 2023.04.07
  • www.mql5.com
Page : https://www.mql5.com/en/docs/globals/globalvariabletime This is inexact, GlobalVariableCheck() does NOT modify the last access time. 2023.04...
 
Багфикс.
Файлы:
MatrixNet.mqh  23 kb
 

Администратор ответил в теме модераторов об этом. Вам может быть интересно

Форум о трейдинге, автоматизированных торговых системах и тестировании торговых стратегий

Ошибки, умолчания или несоответствия в документации mql5.

Рашид Умаров, 2023.04.18 11:36

Будет улучшено в кратчайшие сроки. Некоторое время вы можете использовать этот включаемый файл в качестве ссылки.

@Stanislav Korotky
 
Stanislav Korotky # : Bugfix.

@Stanislav Korotky  

Your efforts to put Neural Network concept with MQL is well appreciated. This is really a great piece of work to start with for beginners like me. Kudos :)

Thanks for updating the file with bug fixed. However, I would suggest to replace the file in the download area.

Luckily I went through the Discussion on the topic and found there is a bug in the file. And than now I was trying to look for the fix, I found this file link here.

I hope there are only these places for bugfix at line number 490-493, 500, 515-527, I could with //* marking. If anywhere else please mention line numbers or mark //*BugFix ...

Regards