Примечания к градиенту политики для обучения с подкреплением

обучение с подкреплением
Post Views = 7

Эта статья взята из: [блог InTheWorld] (Добро пожаловать, чтобы оставить сообщение и обменяться)

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

Его недостатки:
– Легко попасть в локальный оптимум
– Оценка стратегии относительно неэффективна

основная теория

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

Дж ( θ ) знак равно ∫ Икс ∼ п θ ( Икс ) п θ ( Икс ) р ( Икс ) г Икс J(\theta) = \int_{x \sim p_{_\theta}(x)}^{} p_{_\theta}(x)\,r(x) \,dx J(θ)=∫x ∼pθ​(x)​pθ​​(x)r(x)dx

в Икс xx — поведение (может быть вектором), п θ ( Икс ) p_{_\theta}(x) pθ​​(x) — вероятность выбора действия. Дж ( θ ) J(\theta)J(θ) — ожидаемая доходность за весь раунд. С точки зрения алгоритма градиента политики, цель алгоритма состоит в том, чтобы максимизировать ожидаемое значение доходности. Процесс нахождения максимума фактически достигается вычислением градиента.

Производная функция целевой функции выглядит следующим образом:

∇ θ Дж ( θ ) знак равно ∫ Икс ∼ п θ ( Икс ) ∇ θ п θ ( Икс ) р ( Икс ) г Икс \nabla_{\theta} J(\theta) = \int_{x \sim p_{_\theta}(x)}^{} \nabla_{_\theta} p_{_\theta}(x)\,r (x) \,dx ∇θ​J(θ)=∫x∼pθ​​(x)​∇θ​​pθ​​(x)r(x)dx знак равно ∫ Икс ∼ п θ ( Икс ) п θ ( Икс ) ∇ θ п θ ( Икс ) п θ ( Икс ) р ( Икс ) г Икс = \int_{x \sim p_{_\theta}(x)}^{} p_{_\theta}(x)\,\frac{\nabla_{_\theta} p_{_\theta}(x) }{p_{_\theta}(x)}\,r(x) \,dx =∫x∼pθ​​(x)​pθ​​(x)pθ​​(x)∇θ​​pθ​ ​(х)​r(х)dx знак равно ∫ Икс ∼ п θ ( Икс ) п θ ( Икс ) ∇ θ л о г п θ ( Икс ) р ( Икс ) г Икс = \int_{x \sim p_{_\theta}(x)}^{} p_{_\theta}(x)\,\nabla_{_\theta}log\,{p_{_\theta}(x )}\,r(x) \,dx =∫x∼pθ​(x)​pθ​​(x)∇θ​​logpθ​​(x)r(x)dx знак равно Е Икс ∼ п θ ( Икс ) [ ∇ θ л о г п θ ( Икс ) р ( Икс ) ] = E_{x \sim p_{_\theta}(x)}^{} [\nabla_{_\theta}log\,{p_{_\theta}(x)}\,r(x)] =Ex ∼pθ​(x)[∇θ​logpθ​​(x)r(x)]

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

∇ θ л о г п θ ( Икс ) знак равно ∑ т знак равно 0 Т ∇ θ л о г п θ ( а т ∣ с т ) \nabla_{_\theta} log\,{p_{_\theta}(x)} = \sum_{t=0}^{T} \nabla_{_\theta} log\,p _{_\theta} (a_{t}|s_{t}) ∇θ​logpθ​​(x)=t=0∑T​∇θ​​logpθ​​(при​∣st​)

Таким образом, формула для окончательного градиента стоимости полиса выглядит следующим образом:

∇ θ Дж ( θ ) знак равно ∑ я знак равно 1 Н [ ∑ т знак равно 0 Т ∇ θ л о г п θ ( а я , т ∣ с я , т )   ( ∑ т знак равно 0 Т р ( с я , т , а я , т ) ) ] \nabla_{\theta} J(\theta) = \sum_{i=1}^{N}[ \sum_{t=0}^{T} \nabla_{_\theta} log\,p _{_\ тета}(a_{i,t}|s_{i,t}) \ (\sum_{t=0}^{T}r(s_{i,t}, a_{i,t}))] ∇θ ​J(θ)=i=1∑N​[t=0∑T​∇θ​​logpθ​​(ai,t​∣si,t​) (t=0∑Tr​r(si,t​ ,ай,т​)))]

Эта формула на самом деле проблематична. ∑ т знак равно 0 Т р ( с я , т , а я , т ) \sum_{t^{}=0}^{T}r(s_{i,t}, a_{i,t})∑t=0Tr​r(si,t​,ai,t​)Эта часть in Anytime будет умножаться на формулу градиента. Однако действие определенного шага должно влиять только на последующий процесс, поэтому приведенную выше формулу можно изменить в следующем виде:

∇ θ Дж ( θ ) знак равно ∑ я знак равно 1 Н [ ∑ т знак равно 0 Т ∇ θ л о г п θ ( а я , т ∣ с я , т )   ( ∑ т ‘ знак равно т Т р ( с я , т ‘ , а я , т ‘ ) ) ] \nabla_{\theta} J(\theta) = \sum_{i=1}^{N}[ \sum_{t=0}^{T} \nabla_{_\theta} log\,p _{_\ тета}(a_{i,t}|s_{i,t}) \ (\sum_{t^{'}=t}^{T}r(s_{i,t^{'}}, a_{i ,t^{'}}))] ∇θ​J(θ)=i=1∑N​[t=0∑T​∇θ​​logpθ​​(ai,t​∣si,t​) ( t'=t∑Tr​r(si,t'​,ai,t'​))]

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

Реализация TensorFlow

Хотя градиент политики редко используется сам по себе, его полезно понимать в сочетании с реализацией кода. Я все еще смотрю на реализацию Чжоу Мофаня, это чтение кода.

import numpy as np
import tensorflow as tf

np.random.seed(1)
tf.set_random_seed(1)

class PolicyGradient:
    def __init__(self,
                 n_actions,
                 n_features,
                 learning_rate=0.01,
                 reward_decay=0.95,
                 output_graph=False):
        self.n_actions = n_actions
        self.n_features = n_features
        self.lr = learning_rate
        self.gamma = reward_decay

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []
        self._build_net()
        self.sess = tf.Session()
        if output_graph:
            tf.summary.FileWriter("logs/", self.sess.graph)

        self.sess.run(tf.global_variables_initializer())

    def _build_net(self):
        with tf.name_scope('inputs'):
            self.tf_obs = tf.placeholder(tf.float32, [None, self.n_features], name="observations")
            self.tf_acts = tf.placeholder(tf.int32, [None, ], name="actions_num")
            self.tf_vt = tf.placeholder(tf.float32, [None, ], name="actions_value")

        layer = tf.layers.dense(
            inputs=self.tf_obs,
            units=10,
            activation=tf.nn.tanh,
            kernel_initializer=tf.random_normal_initializer(mean=0, stddev=0.3),
            bias_initializer=tf.constant_initializer(0.1),
            name='fc1'
        )

        all_act = tf.layers.dense(
            inputs=layer,
            units=self.n_actions,
            activation=None,
            kernel_initializer=tf.random_normal_initializer(mean=0, stddev=0.3),
            bias_initializer=tf.constant_initializer(0.1),
            name='fc2'
        )

        self.all_act_prob = tf.nn.softmax(all_act, name='act_prob')
        with tf.name_scope('loss'):
            neg_log_prob = tf.reduce_sum(-tf.log(self.all_act_prob) * tf.one_hot(self.tf_acts, self.n_actions), axis=1)
            loss = tf.reduce_sum(neg_log_prob * self.tf_vt)

        with tf.name_scope('train'):
            self.train_op = tf.train.AdamOptimizer(self.lr).minimize(loss)

    def choose_action(self, observation):
        prob_weights = self.sess.run(self.all_act_prob, feed_dict={self.tf_obs: observation[np.newaxis, :]})
        action = np.random.choice(range(prob_weights.shape[1]), p=prob_weights.ravel())
        return action

    def store_transition(self, s, a, r):
        self.ep_obs.append(s)
        self.ep_as.append(a)
        self.ep_rs.append(r)

    def learn(self):
        discounted_ep_rs_norm = self._discount_and_norm_rewards()

        self.sess.run(self.train_op, feed_dict={
            self.tf_obs: np.vstack(self.ep_obs),
            self.tf_acts: np.array(self.ep_as),
            self.tf_vt: discounted_ep_rs_norm,
        })

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []
        return discounted_ep_rs_norm

    def _discount_and_norm_rewards(self):
        discounted_ep_rs = np.zeros_like(self.ep_rs)
        running_add = 0
        for t in reversed(range(0, len(self.ep_rs))):
            running_add = running_add * self.gamma + self.ep_rs[t]
            discounted_ep_rs[t] = running_add
        discounted_ep_rs -= np.mean(discounted_ep_rs)
        discounted_ep_rs /= np.std(discounted_ep_rs)
        return discounted_ep_rs

Сначала посмотрите на функцию _discount_and_norm_rewards, которая содержит логику обработки данных, означает обработку смены и нормализацию. А данные вознаграждения рассчитываются в обратном порядке, то есть вычисляется возвращаемое значение от t до T.

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

После этого буду изучать DDPG и Actor Critic в сочетании с Baseline (здесь сначала будет вырыта яма).