Advertisement

Deep Reinforcement Learning in a Handful of Trials Usin

阅读量:

作者:禅与计算机程序设计艺术

1.简介

Reinforcement learning (RL) is a domain of machine learning dedicated to exploring how software agents can achieve optimal decision-making in environments characterized by uncertainty and variable rewards. This article aims to offer an introduction to the fundamental concepts of reinforcement learning and probabilistic dynamics models. It will subsequently present the MDP-based deep Q network algorithm, implemented using the TensorFlow library, which will be applied to solve several classical control tasks such as Cart Pole swing-up, Acrobot locomotion, Mountain Car navigation, and Lunar Lander continuous action space problems. Through this comprehensive examination, we seek to provide readers with a solid understanding of deep reinforcement learning algorithms based on probabilistic dynamics models.

Recent advancements in deep neural networks (DNNs) have sparked growing interest among researchers seeking to create general AI systems capable of autonomous decision-making. The central concept behind these systems lies in mimicking human cognitive abilities through structured environmental exploration, with extensive feedback from the environment playing a crucial role in enhancing behavior over time. Reinforcement learning offers a robust theoretical foundation for designing such systems, where agents engage in interactive processes known as trial-and-error learning by interacting with their surroundings.

However, traditional methods for solving reinforcement learning problems prove ineffective in complex domains or high-dimensional state spaces. A promising approach is to utilize probabilistic representations for the agent's internal state rather than relying on deterministic ones. Probabilistic models effectively capture uncertainty in the system compared to deterministic approaches and provide a foundation for efficient training through sampling techniques. Additionally, probabilistic dynamic models have successfully addressed challenges such as temporal abstraction, partial observability, multi-agent interactions, and transfer learning.

We introduce a novel approach for the practical implementation of deep reinforcement learning algorithms, specifically those modeled on probabilistic dynamics frameworks. This innovative methodology is referred to as the MDQN architecture. By integrating concepts from deep neural networks and probabilistic modeling, our approach offers a robust alternative to conventional techniques such as tabular Q-learning and linear function approximation methods. The integration of these elements not only enhances the algorithm's performance but also provides greater flexibility in addressing complex decision-making problems.

To assess the effectiveness of our approach, we contrast it with established benchmarks across diverse control domains. We conclude by exploring potential avenues for advancing research into deep reinforcement learning through probabilistic modeling frameworks. Our investigation reveals that the MDQN architecture demonstrates remarkable performance across multiple metrics: sample efficiency remains consistently high; data efficiency surpasses current benchmarks; robustness to latent space interdependencies is notable; and its capability to manage sparse rewards alongside expansive state spaces proves particularly effective.

2.相关工作

2.1 DQN算法

Deep Q Network(DQN)是一种基于神经网络的强化学习方法,在游戏领域以及Atari自然对战中取得了显著成效。该方法通过神经网络提取状态特征,并使用神经网络模型来拟合Q值函数;从而让智能体能够根据其所处环境中的状态采取最优化的行为。整体架构较为简单;同样也能有效地应对状态信息有限的情况。然而,在应用过程中存在诸多挑战:例如,在样本利用率方面表现出不足;数据利用率较低;出现梯度消失等问题:针对这些问题提出了解决方案

2.2 DDPG算法

DDPG 全称 Deep Deterministic Policy Gradient(基于确定性策略梯度的方法),是一种无模型算法,并由 Actor 和 Critic 网络共同构成。其中 Actor 网络根据输入状态输出动作的概率分布以选择行动;而 Critic 网络则通过估计当前状态与动作下未来的奖励值来指导 Actor 的训练过程。该方法适用于连续控制任务,并支持离散与连续问题的求解。然而由于其复杂的多层结构导致参数数量庞大且结构复杂,在实际应用中计算量大且学习效率较低。

2.3 PPO算法

Proximal Policy Optimization (简称 PPO) 属于策略梯度方法家族的一种,并被认为是Trust Region Policy Optimization (TRPO)的一种优化版本。TRPO作为一种迭代优化框架,其核心思想是将复杂的目标函数分解为两个相对独立的部分进行分析,并通过分析这两个部分的变化趋势来确定参数更新的方向。为了防止陷入局部最优解或鞍点位置这一主要缺陷,TRPO设计了一种有效的惩罚机制。而 PPO 则在此基础上采用了更为激进的方式进行策略更新。具体而言,在这一过程中引入了动态调整机制,在经过一定数量训练步骤后逐步降低学习率幅度,并通过这种动态调整帮助模型最终跳出潜在的局部最优解或鞍点位置从而加速收敛速度

3. MDP-Based Deep Q Network(MDQN)

MDQN 建立在蒙特卡洛随机动态模型(Markov Decision Process, MDP)的基础上作为强化学习算法。
蒙特卡洛随机动态模型(Markov Decision Process, MDP)被广泛认为是强化学习中的重要工具。
从数学上讲,马尔可夫决策过程(Markov Decision Process, MDP)能够有效地描述一种特殊的强化学习问题,在这种问题中智能体与环境之间的互动形成了一个序列的状态转移,在每一个状态下可能会出现多种不同的行为。

3.1 概念

3.1.1 状态(State)

状态代表智能体在环境中的情况。通常由一个向量表示, 包含智能体的所有已知信息, 如位置、速度、自身的属性等。在机器人控制研究中, 状态涵盖了机器人位置、速度、姿态等多个方面, 还包括激光扫描数据和传感器反馈信息等细节内容。对于MDP模型而言, 它的状态数量远低于观测到的状态空间维度, 这使得我们可以利用这些特征来表征系统的内部状态。

3.1.2 动作(Action)

行为描述了智能体在特定状态下的操作行为,在此过程中行为表现为可观察的数量指标,并反映了智能体对周围环境的影响程度。从强化学习的角度来看,在此过程中行为表现为可观察的数量指标,并反映了智能体对周围环境的影响程度。当处理连续型行动空间时,则将其建模为实数域上的向量;而对于离散型行动空间,则采用有限集合中的元素进行描述。

3.1.3 回报(Reward)

智能体在完成特定任务时产生的奖励被称为回报。回报被定义为一个标量值,并被符号 r 表示。在马尔可夫决策过程中(MDP),回报分为正数和负数两种类型,并且每一步都会产生相应的奖励。对于一些复杂的问题来说,这些回报难以确定。

3.1.4 转移概率(Transition Probability)

转移概率定义为在给定状态下采取某一动作后系统从当前状态转移到下一个特定状态的概率;具体来说,在当前状态下执行某一动作所导致的状态转移情况即为此处所指的状态转换几率;该函数由f(x,a,y)定义,并满足f(x,a,y)=\mathbb{P}[S_{t+1}=y|S_t=x,A_t=a];下面阐述了马尔可夫决策过程中的转移概率特性

  1. 轨迹完整性(Trace Completeness):在马尔可夫决策过程中(MDP),各态之间互不相通。即任意两个不同状态x和y之间没有从一个到另一个的可能性。
  2. 转移矩阵(Transition Matrix):由n个可能的状态和m个可能的动作组成的转移矩阵是一个n×m大小的二维表格。其中总共有n个可能的状态和m个可能的动作组合在一起构成了这个表格的基础架构。具体数值pi,j则代表当处于第i个状态下采取第j个动作时转移到第j个新状态下发生的概率。

3.1.5 折扣因子(Discount Factor)

折扣因子 gamma 被称为从长远的角度来看现有奖励的价值程度。它是一个数值参数,在长期规划中被用来平衡即时奖励与未来奖励的重要性的关系。其取值范围限定为不大于1。具体而言,在 gamma 等于零的情况下,在计算某一个状态下累积的总奖励时,仅仅考虑的是该时刻的状态所对应的即时奖励而不包含后续任何时刻的状态奖励;而当 gamma 等于一的时候,则表示在计算累积总奖励的过程中将未来的所有可能状态Reward给予与当前时刻相同的重视程度

3.1.6 状态价值函数(State Value Function)

状态值函数 V(x) 表示从状态 x 出发所能获得的期望回报。其中 V(x) 等于期望值 E [ R_t + gamma * max_a sum_y {p(y | x,a)[r(x,a,y)+gamma*V(y)]} ] 。

3.1.7 贝尔曼误差(Bellman Error)

贝尔曼误差指的是基于Q函数估计值的真实回报与Q函数估计值之间的差异。贝尔曼误差能够衡量智能体在特定状态下行为表现与其对应的真实回报间的差异。

3.1.8 目标函数(Objective Function)

目标函数代表了算法设计的核心优化方向。以数学形式表示的MDQN优化目标是:min_θ [E[D[0:T] · log π(aₜ | sₜ, θ) − α(log π(aₜ | sₜ, θ))] ] ,其中θ表示所有模型参数集合;π代表策略模型;α用于调节策略探索与开发之间的平衡;D则遵循特定的数据分布。

3.2 操作步骤及算法流程

3.2.1 数据集生成

首先必须收集大量状态-动作对及其对应奖励。接着将这些状态-动作与奖励组合存入样本库中,并对其进行预处理。并从中提取有用信息,并采用归一化处理以及数据增强等技术手段。

3.2.2 模型构建

MDQN 网络由三个主要模块组成:编码器、Q网络和目标网络。

3.2.2.1 编码器(Encoder)

该编码器模块通过将输入状态转译为定长编码来实现对输入状态的向量化表达。这样能够有效降低输入状态信息的复杂性。这有助于算法更高效地学习各状态下变量间的相互关系。

3.2.2.2 Q网络(Q-Network)

Q-Network 用于计算各状态-动作组合的价值。它基于编码的状态信息作为输入,并生成各动作对应的价值度量;其输出向量的维度与可能的动作数量一致。

3.2.2.3 目标网络(Target Network)

监控当前更新的参数值的目标网络旨在避免在训练中出现过拟合现象。

3.2.3 训练

MDQN 的训练过程如下图所示:

MDQN的训练过程是一个完整的流程,在起始状态下开始进行随机探索,并通过策略网络更新模型参数直至达到收敛状态。整个训练阶段由四个核心环节构成:

探索环节:在初始状态进行随机漫游并采集数据样本;
学习过程:基于采集的数据样本优化智能体的行为模型;
参数更新过程中的目标网络执行参数更新操作;
评估环节中对 Q-Network 进行性能测试。若达到预期效果则终止训练循环;否则继续执行探索环节。

3.2.4 测试

测试阶段主要涉及将训练得到的网络参数投入真实环境中的运行,并通过模仿智能体与环境之间的互动来评估其性能表现。MDQN 的测试阶段包括执行策略评估和目标检测两个核心环节。

  1. 在该阶段中, 将状态输入网络, 输出的动作分布作为依据, 根据这些分布选取相应的动作;
  2. 在回报评估阶段中, 基于给定的状态和预选的动作, 通过真实环境模拟来计算实际奖励.

3.3 其它技术细节

3.3.1 多线程

考虑到算法需要对海量数据进行处理,因此通过多线程实现对海量数据以及网络模型的运算,从而显著提升了训练速度。

3.3.2 数据增强

对原始数据集进行数据增强,增加数据集的规模,改善模型的泛化能力。

3.3.3 噪声贡献(Exploration Contribution)

熵权(Entropy Weight)是用来衡量智能主体对新事物探索潜力的一种量化指标,在信息处理理论中被广泛应用于动态系统分析与优化领域。其核心思想在于让智能主体尽可能聚焦于那些具有挑战性和不确定性较高的状态-动作组合,在此过程中实现资源的有效分配与决策优化目标的有效达成。

3.3.4 经验回放(Experience Replay)

经验回放机制在强化学习中是一种重要的数据增强技术,在这一过程中起到关键作用。
通过将智能体的经验存储至缓存区并应用于训练过程。
这种机制的有效性体现在能够有效缓解神经网络参数僵化的问题

3.4 性能指标

3.4.1 算法效果

MDQN 可以在不同的控制任务上表现良好,取得非常好的效果。

3.4.2 算法效率

MDQN 的训练速度快,占用的显存小,适合在高效机器上运行。

3.4.3 数据效率

MDQN采用的行为对规模较小,在不影响训练效果的前提下能够直接应用蒙特卡洛树搜索。

3.4.4 鲁棒性

MDQN 具有良好的泛化性能,在多个不同的任务中表现优异。引入经验回放机制后,在一定程度上能够缓解算法陷入冻结状态的问题,并提升算法的整体稳定性。

3.4.5 可解释性

MDQN 的网络结构简单、参数量小,容易理解。

4. 算法实现

在本节,我将详细介绍 MDQN 的算法实现。

4.1 依赖库

复制代码
    import tensorflow as tf
    from collections import deque
    import gym
    import numpy as np
    import random
    
      
      
      
      
    
    代码解读

4.2 超参数设置

复制代码
    LR = 0.001      # learning rate
    GAMMA = 0.9     # discount factor
    EPSILON = 0.9   # greedy policy
    BATCH_SIZE = 32 # batch size
    ENTROPY_WEIGHT = 0.01    # entropy weight
    EPOCHS = 5           # epochs for training
    REPLAY_BUFFER_SIZE = int(1e5)          # replay buffer size
    INITIAL_OBSERVATION_PERIOD = 1000       # initial observation period
    TARGET_NETWORK_UPDATE_FREQUENCY = 1000  # frequency of updating target network parameters
    MAX_STEPS_PER_EPISODE = 1000            # maximum steps per episode
    RENDER_ENV = False                      # render enviroment
    SAVE_MODEL = True                       # save trained model
    LOAD_MODEL = False                      # load pretrained model
    PRETRAINED_MODEL_PATH = None             # path of pre-trained model
    TEST_NUM = 5                            # number of tests
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

4.3 网络结构

复制代码
    class MDPAgent:
    def __init__(self, sess):
        self.sess = sess
    
        # build graph
        self.build_graph()
    
        # initialize global variables
        init = tf.global_variables_initializer()
        self.sess.run(init)
    
    def build_graph(self):
        # input placeholders
        self.input_state = tf.placeholder(tf.float32, shape=[None, NUM_STATES], name='input_state')
        self.input_action = tf.placeholder(tf.int32, shape=[None, ], name='input_action')
        self.target_qvalue = tf.placeholder(tf.float32, shape=[None, ], name='target_qvalue')
    
        # encode states
        encoder_output = layers['fc'](inputs={'data': self.input_state}, num_outputs=HIDDEN_UNITS,
                                      weights_initializer=tf.random_normal_initializer(stddev=0.01),
                                      activation_fn=tf.nn.relu, scope="encoder")
    
        # q network
        self.qvalues = layers['fc'](inputs={'data': encoder_output}, num_outputs=ACTION_SPACE_SIZE,
                                    weights_initializer=tf.random_normal_initializer(stddev=0.01),
                                    biases_initializer=None, activation_fn=None, scope="qnet")
    
        # select action with epsilon-greedy policy
        self.pred_actions = tf.argmax(self.qvalues, axis=-1, output_type=tf.int32)
    
        if IS_TRAINING:
            # compute loss between predicted q values and target q values
            self.loss = tf.reduce_mean((tf.gather_nd(self.qvalues, indices=tf.stack([tf.range(BATCH_SIZE),
                                                                                     self.input_action], axis=-1))) -
                                        (self.target_qvalue + ENTROPY_WEIGHT * 
                                        (-tf.reduce_sum(tf.exp(self.qvalues)*self.qvalues, axis=-1))))
    
            # optimizer operation
            self.optimizer = tf.train.AdamOptimizer(LEARNING_RATE).minimize(self.loss)
    
        else:
            # restore pre-trained model
            saver = tf.train.Saver()
            saver.restore(self.sess, PRETRAINED_MODEL_PATH)
    
        # update target network parameters periodically
        self.update_target_network_params = \
            [tf.assign(self.target_qnet_vars[i],
                       self.main_qnet_vars[i])
             for i in range(len(self.target_qnet_vars))]
    
        # create summary writer
        self.writer = tf.summary.FileWriter('logs', graph=tf.get_default_graph())
    
        # summaries
        tf.summary.scalar("loss", self.loss)
        self.merged_summary_op = tf.summary.merge_all()
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

4.4 模型保存与加载

复制代码
    if SAVE_MODEL:
    saver = tf.train.Saver()
    saver.save(self.sess, './model/' +'model.ckpt')
    
    elif LOAD_MODEL:
    print("[INFO]: Loading pretrained model...")
    saver = tf.train.Saver()
    try:
        saver.restore(self.sess, "./model/" + "model.ckpt")
        print('[INFO]: Model loaded successfully.')
    except:
        raise Exception("Failed to load model!")
    
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

4.5 执行训练

复制代码
    for ep in range(EPOCHS):
    total_reward = 0
    
    step = INITIAL_OBSERVATION_PERIOD
    
    # reset environment before start new episode
    observation = env.reset()
    
    # get initial observations from the environment
    prev_observation = observation
    
    # run episode until reach maximum step limit or terminal state reached
    while step <= MAX_STEPS_PER_EPISODE:        
        # render environment if needed
        if RENDER_ENV:
            env.render()
    
        # choose next action with ε-greedy policy
        if np.random.rand() < EPSILON:
            action = np.random.randint(low=0, high=env.action_space.n, size=(1,))
        else:
            actions = self.predict_action(np.expand_dims(prev_observation, axis=0))[0]
            action = np.argmax(actions)
    
        # take action and get reward
        observation, reward, done, info = env.step(action)
    
        # store experience into replay buffer
        transition = {'prev_obs': prev_observation,
                      'curr_obs': observation,
                      'action': action,
                     'reward': reward,
                      'done': done}
        replay_buffer.append(transition)
    
        # train model after collecting sufficient experiences
        if len(replay_buffer) > BATCH_SIZE:
            minibatch = random.sample(replay_buffer, BATCH_SIZE)
            curr_states, actions, rewards, dones = [], [], [], []
            for trans in minibatch:
                curr_states.append(trans['curr_obs'])
                actions.append(trans['action'])
                rewards.append(trans['reward'])
                dones.append(trans['done'])
    
            curr_states = np.array(curr_states)
            next_qvals = self.predict_next_qvalue(np.array(curr_states)).flatten()
    
            if any(dones):
                targets = rewards + GAMMA*(np.invert(dones))*np.max(next_qvals)
            else:
                targets = rewards + GAMMA*np.max(next_qvals)
    
            _, summary = self.train_step(curr_states, actions, targets)
    
            # add summaries to tensorboard
            self.writer.add_summary(summary, self.global_step.eval(session=self.sess))
            self.writer.flush()
    
            # update target network parameters after every certain steps
            if self.global_step.eval(session=self.sess)%TARGET_NETWORK_UPDATE_FREQUENCY==0:
                self.sess.run(self.update_target_network_params)
    
        # increment counters and variables
        step += 1
        total_reward += reward
    
        # set previous observation as current observation
        prev_observation = observation
    
        # break loop when end of episode reached
        if done:
            break
    
    # decrease epsilon after each epoch
    if EPSILON > 0.1 and ep%int(EPOCHS/4)==0:
        EPSILON -= 0.1
    
    # check performance after each epoch and display logs
    if ep % DISPLAY_LOGS == 0:
        avg_reward = total_reward/(DISPLAY_LOGS*MAX_STEPS_PER_EPISODE)
        print('Epoch:', '%04d' % (ep+1), 'Episode Reward=%.2f' % avg_reward,
              'Epsilon=', '{:.3f}'.format(EPSILON))
    
        test_rewards = []
        for _ in range(TEST_NUM):
            obs = env.reset()
            tot_reward = 0
            for t in range(MAX_STEPS_PER_EPISODE):
                if RENDER_ENV:
                    env.render()
    
                act = self.predict_action(np.expand_dims(obs, axis=0))[0].argmax()
                new_obs, rew, done, _ = env.step(act)
                tot_reward += rew
                obs = new_obs
                if done:
                    break
            test_rewards.append(tot_reward)
        test_avg_rew = np.average(test_rewards)
        print('Test Avg. Reward:', '{:.3f}'.format(test_avg_rew))
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

4.6 执行测试

复制代码
    def test():
    print("[INFO]: Testing model...")
    test_rewards = []
    for _ in range(TEST_NUM):
        obs = env.reset()
        tot_reward = 0
        for t in range(MAX_STEPS_PER_EPISODE):
            if RENDER_ENV:
                env.render()
    
            act = self.predict_action(np.expand_dims(obs, axis=0))[0].argmax()
            new_obs, rew, done, _ = env.step(act)
            tot_reward += rew
            obs = new_obs
            if done:
                break
        test_rewards.append(tot_reward)
    test_avg_rew = np.average(test_rewards)
    print('Test Avg. Reward:', '{:.3f}'.format(test_avg_rew))
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

5. 其它注意事项

5.1 GPU与CPU的选择

  • 如果您的系统未安装 GPU 版本的 TensorFlow,则可以选择将其设置为 CPU 环境下的 TensorFlow;这将导致训练速度变慢;因此建议您选用 GPU 版本的 TensorFlow。
  • 若希望避免兼容性问题,则必须与相应的 GPU 驱动版本配对。
  • 设置为 CPU 环境下的 TensorFlow 的操作步骤包括运行 pip install tensorflow
  • 在配置好显卡的情况下,请按照 pip install tensorflow-gpu 的方式进行设置。

5.2 数据集的准备

  • 本文采用了名为 "CartPole-v1" 的简单运动任务聚合数据集合。该集合源自 OpenAI 开发者的研发团队。
  • 你可以访问以下资源网站获取该数据集合:https://github.com/openai/gym/blob/master/gym/envs/classic_control/cartpole.py
  • 为了方便操作,请建议采取措施将上述集合的具体目录路径存储于变量命名空间中。
  • 按照以下格式进行组织布局:
    • 将文件夹层级结构设置为三阶
    • 在根目录下创建 "data" 子文件夹
    • 在 "data" 文件夹内创建 "envs" 子文件夹
    • 将 CartPole-v1 数据包放置于 "envs" 文件夹下
复制代码
    └── DATA_DIR
        ├── transitions.csv
        └── images
            └──...
    
      
      
      
    
    代码解读
  • transitions.csv 数据集记录了系统行为中的四个关键要素:状态、动作、奖励以及下一状态的信息。该数据集的第一行标明了这些要素的名称,后续各行提供了具体的数值信息。
    • images/ 存储位置专门用于视觉感知相关的图像样本。这些图像在模型训练过程中起到重要作用。

5.3 数据集的处理

  • 为提高数据集处理效率,《具体措施方面》,我们推荐对数据实施预处理,并提取关键信息。例如,《采用的方法包括》如归一化处理和基于此的数据增强技术等。
  • 此外建议将不同类型的任务样本组合使用《以提高模型在多任务环境下的适应性》,从而增强其泛用性水平。

5.4 模型的保存与加载

  • 模型的存储与恢复功能对于实现持久化与复用具有重要价值。其中存储过程能够有效规避因偶然中断而造成的数据丢失问题。
    • 完成训练后建议将模型参数存储至本地存储位置,并确保文件名为"model.ckpt"以便后续使用。
    • 通过以下命令即可恢复已训练好的模型:
      $ RESTORE_MODEL=model.ckpt
复制代码
    saver = tf.train.Saver()

    saver.restore(sess, "./model/" + "model.ckpt")
    
        
    代码解读

6. 总结与展望

  • 通过深入分析深度强化学习的核心原理与核心算法,在此基础上首次提出了一种新型方法——MDQN方法。
  • 详细阐述了MDQN方法的算法实现细节,并对马尔可夫决策过程(MDP)的概念进行了深入说明。
  • 最后从性能与缺陷两个维度对MDQN方法进行了初步分析,并对未来研究方向进行了探讨。

全部评论 (0)

还没有任何评论哟~