English 中文 Español Deutsch 日本語
preview
Возможности Мастера MQL5, которые вам нужно знать (Часть 54): Обучение с подкреплением с гибридным SAC и тензорами

Возможности Мастера MQL5, которые вам нужно знать (Часть 54): Обучение с подкреплением с гибридным SAC и тензорами

MetaTrader 5Интеграция |
340 0
Stephen Njuki
Stephen Njuki

Введение

Soft Actor Critic (SAC) — один из алгоритмов, используемых в обучении нейронной сети с подкреплением. Напомню: обучение с подкреплением — это новый метод машинного обучения наряду с обучением с учителем и без учителя.


Буфер воспроизведения

Буфер воспроизведения (replay buffer) - очень важный компонент алгоритма SAC вне политики в обучении с подкреплением, поскольку он сохраняет прошлый опыт состояния, действия, вознаграждения, следующего состояния и флага выполнения (для регистрации завершения или продолжения эпизода) в мини-пакетах образцов для обучения. Его основная цель — декоррелировать различный опыт, чтобы агент мог учиться на более разнообразном опыте, что, как правило, повышает стабильность обучения и эффективность выборки.

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

При ручном подходе используются базовые структуры данных Python, такие как списки или массивы NumPy. Однако при использовании метода на основе тензора используются такие фреймворки глубокого обучения, как TensorFlow или PyTorch, причем этот подход оказывается более эффективным для ускорения на GPU из-за бесшовной интеграции с конвейерами обучения нейронных сетей. При ручном подходе буфер воспроизведения создается с помощью массивов NumPy, что просто и эффективно для задач небольшого масштаба. Это можно сделать следующим образом:

import numpy as np

class ReplayBuffer:
    def __init__(self, max_size, state_dim, action_dim):
        self.max_size = max_size
        self.states = np.zeros((max_size, state_dim), dtype=np.float32)
        self.actions = np.zeros((max_size, action_dim), dtype=np.float32)
        self.rewards = np.zeros(max_size, dtype=np.float32)
        self.next_states = np.zeros((max_size, state_dim), dtype=np.float32)
        self.dones = np.zeros(max_size, dtype=np.float32)
        self.ptr = 0
        self.size = 0

    def add(self, state, action, reward, next_state, done):
             
        ...

    def sample(self, batch_size):
        idx = np.random.randint(0, self.size, size=batch_size)
        return (
            self.states[idx],
            ...

             self.dones[idx],
        )

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

При использовании метода на основе тензора буфер воспроизведения кодируется с помощью PyTorch или TensorFlow. Такой подход, по моему опыту (пока что), кажется несколько проблематичным. Мне удалось настроить графический процессор для работы с TensorFlow, но специфика всей цепочки драйверов и версий сопутствующих программных библиотек, которые должны присутствовать для определенной версии не только TensorFlow, но и Python при использовании конкретного графического процессора ошеломляет.

Позже я попробовал PyTorch. Процесс прошел гораздо более гладко, возможно, благодаря моему предыдущему опыту работы с TensorFlow. Интеграция обучения нейронных сетей PyTorch с ускорением на GPU настолько органична, что набор данных из почти миллиона строк при подаче в довольно сложную сеть с 10 миллионами параметров может обработать одну эпоху примерно за 4 минуты на очень простой видеокарте NVIDIA T4. Простейшую реализацию на Python можно выполнить так:

import torch

class ReplayBuffer:
    def __init__(self, max_size, state_dim, action_dim):
        self.max_size = max_size
        self.states = torch.zeros((max_size, state_dim), dtype=torch.float32)
        ...

        self.ptr = 0
        self.size = 0

    def add(self, state, action, reward, next_state, done):
        self.states[self.ptr] = torch.tensor(state, dtype=torch.float32)
        self.actions[self.ptr] = torch.tensor(action, dtype=torch.float32)
        self.rewards[self.ptr] = torch.tensor(reward, dtype=torch.float32)
        self.next_states[self.ptr] = torch.tensor(next_state, dtype=torch.float32)
        self.dones[self.ptr] = torch.tensor(done, dtype=torch.float32)
        self.ptr = (self.ptr + 1) % self.max_size
        self.size = min(self.size + 1, self.max_size)

    def sample(self, batch_size):
        idx = torch.randint(0, self.size, (batch_size,))
        return (
            self.states[idx],
            self.actions[idx],
            self.rewards[idx],
            self.next_states[idx],
            self.dones[idx],
        )

Этот метод очень эффективен, поскольку он напрямую интегрируется с конвейерами Autograd и оптимизации PyTorch. Итак, подводя итог сравнению ручного и тензорного подходов, преимущество ручного подхода заключается в простоте реализации и отсутствии зависимости от фреймворков глубокого обучения. Минусами являются ограниченная масштабируемость и отсутствие ускорения на GPU. Преимуществами тензорного подхода являются тесная интеграция с нейронными сетями, ускорение на GPU и решение масштабных задач, в то время как недостатками можно назвать хорошее знакомство/знание сложных реализаций TensorFlow/PyTorch.

Поэтому, как правило, при выборе подхода следует учитывать масштаб проблемы и доступность оборудования; при этом тензорные методы предпочтительны для крупномасштабных задач или обучения графического процессора. Кроме того, если в вашей среде имеются состояния переменного размера, как в случае с изображениями, то подойдет метод на основе тензора. Кроме того, SAC можно усовершенствовать с помощью приоритетного воспроизведения опыта (Prioritized Experience Replay, PER), где выборка буфера воспроизведения основана на относительной важности каждого состояния в буфере путем измерения ошибки временной разницы (Temporal Difference Error) или других ключевых показателей. Реализация PER упрощается при использовании буферов воспроизведения на основе тензоров, поскольку она обеспечивает эффективное обновление приоритетов и выборку.

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

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

Итак, подводя итог, можно сказать, что хорошо реализованный буфер SAC имеет решающее значение для успеха SAC и многих алгоритмов вне политики (off policy). Он обеспечивает стабильное и эффективное обучение посредством предоставления разнообразного декоррелированного опыта.


Сеть критики (Critic Network)

В алгоритмах SAC сеть критики оценивает Q-значение (или значение действия состояния, или следующее действие, которое должен предпринять субъект), когда ему представлено текущее состояние среды и выбор субъектом следующего действия. SAC задействует две такие сети критики, чтобы снизить смещение оценки, а также повысить стабильность обучения. Поскольку нейронная сеть принимает в качестве входных данных 2 фиксированных набора данных распределения вероятностей действий акторной сети и «координат» состояний среды, выбор использования NumPy или Tensors будет зависеть от размера проблемы (который определяется размером сети и объемом данных для использования в обучении), а также от доступности оборудования.

Благодаря ручной нетензорной реализации критических сетей NumPy оказывается полезным для матричных операций и обновления градиентов. В случаях, когда сети имеют менее 5 слоев размером не более 15 каждый или в образовательных и иллюстративных целях, это может быть приемлемым решением. При таком подходе проходы прямого и обратного распространения реализуются вручную, что может привести к ошибкам и не так эффективно при масштабировании до больших наборов обучающих данных. Вот как может выглядеть ручная реализация на Python:

import numpy as np

class CriticNetwork:
    def __init__(self, state_dim, action_dim, hidden_dim=256):
        self.state_dim = state_dim
        self.action_dim = action_dim
        self.hidden_dim = hidden_dim

        # Initialize weights and biases
        self.W1 = np.random.randn(state_dim + action_dim, hidden_dim)
        self.b1 = np.zeros(hidden_dim)
        self.W2 = np.random.randn(hidden_dim, hidden_dim)
        self.b2 = np.zeros(hidden_dim)
        self.W3 = np.random.randn(hidden_dim, 1)
        self.b3 = np.zeros(1)

    def forward(self, state, action):
        x = np.concatenate([state, action], axis=-1)
        x = np.maximum(0, x @ self.W1 + self.b1)  # ReLU activation
        x = np.maximum(0, x @ self.W2 + self.b2)  # ReLU activation
        q_value = x @ self.W3 + self.b3
        return q_value

    def update(self, states, actions, targets, learning_rate=1e-3):
        # Manual gradient descent (simplified)
        q_values = self.forward(states, actions)
        error = q_values - targets
        # Backpropagation and weight updates (not shown for brevity)

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

import torch
import torch.nn as nn
import torch.nn.functional as F

class CriticNetwork(nn.Module):
    def __init__(self, state_dim, action_dim, hidden_dim=256):
        super(CriticNetwork, self).__init__()
        self.fc1 = nn.Linear(state_dim + action_dim, hidden_dim)
        self.fc2 = nn.Linear(hidden_dim, hidden_dim)
        self.fc3 = nn.Linear(hidden_dim, 1)

    def forward(self, state, action):
        x = torch.cat([state, action], dim=-1)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        q_value = self.fc3(x)
        return q_value

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

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

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

Если мы помним, сети SAC используют две сети критики (часто называемые Q1 и Q2) для смягчения смещения переоценки. Таким образом, целевое значение Q определяется как минимум из двух значений Q, полученных сетями. Для иллюстрации, сети критиков, как часть выходных данных сети акторов, действительно создают вектор с оценкой вознаграждения за выполнение каждого из доступных действий.

Поэтому, естественно, в пределах каждого такого вектора индекс/действие с наибольшим значением будет прогнозировать наибольшую награду. Основная цель сетей критики — консервативно определить градиент для обратного распространения сети актеров (actor network).

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

Эти сети критики, которые обеспечивают градиент целевой функции, обновляющей сеть актеров, также должны быть обучены. Но поскольку они оценивают будущие вознаграждения за свои действия, как устанавливается их цель обучения? Ответ на обновления критики заключается в том, что SAC не использует напрямую минимальное из двух значений Q. Вместо этого обновление выполняется для каждого критика (Q1 и Q2) с использованием мягкой цели, полученной с помощью уравнения Беллмана.

class DoubleCriticNetwork(nn.Module):
    def __init__(self, state_dim, action_dim, hidden_dim=256):
        super(DoubleCriticNetwork, self).__init__()
        self.Q1 = CriticNetwork(state_dim, action_dim, hidden_dim)
        self.Q2 = CriticNetwork(state_dim, action_dim, hidden_dim)

    def forward(self, state, action):
        q1 = self.Q1(state, action)
        q2 = self.Q2(state, action)
        return q1, q2

Кроме того, целевые сети в SAC представляют собой еще один отдельный набор сетей (по одной для каждого критика Q1 и Q2), которые используются для вычисления целевых значений Q, являющихся ключевыми в обратном распространении этих сетей критики. Они сами по себе медленно обновляются посредством усреднения Поляка, чтобы обеспечить стабильность во время обучения. Использование целевых сетей обусловлено необходимостью обеспечить стабильную цель для уравнения Беллмана, без которой, как утверждается, оценки Q-значений сетей критики будут расходиться или колебаться из-за петли обратной связи между Q-значениями и целями.

for target_param, param in zip(target_critic.parameters(), critic.parameters()):
    target_param.data.copy_(tau * param.data + (1 - tau) * target_param.data)
```
where `tau` is the polyak averaging coefficient (e.g., 0.005).

Функция потерь для критиков будет тогда представлять собой среднеквадратичную ошибку (MSE) между прогнозируемым значением Q и целевым значением Q, установленным уравнением Беллмана с помощью вышеупомянутых целевых сетей.

target_q_value = reward + (1 - done) * gamma * min(Q1_target(next_state, next_action), Q2_target(next_state, next_action))
```
where `gamma` is the discount factor.

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

optimizer = torch.optim.Adam(critic.parameters(), lr=learning_rate)

Отладку и тестирование можно выполнять, подавая фиктивные входные данные и проверяя форму и значения выходных данных. Необходимо убедиться, что сеть может адаптироваться к небольшому набору данных. Как уже упоминалось, для проверки входных данных могут использоваться утверждения Python. Сети критики интегрируются в цикл обучения SAC путем вычисления Q-значений, обновления потерь критики и синхронизации целевых сетей. Важно обеспечить обновление сети критики одновременно с сетями актеров и значений, поэтому тензоры и, в частности, использование графических процессоров здесь играют важную роль.

Для сетей критики можно также применить несколько дополнительных советов по оптимизации, в первую очередь, к ним относятся пакетная нормализация или нормализация слоев. Во-вторых, эксперименты с различными функциями активации, такими как ReLU или Leaky, могут дать разные результаты в зависимости от тестируемых данных и характера используемой сети. Кроме того, можно точно настраивать такие гиперпараметры, как скорость обучения и глубина сети. Мониторинг потерь критики во время обучения важен для выявления таких проблем, как переобучение и нестабильность.

В заключение следует отметить, что сеть критики является важнейшим компонентом SAC, играющим важную роль в оценке Q-значений, а также направляющим обновления политики субъектов. Хорошо реализованная сеть критики обеспечивает стабильное и эффективное обучение.


Сети значений (Value Networks)

Эта сеть, также называемая функцией состояния-значения (state-value function), является дополнительной частью SAC, которую мы можем использовать по своему усмотрению. Ее цель — оценить ожидаемую совокупную выгоду состояния при текущей политике с помощью функции мягкого значения. Хотя использование сети создания стоимости является «необязательным», при правильной реализации оно имеет ряд преимуществ. Во-первых, поскольку функция мягкого значения (soft value) явно включает в себя энтропию, она стимулирует политику к более эффективному и результативному исследованию. Действие функции мягкого значения имеет тенденцию обеспечивать более плавную цель для обучения, что может помочь стабилизировать обучение.

Такая стабильность очень полезна при работе с входными данными большой размерности (когда вектор входных данных имеет размер >10) или пространства действий являются непрерывными по своей природе (например, вариант действия (0,14, 0,67, 1,51) в отличие от (купить, продать, удержать)), или когда среды данных сталкиваются с несколькими локальными оптимумами (сценарий, в котором много различных конфигураций веса сети, по-видимому, дают достойные результаты, когда каждая конфигурация обучается на отдельных наборах данных или средах, но ни одна из этих конфигураций веса не может обобщать или сохранять свою производительность на более широких наборах данных).

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

Помимо использования одной сети значений, описанной выше, для регулирования целей обучения сети критики, мы также можем использовать две сети значений. В этом сценарии как сеть значений, так и целевая сеть также используются для оценки функции значений, которая предсказывает ожидаемую доходность (кумулятивное вознаграждение) из любого заданного состояния. В частности, целевая сеть значений используется для стабилизации обучения не только в этом случае, но и в глубоких QN-сетях. Являясь копией сети значений, она обновляется реже и обеспечивает стабильную цель для обучения.


Сеть актеров (Actor Network)

Это основная сеть, ее также называют сетью политики. В качестве входных данных она принимает состояния среды и выводит два вектора: среднее значение и стандартное отклонение, которые служат параметрами распределения вероятностей действий, которые можно использовать для стохастической выборки. Две сети критики, сопутствующие им целевые сети и сеть значений, если они используются, служат для содействия обратному распространению и обучению этой сети.

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

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.distributions as dist

class ActorNetwork(nn.Module):
    def __init__(self, state_dim, action_dim, hidden_dim=256):
        super(ActorNetwork, self).__init__()
        self.fc1 = nn.Linear(state_dim, hidden_dim)
        self.fc2 = nn.Linear(hidden_dim, hidden_dim)
        self.fc_mean = nn.Linear(hidden_dim, action_dim)
        self.fc_log_std = nn.Linear(hidden_dim, action_dim)

    def forward(self, state):
        x = F.relu(self.fc1(state))
        x = F.relu(self.fc2(x))
        mean = self.fc_mean(x)
        log_std = self.fc_log_std(x)
        return mean, log_std

    def sample_action(self, state):
        mean, log_std = self.forward(state)
        std = torch.exp(log_std)
        normal = dist.Normal(mean, std)
        action = normal.rsample()  # Reparameterization trick
        return torch.tanh(action), normal.log_prob(action).sum(dim=-1, keepdim=True)

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

import torch

def select_action(mean, log_std):
    """
    Given the SAC actor's output (mean and log_std), this function selects an action index.
    
    Args:
        mean (torch.Tensor): Mean of the action distribution, shape (n_actions,)
        log_std (torch.Tensor): Log standard deviation, shape (n_actions,)

    Returns:
        int: The index of the selected action.
    """
    std = log_std.exp()  # Convert log standard deviation back to standard deviation
    ....  
    return selected_index

# Example inputs
mean = torch.tensor([0.2, -0.5, 1.0, 0.3])  # Example mean values for 4 actions
log_std = torch.tensor([-1.0, -0.7, -0.2, -0.5])  # Example log std values

# Select action
action_index = select_action(mean, log_std)
print("Selected Action Index:", action_index)

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

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

Кроме того, исходя из нашей функции Python, приведенной выше, поскольку большинство действий в реальных приложениях имеют область действия или ограничены, SAC применяет функцию Tanh для сжатия выборочных действий до диапазона от -1 до +1. Это гарантирует, что действие остается в управляемом диапазоне, сохраняя при этом стохастическую природу процесса.


Агент

Агент в SAC, который мы здесь представляем как класс агента в Python, сочетает оптимизацию политики (сеть актеров) с аппроксимацией функции значений (объединение двух сетей критики — сети значений и целевой сети значений). Агент должен обладать высокой эффективностью выборки и уметь обрабатывать непрерывные пространства действий. Это связано с тем, что он объединяет не только эти сети, но и буфер воспроизведения с целью обучения «оптимальной политике» или подходящим весам и смещениям для сети актеров.

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

import torch
import torch.nn.functional as F
import torch.optim as optim

class SACAgent:
    def __init__(self, state_dim, action_dim, hidden_dim=256, replay_buffer_size=1e6, batch_size=256, gamma=0.99, tau=0.005, alpha=0.2):
        self.state_dim = state_dim
        ...

        self.alpha = alpha

        # Initialize networks and replay buffer
        self.actor = ActorNetwork(state_dim, action_dim, hidden_dim)
        ....

        self.value_optimizer = optim.Adam(self.value_network.parameters(), lr=3e-4)

    def select_action(self, state):
        state = torch.FloatTensor(state).unsqueeze(0)
        action, _ = self.actor.sample_action(state)
        return action.detach().numpy()[0]

    def update(self):
        # Sample a batch from the replay buffer
        states, actions, rewards, next_states, dones = self.replay_buffer.sample(self.batch_size)

        # Convert to tensors
        states = torch.FloatTensor(states)
        ...

        dones = torch.FloatTensor(dones).unsqueeze(1)

        # Update value network
        target_value = self.target_value_network(next_states)
        ...

        # Update critic networks
        q1_value = self.critic1(states, actions)
             
        ...

        self.critic2_optimizer.step()

        # Update actor network
        new_actions, log_probs = self.actor.sample_action(states)
             
        ...

        self.actor_optimizer.step()

        # Update target networks
        for target_param, param in zip(self.target_value_network.parameters(), self.value_network.parameters()):
            target_param.data.copy_(self.tau * param.data + (1 - self.tau) * target_param.data)

Поскольку мы используем тензоры с PyTorch, важно подчеркнуть, что ручное назначение устройства GPU, если оно доступно, во многом способствует обеспечению максимально эффективной работы/выполнения тензоров.


Окружение

Окружение — это место, где определяются наборы данных для обучения и целей/действий. По сути, оно определяет проблему, которую пытается решить агент, предоставляя агенту сигнал о состоянии, вознаграждении и завершении на основе его действий. Среду можно реализовать вручную (т. е. из первых принципов) или путем наследования с использованием библиотек, таких как OpenAI Gym для стандартизированных сред. Окружение на основе тензора можно реализовать следующим образом:

import torch

class TensorEnvironment:
    def __init__(self):
        self.state_space = 4  # Example: state dimension
        self.action_space = 2  # Example: action dimension
        self.state = torch.zeros(self.state_space)  # Initial state

    def reset(self):
        self.state = torch.randn(self.state_space)  # Reset to a random state
        return self.state

    def step(self, action):
        # Define transition dynamics and reward function
        next_state = self.state + action  # Simple transition
        ...

        self.state = next_state
        return next_state, reward, done, {}

    def render(self):
        print(f"State: {self.state}")

Затем можно использовать цикл для сбора опыта и периодического обновления агента:

for episode in range(num_episodes):
    state = env.reset()
    episode_reward = 0
    for step in range(max_steps):
        action = agent.select_action(state)
        next_state, reward, done, _ = env.step(action)
        agent.replay_buffer.add(state, action, reward, next_state, done)
        state = next_state
        episode_reward += reward
        if len(agent.replay_buffer) > batch_size:
            agent.update()
        if done:
            break
    print(f"Episode {episode}, Reward: {episode_reward}")


Сборка и тестирование мастера

Мы тестируем нашу гибридную модель SAC на основе тензора, которая помимо сети актеров и двух сетей критиков использует сеть значений и целевую сеть значений вместо двух целевых сетей (которые обучают критиков). Мы используем пару EURUSD на 4-часовом таймфрейме за 2023 год.

TensorFlow и PyTorch позволяют не только обучать модели, но и проводить их перекрестную проверку. TensorFlow позволяет передавать проверочные значения данных x и y в свою функцию fit, тогда как PyTorch по сути позволяет то же самое при передаче этих данных в data_loader. Тестовый запуск советника, скомпилированного на MQL5, который не выполняет перекрестную проверку (или вывод), дает нам следующие результаты для EURUSD за 2023 год:

R1

C1

Мы используем, как и в последней статье SAC, ONNX для экспорта модели из Python и импорта ее в MQL5. Мы имеем дело с 5 нейронными сетями, и пока только одна из них делает нужные нам прогнозы, так как остальные 4 помогают только в обратном распространении. Сеть, которая нам нужна и которую мы экспортируем, — это сеть актеров. Однако эта сеть выводит не один, а два вектора, как уже упоминалось. Среднее значение и стандартное отклонение. Поэтому, прежде чем мы сможем использовать модель ONNX в MQL5, нам необходимо точно определить выходные фигуры этой модели. Входная форма проста. Мы устанавливаем фигуры в MQL5 следующим образом:

//+------------------------------------------------------------------+
//| Validation arch protected data.                                  |
//+------------------------------------------------------------------+
bool CSignalSAC::ValidationSettings(void)
{  if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_period != PERIOD_H4)
   {  Print(" time frame should be H4 ");
      return(false);
   }
   if(m_actor_handle == INVALID_HANDLE)
   {  Print("Actor OnnxCreateFromBuffer error ", GetLastError());
      return(false);
   }
   // Set input shapes
   const long _actor_in_shape[] = {1, __STATES};
   // Set output shapes
   const long _actor_out_shape[] = {1, __ACTIONS};
   if(!OnnxSetInputShape(m_actor_handle, ONNX_DEFAULT, _actor_in_shape))
   {  Print("Actor OnnxSetInputShape error ", GetLastError());
      return(false);
   }
   if(!OnnxSetOutputShape(m_actor_handle, 0, _actor_out_shape))
   {  Print("Actor OnnxSetOutputShape error ", GetLastError());
      return(false);
   }
   if(!OnnxSetOutputShape(m_actor_handle, 1, _actor_out_shape))
   {  Print("Actor OnnxSetOutputShape error ", GetLastError());
      return(false);
   }
//read best weights
//--- ok
   return(true);
}
Обработка осуществляется в функции проверки нашего пользовательского класса сигналов, поскольку модель ONNX не будет работать, если эти формы не будут точно определены. Новые читатели найдут руководства по сборке советника в пользовательском файле *.*mqh сигнала здесь и здесь.


Заключение

Мы реализовали алгоритм обучения с подкреплением Soft Actor Critic на Python с помощью тензоров. Тензоры играют решающую роль в машинном обучении, поскольку они обеспечивают огромный рост эффективности при обучении моделей, а этот аспект особенно важен для трейдеров. Размер обучающих наборов данных и необходимость использования более сложно спроектированных сетей, как правило, приводят к замедлению процессов обучения. Таким образом, эта проблема решается не только за счет использования тензоров, но и за счет задействования мощности графических процессоров.

Имя Описание
hybrid_sac.mq5 Собранный в Мастере советник с заголовком, показывающим используемые файлы 
SignlWZ_54.mqh Файл класса пользовательских сигналов
model.onnx Файл сети ONNX

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/17159

Прикрепленные файлы |
model.onnx (271.1 KB)
SignalWZ_54.mqh (8.44 KB)
hybrid_sac.mq5 (6.24 KB)
Нейросети в трейдинге: Агрегация движения по времени (TMA) Нейросети в трейдинге: Агрегация движения по времени (TMA)
Фреймворк TMA открывает новый взгляд на рыночную динамику, позволяя моделям улавливать не только состояние рынка, но и само течение времени. Его способность извлекать закономерности из непрерывного потока данных делает анализ глубже и точнее, чем при классических подходах. А рекуррентная адаптация превращает этот метод в практичный инструмент для работы с реальными котировками.
Система самообучения с подкреплением для алгоритмической торговли на MQL5 Система самообучения с подкреплением для алгоритмической торговли на MQL5
В статье создаётся многоагентная система машинного обучения для алгоритмической торговли на MetaTrader 5 на основе обучения с подкреплением. Система имеет трёхуровневую архитектуру: нейроны памяти хранят опыт, агенты принимают независимые решения, коллективный разум объединяет их через взвешенное голосование. Система непрерывно совершенствуется через Q-обучение, прунинг неэффективных нейронов и эволюционное снижение исследования.
Выборочные методы MCMC: Алгоритм выборки по уровням (Slice sampling) Выборочные методы MCMC: Алгоритм выборки по уровням (Slice sampling)
В этой статье исследуется метод выборки по уровням (slice sampling) — адаптивный алгоритм MCMC, который самостоятельно регулирует параметры сэмплирования. Его эффективность продемонстрирована на моделях байесовской линейной и логистической регрессии, а результаты сравниваются с классическими частотными методами.
Моделирование рынка (Часть 07): Сокеты (I) Моделирование рынка (Часть 07): Сокеты (I)
Сокеты. Знаете ли вы, для чего они нужны или как их использовать в MetaTrader 5? Если ответ отрицательный, давайте начнем с их изучения. В сегодняшней статье рассмотрим основы. Но поскольку существует несколько способов сделать то же самое, а нас всегда интересует результат, я хочу показать, что в самом деле существует простой способ передачи данных из MetaTrader 5 в другие программы, такие как, например, Excel. Однако основная идея заключается не в том, чтобы перенести данные из MetaTrader 5 в Excel, а в обратном, то есть в переносе данных из Excel или любой другой программы в MetaTrader 5.