[Aprendizaje de refuerzo] Explicación detallada del algoritmo de gradiente de política (gradiente de estrategia)

1 Introducción al gradiente de políticas

1.1 Los métodos de aprendizaje por refuerzo basados ​​en políticas y basados ​​en valores son diferentes

El aprendizaje por refuerzo es un mecanismo para aprender el comportamiento correcto a través de recompensas y castigos. Hay muchos miembros diferentes en la familia, con recompensas y castigos de aprendizaje, y eligen comportamientos en función de lo que cree que son valores altos, como Q-Learning, Deep-Q-network, y también hay un método para generar comportamientos directamente sin análisis de recompensas y castigos Este es el gradiente de política del que vamos a hablar hoy agrega una red neuronal para generar acciones predichas. En comparación con los métodos basados ​​en valores, la mayor ventaja de la salida directa de acciones de Policy Gradient es que puede seleccionar acciones en un intervalo continuo, mientras que los métodos basados ​​en valores, como Q-Learning, si calcula el valor de un número infinito de acciones, así que elige comportarse, lo cual es demasiado para él.

1.2 Actualización del algoritmo

Ciertamente es conveniente tener una red neuronal, pero ¿cómo revertimos la transferencia de errores de la red neuronal? ¿Cuál es el error de Policy Gradient? La respuesta es ningún error. Pero en realidad está realizando una especie de transmisión hacia atrás. El propósito de este paso atrás es hacer que el comportamiento seleccionado tenga más probabilidades de ocurrir la próxima vez. Pero, ¿cómo determinamos si este comportamiento debería aumentar la probabilidad de ser seleccionado? En este momento, las recompensas y los castigos pueden ser útiles en este momento.

1.3 Pasos de actualización específicos

inserte la descripción de la imagen aquí

Ahora demuestre nuevamente, la información observada es analizada por la red neuronal, y se selecciona el comportamiento de la izquierda, y realizamos directamente la transmisión inversa, de modo que aumenta la posibilidad de ser seleccionado la próxima vez, pero la información de recompensa y castigo dice nos dice que este comportamiento no es correcto.De acuerdo, entonces el aumento de nuestras posibilidades de acción se reduce en consecuencia. De esta forma, las recompensas pueden usarse para controlar el paso hacia atrás de nuestra red neuronal. Tomemos otro ejemplo, si la información de observación esta vez hace que la red neuronal elija el comportamiento de la derecha, el comportamiento de la derecha se transmitirá a la inversa, de modo que el comportamiento de la derecha se seleccionará un poco más la próxima vez. esta vez, la información de recompensa y castigo también vendrá, dinos que este es un buen comportamiento, luego aumentaremos nuestros esfuerzos en este pase inverso, para que sea seleccionado más violentamente la próxima vez. Esta es la idea central de Policy Gradient.

2 Actualización del algoritmo de gradiente de políticas

La dirección de descarga gratuita de todos los códigos es la siguiente:
https://download.csdn.net/download/shoppingend/85194070

2.1 Puntos principales

Policy Gradient es una gran familia en RL, no es como el método Value-based (Q-Learning, Sarsa), pero también recibe información del entorno (observación), la diferencia es que no da salida al valor de la acción, pero la acción específica de That, por lo que Policy Gradient salta la etapa de valor. Y una de las mayores ventajas de Policy Gradient es que la salida de la acción puede ser un valor continuo. El método basado en valores que mencionamos antes genera valores discontinuos, y luego se selecciona la acción con el valor más grande. El gradiente de política puede seleccionar una acción en una distribución continua.

2.2 Algoritmo

El algoritmo de gradiente de política más simple que presentamos es una actualización basada en la ronda completa de datos, también llamada método REINFORCE. Este método es el método más básico de Policy Gradient. Con esta base, haremos otros más avanzados.
inserte la descripción de la imagen aquí
Δ(log(Política(s,a))*V representa el grado de sorpresa de la acción seleccionada a en el estado s, si la probabilidad de Política(s,a) es menor, logaritmo inverso(Política(s,a)) (Es decir, -log§) es mayor. Si obtiene una R grande cuando Policy(s,a) es pequeña, es decir, una V grande, entonces -Δ(log(Policy(s,a))* La V es más grande, lo que significa más sorprendido (Elegí una acción que no se selecciona a menudo, pero descubrí que puede obtener una buena recompensa, por lo que esta vez tengo que hacer una modificación importante en mis parámetros). Este es el significado físico de el asombro se ha ido.

2.3 Formación de código de algoritmo

Primero defina el bucle para la actualización principal:

import gym
from RL_brain import PolicyGradient
import matplotlib.pyplot as plt

RENDER = False  # 在屏幕上显示模拟窗口会拖慢运行速度, 我们等计算机学得差不多了再显示模拟
DISPLAY_REWARD_THRESHOLD = 400  # 当 回合总 reward 大于 400 时显示模拟窗口

env = gym.make('CartPole-v0')   # CartPole 这个模拟
env = env.unwrapped     # 取消限制
env.seed(1)     # 普通的 Policy gradient 方法, 使得回合的 variance 比较大, 所以我们选了一个好点的随机种子

print(env.action_space)     # 显示可用 action
print(env.observation_space)    # 显示可用 state 的 observation
print(env.observation_space.high)   # 显示 observation 最高值
print(env.observation_space.low)    # 显示 observation 最低值

# 定义
RL = PolicyGradient(
    n_actions=env.action_space.n,
    n_features=env.observation_space.shape[0],
    learning_rate=0.02,
    reward_decay=0.99,   # gamma
    # output_graph=True,    # 输出 tensorboard 文件
)

bucle principal:

for i_episode in range(3000):

    observation = env.reset()

    while True:
        if RENDER: env.render()

        action = RL.choose_action(observation)

        observation_, reward, done, info = env.step(action)

        RL.store_transition(observation, action, reward)    # 存储这一回合的 transition

        if done:
            ep_rs_sum = sum(RL.ep_rs)

            if 'running_reward' not in globals():
                running_reward = ep_rs_sum
            else:
                running_reward = running_reward * 0.99 + ep_rs_sum * 0.01
            if running_reward > DISPLAY_REWARD_THRESHOLD: RENDER = True     # 判断是否显示模拟
            print("episode:", i_episode, "  reward:", int(running_reward))

            vt = RL.learn() # 学习, 输出 vt, 我们下节课讲这个 vt 的作用

            if i_episode == 0:
                plt.plot(vt)    # plot 这个回合的 vt
                plt.xlabel('episode steps')
                plt.ylabel('normalized state-action value')
                plt.show()
            break

        observation = observation_

3 Decisión de pensamiento de gradiente de política

3.1 Estructura del código principal

Usando el algoritmo de gradiente de política básico, se ve muy similar al algoritmo anterior basado en valores.

class PolicyGradient:
    # 初始化 (有改变)
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):

    # 建立 policy gradient 神经网络 (有改变)
    def _build_net(self):

    # 选行为 (有改变)
    def choose_action(self, observation):

    # 存储回合 transition (有改变)
    def store_transition(self, s, a, r):

    # 学习更新参数 (有改变)
    def learn(self, s, a, r, s_):

    # 衰减回合的 reward (新内容)
    def _discount_and_norm_rewards(self):

inicialización:

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   # reward 递减率

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []    # 这是我们存储 回合信息的 list

        self._build_net()   # 建立 policy 神经网络

        self.sess = tf.Session()

        if output_graph:    # 是否输出 tensorboard 文件
            # $ tensorboard --logdir=logs
            # http://0.0.0.0:6006/
            # tf.train.SummaryWriter soon be deprecated, use following
            tf.summary.FileWriter("logs/", self.sess.graph)

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

3.2 Establecer una red neuronal de políticas

La red neuronal que vamos a construir esta vez es así:
inserte la descripción de la imagen aquí
debido a que esto es aprendizaje por refuerzo, no hay una etiqueta y en el aprendizaje supervisado en la red neuronal. En su lugar, elegimos la acción.

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        with tf.name_scope('inputs'):
            self.tf_obs = tf.placeholder(tf.float32, [None, self.n_features], name="observations")  # 接收 observation
            self.tf_acts = tf.placeholder(tf.int32, [None, ], name="actions_num")   # 接收我们在这个回合中选过的 actions
            self.tf_vt = tf.placeholder(tf.float32, [None, ], name="actions_value") # 接收每个 state-action 所对应的 value (通过 reward 计算)

        # fc1
        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'
        )
        # fc2
        all_act = tf.layers.dense(
            inputs=layer,
            units=self.n_actions,   # 输出个数
            activation=None,    # 之后再加 Softmax
            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')  # 激励函数 softmax 出概率

        with tf.name_scope('loss'):
            # 最大化 总体 reward (log_p * R) 就是在最小化 -(log_p * R), 而 tf 的功能里只有最小化 loss
            neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=all_act, labels=self.tf_acts) # 所选 action 的概率 -log 值
            # 下面的方式是一样的:
            # 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_mean(neg_log_prob * self.tf_vt)  # (vt = 本reward + 衰减的未来reward) 引导参数的梯度下降

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

¿Por qué usar loss=-log(prob)*Vt como loss. En pocas palabras, arriba se mencionan dos tipos de líneas para calcular neg_log_prob.Estos dos tipos de líneas son exactamente iguales, excepto que la segunda es la expansión de la primera. Si observa detenidamente la primera fila, se trata de entropía cruzada en el problema de clasificación de redes neuronales. Los parámetros de la red neuronal se mejoran de acuerdo con esta verdad básica usando softmax. Obviamente, esto no es muy diferente de un problema de clasificación.Podemos entender este neg_log_prob como un error de clasificación de entropía cruzada. La etiqueta en el problema de clasificación es la y correspondiente a la x real, y en nuestro gradiente de política, x es el estado e y es el número de acción que realiza de acuerdo con esta x. Entonces también se puede entender que la acción que hace según x es siempre correcta (la acción que sale es siempre la etiqueta correcta, y siempre modificará sus parámetros según esta etiqueta correcta. Pero no es así, su las acciones no son necesariamente todas Es la etiqueta correcta, que es la diferencia entre Gradiente de política y clasificación
Para garantizar que esta acción sea la etiqueta correcta, nuestra pérdida se multiplica por Vt en la línea de entropía cruzada original, y Vt es se usa para decir a la cruz ¿Es el gradiente calculado por -entropía un gradiente confiable? Si Vt es pequeño o negativo, significa que el descenso del gradiente está en la dirección incorrecta, y debemos actualizar los parámetros en otra dirección. Si este Vt es positivo , o si es muy grande, Vt elogiará el gradiente de entropía cruzada, y el gradiente caerá en esta dirección. Hay una imagen a continuación, que es exactamente la idea explicada. Y por qué es loss=-log(prob
inserte la descripción de la imagen aquí
) Vt en lugar de loss= -prob Vt. La razón es que el prob aquí proviene de softmax, y el cálculo de todos los gradientes de parámetros en la red neuronal usa entropía cruzada, y luego multiplica este gradiente por Vt para controlar la dirección y la intensidad de descenso de gradiente.

3.3 Comportamiento de selección

Este comportamiento ya no se selecciona por valor Q, sino por probabilidad. Incluso sin epsilon-greedy, tiene un cierto grado de aleatoriedad.

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        ...
    def choose_action(self, observation):
        prob_weights = self.sess.run(self.all_act_prob, feed_dict={
    
    self.tf_obs: observation[np.newaxis, :]})    # 所有 action 的概率
        action = np.random.choice(range(prob_weights.shape[1]), p=prob_weights.ravel())  # 根据概率来选 action
        return action

3.4 Ronda de almacenamiento

Esta parte es para agregar la observación, la acción y la recompensa de este paso a la lista. Debido a que la lista debe borrarse después del final de esta ronda, y luego se almacenarán los datos para la próxima ronda, por lo que borraremos la lista en learn()

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        ...
    def choose_action(self, observation):
        ...
    def store_transition(self, s, a, r):
        self.ep_obs.append(s)
        self.ep_as.append(a)
        self.ep_rs.append(r)

3.5 Aprendizaje

El método learn() en esta sección es muy simple. En primer lugar, tenemos que manipular todos los recursos de esta ronda para que sea más adecuado para el aprendizaje. La primera es usar γ para atenuar las recompensas futuras a medida que pasa el tiempo, y luego reducir la varianza de la ronda del gradiente de política hasta cierto punto.

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        ...
    def choose_action(self, observation):
        ...
    def store_transition(self, s, a, r):
        ...
    def learn(self):
        # 衰减, 并标准化这回合的 reward
        discounted_ep_rs_norm = self._discount_and_norm_rewards()   # 功能再面

        # train on episode
        self.sess.run(self.train_op, feed_dict={
    
    
             self.tf_obs: np.vstack(self.ep_obs),  # shape=[None, n_obs]
             self.tf_acts: np.array(self.ep_as),  # shape=[None, ]
             self.tf_vt: discounted_ep_rs_norm,  # shape=[None, ]
        })

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []    # 清空回合 data
        return discounted_ep_rs_norm    # 返回这一回合的 state-action value

Mira de nuevo discounted_ep_rs_norm

vt = RL.learn() # 学习, 输出 vt, 我们下节课讲这个 vt 的作用

if i_episode == 0:
    plt.plot(vt)    # plot 这个回合的 vt
    plt.xlabel('episode steps')
    plt.ylabel('normalized state-action value')
    plt.show()

Finalmente, cómo usar el algoritmo para realizar la atenuación de recompensas futuras

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        ...
    def choose_action(self, observation):
        ...
    def store_transition(self, s, a, r):
        ...
    def learn(self):
        ...
    def _discount_and_norm_rewards(self):
        # discount episode rewards
        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

        # normalize episode rewards
        discounted_ep_rs -= np.mean(discounted_ep_rs)
        discounted_ep_rs /= np.std(discounted_ep_rs)
        return discounted_ep_rs

Fuente del artículo: Aprendizaje por refuerzo de Mofan https://mofanpy.com/tutorials/machine-learning/reinforcement-learning/

Supongo que te gusta

Origin blog.csdn.net/shoppingend/article/details/124297444
Recomendado
Clasificación