6.Методы обратного прохода Dropout

Традиционно после реализации алгоритма прямого прохода мы переходим к организации процесса обратного прохода. Как вы знаете, в базовом классе нейронного слоя алгоритм обратного прохода реализован четырьмя виртуальными методами:

  • метод расчета градиента ошибки на выходе нейронной сети CalcOutputGradient;
  • метод распространения градиента через скрытый слой CalcHiddenGradient;
  • метод необходимого расчета корректирующих значений для весовых коэффициентов CalcDeltaWeights;
  • метод обновления матрицы весовых коэффициентов UpdateWeights.

Все вышеуказанные методы переопределяются в новых классах по мере необходимости. Как уже было сказано ранее, наш слой Dropout не содержит обучаемых параметров. Как следствие, он не содержит матрицы весовых коэффициентов. Таким образом, последние два метода не актуальны для нашего класса. В то же время нам придется их переопределить для поддержания целостности архитектуры нашей модели, ведь в процессе обучения она будет вызывать указанные методы для всех используемых нейронных слоев. И если мы их не переопределим, то при вызове указанных методов будут осуществляться операции унаследованного родительского метода. При этом отсутствие буфера матрицы весовых коэффициентов и сопутствующих объектов может привести к критическим ошибкам. В лучшем случае, в результате работы наших контролей мы завершим работу метода с ложным результатом, а это приведет к остановке процесса обучения. Поэтому мы переопределим данные методы и заменим их пустыми методами, которые всегда будут возвращать положительный результат.

   virtual bool      CalcDeltaWeights(CNeuronBase *prevLayerbool read)
                                                        override { return true; }
   virtual bool      UpdateWeights(int batch_sizeTYPE learningRate,
                          VECTOR &BetaVECTOR &Lambdaoverride { return true; }

Первый метод CalcOutputGradient используется только для слоя результатов. Принцип работы Dropout не предполагает его использование в качестве слоя результатов. Следовательно, его мы не будем переопределять.

Таким образом нам осталось переопределить только один метод — метод распространения градиента через скрытый слой CalcHiddenGradient. Данный метод, как и большинство предыдущих, объявлен виртуальным в базовом классе нейронной сети переопределяется во всех новых классах для выстраивания конкретного алгоритма работы нейронного слоя. В параметрах метод получает указатель на объект предыдущего слоя. Сразу в теле метода организуем блок контролей для проверки действительности указателей на используемые методом объекты. Как и в методе прямого прохода, мы проверяем указатели на все используемые объекты, и внешние, и внутренние.

bool CNeuronDropout::CalcHiddenGradient(CNeuronBase *prevLayer)
  {
//--- блок контролей
   if(!prevLayer || !prevLayer.GetGradients() || !m_cGradients)
      return false;

После успешного прохождения блока контролей мы должны создать разветвление алгоритма в зависимости от вычислительного устройства. И, как всегда, в этом разделе мы рассмотрим реализацию алгоритма средствами MQL5, а к многопоточной реализации алгоритма вернемся в следующем разделе.

//--- разветвление алгоритма в зависимости от устройства выполнения операций
   ulong total = m_cOutputs.Total();
   if(!m_cOpenCL)
     {

В блоке реализации средствами MQL5 мы проверяем режим работы класса. В случае работы в режиме промышленной эксплуатации мы просто копируем данные из буфера градиентов ошибки текущего слоя в аналогичный буфер предыдущего слоя.

      //--- проверка флага режима работы
      if(!m_bTrain)
         prevLayer.GetGradients().m_mMatrix = m_cGradients.m_mMatrix;
      else
         prevLayer.GetGradients().m_mMatrix = m_cGradients.m_mMatrix *
                                              m_cDropOutMultiplier.m_mMatrix;
     }
   else  // блок OpenCL
     {
      return false;
     }
//---
   return true;
  }

В случае работы метода в режиме обучения модели, согласно алгоритму работы Dropout, нам необходимо поэлементно умножить буфер градиентов ошибки текущего слоя на буфер вектора маскирования. Матричная операция умножения нам позволяет сделать это буквально в одну строку кода.

Как видите, на данном этапе мы передали градиент ошибки в буфер предыдущего слоя. Следовательно, задача, поставленная перед данным методом, решена, и мы можем завершить работу метода. Предварительно установим заглушку в блоке организации многопоточных операций. К ней мы вернемся в одном из последующих разделов.

Таким образом, мы полностью реализовали алгоритм работы Dropout стандартными средствами MQL5. Уже сейчас можно создать модель и получить первые результаты работы подхода. Но мы уже не раз говорили, что для полноценной работы любого нейронного слоя в рамках модели не менее важно иметь возможность восстановить работоспособность обученной ранее модели в любое удобное для пользователя время. Поэтому в следующем разделе мы рассмотрим методы сохранения данных нейронного слоя и восстановления функционирования слоя из ранее сохраненных данных.