强化学习是一种机器学习方法,它可以帮助计算机学会在不断尝试和经验积累中做出最佳决策。用通俗的方式来说,强化学习就像是训练一只宠物狗学会做任务一样。
想象一只狗要学会取球。一开始,它可能不知道该怎么做,但主人可以使用奖励和惩罚来引导它学习。如果狗成功地取到球,主人就会给它一些小吃作为奖励。狗会记住这个行为,并在未来更努力地去取球,因为它知道这会带来奖励。如果狗一次次试图但没有成功,它可能会明白自己需要改变策略。
强化学习中的计算机也是这样学习的。它通过不断地尝试各种行动,观察结果,并根据奖励或惩罚来调整策略,逐渐学会如何在特定环境中做出最好的决策。这种方法在自动驾驶、游戏中的人工智能,以及其他需要智能决策的领域都有广泛的应用。就像训练一只宠物一样,强化学习是通过实践和反馈来提高机器的能力,使其能够在复杂的环境中做出明智的选择。
监督学习和强化学习是两种不同的机器学习方法,它们之间有一些重要的区别:
数据标签的存在与否:
学习方式:
应用领域:
反馈类型:
总之,监督学习和强化学习是两种不同的学习范式,适用于不同类型的问题和应用领域。监督学习依赖于有标签的数据和明确的正误反馈,而强化学习则依赖于与环境的互动和稀疏的奖励信号来学习如何在复杂任务中做出决策。
Model-Free(无模型)和Model-Based(有模型)是强化学习中两种不同的方法,用于解决决策问题。它们之间的主要区别在于如何处理环境和决策的方式。
Model-Free(无模型)强化学习:
基本思想:Model-Free方法不试图建立关于环境的内部模型,而是直接学习从状态到动作的映射,并基于已经观察到的经验来做出决策。
工作方式:模型无关的方法通常使用价值函数(Value Function)或策略函数(Policy Function)来表示决策策略。这些函数告诉智能体在给定状态下应该选择哪个动作以最大化累积奖励。
优点:无模型方法通常更适用于复杂的、不确定的环境,因为它们不需要对环境的内部工作方式进行建模。它们可以通过不断尝试来学习最佳策略。
示例应用:Q-learning、Deep Q-Networks(DQN)等都是无模型强化学习方法的示例。
Model-Based(有模型)强化学习:
基本思想:Model-Based方法试图建立一个关于环境的内部模型,这个模型可以模拟环境的动态,包括状态转移和奖励的生成。
工作方式:有模型方法首先学习环境模型,然后使用模型来进行规划和决策。通过模拟环境,它们可以在不实际执行动作的情况下预测未来可能的状态和奖励,并选择最佳的动作。
优点:有模型方法通常更高效,因为它们可以使用模型来规划未来的决策,而不必在实际环境中进行大量的试错。这些方法通常在数据效率上表现较好。
示例应用:Monte Carlo Tree Search(MCTS)、Model Predictive Control(MPC)等都是有模型强化学习方法的示例。
选择Model-Free还是Model-Based方法通常取决于问题的性质和可用的数据。在不确定性高、模型复杂或者数据稀缺的情况下,Model-Free方法可能更适合。而在可建模且可控制的环境中,Model-Based方法可能更有效。有时候,这两种方法也可以结合使用,以充分利用它们的优势。
在强化学习中,基于概率和基于价值是两种不同的方法,用于建立决策策略和指导智能体的行为。以下是它们的介绍:
基于概率的方法:
基本思想:基于概率的方法关注的是建立一个策略函数(Policy Function),该函数定义了在每个状态下采取每个可能动作的概率分布。智能体根据这个概率分布来选择动作。
工作方式:策略函数可以是确定性策略,即给定状态总是选择相同的动作,也可以是随机性策略,即给定状态下选择动作的概率分布。智能体根据这些概率来做出决策。
优点:基于概率的方法可以处理不确定性,并允许智能体在相同状态下采取不同的行动,以便更好地探索环境。它们也适用于连续动作空间的问题。
示例应用:策略梯度方法(Policy Gradient Methods)是基于概率的方法的典型示例,它们通过最大化累积奖励来更新策略参数。
基于价值的方法:
基本思想:基于价值的方法侧重于估计每个状态或状态-动作对的价值,即它们对于实现累积奖励的贡献有多大。这些价值函数用于指导动作选择。
工作方式:有两种主要类型的价值函数,一种是状态值函数(State Value Function),用于估计在某个状态下能够获得的期望累积奖励;另一种是动作值函数(Action Value Function),用于估计在某个状态下采取某个动作后能够获得的期望累积奖励。
优点:基于价值的方法可以提供更具体的指导,告诉智能体在每个状态下应该采取哪个动作或者在哪个状态下更有价值。它们通常在数据效率上更高,因为它们可以使用状态的价值信息来规划决策。
示例应用:Q-learning和Deep Q-Networks(DQN)是基于价值的方法的典型示例,它们估计状态-动作对的价值,并根据最大化估计的价值来选择动作。
选择基于概率还是基于价值的方法通常取决于问题的性质和需要。基于概率的方法适用于处理随机性较大的问题,而基于价值的方法更适合于需要具体的动作建议和规划的问题。有时候,这两种方法也可以结合使用,以充分利用它们的优势。
在强化学习中,回合更新(Episodic Updates)和单步更新(Online Updates)是两种不同的策略,用于更新智能体的学习模型(例如价值函数或策略函数)。它们有不同的更新时间点和应用场景:
回合更新(Episodic Updates):
基本思想:回合更新是指在每个完整的任务或回合结束后才进行模型的更新。在这种方法中,智能体需要完成一个完整的任务,然后根据任务的结果来调整学习模型。
工作方式:智能体收集经验并执行一系列动作,直到任务结束。一旦任务结束,智能体会回顾整个任务的经验,然后使用这些经验来更新模型参数,以改进未来的决策策略。
应用场景:回合更新通常用于在每个任务或回合之后进行学习,适用于离散任务或那些可以分为不同回合的连续任务,例如棋类游戏或机器人导航。
单步更新(Online Updates):
基本思想:单步更新是指在每一步操作后都对模型进行更新。在这种方法中,智能体在每个时间步都学习并更新模型,而不必等待整个任务结束。
工作方式:智能体在执行每个动作后,会立即观察到奖励信号并更新模型参数。这样,模型可以在任务进行中实时地调整决策策略。
应用场景:单步更新通常用于连续任务,尤其是那些需要实时决策的情况,例如自动驾驶或实时游戏。
选择回合更新还是单步更新取决于问题的性质和要求。回合更新通常对于离散任务或任务可以划分为不同回合的情况更为适用,因为它们在任务结束后才进行一次学习,可以更好地考虑长期的奖励。而单步更新适用于需要实时决策的连续任务,因为它们允许智能体在任务进行中及时适应变化的环境。在实际应用中,有时候也可以结合使用这两种更新策略,以兼顾长期和实时决策的需求。
在线学习(Online Learning)和离线学习(Offline Learning)是两种不同的机器学习方法,它们关注数据的获取方式和学习模型的时间点。以下是它们的介绍:
在线学习(Online Learning):
基本思想:在线学习是一种持续学习的方式,模型会在不断产生新数据的情况下逐步更新自己。模型会在实时或连续产生的数据流中进行学习,而不需要事先存储所有数据。
工作方式:在在线学习中,模型接收一个样本(数据点)后,立即进行学习和参数更新。然后,模型可以丢弃该样本,继续接收下一个样本。这个过程是连续的,模型不会停止学习,以适应新的数据和变化的环境。
应用场景:在线学习适用于需要实时更新和适应性的任务,如在线广告点击预测、机器人控制、金融交易等领域。模型在不断变化的数据流中进行学习,以保持其性能。
离线学习(Offline Learning):
基本思想:离线学习是一种批量学习的方式,模型在已经收集好的数据集上进行学习和训练。数据集通常是固定的,不再添加新数据。
工作方式:在离线学习中,模型首先获取整个数据集,然后在这个数据集上进行批量学习。一旦模型完成了学习过程,它通常不会再使用这个数据集,除非需要重新训练。
应用场景:离线学习适用于那些数据不再改变或只会定期更新的任务。例如,通过历史销售数据来预测未来销售趋势,或者通过固定的数据集进行图像分类。
选择在线学习还是离线学习取决于问题的性质和可用的数据。在线学习适用于需要实时性和持续适应性的任务,而离线学习适用于那些数据不再改变或只有周期性更新的任务。在实际应用中,有时候也可以将两者结合使用,例如,使用离线学习在静态数据集上进行预训练,然后通过在线学习来进行模型的在线微调。
Q-learning的行为准则可以用一句通俗易懂的话来概括:
Q-learning告诉智能体在每种情况下,应该选择哪个动作以便获得最多奖励。
具体来说,Q-learning使用一个叫做Q值的表格,其中每一行表示一种情况(也叫状态),每一列表示可选的动作。每个单元格中的数字表示采取某个动作后,可以获得的奖励预期值。
智能体在每个时刻根据当前情况,查看Q值表格,然后选择具有最高Q值的动作。但为了探索新的可能性,有时候它也会随机尝试其他动作。随着不断的尝试和奖励的反馈,Q-learning会逐渐调整Q值,以便在每种情况下做出最优的动作选择。
通过这种方式,Q-learning可以帮助智能体在不断的学习和尝试中,逐渐学会如何在复杂的环境中做出明智的决策,以最大化累积的奖励。这就像是一个人在不断的试错中学会了在每种情况下采取最好行动一样。
Q-learning 的行为准则 Q 表格是通过不断地在智能体与环境互动的过程中进行更新和提升的。下面是关于如何更新和提升 Q 表的整理:
Q 表的初始化:
智能体与环境的互动:
Q 值的更新:
重复迭代:
探索和利用:
通过这个过程,Q-learning 的行为准则 Q 表格逐渐收敛到最优策略,使智能体能够在不断的尝试和学习中,做出最优的决策以最大化累积的奖励。这就是 Q-learning 如何通过不断更新 Q 值来提升决策策略的方式。
Q-learning使用Q表格来记录每种情况下采取不同动作的预期奖励值。通过贝尔曼方程的迭代,可以将Q值向未来的状态传播,形成一个关于状态的长期奖励观念。
- 初始时,Q值被初始化为一些初始值,通常为零。
- 当智能体与环境互动时,它会选择动作并观察奖励和新状态。
- 智能体使用贝尔曼方程来更新Q值,这个方程考虑了当前奖励以及在未来状态下选择最佳动作可能带来的奖励。
- 贝尔曼方程的 γ(折扣因子)部分代表了时间的衰减效应。当 γ 为1时,Q值考虑未来所有奖励。当 γ 为0时,智能体只关注当前奖励。
- 随着γ从0变化到1,可以将其视为机器人逐渐获得更好的“眼镜”,能够看到未来奖励,并逐渐变得有远见,不仅考虑眼前的奖励,还为自己的未来着想。
总之,Q-learning通过迭代地更新Q值,考虑未来奖励和折扣因子γ的影响,使智能体能够学会长期最优决策策略,类似于具有不同度数“近视”的机器人逐渐变得有远见,更好地规划未来行动。
-o---T
# T 就是宝藏的位置, o 是探索者的位置
有个大概的 RL 概念就行, 知道 RL 的一些关键步骤就行, 这节的算法不用仔细研究。
import numpy as np
import pandas as pd
import time
N_STATES = 6 # 1维世界的宽度
ACTIONS = ['left', 'right'] # 探索者的可用动作
EPSILON = 0.9 # 贪婪度 greedy
ALPHA = 0.1 # 学习率
GAMMA = 0.9 # 奖励递减值
MAX_EPISODES = 13 # 最大回合数
FRESH_TIME = 0.3 # 移动间隔时间
def build_q_table(n_states, actions):
table = pd.DataFrame(
np.zeros((n_states, len(actions))), # q_table 全 0 初始
columns=actions, # columns 对应的是行为名称
)
return table
# 在某个 state 地点, 选择行为
def choose_action(state, q_table):
state_actions = q_table.iloc[state, :] # 获取当前状态对应的所有动作的Q值
if (np.random.uniform() > EPSILON) or (state_actions.all() == 0):
# 如果随机数大于贪婪度(EPSILON)或者当前状态的所有动作都没有探索过(Q值都为0)
action_name = np.random.choice(ACTIONS) # 随机选择一个动作
else:
action_name = state_actions.idxmax() # 否则,选择Q值最大的动作(贪婪模式)(这里本来idxmax是argmax,但是运行到一半总会报错。原因还不知)
return action_name
def get_env_feedback(S, A):
# 这是智能体与环境互动的方式
if A == 'right': # 如果选择动作是向右移动
if S == N_STATES - 2: # 如果智能体已经到达了右边界,即终止状态
S_ = 'terminal' # 下一个状态是终止状态
R = 1 # 智能体获得奖励值为1
else:
S_ = S + 1 # 否则,向右移动一步
R = 0 # 没有奖励
else: # 如果选择动作是向左移动
R = 0 # 没有奖励
if S == 0: # 如果智能体已经到达了左边界,即墙壁
S_ = S # 下一个状态还是当前状态(不动)
else:
S_ = S - 1 # 否则,向左移动一步
return S_, R # 返回下一个状态和奖励值
# 环境更新,不用细看
def update_env(S, episode, step_counter):
# 这是环境如何被更新的方式
env_list = ['-'] * (N_STATES - 1) + ['T'] # 创建表示环境的列表,'---------T' 表示环境,'-' 表示空格,'T' 表示终止状态
if S == 'terminal': # 如果智能体达到了终止状态
interaction = 'Episode %s: total_steps = %s' % (episode + 1, step_counter)
print('\r{}'.format(interaction), end='') # 打印出本轮的信息,包括轮次和总步数
time.sleep(2) # 等待2秒以便观察
print('\r ', end='') # 清除打印的信息,准备下一轮
else:
env_list[S] = 'o' # 在环境列表中标记智能体的当前位置为'o'
interaction = ''.join(env_list) # 将环境列表转换为字符串
print('\r{}'.format(interaction), end='') # 打印出环境的可视化表示
time.sleep(FRESH_TIME) # 等待一段时间以便观察
下面的内容, 大家大概看看就行, 这节内容不用仔细研究,根据这张图能看懂逻辑步骤
def rl():
q_table = build_q_table(N_STATES, ACTIONS) # 初始化Q值表
for episode in range(MAX_EPISODES): # 循环每个回合
step_counter = 0
S = 0 # 回合初始位置
is_terminated = False # 是否回合结束
update_env(S, episode, step_counter) # 更新环境的可视化表示
while not is_terminated:
A = choose_action(S, q_table) # 根据当前状态选择行为
S_, R = get_env_feedback(S, A) # 执行选择的行为并获取环境的反馈
q_predict = q_table.loc[S, A] # 预测的(状态-行为)值
# print(f"State S: {S}, Action A: {A}")
if S_ != 'terminal': # 如果回合未结束
q_target = R + GAMMA * q_table.iloc[S_, :].max() # 实际的(状态-行为)值
else: # 如果回合结束
q_target = R # 实际的(状态-行为)值
is_terminated = True # 标记回合结束
q_table.loc[S, A] += ALPHA * (q_target - q_predict) # 更新Q值表
S = S_ # 将状态更新为下一个状态
update_env(S, episode, step_counter + 1) # 更新环境的可视化表示
step_counter += 1
return q_table
q_table.loc[S, A]
是用来从Q表格中获取给定状态 S 和动作 A 对应的Q值的操作。这实际上是使用 loc 方法来根据行标签(状态)和列标签(动作)从Q表格中提取值。
q_table.iloc[S_, :]
的意思是从Q表格中选择状态为 S_ 的行,并获取该状态下所有动作的Q值。这可以用于查看特定状态下所有动作的Q值,以帮助智能体选择最优的动作来最大化累积奖励。
loc
主要基于标签进行选择,而iloc
主要基于整数位置进行选择。
我遇到的问题:为什么叫预测值,不是Q表中都给出了吗?
之所以把它称为"预测值",是因为这个值是通过学习算法估计出来的,代表着在状态S下采取行为A的期望回报。它是对这个状态-行为值的一个预测,不完全等同于真实的回报值。
随着算法的迭代和学习,q_predict 会不断地逼近实际的最优Q值。
然后就可以运行代码了
if __name__ == "__main__":
q_table = rl()
print('\r\nQ-table:\n')
print(q_table)
让探索者学会走迷宫. 黄色的是天堂 (reward 1), 黑色的地狱 (reward -1)。
Q-learning 算法更新
整个算法就是一直不断更新 Q table 里的值, 然后再根据新的值来判断要在某个 state 采取怎样的 action. Qlearning 是一个 off-policy 的算法, 因为里面的 max action 让 Q table 的更新可以不基于正在经历的经验(可以是现在学习着很久以前的经验,甚至是学习他人的经验).
不过这一次的例子, 我们没有运用到 off-policy, 而是把 Qlearning 用在了 on-policy 上, 也就是现学现卖, 将现在经历的直接当场学习并运用
maze_env 是我们的环境模块, 已经编写好了, 大家可以直接在文章顶部下载, maze_env 模块我们可以不深入研究(但说实话,想真正看懂后面的代码还是要看看这部分)
RL_brain 这个模块是 RL 的大脑部分, 我们下节会讲
个人感觉这段代码最好看了后面具体RL_brain模块的再细看(也可以先看,好纠结,都看了就行)
from maze_env import Maze
from RL_brain import QLearningTable
def update():
# 学习 100 回合
for episode in range(100):
# 初始化 state 的观测值
observation = env.reset()
while True:
# 更新可视化环境
env.render()
# RL 大脑根据 state 的观测值挑选 action
action = RL.choose_action(str(observation))
# 探索者在环境中实施这个 action, 并得到环境返回的下一个 state 观测值, reward 和 done (是否是掉下地狱或者升上天堂)
observation_, reward, done = env.step(action)
# RL 从这个序列 (state, action, reward, state_) 中学习
RL.learn(str(observation), action, reward, str(observation_))
# 将下一个 state 的值传到下一次循环
observation = observation_
# 如果掉下地狱或者升上天堂, 这回合就结束了
if done:
break
# 结束游戏并关闭窗口
print('game over')
env.destroy()
if __name__ == "__main__":
# 定义环境 env 和 RL 方式
env = Maze() # 创建迷宫环境
RL = QLearningTable(actions=list(range(env.n_actions))) # 创建Q-learning智能体,env.n_actions是行为个数的长度,比如上下左右,则结果为4
# 开始可视化环境 env
env.after(100, update) # 每100毫秒调用一次update函数,用于训练智能体
env.mainloop() # 开启可视化环境的主循环
我的问题2:代码是怎么跑起来的,都没有具体传入的初始值怎么弄?
在这个示例中,初始状态是由
env.reset()
函数初始化的。让我来解释一下整个过程:
env = Maze()
创建了一个迷宫环境对象env
。RL = QLearningTable(actions=list(range(env.n_actions)))
创建了一个Q-learning智能体对象RL
。在这里,env.n_actions
是用来指定动作的数量,根据您的环境设置,通常是4,表示上、下、左、右等四个动作。- 接下来,通过
env.reset()
初始化迷宫环境,这个函数会将智能体放置在迷宫的初始位置。这时,observation
就是迷宫环境的初始状态的观测值。- 在进入主循环之前,智能体会首先执行一次
RL.choose_action(str(observation))
,从初始状态开始选择一个初始动作。
然后,在主循环中,智能体会根据观测值observation
选择动作,并与环境互动。环境返回下一个状态observation_
、奖励reward
和标志done
,表示是否达到了终止状态。
在每一轮循环中,智能体会使用RL.learn()
函数来学习,并不断地更新Q值。然后,将下一个状态的观测值observation_
存储在observation
变量中,以准备进行下一步循环。
这个循环会一直进行,直到达到终止状态done
为止,表示一轮回合结束。然后,它将开始新的回合,直到完成指定的回合数(在这里是100轮)。总之,初始状态是通过
env.reset()
初始化的,然后智能体通过选择动作和与环境互动来逐步学习和改进其策略。
接着上节内容, 我们来实现 RL_brain
的 QLearningTable
部分, 这也是 RL
的大脑部分, 负责决策和思考.
我们将要以一个 class 形式定义 Q learning, 并把这种 tabular q learning 方法叫做 QLearningTable
.
class QLearningTable:
# 初始化
def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9):
# 选行为
def choose_action(self, observation):
# 学习更新参数
def learn(self, s, a, r, s_):
# 检测 state 是否存在
def check_state_exist(self, state):
import numpy as np
import pandas as pd
class QLearningTable:
def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9):
self.actions = actions # a list
self.lr = learning_rate # 学习率
self.gamma = reward_decay # 奖励衰减
self.epsilon = e_greedy # 贪婪度
self.q_table = pd.DataFrame(columns=self.actions, dtype=np.float64) # 初始 q_table
注意,后面的函数都是放到QLearningTable
这个类里的
def choose_action(self, observation):
self.check_state_exist(observation) # 检测本 state 是否在 q_table 中存在(见后面标题内容)
# 选择 action
if np.random.uniform() < self.epsilon: # 选择 Q value 最高的 action
state_action = self.q_table.loc[observation, :]
# 同一个 state, 可能会有多个相同的 Q action value, 所以我们乱序一下
action = np.random.choice(state_action[state_action == np.max(state_action)].index)
else: # 随机选择 action
action = np.random.choice(self.actions)
return action
这段代码是
QLearningTable
类中的choose_action
方法,它用于根据Q值来选择一个动作。以下是这段代码的解释:
self.check_state_exist(observation)
: 这一行代码调用了类中的check_state_exist
方法,它的目的是检查当前观察(状态)是否存在于Q表格中。如果观察不存在于Q表格中,check_state_exist
方法会在Q表格中添加一个新的状态行。if np.random.uniform() < self.epsilon:
: 这是一个条件语句,它检查一个随机数是否小于贪婪度epsilon
。贪婪度epsilon
表示在探索和利用之间的权衡,用于决定在当前状态下是选择最优动作还是进行随机探索。state_action = self.q_table.loc[observation, :]
: 如果随机数小于epsilon
,则智能体选择基于Q值的最优动作。这行代码从Q表格中获取当前观察(状态)下所有可能动作的Q值,并将其存储在state_action
中。action = np.random.choice(state_action[state_action == np.max(state_action)].index)
: 在同一状态下,可能有多个具有相同最大Q值的动作。为了增加一些随机性,代码使用np.random.choice
从这些最大Q值的动作中随机选择一个。这样做是为了确保在相同Q值的动作中有一些随机性,以便更好地探索环境。
我们举个例子更好的理解一下
import numpy as np
import pandas as pd
# 假设 state_action 是一个包含Q值的Series对象
state_action = pd.Series({
'action_1': 0.5,
'action_2': 0.8,
'action_3': 0.8,
'action_4': 0.6
})
# 最大的 Q 值是 0.8,对应的动作是 'action_2' 和 'action_3'
# 下面的代码将在 'action_2' 和 'action_3' 中随机选择一个
action = np.random.choice(state_action[state_action == np.max(state_action)].index)
print(state_action == np.max(state_action))
print(state_action[state_action == np.max(state_action)])
print(state_action[state_action == np.max(state_action)].index)
print(action)
else:
: 如果随机数大于或等于epsilon
,则智能体选择随机动作。这是探索环境的一种方式,以便发现新的策略和奖励。return action
: 最终,choose_action
方法返回选择的动作,可以用于在环境中执行该动作。总之,
choose_action
方法根据贪婪度epsilon
选择动作,可以是根据Q值选择最优动作或随机选择动作,以在Q-learning算法中平衡探索和利用。
def learn(self, s, a, r, s_):
self.check_state_exist(s_) # 检测 q_table 中是否存在 s_ (见后面标题内容)
q_predict = self.q_table.loc[s, a]
if s_ != 'terminal':
q_target = r + self.gamma * self.q_table.loc[s_, :].max() # 下个 state 不是 终止符
else:
q_target = r # 下个 state 是终止符
self.q_table.loc[s, a] += self.lr * (q_target - q_predict) # 更新对应的 state-action 值
这段代码是
QLearningTable
类中的learn
方法,它用于根据Q-learning算法更新Q表格中的值。以下是这段代码的解释:
self.check_state_exist(s_)
: 这一行代码调用了类中的check_state_exist
方法,它的目的是检查下一个状态s_
是否在Q表格中存在。如果下一个状态不存在于Q表格中,check_state_exist
方法会在Q表格中添加一个新的状态行。q_predict = self.q_table.loc[s, a]
: 这一行代码获取了当前状态s
下动作a
的Q值,并将其存储在q_predict
变量中。这个值代表了当前状态下对应动作的估计Q值。if s_ != 'terminal':
:这是一个条件语句,检查下一个状态s_
是否为终止状态。如果'terminal'
是终止状态的标志,那么如果's_'
不等于'terminal'
,就执行下面的操作。这是因为终止状态下的Q值通常是确定的,不需要进行更新。q_target = r + self.gamma * self.q_table.loc[s_, :].max()
: 如果下一个状态s_
不是终止状态,这一行代码计算了目标Q值q_target
。它使用了以下公式来更新Q值:
r
是当前状态s
执行动作a
后获得的奖励。self.gamma
是奖励的衰减因子,用于权衡当前奖励和未来奖励的重要性。self.q_table.loc[s_, :].max()
获取下一个状态s_
下所有动作中的最大Q值,表示未来的最大预期奖励。self.q_table.loc[s, a] += self.lr * (q_target - q_predict)
: 这一行代码使用Q-learning的更新规则,将q_predict
和q_target
之间的差异乘以学习率self.lr
,并将结果加到当前状态s
和动作a
对应的Q值上,以更新Q表格中的Q值。总之,
learn
方法实现了Q-learning算法的学习过程,它根据当前状态、动作、奖励和下一个状态来更新Q值,以帮助智能体不断改进其策略,以获得更好的累积奖励。
def check_state_exist(self, state):
if state not in self.q_table.index:
# append new state to q table
self.q_table = self.q_table._append(
pd.Series(
[0]*len(self.actions),
index=self.q_table.columns,
name=state,
)
)
这段代码是
QLearningTable
类中的check_state_exist
方法,它用于检查给定的状态是否存在于Q表格中,并在Q表格中添加新的状态行(如果状态不存在)。以下是这段代码的解释:
if state not in self.q_table.index:
:这一行代码检查给定的state
是否在Q表格的索引中。如果state
不存在于索引中,说明这是一个新的状态,需要将其添加到Q表格中。pd.Series(...)
: 在这行代码中,首先创建了一个新的pd.Series
对象,它代表了新状态的Q值行。具体来说:
[0]*len(self.actions)
创建了一个包含多个零的列表,其中的零数量等于动作的数量,这将作为新状态的Q值初始化。index=self.q_table.columns
指定了新pd.Series
的索引,这里使用了Q表格的列标签作为索引,确保了新行的结构与Q表格的列结构相匹配。name=state
给新行设置了一个名称,该名称就是新状态的标识符。self.q_table = self.q_table._append(...)
: 一旦创建了新的pd.Series
对象,它会被添加到Q表格中。这里使用_append
方法将新行添加到Q表格。这样,Q表格就会动态地扩展以包含新的状态行。总之,
check_state_exist
方法的目的是检查给定状态是否在Q表格中存在,如果不存在,则将新状态添加到Q表格中,以确保Q表格可以包含所有可能的状态。这是Q-learning算法中的一个重要步骤,因为Q表格需要跟踪所有可能的状态-动作对的Q值。
当涉及到强化学习算法时,可以使用以下比喻来解释SARSA和Q-learning的区别:
SARSA 就像是一个小车在驾驶中,它会考虑当前的驾驶策略,选择一个动作,然后执行它。当小车行驶过程中,它会不断地根据当前策略来选择下一个动作,并根据实际的驾驶经验来更新自己的策略。这就好比你一直在开车,根据实际的道路情况来决定下一步怎么开。
Q-learning 则像是一个规划师在做规划,他会提前计划好整个行程,选择一个最优的路线,然后一直按照这个计划走。在每个路口,他会选择那条在地图上看起来最短的路线,而不考虑实际驾驶时的交通情况。这就好比你提前查看了地图,然后按照地图上的最短路径来开车,不管实际的交通状况如何。
简而言之,SARSA更像是一种根据实际经验调整的实时决策策略,而Q-learning更像是一种事先计划好的最优策略。选择哪种方法通常取决于问题的性质以及你更关心的是实时适应还是最优决策。
让我再以更清晰的方式解释SARSA和Q-learning的区别:
SARSA(State-Action-Reward-State-Action):
SARSA 是一种基于"实际经验"的学习方法。它像是一个驾驶员,他在驾车时会不断根据当前的交通情况来选择下一个行动。
具体地,SARSA会在每一步中,根据当前状态选择一个动作,然后执行它,观察到下一个状态和获得的奖励,并使用这些信息来更新自己的行动策略。这意味着它是一种"实时"学习方法,会根据不同情况进行调整。
Q-learning:
Q-learning 是一种基于"计划"的学习方法。它像是一个旅行者,他在旅行前会先规划好整个行程,包括选择最优路径。
具体地,Q-learning会在每一步中,根据当前状态选择一个动作,但不会立即执行它。相反,它会考虑所有可能的动作,并选择具有最大Q值的动作,即选择一个看似最好的动作,然后将这个计划放在一旁。然后,它会在之后的某个时间点执行这个计划,然后更新自己的策略。
总之,SARSA更像是根据实际经验来做决策的方法,而Q-learning更像是提前计划并在之后执行的方法。这些方法在不同的问题和环境中都有各自的优势和用途。