Отличный и полезный материал статьи
Спасибо!
Да, планируется :)
Дмитрий, подскажите, сходу не въехал, зачем синус и косинус прибавляются к входным значениям
neuron.setOutputVal(inputVals.At(i)+(i%2==0 ? sin(i) : cos(i)) );
Ещё совет нужен - стоит ли попробовать для своих задач каким-либо образом нормализовать входные данные?
сейчас в примерах как я понял подаётся всё "как есть". Но даже в примерах с фракталами какие то осцилляторы от 0 до 1, а цены могут быть в зависимости от инструмента и гораздо больше 1.
Не создаёт ли это изначальный перекос при обучении на ненормализованных входах?
Дмитрий, подскажите, сходу не въехал, зачем синус и косинус прибавляются к входным значениям
Ещё совет нужен - стоит ли попробовать для своих задач каким-либо образом нормализовать входные данные?
сейчас в примерах как я понял подаётся всё "как есть". Но даже в примерах с фракталами какие то осцилляторы от 0 до 1, а цены могут быть в зависимости от инструмента и гораздо больше 1.
Не создаёт ли это изначальный перекос при обучении на ненормализованных входах?
Это для тайм эмбединга. Подробнее расскажу в следующей статье.
Усиленно пытаюсь понять смысл)
Входные значения арифметически корректируются на константную матрицу от 0 до 1, причём вне зависимости от того, что из себя представляют входные данные и их абсолютных значений.
Тайм-эмбединг в этом смысле я понимаю так - накладываешь синусоиду на временной ряд, чтобы значимость прошлых свечей колебалась во времени.
Ок, это понятно, видимо не важно что колебания входных данных каждого бара с разной фазой, или это фича.
Но тогда вопрос про нормализацию тем более становиться актуальным. Совсем разная значимость получается к примеру для EURUSD и SP500.
И видимо правильно этот тайм-эмбединг вынести из библы в функцию Train.
@Dmitriy Gizlyk, вопрос возник при изучении и работе с библиотекой:
в методе вычисления градиента для скрытых слоёв прибавляете outputVal
это для последующей компенсации его значения в дальнейшем в методе calcOutputGradients для универсальности, верно?
Также вы добавили нормализацию градиента
bool CNeuron::calcHiddenGradients(CLayer *&nextLayer) { double targetVal=sumDOW(nextLayer)+outputVal; return calcOutputGradients(targetVal); } //+------------------------------------------------------------------+ bool CNeuron::calcOutputGradients(double targetVal) { double delta=(targetVal>1 ? 1 : targetVal<-1 ? -1 : targetVal)-outputVal; gradient=(delta!=0 ? delta*activationFunctionDerivative(outputVal) : 0); return true; }
Вопрос собственно - не правильнее ли будет нормализовать не таргет, а итоговую дельту вот так
double delta=targetVal-outputVal; delta=delta>1?1:delta<-1?-1:delta;
почему? Пример: Если outputVal близка к 1, а суммарный взвешенный градиент следующего слоя тоже высок и положительный, то сейчас получаем в итоге дельту близкую к нулю, что видится неверным.
Ведь дельта градиента должна быть пропорциональна ошибке следующего слоя, т.е. другими словами при отрицательном эффективном весе нейрона (а возможно и ещё в каких случаях) нейрон наказывается за ошибку меньше чем с положительным весом. Возможно сумбурно объяснил, но надеюсь кто в теме поймут мысль :) Может этот момент вами уже заметен-рассмотрен и принято именно такое решение, было бы интересно прояснить причины.
Также этот же момент и для OCL кода
__kernel void CalcHiddenGradient(__global double *matrix_w, __global double *matrix_g, __global double *matrix_o, __global double *matrix_ig, int outputs, int activation) { .............. switch(activation) { case 0: sum=clamp(sum+out,-1.0,1.0)-out; sum=sum*(1-pow(out==1 || out==-1 ? 0.99999999 : out,2));
@Dmitriy Gizlyk, вопрос возник при изучении и работе с библиотекой:
в методе вычисления градиента для скрытых слоёв прибавляете outputVal
это для последующей компенсации его значения в дальнейшем в методе calcOutputGradients для универсальности, верно?
Также вы добавили нормализацию градиента
Вопрос собственно - не правильнее ли будет нормализовать не таргет, а итоговую дельту вот так
почему? Пример: Если outputVal близка к 1, а суммарный взвешенный градиент следующего слоя тоже высок и положительный, то сейчас получаем в итоге дельту близкую к нулю, что видится неверным.
Ведь дельта градиента должна быть пропорциональна ошибке следующего слоя, т.е. другими словами при отрицательном эффективном весе нейрона (а возможно и ещё в каких случаях) нейрон наказывается за ошибку меньше чем с положительным весом. Возможно сумбурно объяснил, но надеюсь кто в теме поймут мысль :) Может этот момент вами уже заметен-рассмотрен и принято именно такое решение, было бы интересно прояснить причины.
Также этот же момент и для OCL кода
Не совсем так. Мы проверяем значения таргета, как и в скрытых слоях прибавляем к градиенту outpuVal для получения таргета и проверки его значения. Дело в том, что сигмоиды имеют ограниченный диапазон результатов: логистическая функция от 0 до 1, tanh - от -1 до 1. Если мы будем неограниченно наказывать нейрон за отклонение и увеличивать весовой коэффициент, то придем к переполнению веса. Ведь если мы в какой-то пришли к значению нейрона равному 1, а последующий слой передавая ошибку говорит что надо нарастить значение до 1,5. Нейрон будет послушно на каждой итерации увеличивать веса, а функция активации будет обрезать значения на уровне 1. Поэтому, я ограничиваю значения таргета диапазонам допустимых значений функции активации. А корректировку за пределами диапазона оставляю на веса последующего слоя.
Не совсем так. Мы проверяем значения таргета, как и в скрытых слоях прибавляем к градиенту outpuVal для получения таргета и проверки его значения. Дело в том, что сигмоиды имеют ограниченный диапазон результатов: логистическая функция от 0 до 1, tanh - от -1 до 1. Если мы будем неограниченно наказывать нейрон за отклонение и увеличивать весовой коэффициент, то придем к переполнению веса. Ведь если мы в какой-то пришли к значению нейрона равному 1, а последующий слой передавая ошибку говорит что надо нарастить значение до 1,5. Нейрон будет послушно на каждой итерации увеличивать веса, а функция активации будет обрезать значения на уровне 1. Поэтому, я ограничиваю значения таргета диапазонам допустимых значений функции активации. А корректировку за пределами диапазона оставляю на веса последующего слоя.
Думаю я понял. Но всё же интересно насколько это верный подход, такой пример:
если сеть ошиблась выдав 0, когда реально 1. С последнего слоя тогда градиент взвешенный на предыдущий приходит (скорее всего, как я понимаю) положительный и может быть более 1, допустим 1,6.
Допустим в предыдущем слое есть нейрон, который выдавал +0,6, т.е. он же выдавал значение верное - его вес должен увеличиться в плюс. А этой нормировкой мы урезаем изменение его веса.
получится норм(1,6)=1. 1-0,6=0,4, а если нормировать как я предложил, то будет 1. В этом случае мы тормозим усиление правильного "нейрона".
Как считаете?
Насчёт бесконечного увеличения весов, что-то вроде слышал что это бывает в случае "плохой функции ошибок", когда много локальных минимумов и нет выраженного глобального, или функция невыпуклая, что-то такое, я не супер спец, просто полагаю что бороться с бесконечными весами можно и нужно и другими методами.
Проситься эксперимент протестить оба варианта. Если додумаюсь как сформулировать тест )
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Опубликована статья Нейросети — это просто (Часть 9): Документируем проделанную работу:
Мы уже проделали довольно большой путь и код нашей библиотеке сильно разрастается. Становится сложно отслеживать все связи и зависимости. И конечно, перед продолжением развития проекта нам нужно задокументировать уже проделанную работу и актуализировать документацию на каждом последующем шаге. Правильно подготовленная документация поможет нам увидеть целостность нашей работы.
После отработки программы получаем готовую к использованию документацию. Некоторые скриншоты приведены ниже. С полной документацией можно ознакомиться во вложении.
Автор: Dmitriy Gizlyk