Привет, я аспирант, изучаю глубокое обучение с подкреплением. Я написал предыдущий пост в блоге о реализации Deep Q-Network с NNabla.



Здесь я познакомлю вас с глубинными детерминированными градиентами политики (DDPG) с NNabla. Полная реализация находится здесь.

DDPG

DDPG - это метод градиента политики для задач непрерывного контроля.



В DDPG есть 2 сети: сеть политики (субъект) и сеть ценности действия (критик). Этот вид алгоритмов называется «субъект-критик», поскольку субъект изучает функцию политики, чтобы максимизировать накопленное вознаграждение, а критик изучает функцию (действие-) ценности, чтобы правильно предсказывать результаты.

Давайте сделаем эти две нейронные сети с помощью NNabla.

import nnabla as nn
import nnabla.functions as F
import nnabla.parametric_functions as PF
def q_network(obs_t, action_t):
    with nn.parameter_scope('critic'):
        out = PF.affine(obs_t, 64, name='fc1')
        out = F.tanh(out)
        out = F.concatenate(out, action_t, axis=1)
        out = PF.affine(out, 64, name='fc2')
        out = F.tanh(out)
        out = PF.affine(out, 1, name='fc3')
        return out
def policy_network(obs, action_size):
    with nn.parameter_scope('actor'):
        out = PF.affine(obs, 64, name='fc1')
        out = F.tanh(out)
        out = PF.affine(out, 64, name='fc2')
        out = F.tanh(out)
        out = PF.affine(out, action_size, name='fc3')
        return F.tanh(out)

Довольно просто! NNabla управляет весами и смещениями на основе системы пространств имен, подобной TensorFlow, объявленной nn.parameter_scope().

Потеря критика

Критик обучается с помощью одноступенчатой ​​ошибки временной разницы (TD):

Это можно записать с помощью NNabla следующим образом:

# N is a batch size
# state_size is a size of input vectors
# action_size is a size of the policy output
obs_t = nn.Variable((N, state_size))   # observation at t
act_t = nn.Variable((N, action_size))  # take action at t
rew_tp1 = nn.Variable((N, 1))          # reward value at t+1
obs_tp1 = nn.Variable((N, state_size)) # observation at t+1
ter_tp1 = nn.Variable((N, 1))          # 1.0 if terminal state
with nn.parameter_scope('trainable'):
    q_t = q_function(obs_t, act_t)
with nn.parameter_scope('target'):
    act_tp1 = policy_function(obs_tp1, action_size)
    q_tp1 = q_function(obs_tp1, act_tp1)
y = rew_tp1 + gamma * q_tp1 * (1.0 - ter_tp1)
critic_loss = F.mean(F.squared_error(q_t, y))

Приведенный выше код строит граф вычислений для вычисления квадрата ошибки TD.

Потеря актера

Напротив, действия по установлению истины напрямую не доступны. Таким образом, актера учат максимально оценивать критику. Градиент сети политики рассчитывается следующим образом.

Этот расчет градиента можно также записать в NNabla.

with nn.parameter_scope('trainable'):
    policy_t = policy_function(obs_t, action_size)
    q_t_with_actor = q_function(obs_t, policy_t)
actor_loss = -F.mean(q_t_with_actor) # gradient ascent

- необходимо обновить актера, чтобы максимизировать оценку ценности. В конце концов, актер направляется в высокоценное пространство, полученное с помощью функции «действие-ценность».

Целевое обновление

В отличие от DQN, целевое обновление DDPG постепенно синхронизирует целевые функции с последними параметрами.

with nn.parameter_scope('trainable'):
    trainable_params = nn.get_parameters()
with nn.parameter_scope('target'):
    target_params = nn.get_parameters()
update_ops = []
for key, src in trainable_params.items():
    dst = target_params[key]
    update_ops.append(F.assign(dst, (1.0 - tau) * dst + tau * src)))
target_update = F.sink(*update_ops)

F.assign почти такой же, как tf.assign. F.sink - это конечный узел для одновременного запуска всех входов.

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

Заключение

Я представил реализацию DDPG с помощью фреймворка SONY для глубокого обучения NNabla. Если вы попробуете эту реализацию с графическим процессором, вы обнаружите, что скорость обучения у него высокая.

Если вам нужна дополнительная информация о NNabla, посетите здесь.