6.Методы работы с файлами

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

И как всегда, начиная подобную работу, мы критически оцениваем переменные и объекты нашего класса чтобы решить, сохранить их в файл полностью или частично, или же восстановить их по каким-то параметрам.

class CNeuronDropout    :  public CNeuronBase
  {
protected:
   TYPE              m_dOutProbability;
   int               m_iOutNumber;
   TYPE              m_dInitValue;
   CBufferType       m_cDropOutMultiplier;
 
public:
                     CNeuronDropout(void);
                    ~CNeuronDropout(void);
   //---
   virtual bool      Init(const CLayerDescription *descoverride;
   virtual bool      FeedForward(CNeuronBase *prevLayeroverride;
   virtual bool      CalcHiddenGradient(CNeuronBase *prevLayeroverride;
   virtual bool      CalcDeltaWeights(CNeuronBase *prevLayerbool read)
                                                       override { return true; }
   virtual bool      UpdateWeights(int batch_sizeTYPE learningRate,
                         VECTOR &BetaVECTOR &Lambdaoverride { return true; }
   //--- методы работы с файлами
   virtual bool      Save(const int file_handleoverride;
   virtual bool      Load(const int file_handleoverride;
   //--- метод идентификации объекта
   virtual int       Type(voidoverride     const { return(defNeuronDropout); }
  };

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

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

bool CNeuronDropout::Save(const int file_handle)
  {
//--- вызов метода родительского класса
   if(!CNeuronBase::Save(file_handle))
      return false;
//--- сохраняем константу вероятности "выкидывания" элементов
   if(FileWriteDouble(file_handlem_dOutProbability) <= 0)
      return false;
//---
   return true;
  }

Метод восстановления работоспособности слоя CNeuronDropout::Load выглядит немного сложнее метода сохранения. Как и метод сохранения данных, в параметрах метод загрузки данных получает хендл файла с данными для загрузки. Мы помним об основном правиле загрузке данных — считывание данных из файла осуществляется в строгом соответствии последовательности их записи. Следовательно, в теле метода мы первым вызываем аналогичный метод родительского класса, в котором уже реализованы все контроли и загрузка данных, унаследованных от родительского класса объектов.

bool CNeuronDropout::Load(const int file_handle)
  {
//--- вызов метода родительского класса
   if(!CNeuronBase::Load(file_handle))
      return false;

Обязательно проверяем результат выполнения метода родительского класса, так как в нем подтверждается не только загрузка данных, но и прохождение всех реализованных контролей.

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

//--- считывание и восстановление констант
   m_dOutProbability = (TYPE)FileReadDouble(file_handle);
   m_iOutNumber = (int)(m_cOutputs.Total() * m_dOutProbability);
   m_dInitValue = (TYPE)(1.0 / (1.0 - m_dOutProbability));

В завершение метода восстановления работоспособности нашего слоя инициализируем буфер для записи вектора маскирования.

//--- инициализация буфера маскирования данных
   if(!m_cDropOutMultiplier.BufferInit(m_cOutputs.Rows(), m_cOutputs.Cols(),
                                                              m_dInitValue))
      return false;
//---
   return true;
  }

После успешной загрузки данных и инициализации объектов нашего слоя выходим из метода с положительным результатом.

На данном этапе мы завершаем работу над классом слоя Dropout стандартными средствами MQL5. В следующем разделе мы рассмотрим реализацию многопоточного алгоритма с использованием технологии OpenCL.