Я немного поэксперементировал с RNN и похоже, что она просто запоминает примеры обучения (важные в связке с шумовыми предикторами), а на новых данных шумовые предикторы портят результат. Т.е. RNN склонна к переобучению. По крайней мере для логических задач, где 0 и 1.
То что правильность работы RNN нарушает шум можно проверить следущим экспериментом.
Создан советник с оригинальной функцией RNN.
Обучим систему на решение задачи XOR на 1-м и 2-м входах (0 и 1 бит), на 3-й вход подадим не влияющий на задачу XOR шумовой сигнал.
int in[8][3] = { {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1} };
В матрице входы идут справа налево {3й,2-й,1й}
Составим правильные ответы
int out[8] = { 0,1,1,0,0,1,1,0}; //XOR по 1 и 2 входу, 3-й вход шумовой не должен влиять
Обучим RNN на 75% полной матрицы (6 примеров) и проверим на последних 2-х
Для этого запустим эксперт в тестере, в режиме оптимизации с полным перебором параметров, и в режиме математических вычислений.
Для входных переменных зададим старт = 0, шаг = 100, стоп=100, т.е. по 2 варианта для каждой переменной попробуем, что и нужно для логических задач типа XOR. В программе 100% будет сконвертировано в вероятность, т.е. =1.
После завершения оптимизации получим 255 вариантов. В работу запускать будем с максимальным значением, для этого сортируем список по Custom.
Pass Custom x0 x1 x2 x3 x4 x5 x6 x7
230 6 0 100 100 0 0 100 100 100
166 6 0 100 100 0 0 100 0 100
102 6 0 100 100 0 0 100 100 0
38 6 0 100 100 0 0 100 0 0
246 5 0 100 100 0 100 100 100 100
238 5 0 100 100 100 0 100 100 100
231 5 100 100 100 0 0 100 100 100
228 5 0 0 100 0 0 100 100 100
......
Это строка:
102 6 0 100 100 0 0 100 100 0 (где 100 соответствует 1 в обучающей матрице.)
Для проверки можно запустить все варианты с Custom=6 в одиночные тесты, двойным кликом.
Получим сообщения для участка "Проверка на новых данных":
Правильно:110 вычислил 1
ошибка:111 вычислил 1, должен вычислсть 0
для 166 6 0 100 100 0 0 100 0 100
ошибка:110 вычислил 0, должен вычислсть 1
ошибка:111 вычислил 1, должен вычислсть 0
для
102 6 0 100 100 0 0 100 100 0
Правильно:110 вычислил 1
Правильно:111 вычислил 0
для
38 6 0 100 100 0 0 100 0 0
ошибка:110 вычислил 0, должен вычислсть 1
Правильно:111 вычислил 0
Сообщения показывают правильность или ошибочность вычислений RNN.
Таким образом только 1 из 4-х вариантов обучения является верным.
Не зная правильного ответа, мы выберем случайный вариант из этих 4-х, и на новых данным можем иметь ошибку от 0 до 100% (смотря какой вариант возьмем). В среднем 50%.
В итоге можно сделать вывод, что RNN обучилась не решению задачи XOR на 1 и 2 входах, а некоей другой задаче вместе с шумовым входом. Т.е. шум на RNN оказывает значительное влияние, приводящий к ошибке на новых данных в среднем равной 50% (для 4х вариантов мы в сумме имеем 4 правильных и 4 неправильных ответа). И RNN не научилась решать задачу XOR вложенную в первые 2 входа, а обучилась некоей другой задаче с учетом шумового входа.
Т.е. относительно задачи XOR можно сказать, что RNN переобучилась. А относительно задачи "XOR+ шумовой вход" RNN недообучилась, ведь мы не подали на обучение все варианты шума.
Однако, одновременно с этим мы видим абсолютную точность при проверке на известных данных, т.е. ни одной ошибки.
Можно сделать еще один вывод, что RNN очень точно запоминает обучающие данные. И не исключено, что она так же хорошо справится с данными лежащими между 0 и 1. Т.е. хорошо сможет находить ответы в пределах обучающего множества. Т.е. что она будет неплохо интерполировать.
Но это тема для отдельного исследования.
П.С.
Обычная нейросеть решила задачу XOR+ шум лучше, о с не нулевой ошибкой на обучающих примерах. Хотя ошибку в 0,1% смешно считать ошибкой)) Так что обычный MLP на незнакомых данных лучше справился.
Средняя ошибка на обучающем (75.0%) участке =0.001 (0.1%)
Средняя ошибка на валидационном (25.0%) участке =0.034 (3.4%)
Обучающий участок
0.00000000, 0.00000000, 0.00000000, 0.00106781
0.00000000, 0.00000000, 1.00000000, 0.99912817
0.00000000, 1.00000000, 0.00000000, 0.99887599
0.00000000, 1.00000000, 1.00000000, 0.00146612
1.00000000, 0.00000000, 0.00000000, 0.00015709
1.00000000, 0.00000000, 1.00000000, 0.99958727
Валидация:
1.00000000, 1.00000000, 0.00000000, 1.00136207
1.00000000, 1.00000000, 1.00000000, 0.04871333
П.П.С.
Дополнительные эксперименты после изменения советника показали следующие результаты, в сравнении с обычным MLP 3-5-1.
Для проверок использовались разные формулы:
//double func(double d1,double d2,double d3 ){return d1*d2;} //ошибка 0-2% , т.к. умножение заложено в формулы. 2% получается т.к. генетический оптимизатор не всегда останавливается не на идеальном решении.
//double func(double d1,double d2,double d3 ){return d1*d2*d3;}// ошибка 0-2% умножение заложено в формулы, на MLP 1%
//double func(double d1,double d2,double d3 ){return MathSin(d1);}// ошибка 2-6%, на MLP 0,1%
//double func(double d1,double d2,double d3 ){return MathSin(d1)*MathSin(d2)*MathSin(d3);}// ошибка 2%, на MLP 1%
//double func(double d1,double d2,double d3 ){return MathSin(d1)*MathSin(d2)*MathSqrt(d3);}// ошибка 3-4%, на MLP 1%
//double func(double d1,double d2,double d3 ){return MathSin(d1)*MathPow(d2,.33)*MathSqrt(d3);}// ошибка 8-4%, на MLP 1.5%
//double func(double d1,double d2,double d3 ){return MathPow(d1,2)*MathPow(d2,.33)*MathSqrt(d3);}// ошибка 8-4%, на MLP 1.5%
В итоге можно сделать вывод, что обычный MLP имеет ошибку в 2-3 раза меньше, чем RNN Решетова. Возможно, часть этой ошибки возникает из за того, что генетический оптимизатор терминала МТ5 останавливается не на идеальном решении.
Прикреплены файлы на которых производилось тестирование и оригинальный RNN c примером торговой стратегии.