- Постановка задачи
- Структура расположения файлов
- Выбор исходных данных
- Закладываем скелет будущей программы MQL5
- Описание структуры скрипта Python
- Полносвязный нейронный слой
- Организация параллельных вычислений средствами OpenCL
- Реализация модели перцептрона в Python
- Создание обучающей и тестовой выборки
- Проверка корректности распределения градиента
- Сравнительное тестирование реализаций
Описание структуры скрипта Python
Python — интерпретируемый язык программирования с минималистичным синтаксисом. Такой синтаксис позволяет быстро писать небольшие блоки кода и сразу проверять их работоспособность. Поэтому Python позволяет сосредоточиться на решении задачи, а не на программировании. Наверное, именно благодаря этой особенности Python получил такую популярность.
Несмотря на то, что интерпретируемые языки программирования работают медленнее компилируемых, в настоящее время Python стал наиболее популярным языков программирования для создания и проведения экспериментов с нейронными сетями. Вопрос скорости выполнения решается с помощью использования различных библиотек, написанных, в том числе, и на компилируемых языках программирования. Благо Python имеет возможность легко расширяться и подключать библиотеки, написанные практически на всех доступных языках программирования.
Мы с вами тоже не будем выстраивать сложные алгоритмы, а воспользуемся готовыми решениями, среди которых есть библиотеки как для построения нейронных сетей, так и для трейдинга. Давайте для начала познакомимся с некоторыми из них.
Модуль os содержит функции для работы с операционной системой. Использование данной библиотеки позволяет создавать кросс-платформенные приложения, так как работа функций этого модуля не зависит от установленной операционной системы. Приведем лишь некоторые функции библиотеки os:
- os.name — возвращает имя операционной системы. В результате выполнения функции возможны следующие варианты: 'posix', 'nt', 'mac', 'os2', 'ce', 'java'.
- os.environ — функция для работы с переменными окружения, позволяющая изменять, добавлять и удалять переменные окружения.
- os.path — содержит целый ряд функций для работы с путями файлов и директорий.
Модуль Pandas представляет собой библиотеку для обработки и анализа данных. Библиотека предоставляет специальные структуры данных и операции для обработки числовых таблиц и временных рядов. Она позволяет проводить анализ и моделирование данных без использования специализированных для статистической обработки языков программирования, таких как R и Octave.
Пакет предназначен для очистки и первичной оценки данных по общим статистическим показателям. Он позволяет вычислять среднее значение, квантили и т. д. В то же время пакет нельзя назвать статистическим в полном смысле, однако создаваемые им наборы данных типов DataFrame и Series применяются в качестве входных в большинстве модулей анализа данных и машинного обучения SciPy, Scikit-Learn и других.
Объект DataFrame создан в библиотеке Pandas. Он предназначен для работы с индексированными массивами двумерных данных.
Кроме того, библиотека предоставляет:
- инструменты для обмена данными между структурами в памяти и файлами различных форматов;
- встроенные средства совмещения данных и способы обработки отсутствующей информации;
- переформатирование наборов данных, в том числе создание сводных таблиц;
- расширенные возможности индексирования и выборки из больших наборов данных;
- возможности группировки позволяют выполнять трехэтапные операции типа «разделение, изменение, объединение»;
- слияние и объединение различных наборов данных.
Библиотека дает возможность создания иерархического индексирования, что позволяет работать с данными высокой размерности в структурах меньшей размерности. Функции для работы с временными рядами позволяют формировать временные периоды и изменять интервалы. Библиотека оптимизирована для высокой производительности, наиболее важные части кода написаны на Cython и C.
Еще одна библиотека для работы с многомерными массивами — NumPy — представляет собой библиотеки с открытым исходным кодом. Основными возможностями данного модуля являются поддержка многомерных массивов (включая матрицы) и высокоуровневых математических функций, предназначенных для работы с многомерными массивами.
В библиотеке NumPy реализованы вычислительные алгоритмы в виде функций и операторов, которые оптимизированы для работы с многомерными массивами. Библиотека представляет возможность проведения векторных операций над данными. При этом все функции написаны на C и оптимизированы для максимальной производительности. В результате любой алгоритм, который может быть выражен в виде последовательности операций над массивами (матрицами) и реализованный с использованием NumPy, работает так же быстро, как эквивалентный код, выполняемый в MATLAB.
При этом NumPy можно рассматривать в качестве альтернативы использования MATLAB. Оба языка интерпретируемые и позволяют выполнять операции над массивами.
NumPy часто используется в качестве базы для работы с многомерными массивами в других библиотеках. В том числе представленный выше Pandas также использует библиотеку NumPy для низкоуровневых операций с массивами.
Модуль Matplotlib — это комплексная библиотека для создания статических, анимированных и интерактивных визуализаций. Она с легкостью позволяет визуализировать большие объемы данных.
Для создания моделей нейронных сетей мы будем использовать библиотеку TensorFlow. Это комплексная платформа с открытым исходным кодом для машинного обучения. Имеет гибкую экосистему инструментов, библиотек и ресурсов сообщества, которая позволяет исследователям продвигать новейшие достижения в области машинного обучения, а разработчикам легко создавать и развертывать приложения на основе машинного обучения.
Библиотека позволяет создавать и обучать модели машинного обучения с помощью интуитивно понятных высокоуровневых API с активным исполнением, таких как Keras. Это обеспечивает немедленную интеграцию модели и облегчает ее отладку.
И конечно, для интеграции с терминалом MetaTrader 5 мы будем использовать одноименную библиотеку MetaTrader5. Она предоставляет ряд функций для обмена данными с терминалом, в том числе функции получения рыночной информации и совершения торговых операций.
Для технического анализа данных можно воспользоваться библиотекой TA-lib, предоставляющей большое количество функций технических индикаторов.
Перед использованием библиотек нужно установить их в используемом окружении Python. Для этого в командной строке или Windows PowerShell с правами администратора системы нужно выполнить ряд команд:
- установка NumPy
pip install numpy |
- установка Pandas
pip install pandas |
- установка Matplotlib
pip install matplotlib |
- установка TensorFlow
pip install tensorflow |
- установка Keras
pip install keras |
- установка библиотеки MetaTrader 5
pip install MetaTrader5 |
Переходя непосредственно к структуре нашего скрипта, создадим шаблон template.py. Скрипт будет состоять из нескольких блоков. Сначала нужно подключить необходимые библиотеки к нашему скрипту.
# импорт библиотек |
После обучения моделей мы будем строить графики визуализации процесса обучения и сопоставления работы различных моделей. Для стандартизации графиков зададим общие параметры их построения.
# устанавливаем параметры графиков результатов |
Обучение и тестирование всех моделей будем осуществлять на одном наборе данных, который мы специально предварительно выгрузим в файл на локальном диске. Такой подход позволит нам исключить влияние несопоставимых данных и позволит оценить работу различных моделей нейронных сетей в одних условиях.
Следовательно, на следующем шаге мы загрузим исходные данные из файла в таблицу. Обратите внимание на следующий момент: поскольку MetaTrader 5 ограничивает доступ к файлам из своих программ размерами песочницы, нужно указывать полный путь доступа к файлу исходных данных. Он будет находиться в каталоге MQL5\Files вашего терминала или его подкаталогах, если они были указаны при сохранении файла данных.
Вместо того, чтобы однозначно прописывать путь к песочнице терминала в коде нашей программы, мы просто запросим его из MetaTrader 5 средствами предлагаемого API. Для этого мы сначала подключаемся к установленному терминалу и проверяем результат выполнения данной операции.
# Подключаемся к терминалу MetaTrader 5 |
После успешного подключения к терминалу запросим путь к песочнице и отключимся от терминала, потому что дальнейшие операции создания и обучения модели мы будем осуществлять средствами Python. Совершать какие-либо торговые операции в данном скрипте мы не планируем.
# Запрашиваем путь в песочницу |
В следующем небольшом блоке загрузки данных можно увидеть использование функций сразу трех вышеуказанных библиотек. С помощью функции os.path.join мы сцепляем путь к рабочему каталогу с именем файла обучающей выборки. Функцией read_table из библиотеки Pandas мы считываем и преобразуем содержимое CSV-файла в таблицу. Затем полученную таблицу преобразуем в двумерный массив с помощью функции библиотеки NumPy.
# Загрузка обучающей выборки |
Непосредственно считывание содержимого CSV-файла и преобразование строк в таблицу осуществляется функцией read_table из библиотеки Pandas. Данная функция имеет довольно много параметров для точной настройки методов преобразования строчных данных в требуемый числовой тип данных. Полное их описание можно найти в документации к библиотеке. Мы же опишем лишь используемые:
- filename — имя считываемого файла с указанием полного или относительного пути;
- sep — указываем используемый в файле разделитель данных;
- header — номера строк для использования в качестве имен столбцов и начала данных, при отсутствии заголовков указываем значении None;
- skipinitialspace — логический параметр указывает, пропускать ли пробелы после разделителя;
- encoding — указываем тип используемой кодировки;
- float_precision — определяет, какой преобразователь должен использоваться для значений с плавающей запятой;
- dtype — указывает конечный тип данных;
- low_memory — внутренняя обработка файла по частям, что приведет к меньшему использованию памяти при синтаксическом анализе.
В результате этих операций все данные обучающей выборки были загружены в объект двумерного массива типа numpy.ndarray из библиотеки NumPy. Среди загруженных данных есть элементы исходных данных и целевые значения. Но для обучения нейронной сети нам нужно отдельно подавать на ее вход исходные данные, а после прямого прохода сравнить полученный результат с целевыми значениями. Получается, что исходные данные и цели для нейронной сети разделены во времени и месту использования.
Следовательно, нам нужно разделить эти данные в отдельные массивы. Пусть каждая строка данных представляет отдельный паттерн данных, и последние два элемента строки содержат целевые точки данного паттерна. Функция shape покажет размер нашего массива, а значит с ее помощью мы можем определить размерности исходных данных и целевых значений. Только зная эти размерности, мы можем скопировать определенные выборки в новые массивы.
В блоке ниже мы разделим обучающую выборку на 2 таблицы. При этом мы разделяем только столбцы, полностью сохраняя структуру строк. Таким образом, мы получаем в одном массиве исходные данные, а в другом — целевые значения. Паттерны можно сопоставить с соответствующими целевыми значениями по номеру строки.
# Разделение обучающей выборки на исходные данные и цели |
Теперь, когда у нас есть данные для обучения, можно приступить к созданию модели нейронной сети. Модели мы будем создавать с помощью функции Sequential из библиотеки Keras.
# Создание модели нейронной сети |
Модель Sequential представляет собой линейный стек слоев. Можно создать модель Sequential, передав список слоев конструктору модели, а также можно добавлять слои с помощью метода add.
Прежде всего наша модель должна знать, какую размерность данных ожидать на входе. В связи с этим первый слой модели Sequential должен получать информацию о размерности входных данных. Все последующие слои производят автоматический расчет размерности.
Есть несколько способов указать размерность исходных данных:
- Передать аргумент input_shape первому слою.
- Некоторые 2D-слои поддерживают спецификацию размерности входных данных через аргумент input_dim. Некоторые 3D-слои поддерживают аргументы input_dim и input_length.
- Использовать специальный тип нейронного слоя для исходных данных Input с параметром shape, в котором указывается размер слоя.
# Создание модели нейронной сети |
С типами предлагаемых нейронных слоев мы познакомимся по мере изучения их архитектуры. Сейчас давайте посмотрим на общие принципы построения и организации моделей.
После создания модели необходимо подготовить ее к обучению, настроить процесс. Этот функционал выполняется в методе compile, который имеет несколько параметров:
- optimizer — оптимизатор, может быть задан строковым идентификатором существующего оптимизатора или как экземпляр класса Optimizer;
- loss — функция потерь, может быть задана строковым идентификатором существующей функции потерь, или собственная функция;
- metrics — список показателей, которые модель должна оценивать во время обучения и тестирования, к примеру, для задачи классификации можно использовать ‘accuracy’;
- loss_weights — необязательный список или словарь, определяющий скалярные коэффициенты для взвешивания вкладов в потери различных выходных данных модели;
- weighted_metrics — список показателей, которые будут оценены и взвешены во время обучения и тестирования.
Для каждого параметра библиотека Keras предлагает свой список возможных значений, но при этом не ограничивает пользователя предложенными вариантами — для каждого параметра существует возможность добавления пользовательских классов и алгоритмов.
model.compile(optimizer='Adam', |
Далее мы можем начать обучения созданной модели с помощью метода fit, который позволяет обучать модель с фиксированным количеством эпох. Данный метод имеет свои параметры для настройки процесса обучения.
- x — массив исходных данных;
- y — массив целевых результатов;
- batch_size — необязательный параметр, указывает количество наборов пар «исходные данные — целевые значения» до обновления матрицы весов;
- epochs — количество эпох обучения;
- verbose — необязательный параметр, указывает уровень детализации логирования обучения: 0 — без сообщений, 1 — индикатор выполнения, 2 — одна строка на эпоху, auto — автоматический выбор;
- callbacks — список обратных вызовов для применения во время обучения;
- validation_split — выделение части обучающей выборки для валидации, указывается в долях от 1,0;
- validation_data — отдельная выборка для валидации процесса обучения;
- shuffle — логическое значение, которое указывает на необходимость перемешивания данных обучающей выборки перед следующей эпохой;
- class_weight — необязательные индексы классов сопоставления словаря в значение веса, используемое для взвешивания функции потерь (только во время обучения);
- sample_weight — необязательный массив весов NumPy для обучающей выборки, используемый для взвешивания функции потерь (только во время обучения);
- initial_epoch — эпоха начала тренировки, может быть полезен для возобновления предыдущего тренировочного цикла;
- steps_per_epoch — общее количество пакетов перед объявлением одной эпохи завершенной и началом следующей, по умолчанию равен размеру обучающей выборки;
- validation_steps — общее количество пакетов из валидационной выборки перед остановкой при выполнении проверки в конце каждой эпохи, по умолчанию равен размеру валидационной выборки;
- validation_batch_size — количество образцов на партию валидации;
- validation_freq — целое число, указывает количество периодов обучения перед выполнением нового прогона валидации.
Конечно, мы не будем использовать полный набор параметров в первой же модели. Предлагаю остановиться на параметре callbacks — список обратных вызовов. Данный параметр предоставляет методы интерактивного взаимодействия с процессом обучения.
Его использование позволяет настроить получение оперативной информации о процессе обучения и управлять самим процессом. В частности можно накапливать средние значения показателей за эпоху или сохранять результаты каждой эпохи в файл CSV. Также можно отслеживать показатели обучения и уменьшать коэффициент обучения или вовсе остановить процесс обучения, когда отслеживаемый показатель перестал улучшаться. В то же время существует возможность добавления собственных классов обратного вызова.
Я предлагаю использовать ранний выход из процедуры обучения в том случае, если в течение пяти эпох не будет улучшения показателя функции ошибки.
callback = tf.keras.callbacks.EarlyStopping(monitor='loss', patience=5) |
После завершения обучения сохраним обученную модель в файл на локальном диске. Для этого воспользуемся методами библиотек Keras и os.
# Сохранение обученной модели |
Для наглядности и понимания процесса обучения выведем динамику изменения метрик в процессе обучения и валидации на графики. Здесь мы воспользуемся методами библиотеки Matplotlib.
# Отрисовка результатов обучения модели |
После обучения нам необходимо проверить работу нашей модели на тестовой выборке, ведь прежде, чем эксплуатировать модель в реальных условиях, нам необходимо знать, как она поведет себя на новых данных. Для этого мы загрузим тестовую выборку. Процедура загрузки данных полностью аналогична загрузке обучающей выборки — изменяем только имя файла.
# Загрузка тестовой выборки |
После загрузки данных разделим полученную таблицу на исходные данные и целевые метки, как и в случае с обучающей выборкой.
# Разделение тестовой выборки на исходные данные и цели |
Проверку качества работы обученной модели на тестовой выборке будем осуществлять с помощью метода evaluate из библиотеки Keras. В результате вызова указанного метода на выходе получаем значение функции потерь и метрик на тестовой выборке. Метод имеет ряд параметров для настройки процесса тестирования:
- x — массив исходных данных тестовой выборки;
- y — массив целей тестовой выборки;
- batch_size — размер пакета тестирования;
- verbose — режим детализации логирования процесса (0 — без логирования, 1 — индикация выполнения);
- sample_weight — необязательный параметр, используемый для взвешивания функции потерь;
- steps — общее количество шагов для объявления процесса тестирования завершенным;
- callbacks — список обратных вызовов, используемых в процессе обучения;
- return_dict — логическая переменная, которая определяет формат вывода результатов работы метода (True — в виде словаря «метрика - значение», False — в виде списка).
Большинство из указанных параметров необязательные, а также имеют значения по умолчанию. Для запуска процесса тестирования в большинстве случаев достаточно просто указать массивы данных.
# Проверка результатов модели на тестовой выборке |
В заключение выведем результаты тестирования в журнал и отобразим построенные ранее графики.
# Вывод результатов тестирования в журнал |
На этом базовый шаблон скрипта можно считать завершенным. Надо сказать, что при попытке запуска данного скрипта мы получим ошибку. И это не связано с ошибками в построении шаблона. Просто мы еще не дали описания нашей модели, а оставили пустой блок. В процессе рассмотрения различных решений нейронных сетей мы будем заполнять блок описания архитектуры модели и в полной мере сможем оценить работу нашего шаблона.