赞
踩
强化学习 (RL) 是机器学习生态系统的一部分,其中代理通过与环境交互来学习,以获得实现目标的最佳策略。它与监督式机器学习算法完全不同,在监督式机器学习算法中,我们需要提取和处理这些数据。强化学习不需要数据。相反,它从环境和奖励系统中学习以做出更好的决策。
例如,在马里奥视频游戏中,如果角色采取随机动作(例如向左移动),则根据该动作,它可能会获得奖励。采取行动后,代理(马里奥)处于新状态,该过程重复进行,直到游戏角色到达关卡终点或死亡。
此情节将重复多次,直到马里奥学会通过最大化奖励来驾驭环境。
我们可以将强化学习分为五个简单的步骤:
Q 学习是一种无模型、基于价值的离策略算法,它将根据代理的当前状态找到最佳的一系列操作。“Q”代表质量。质量表示该操作在最大化未来奖励方面有多大价值。
基于模型的算法使用转换和奖励函数来估计最优策略并创建模型。相比之下,无模型算法则通过没有转换和奖励函数的经验来学习其行为的后果。
基于价值的方法训练价值函数,以了解哪种状态更有价值并采取行动。另一方面,基于策略的方法直接训练策略,以了解在给定状态下应采取哪种行动。
在离策略中,算法评估并更新与采取行动所用策略不同的策略。相反,在策略算法评估并改进采取行动所用相同策略。
在我们了解 Q-learning 的工作原理之前,我们需要学习一些有用的术语来理解 Q-learning 的基础知识。
我们将以结冰的湖泊为例,详细了解 Q 学习的工作原理。在这个环境中,代理必须从起点穿过结冰的湖泊到达目标,而不能掉进洞里。最好的策略是走最短的路径到达目标。
代理将使用 Q 表根据环境中每个状态的预期奖励采取最佳行动。简而言之,Q 表是一组动作和状态的数据结构,我们使用 Q 学习算法来更新表中的值。
Q 函数使用贝尔曼方程,以状态(s)和动作(a)作为输入。该方程简化了状态值和状态动作值的计算。
我们首先初始化 Q 表。我们将根据动作数量构建列,根据状态数量构建行。
在我们的示例中,角色可以上下左右移动。我们有四种可能的动作和四种状态(开始、空闲、错误路径和结束)。您还可以考虑掉入洞中的错误路径。我们将使用 0 值初始化 Q-Table。
第二步很简单。一开始,代理会选择采取随机动作(向下或向右),第二次运行时,它将使用更新的 Q 表来选择动作。
选择一个动作并执行该动作将重复多次,直到训练循环停止。使用 Q 表选择第一个动作和状态。在我们的例子中,Q 表的所有值都是零。
然后,代理将向下移动并使用贝尔曼方程更新 Q 表。每次移动时,我们都会更新 Q 表中的值,并使用它来确定最佳行动方案。
最初,代理处于探索模式,并选择随机动作来探索环境。Epsilon 贪婪策略是一种平衡探索和利用的简单方法。epsilon 代表在探索机会较小的情况下选择探索和利用的概率。
开始时,epsilon 率较高,这意味着代理处于探索模式。在探索环境时,epsilon 会降低,代理会开始利用环境。在探索过程中,随着每次迭代,代理对估计 Q 值的信心会越来越强
在冰冻湖泊示例中,代理不知道环境,因此需要采取随机动作(向下移动)才能启动。如上图所示,Q 表使用贝尔曼方程进行更新。
采取行动后,我们将衡量结果和回报。
我们将使用方程更新函数 Q(S t , A t )。它使用前一集的估计 Q 值、学习率和时间差异误差。时间差异误差是使用即时奖励、折扣后的最大预期未来奖励和前一个估计 Q 值计算的。
该过程重复多次,直到 Q 表更新并且 Q 值函数最大化。
一开始,代理会探索环境以更新 Q 表。当 Q 表准备就绪时,代理将开始利用并开始做出更好的决策。
在湖面结冰的情况下,代理将学习采取最短路径到达目标并避免跳入洞中。
我们将使用 Gym 环境、Pygame 和 Numpy 从头开始构建 Q 学习模型。Python 教程是Thomas Simonini 的Notebook的修改版本。它包括初始化环境和 Q 表、定义贪婪策略、设置超参数、创建和运行训练循环和评估以及可视化结果。
如果您在创建和运行训练循环时遇到问题,您可以使用输出 检查代码源。
设置虚拟显示
我们首先安装所有依赖项以生成回放视频(Gif)。我们需要一个虚拟屏幕(pyvirtualdisplay)来渲染环境并记录帧。
注意:通过使用“%%capture”,我们抑制了 Jupyter 单元的输出。
- %%capture
- !pip install pyglet==1.5.1
- !apt install python-opengl
- !apt install ffmpeg
- !apt install xvfb
- !pip3 install pyvirtualdisplay
-
- # Virtual display
- from pyvirtualdisplay import Display
-
- virtual_display = Display(visible=0, size=(1400, 900))
- virtual_display.start()
我们现在将安装依赖项来帮助我们创建、运行和评估训练循环。
- %%capture
- !pip install gym==0.24
- !pip install pygame
- !pip install numpy
-
- !pip install imageio imageio_ffmpeg
我们现在将导入所需的库。
- import numpy as np
- import gym
- import random
- import imageio
- from tqdm.notebook import trange
我们将使用冰冻湖健身库创建一个防滑的 4x4 环境。
初始化环境之后,我们来进行环境分析。
- env = gym.make("FrozenLake-v1",map_name="4x4",is_slippery=False)
-
- print("Observation Space", env.observation_space)
- print("Sample observation", env.observation_space.sample()) # display a random observation
- Observation Space Discrete(16)
- Sample observation 15
行动空间:
奖励函数:
- print("Action Space Shape", env.action_space.n)
- print("Action Space Sample", env.action_space.sample())
-
Action Space Shape 4
Action Space Sample 1
Q 表的列表示动作,行表示状态。我们可以使用 OpenAI Gym 来查找动作空间和状态空间。然后我们将使用此信息来创建 Q 表。
- state_space = env.observation_space.n
- print("There are ", state_space, " possible states")
- action_space = env.action_space.n
- print("There are ", action_space, " possible actions")
There are 16 possible states There are 4 possible actions
为了初始化 Q 表,我们将创建一个包含 state_space 和 action 空间的 Numpy 数组。我们将创建一个 16 X 4 数组。
- def initialize_q_table(state_space, action_space):
- Qtable = np.zeros((state_space, action_space))
- return Qtable
- Qtable_frozenlake = initialize_q_table(state_space, action_space)
在上一节中,我们了解了处理探索和利用权衡的 epsilon 贪婪策略。以 1 - ε 的概率,我们进行利用;以 ε 的概率,我们进行探索。
在 epsilon_greedy_policy 中我们将:
- def epsilon_greedy_policy(Qtable, state, epsilon):
- random_int = random.uniform(0,1)
- if random_int > epsilon:
- action = np.argmax(Qtable[state])
- else:
- action = env.action_space.sample()
- return action
我们现在知道 Q 学习是一种离策略算法,这意味着采取行动和更新函数的策略是不同的。
在这个例子中,Epsilon Greedy 策略是代理策略,而 Greedy 策略是更新策略。
贪婪策略也将是训练代理时的最终策略。它用于从 Q 表中选择最高的状态和动作值。
- def greedy_policy(Qtable, state):
- action = np.argmax(Qtable[state])
- return action
这些超参数用于训练循环,对其进行微调将会给你带来更好的结果。
代理需要探索足够的状态空间才能学习良好的值近似值;我们需要逐步衰减 epsilon。如果衰减率很高,代理可能会卡住,因为它没有探索足够的状态空间。
- # Training parameters
- n_training_episodes = 10000
- learning_rate = 0.7
-
- # Evaluation parameters
- n_eval_episodes = 100
-
- # Environment parameters
- env_id = "FrozenLake-v1"
- max_steps = 99
- gamma = 0.95
- eval_seed = []
-
- # Exploration parameters
- max_epsilon = 1.0
- min_epsilon = 0.05
- decay_rate = 0.0005
在训练循环中,我们将:
- def train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable):
- for episode in trange(n_training_episodes):
-
- epsilon = min_epsilon + (max_epsilon - min_epsilon)*np.exp(-decay_rate*episode)
- # Reset the environment
- state = env.reset()
- step = 0
- done = False
-
- # repeat
- for step in range(max_steps):
-
- action = epsilon_greedy_policy(Qtable, state, epsilon)
-
-
- new_state, reward, done, info = env.step(action)
-
-
- Qtable[state][action] = Qtable[state][action] + learning_rate * (reward + gamma * np.max(Qtable[new_state]) - Qtable[state][action])
-
- # If done, finish the episode
- if done:
- break
-
- # Our state is the new state
- state = new_state
- return Qtable
我们花了3秒完成10,000次训练。
Qtable_frozenlake = train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable_frozenlake)
我们可以看到,训练过的 Q 表具有值,代理现在将使用这些值来导航环境并实现目标。
-
- Qtable_frozenlake
- array([[0.73509189, 0.77378094, 0.77378094, 0.73509189],
- [0.73509189, 0. , 0.81450625, 0.77378094],
- [0.77378094, 0.857375 , 0.77378094, 0.81450625],
- [0.81450625, 0. , 0.77378094, 0.77378094],
- [0.77378094, 0.81450625, 0. , 0.73509189],
- [0. , 0. , 0. , 0. ],
- [0. , 0.9025 , 0. , 0.81450625],
- [0. , 0. , 0. , 0. ],
- [0.81450625, 0. , 0.857375 , 0.77378094],
- [0.81450625, 0.9025 , 0.9025 , 0. ],
- [0.857375 , 0.95 , 0. , 0.857375 ],
- [0. , 0. , 0. , 0. ],
- [0. , 0. , 0. , 0. ],
- [0. , 0.9025 , 0.95 , 0.857375 ],
- [0.9025 , 0.95 , 1. , 0.9025 ],
- [0. , 0. , 0. , 0. ]])
Evaluation_agent 运行“n_eval_episodes”事件并返回奖励的平均值和标准差。
- def evaluate_agent(env, max_steps, n_eval_episodes, Q, seed):
-
- episode_rewards = []
- for episode in range(n_eval_episodes):
- if seed:
- state = env.reset(seed=seed[episode])
- else:
- state = env.reset()
- step = 0
- done = False
- total_rewards_ep = 0
-
- for step in range(max_steps):
- # Take the action (index) that have the maximum reward
- action = np.argmax(Q[state][:])
- new_state, reward, done, info = env.step(action)
- total_rewards_ep += reward
-
- if done:
- break
- state = new_state
- episode_rewards.append(total_rewards_ep)
- mean_reward = np.mean(episode_rewards)
- std_reward = np.std(episode_rewards)
-
- return mean_reward, std_reward
如你所见,我们获得了满分,标准差为零。这意味着我们的代理在所有 100 集中都达到了目标。
- # Evaluate our Agent
- mean_reward, std_reward = evaluate_agent(env, max_steps, n_eval_episodes, Qtable_frozenlake, eval_seed)
- print(f"Mean_reward={mean_reward:.2f} +/- {std_reward:.2f}")
Mean_reward=1.00 +/- 0.00
到目前为止,我们一直在玩数字,为了进行演示,我们需要创建一个代理从一开始直到达到目标的动画 Gif。
- def record_video(env, Qtable, out_directory, fps=1):
- images = []
- done = False
- state = env.reset(seed=random.randint(0,500))
- img = env.render(mode='rgb_array')
- images.append(img)
- while not done:
- # Take the action (index) that have the maximum expected future reward given that state
- action = np.argmax(Qtable[state][:])
- state, reward, done, info = env.step(action) # We directly put next_state = state for recording logic
- img = env.render(mode='rgb_array')
- images.append(img)
- imageio.mimsave(out_directory, [np.array(img) for i, img in enumerate(images)], fps=fps)
- video_path="/content/replay.gif"
- video_fps=1
- record_video(env, Qtable_frozenlake, video_path, video_fps)
-
- from IPython.display import Image
- Image('./replay.gif')
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。