- 6.1.2.1 Метод прямого прохода пакетной нормализации
- 6.1.2.2 Методы обратного прохода класса пакетной нормализации
- 6.1.2.3 Методы работы с файлами
6.Метод прямого прохода пакетной нормализации
Мы продолжаем движение вперед по пути построения класса пакетной нормализации, а вместе с тем и по пути познания строения и методов организации нейронных сетей. Ранее мы с вами рассматривали различные архитектуры построения нейронных слоев для решения каких-либо практических задач. Работа же слоя пакетной нормализации не менее важна в организации работы нейронной сети, хотя и решаемая им задача не лежит на поверхности. Скорее она скрыта внутри организации процессов самой нейронной сети и служит больше для стабильности работы нашей модели.
Мы уже построили методы инициализации класса, теперь пришло время выстраивать непосредственно алгоритм работы метода. Начинаем мы этот процесс с метода прямого прохода FeedForward. Данный метод объявлен виртуальным в базовом классе нейронных слоев нашей библиотеки CNeuronBase и переопределяется в каждом новом классе.
Напомню, такой подход позволяет исключить использование диспетчерских методов и функций по перераспределению информационных потоков и вызова различных методов в зависимости от используемого класса объекта. Практически мы можем просто передать указатель на любой объект-наследник в локальную переменную базового класса нейронного слоя и вызвать метод, объявленный в базовом классе. При этом весь диспетчерский функционал система выполнит без нашего участия. Она вызовет метод, относящийся к фактическому типу объекта.
Именно это свойство мы и эксплуатируем, когда в параметрах метода ожидаем получить указатель на объект базового класса нейронного слоя. В то же время в параметрах может быть передан указатель на любой из объектов нейронных слоев нашей библиотеки. Можем с ним работать благодаря использованию переопределенных виртуальных функций.
Работа самого метода прямого прохода начинается с контрольного блока проверки указателей на используемые методом объекты. Здесь мы проверяем как указатель на объект предыдущего слоя, полученный в параметрах, так и указатели на внутренние объекты.
bool CNeuronBatchNorm::FeedForward(CNeuronBase *prevLayer)
|
Обратите внимание, что наряду с другими объектами мы проверяем и указатель на объект функции активации. Хотя алгоритмом пакетной нормализации не предусматривается использование функции активации. Тем не менее, мы не будем ограничивать возможности пользователя и предоставим ему возможность использования функции активации на его усмотрение. Тем более существуют практические кейсы с применением функции активации после нормализации данных. К примеру, авторы метода рекомендуют использовать нормализацию данных непосредственно перед применением функции активации. На первый взгляд, для применения такого подхода требуется внести изменения в каждый ранее рассмотренный класс. Но мы можем реализовать тот же функционал и без внесения изменений в написанные классы. Нам всего лишь надо объявить требуемый нейронный слой без функции активации, а за ним поставить слой нормализации с требуемой функцией активации. Поэтому использование функции активации в нашем классе считаю вполне обоснованным.
Далее мы сделаем ответвление алгоритма для размера пакета нормализации равного 1 и менее. Надо понимать, что при пакете равном 1 нормализация не осуществляется, и мы просто передаем тензор исходных данных на выход нейронного слоя. После завершения копирования данных буфера мы взвываем метод активации и выходим из метода, предварительно проверив результаты выполнения операций.
//--- проверка размера пакета нормализации
|
Далее нам предстоит построить алгоритм работы метода. В соответствии с принятой нами концепцией мы будем создавать два варианта реализации алгоритма: стандартными средствами MQL5 и в режиме многопоточных вычислений с использованием технологии OpenCL. Поэтому дальше мы создаем еще одно разветвление алгоритма в зависимости от выбора вычислительного устройства пользователем. В данном разделе мы рассмотрим построение алгоритма стандартными средствами MQL5, а к построению алгоритма средствами OpenCL мы вернемся в следующих разделах нашей книги.
//--- разветвление алгоритма по вычислительному устройству
|
Блок операций средствами MQL5 мы начинаем с небольшой подготовительной работы. Для упрощения процесса доступа к данным мы сохраним в локальную матрицу последовательность исходных данных.
MATRIX inputs = prevLayer.GetOutputs().m_mMatrix;
|
Согласно алгоритму нормализации данных мы находим среднее значение. При рассмотрении архитектуры нашего решения мы определились использовать экспоненциальное среднее значение, которое определяется по формуле.
VECTOR mean = (m_cBatchOptions.Col(0) * ((TYPE)m_iBatchSize - 1.0) +
|
После определения скользящей средней находим среднюю дисперсию.
VECTOR delt = inputs.Row(0) - mean;
|
Когда значения средней и дисперсии найдены, довольно легко вычислить нормализованное значение текущего элемента последовательности.
VECTOR std = sqrt(variance) + 1e-32;
|
Обратите внимание, что к дисперсии мы прибавляем небольшую константу для исключения ошибки деления на ноль.
Следующий шаг алгоритма пакетной нормализации — сдвиг и масштабирование.
VECTOR res = m_cWeights.Col(0) * nx + m_cWeights.Col(1); |
После этого нам остается лишь сохранить полученные значения в соответствующие элементы буферов. Обращаю ваше внимание на то, что мы сохраняем не только результат выполнения операций алгоритма в буфер результатов, но и наши промежуточные значения в буфер параметров нормализации. Они нам потребуются при последующих итерациях алгоритма. Не забываем проверить результат выполнения операций.
if(!m_cOutputs.Row(res, 0) ||
|
На этом мы завершаем блок разделения алгоритма в зависимости от используемого вычислительного устройства. Как всегда, для блока OpenCL мы установим временную заглушку в виде возврата ложного значения. Вернемся к этому позже.
А сейчас, перед выходом из метода, проведем активацию значений в буфере результатов нашего класса. Для этого достаточно вызвать метод Activation нашего специального объекта для работы с функцией активации m_cActivation. После проверки результата выполнения операции завершаем работу метода.
if(!m_cActivation.Activation(m_cOutputs))
|
На этом мы завершаем работу с методом прямого прохода класса пакетной нормализации CNeuronBatchNorm. Надеюсь, понимание логики его построения не вызвало у вас сложности. Переходим к построению методов обратного прохода.