[Aprendizaje por refuerzo] Red Q profunda Red Q profunda (DQN)

1 Introducción a DQN

1.1 Aprendizaje por refuerzo y redes neuronales

El método de aprendizaje por refuerzo es un método que combina una red neuronal y Q-Learning, denominado Deep Q Network.
Q-Learning utiliza una tabla para almacenar cada estado y el valor Q de cada acción en este estado. Los problemas de hoy son demasiado complicados y puede haber tantos estados como estrellas en el cielo (como jugar al Go). Si usamos tablas para almacenarlos todos, me temo que nuestra computadora no tendrá suficiente memoria y llevará mucho tiempo buscar el estado correspondiente en una tabla tan grande cada vez. Pero en el aprendizaje automático, hay un método que es excelente para este tipo de cosas, y son las redes neuronales. Podemos usar el estado y la acción como entrada de la red neuronal, y luego obtener el valor Q de la acción a través del análisis de la red neuronal, de modo que no necesitemos registrar el valor Q en la tabla, sino directamente use el análisis de la red neuronal para obtener el valor Q de la acción. De esta manera, no necesitamos registrar el valor Q en la tabla, sino usar directamente la red neuronal para generar el valor Q. Otra forma es esta, solo podemos ingresar el valor de estado, generar todos los valores de acción y luego seleccionar directamente la acción con el valor máximo como la siguiente acción de acuerdo con el principio de Q-Learning. Podemos imaginar que la red neuronal recibe información externa, lo que equivale a recopilar información de los ojos a los oídos, y luego emite el valor de cada acción a través del procesamiento cerebral y, finalmente, selecciona la acción a través del aprendizaje por refuerzo.

1.2 Actualización de la red neuronal

inserte la descripción de la imagen aquí

A continuación, analizamos en función de la segunda red neuronal. Sabemos que la red neuronal debe estar entrenada para predecir valores precisos. Entonces, en el aprendizaje por refuerzo, ¿cómo se entrena la red neuronal? En primer lugar, necesitamos el valor Q correcto de a1 y a2. Reemplazaremos este valor Q con la realidad Q en Q-Learning antes. De manera similar, también necesitamos una estimación Q para implementar la actualización de la red neuronal. Entonces, los parámetros de la red neuronal son los parámetros NN antiguos más la tasa de aprendizaje α multiplicada por la brecha entre la realidad Q y la estimación Q. Ordenemos y
inserte la descripción de la imagen aquí
predigamos los valores de Q(s2, a1) y Q(s2, a2) a través de NN, que es la estimación de Q. Luego elegimos la acción con el mayor valor en la estimación Q a cambio de una recompensa en el entorno. La realidad Q también incluye dos estimaciones Q analizadas desde la red neuronal, pero esta estimación Q está dirigida al siguiente paso en la estimación de s'. Finalmente, actualice los parámetros en la red neuronal a través del algoritmo que acabamos de mencionar. Pero esta no es la razón fundamental por la que DQN puede reproducir ordenadores. Hay otros dos factores que respaldan DQN y lo hacen extremadamente poderoso. Estos dos factores son la repetición de experiencia y los objetivos Q fijos.

1.3 Dos armas principales de DQN

En términos simples, DQN tiene un banco de memoria para aprender de experiencias previas. Q-Learning es un método de aprendizaje fuera de línea fuera de la política. Puede aprender lo que está experimentando actualmente, lo que ha experimentado en el pasado e incluso la experiencia de otros. Entonces, cada vez que se actualiza DQN, podemos extraer aleatoriamente algunas experiencias previas para aprender. El muestreo aleatorio interrumpe la correlación entre experiencias y hace que las actualizaciones de redes neuronales sean más eficientes. Los objetivos Q fijos también son un mecanismo para interrumpir la correlación. Si se utilizan objetivos Q fijos, también es un mecanismo para interrumpir la correlación. Si se utilizan objetivos Q fijos, utilizaremos dos estructuras con la misma estructura pero en DQN. La red neuronal con diferentes parámetros, la red neuronal que predice la estimación de Q tiene los últimos parámetros y la red neuronal que predice la Q real usa parámetros que son muy antiguos. Con estos dos medios de mejora, DQN puede superar a los humanos en algunos juegos.

2 actualización del algoritmo DQN

2.1 Puntos principales

La abreviatura de Deep Q Network se llama DQN, que combina las ventajas de Q-Learning con Neual Networks. Si usamos Q-Learning tabular, para cada estado y acción necesitamos almacenarlos en una tabla q_table. Si tenemos decenas de millones de estados como en la vida real, si ponemos los valores de estas decenas de millones de estados en la tabla, está limitado por el hardware de nuestra computadora, por lo que es ineficiente obtener datos de la tabla y actualizar los datos. Esta es la razón de DQN. Podemos usar una red neuronal para estimar el valor de este estado, por lo que no necesitamos una tabla.

2.2 Algoritmo

inserte la descripción de la imagen aquí
Todo el algoritmo se basa en el algoritmo Q-Learning con algunas modificaciones. El algoritmo Q-Learning se puede revisar aquí: https://blog.csdn.net/shoppingend/article/details/124291112?spm=1001.2014.3001.5501
Estas decoraciones incluyen: banco de memoria (para aprendizaje repetido), valor Q de cálculo de red neuronal , congela temporalmente q_target (corta dependencias)

2.3 El formato de línea de código del algoritmo

El siguiente código es la parte más importante de la interacción de DQN con el entorno.

def run_maze():
    step = 0    # 用来控制什么时候学习
    for episode in range(300):
        # 初始化环境
        observation = env.reset()

        while True:
            # 刷新环境
            env.render()

            # DQN 根据观测值选择行为
            action = RL.choose_action(observation)

            # 环境根据行为给出下一个 state, reward, 是否终止
            observation_, reward, done = env.step(action)

            # DQN 存储记忆
            RL.store_transition(observation, action, reward, observation_)

            # 控制学习起始时间和频率 (先累积一些记忆再开始学习)
            if (step > 200) and (step % 5 == 0):
                RL.learn()

            # 将下一个 state_ 变为 下次循环的 state
            observation = observation_

            # 如果终止, 就跳出循环
            if done:
                break
            step += 1   # 总步数

    # end of game
    print('game over')
    env.destroy()


if __name__ == "__main__":
    env = Maze()
    RL = DeepQNetwork(env.n_actions, env.n_features,
                      learning_rate=0.01,
                      reward_decay=0.9,
                      e_greedy=0.9,
                      replace_target_iter=200,  # 每 200 步替换一次 target_net 的参数
                      memory_size=2000, # 记忆上限
                      # output_graph=True   # 是否输出 tensorboard 文件
                      )
    env.after(100, run_maze)
    env.mainloop()
    RL.plot_cost()  # 观看神经网络的误差曲线

3 decisión de pensamiento DQN

Estructura principal del código:

class DeepQNetwork:
    # 上次的内容
    def _build_net(self):

    # 这次的内容:
    # 初始值
    def __init__(self):

    # 存储记忆
    def store_transition(self, s, a, r, s_):

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

    # 学习
    def learn(self):

    # 看看学习效果 (可选)
    def plot_cost(self):

Valor inicial:

class DeepQNetwork:
    def __init__(
            self,
            n_actions,
            n_features,
            learning_rate=0.01,
            reward_decay=0.9,
            e_greedy=0.9,
            replace_target_iter=300,
            memory_size=500,
            batch_size=32,
            e_greedy_increment=None,
            output_graph=False,
    ):
        self.n_actions = n_actions
        self.n_features = n_features
        self.lr = learning_rate
        self.gamma = reward_decay
        self.epsilon_max = e_greedy     # epsilon 的最大值
        self.replace_target_iter = replace_target_iter  # 更换 target_net 的步数
        self.memory_size = memory_size  # 记忆上限
        self.batch_size = batch_size    # 每次更新时从 memory 里面取多少记忆出来
        self.epsilon_increment = e_greedy_increment # epsilon 的增量
        self.epsilon = 0 if e_greedy_increment is not None else self.epsilon_max # 是否开启探索模式, 并逐步减少探索次数

        # 记录学习次数 (用于判断是否更换 target_net 参数)
        self.learn_step_counter = 0

        # 初始化全 0 记忆 [s, a, r, s_]
        self.memory = np.zeros((self.memory_size, n_features*2+2)) # 和视频中不同, 因为 pandas 运算比较慢, 这里改为直接用 numpy

        # 创建 [target_net, evaluate_net]
        self._build_net()

        # 替换 target net 的参数
        t_params = tf.get_collection('target_net_params')  # 提取 target_net 的参数
        e_params = tf.get_collection('eval_net_params')   # 提取  eval_net 的参数
        self.replace_target_op = [tf.assign(t, e) for t, e in zip(t_params, e_params)] # 更新 target_net 参数

        self.sess = tf.Session()

        # 输出 tensorboard 文件
        if output_graph:
            # $ tensorboard --logdir=logs
            tf.summary.FileWriter("logs/", self.sess.graph)

        self.sess.run(tf.global_variables_initializer())
        self.cost_his = []  # 记录所有 cost 变化, 用于最后 plot 出来观看

Almacene la memoria, la esencia de DQN es solo una: registre todos los pasos que ha experimentado, estos pasos se pueden aprender repetidamente, por lo que este es un método fuera de la política, incluso puede jugar solo y luego grabar su propia experiencia de juego, Deja que este DQN aprenda cómo pasas los niveles.

class DeepQNetwork:
    def __init__(self):
        ...
    def store_transition(self, s, a, r, s_):
        if not hasattr(self, 'memory_counter'):
            self.memory_counter = 0

        # 记录一条 [s, a, r, s_] 记录
        transition = np.hstack((s, [a, r], s_))

        # 总 memory 大小是固定的, 如果超出总大小, 旧 memory 就被新 memory 替换
        index = self.memory_counter % self.memory_size
        self.memory[index, :] = transition # 替换过程

        self.memory_counter += 1

Comportamiento opcional:

class DeepQNetwork:
    def __init__(self):
        ...
    def store_transition(self, s, a, r, s_):
        ...
    def choose_action(self, observation):
        # 统一 observation 的 shape (1, size_of_observation)
        observation = observation[np.newaxis, :]

        if np.random.uniform() < self.epsilon:
            # 让 eval_net 神经网络生成所有 action 的值, 并选择值最大的 action
            actions_value = self.sess.run(self.q_eval, feed_dict={
    
    self.s: observation})
            action = np.argmax(actions_value)
        else:
            action = np.random.randint(0, self.n_actions)   # 随机选择
        return action

Aprendizaje, este es el paso más importante, es cómo aprender y actualizar los parámetros en Deep Q Network. El uso interactivo de target_net y eval_net está diseñado aquí.

class DeepQNetwork:
    def __init__(self):
        ...
    def store_transition(self, s, a, r, s_):
        ...
    def choose_action(self, observation):
        ...
    def _replace_target_params(self):
        ...
    def learn(self):
        # 检查是否替换 target_net 参数
        if self.learn_step_counter % self.replace_target_iter == 0:
            self.sess.run(self.replace_target_op)
            print('\ntarget_params_replaced\n')

        # 从 memory 中随机抽取 batch_size 这么多记忆
        if self.memory_counter > self.memory_size:
            sample_index = np.random.choice(self.memory_size, size=self.batch_size)
        else:
            sample_index = np.random.choice(self.memory_counter, size=self.batch_size)
        batch_memory = self.memory[sample_index, :]

        # 获取 q_next (target_net 产生了 q) 和 q_eval(eval_net 产生的 q)
        q_next, q_eval = self.sess.run(
            [self.q_next, self.q_eval],
            feed_dict={
    
    
                self.s_: batch_memory[:, -self.n_features:],
                self.s: batch_memory[:, :self.n_features]
            })

        # 下面这几步十分重要. q_next, q_eval 包含所有 action 的值,
        # 而我们需要的只是已经选择好的 action 的值, 其他的并不需要.
        # 所以我们将其他的 action 值全变成 0, 将用到的 action 误差值 反向传递回去, 作为更新凭据.
        # 这是我们最终要达到的样子, 比如 q_target - q_eval = [1, 0, 0] - [-1, 0, 0] = [2, 0, 0]
        # q_eval = [-1, 0, 0] 表示这一个记忆中有我选用过 action 0, 而 action 0 带来的 Q(s, a0) = -1, 所以其他的 Q(s, a1) = Q(s, a2) = 0.
        # q_target = [1, 0, 0] 表示这个记忆中的 r+gamma*maxQ(s_) = 1, 而且不管在 s_ 上我们取了哪个 action,
        # 我们都需要对应上 q_eval 中的 action 位置, 所以就将 1 放在了 action 0 的位置.

        # 下面也是为了达到上面说的目的, 不过为了更方面让程序运算, 达到目的的过程有点不同.
        # 是将 q_eval 全部赋值给 q_target, 这时 q_target-q_eval 全为 0,
        # 不过 我们再根据 batch_memory 当中的 action 这个 column 来给 q_target 中的对应的 memory-action 位置来修改赋值.
        # 使新的赋值为 reward + gamma * maxQ(s_), 这样 q_target-q_eval 就可以变成我们所需的样子.
        # 具体在下面还有一个举例说明.

        q_target = q_eval.copy()
        batch_index = np.arange(self.batch_size, dtype=np.int32)
        eval_act_index = batch_memory[:, self.n_features].astype(int)
        reward = batch_memory[:, self.n_features + 1]

        q_target[batch_index, eval_act_index] = reward + self.gamma * np.max(q_next, axis=1)

        """
        假如在这个 batch 中, 我们有2个提取的记忆, 根据每个记忆可以生产3个 action 的值:
        q_eval =
        [[1, 2, 3],
         [4, 5, 6]]

        q_target = q_eval =
        [[1, 2, 3],
         [4, 5, 6]]

        然后根据 memory 当中的具体 action 位置来修改 q_target 对应 action 上的值:
        比如在:
            记忆 0 的 q_target 计算值是 -1, 而且我用了 action 0;
            记忆 1 的 q_target 计算值是 -2, 而且我用了 action 2:
        q_target =
        [[-1, 2, 3],
         [4, 5, -2]]

        所以 (q_target - q_eval) 就变成了:
        [[(-1)-(1), 0, 0],
         [0, 0, (-2)-(6)]]

        最后我们将这个 (q_target - q_eval) 当成误差, 反向传递会神经网络.
        所有为 0 的 action 值是当时没有选择的 action, 之前有选择的 action 才有不为0的值.
        我们只反向传递之前选择的 action 的值,
        """

        # 训练 eval_net
        _, self.cost = self.sess.run([self._train_op, self.loss],
                                     feed_dict={
    
    self.s: batch_memory[:, :self.n_features],
                                                self.q_target: q_target})
        self.cost_his.append(self.cost) # 记录 cost 误差

        # 逐渐增加 epsilon, 降低行为的随机性
        self.epsilon = self.epsilon + self.epsilon_increment if self.epsilon < self.epsilon_max else self.epsilon_max
        self.learn_step_counter += 1

Para ver el efecto de aprendizaje, finalmente generamos la curva de cambio de costo durante el proceso de aprendizaje.

class DeepQNetwork:
    def __init__(self):
        ...
    def store_transition(self, s, a, r, s_):
        ...
    def choose_action(self, observation):
        ...
    def _replace_target_params(self):
        ...
    def learn(self):
        ...
    def plot_cost(self):
        import matplotlib.pyplot as plt
        plt.plot(np.arange(len(self.cost_his)), self.cost_his)
        plt.ylabel('Cost')
        plt.xlabel('training steps')
        plt.show()

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/124379079
Recomendado
Clasificación