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

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

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

class CNeuronBatchNorm    :  public CNeuronBase
  {
protected:
   CBufferType       m_cBatchOptions;
   uint              m_iBatchSize;       // размер пакета
 
public:
                     CNeuronBatchNorm(void);
                    ~CNeuronBatchNorm(void);
   //---
   virtual bool      Init(const CLayerDescriptiondescriptionoverride;
   virtual bool      SetOpenCL(CMyOpenCL *opencloverride;
   virtual bool      FeedForward(CNeuronBaseprevLayeroverride;
   virtual bool      CalcHiddenGradient(CNeuronBaseprevLayeroverride;
   virtual bool      CalcDeltaWeights(CNeuronBaseprevLayer,bool read)override;
   //--- методы работы с файлами
   virtual bool      Save(const int file_handleoverride;
   virtual bool      Load(const int file_handleoverride;
   //--- метод идентификации объекта
   virtual int       Type(void)  override   const {return defNeuronBatchNorm;}
  };

Определившись с масштабом работы мы приступаем непосредственно к созданию методов работы с файлами нашего класса. Как всегда, первым мы создаем метод записи данных в файл CNeuronBatchNorm::Save. Как и все ранее рассмотренные методы, он также создан виртуальным в базовом классе нейронного слоя и переопределяется в каждом новом классе нейронного слоя для полного сохранения всей необходимой информации с целью последующего восстановления корректной работы сохраняемых объектов. В параметрах метод получает хендл файла для записи данных.

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

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

   if(!CNeuronBase::Save(file_handle))
      return false;

Использовать метод родительского класса очень удобно. Такое использование выполняет двойную функцию. Первая функция — контрольная, так как в родительском классе уже реализованы ряд контролей, которые не нужно повторять в новом методе. Достаточно одного вызова метода родительского класса и проверки результата его работы. Вторая — функциональная. В методе родительского класса уже реализовано сохранение всех унаследованных объектов и переменных. Здесь та же ситуация: мы один раз вызываем метод родительского класса и тем самым сразу сохраняем все унаследованные объекты и переменные. Удобно, не правда ли? Более того, нам не надо вызывать метод для каждого отдельного функционала. Одним вызовом мы убиваем двух зайцев: контроль и сохранение унаследованных объектов. Проверка результата выполнения функции подтверждает корректное выполнение обоих функций метода.

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

//--- сохраняем размер пакета нормализации
   if(FileWriteInteger(file_handlem_iBatchSize) <= 0)
      return false;

В заключение метода сохраняем буфер параметров нормализации m_cBatchOptions. Для этого достаточно вызвать соответствующий метод указанного объекта и проверить результат его работы.

//--- сохранение параметров нормализации
   if(!m_cBatchOptions.Save(file_handle))
      return false;
//---
   return true;
  }

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

Аналогичным образом создадим метод загрузки данных из файла CNeuronBatchNorm::Load. Надо сказать, что данный метод отвечает не только за чтение данных из файла, но и за полное восстановление функциональности объекта до состояния на момент сохранения данных. Поэтому в методе должны быть предусмотрены операции создания экземпляров объектов, необходимых для корректного функционирования объекта нашего класса пакетной нормализации. Кроме того, мы должны инициализировать начальными значениями все несохраненные объекты и переменные.

В параметрах метод CNeuronBatchNorm::Load, как и предыдущий метод сохранения данных, получает хендл файла с сохраненными данными. Нам предстоит организовать чтение данных из файла в строгом соответствии с последовательностью их записи в файл. На этот раз в теле метода мы сразу вызываем метод родительского класса. Расчет здесь тот же: одним вызовом метода родительского класса мы сразу выполняем весь функционал с унаследованными объектами и переменными. При этом нам достаточно один раз проверить результат выполнения метода родительского класса, чтобы убедиться в корректности выполнения всех его операций.

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

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

   m_iBatchSize = FileReadInteger(file_handle);

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

//--- инициализируем динамический массив параметров оптимизации
   if(!m_cBatchOptions.Load(file_handle))
      return false;
//---
   return true;
  }

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

Мы закончили работу над созданием слоя пакетной нормализации данных стандартными средствами MQL5. Для завершения работы над классом CNeuronBatchNorm осталось дополнить его функционал возможностью выполнения многопоточных математических операций с помощью технологии OpenCL. Этим мы займемся в следующем разделе. Но уже сейчас у нас есть возможность провести первое тестирование его работы.