网站首页 > 技术文章 正文
0、主要参考
1、代码:https://github.com/lansinuote/More_Simple_Reinforcement_Learning
2、原理:https://zhuanlan.zhihu.com/p/626998396
1、什么是Q-Learning?
- Q-learning是一种无模型(model-free)的强化学习算法。它通过估计动作值函数(action-value function),即Q函数(Q-function),来学习智能体在环境中采取各种动作所能获得的期望奖励。Q-learning算法可以应用于有限MDP(Markov Decision Process)问题。
- Q-learning算法的核心是基于TD算法来训练其动作值函数,所以可以称之为一种TD算法。
- 在代码中,我们的 Q 函数由 Q 表编码,Q 表中的每个单元格对应于一个状态-动作对值。将此 Q 表视为我们 Q 函数。
2、什么是Q表
转载了:https://zhuanlan.zhihu.com/p/626998396
(1)以下用mouse吃奶酪举例:
这个图中,一共有6个格子,每个格子有上下左右四种动作。而对应Q 表已初始化,所有值都 = 0(初始未训练)。此表包含每个状态和动作的相应状态动作值:
所以:Q 函数使用一个 Q 表,该表具有每个状态-动作对的值。给定一个状态和动作,我们的 Q 函数将在其 Q 表中搜索以输出值。
3、Q_learning基本流程
所以Q_learning算法包含两个阶段:训练和推理
(1)在训练阶段,我们不断Exploration(探索)和 Exploitation(利用),以生成一个最优的Q函数。
(2)在推理阶段,我们在Q表中搜索相应的值,然后采用最优策略(选择最大Q值的动作)来进行下一步动作。
3.1训练
3.2推理
3.3Q_learning算法具体实现
(1)第一步,初始化 Q 表,我们需要为每个状态-动作对初始化 Q 表。大多数情况下,我们使用值 0 进行初始化。
(2)第二步,使用 epsilon 贪婪策略选择操作
(3)第 3 步:在执行操作,获得奖励 Rt+1 和下一个状态 St+1
(4)第 4 步:更新 Q(St, at)
在TD学习中,我们会在交互的一个步骤后更新我们的价值函数。
为了制定我们的TD目标,我们这里的价值函数是Q,因为我们推理的策略是找Q表最大值,所以公式通过查找在下一个状态下最大化当前 Q 函数的动作来计算。
因此,我们的更新公式如下所示:
在此episode结束时,会不断开始新的episode的训练,经过足够多次迭代后,Q值表会收敛,智能体可以通过查询Q值表来确定在每个状态下应该采取的最优动作。
4、代码实现和测试
4.1定义一个环境类
(1)代码如下
#定义环境
class MyWrapper(gym.Wrapper):
def __init__(self):
#is_slippery控制会不会滑
env = gym.make('FrozenLake-v1',
render_mode='rgb_array',
is_slippery=False)
super().__init__(env)
self.env = env
def reset(self):
state, _ = self.env.reset()
return state
def step(self, action):
state, reward, terminated, truncated, info = self.env.step(action)
over = terminated or truncated
#走一步扣一份,逼迫机器人尽快结束游戏
if not over:
reward = -1
#掉坑扣100分
if over and reward == 0:
reward = -100
return state, reward, over
#打印游戏图像
def show(self):
plt.figure(figsize=(3, 3))
plt.imshow(self.env.render())
plt.show()
(2)注意:该类定义了一个FrozenLake-v1对象,该类的step方法返回的是:当前的状态state,该步骤的奖励reward(正常走路-1分,掉坑里-100分),以及是否结束了over的标记(True为结束了)
(3)可以简单测试一下这个环境
import gymnasium as gym
from matplotlib import pyplot as plt
#定义环境
class MyWrapper(gym.Wrapper):
def __init__(self):
#is_slippery控制会不会滑
env = gym.make('FrozenLake-v1',
render_mode='rgb_array',
is_slippery=False)
super().__init__(env)
self.env = env
def reset(self):
state, _ = self.env.reset()
return state
def step(self, action):
state, reward, terminated, truncated, info = self.env.step(action)
over = terminated or truncated
#走一步扣一份,逼迫机器人尽快结束游戏
if not over:
reward = -1
#掉坑扣100分
if over and reward == 0:
reward = -100
return state, reward, over
#打印游戏图像
def show(self):
plt.figure(figsize=(3, 3))
plt.imshow(self.env.render())
plt.show()
if __name__ == '__main__':
#(1)创建环境
env = MyWrapper()
env.reset()
state, reward, over =env.step(2) #先前一步
print(state, reward, over)
state, reward, over =env.step(2) #先前一步
print(state, reward, over)
env.show()
(4)测试结果如下:
4.2建立一个空的Q表
(1)初始化Q表,定义了每个状态下每个动作的价值,因为我们定义的空间大小为4*4=16,而且每个坐标state的可能动作为4个(上下左右),所以定义的Q表大小为16*4
Q = np.zeros((16, 4))
4.3 下一步如何走使用系统随机采样方法
gym提供了下一步如何走没有很好的选择情况下的随机走(值)的获取方法,函数使用方法如下
action = env.action_space.sample()
注意:上面获取的action是随机走的,对于我们这个游戏
action 为:2向右,1向下,0向左,3向上
{0: "←", 1: "↓", 2: "→", 3: "↑"}
4.4 贪婪策略跑一轮的实现,直到失败(掉坑里了)
(1)小概率e概率(下面为0.1)下,随机空间获取如何走
(2)剩下的都从Q表里面取值(虽然一开始都是0),后面会训练出来的,不用愁
4.4.1主要过程
- (1)如果没结束,一直尝试下去
- (2)大部分情况下从Q值获取动作
- (3)贪婪策略,小概率情况下,随机
- (4)输入下一步动作,获取下一步状态state,奖励reward,以及是否结束over
- (5)把每一步的状态state,动作action,奖励reward,下一状态next_state,是否结束over都记下来
- (6)计算累积的奖励reward_sum
- (7)更新状态
4.4.2主要代码
(1)代码如下
#贪婪策略玩一局游戏并记录数据
def play(show=False):
data = []
reward_sum = 0
state = env.reset()
over = False
#(1)如果没结束,一直尝试下去
while not over:
#(2)大部分情况下从Q值获取动作
action = Q[state].argmax()
#(3)贪婪策略,小概率情况下,随机
if random.random() < 0.1:
action = env.action_space.sample()
print("random.random() env.action_space.sample()")
#(4)输入下一步动作,获取下一步状态state,奖励reward,以及是否结束over
next_state, reward, over = env.step(action)
#(5)把每一步的状态state,动作action,奖励reward,下一状态next_state,是否结束over都记下来
data.append((state, action, reward, next_state, over))
#(6)计算累积的奖励reward_sum
reward_sum += reward
#(7)更新状态
state = next_state
print(action,over)
if show:
display.clear_output(wait=True)
env.show()
return data, reward_sum
(2)简单测试
data, reward_sum = play()
print(data,reward_sum)
(3)注意返回的值,为一些列的过程数据state, action, reward, next_state, over和,reward_sum
4.5经验池子Pool
4.5.1池子的定义
- (1)经验池子的作用是记录以前走过的路,记下来再说,供后续参考。
- (2)具体记录的数据为上图中data返回的值,包含了(state, action, reward, next_state, over)五个数据。
- (3)上述贪婪的play步骤一次方法的data记录中可能包含了几十个甚至上百个尝试的步骤。
- (4)当然pool中记录的数据不会无限的长,太多也没有,比如说记录个1万条数据或者一百万条数据(咔咔,哈哈)。
具体池子的简单代码定义如下
#数据池
class Pool:
#初始化一个空的元组
def __init__(self):
self.pool = []
#返回长度
def __len__(self):
return len(self.pool)
#获取第i个元素
def __getitem__(self, i):
return self.pool[i]
#更新动作池
def update(self):
#每次更新不少于N条新数据
old_len = len(self.pool)
# 下述while中len(pool)至少会增加200条
while len(pool) - old_len < 200:
#下面的操作一下子可能会添加好多元素,
# 比如100条,而且有可能重复的
self.pool.extend(play()[0])
#只保留最新的N条数据
self.pool = self.pool[-1_0000:]
#从Pool中获取一批数据样本
def sample(self):
return random.choice(self.pool)
4.5.2池子的简单测试
(1)测试代码
#(4)数据池
pool = Pool()
pool.update()
(2)注意,Pool中的数据简单如下图所示
4.6训练一轮
(1)逻辑如下
- (1)先更新一下池子Pool,也就是跑了最小N条数据
- (2)每次更新数据后,训练M次,可修改
- (3)随机从Pool中抽一条数据
- (4)Q矩阵当前估计的state下action的价值,最开始Q都是0
- (5)实际玩了之后得到的reward+下一个状态的价值*0.9
- (6)value和target应该是相等的,说明Q矩阵的评估准确。如果有误差,则应该以target为准更新Q表,修正它的偏差。这就是TD误差,指评估值之间的偏差,以实际成分高的评估为准进行修正。
- (7)更新Q表
(2)训练一次的代码如下所示
#训练一轮的函数
def trainOneEpoch( ):
#(1)先更新一下池子Pool,也就是跑了最小N条数据
pool.update()
#(2)每次更新数据后,训练M次,可修改
for i in range(200):
#(3)随机从Pool中抽一条数据
state, action, reward, next_state, over = pool.sample()
#(4)Q矩阵当前估计的state下action的价值
# 最Q开始都是0
value = Q[state, action]
#(5)实际玩了之后得到的reward+下一个状态的价值*0.9
target = reward + Q[next_state].max() * 0.9
#(6)value和target应该是相等的,说明Q矩阵的评估准确
#如果有误差,则应该以target为准更新Q表,修正它的偏差
#这就是TD误差,指评估值之间的偏差,以实际成分高的评估为准进行修正
update = (target - value) * 0.1
#(7)更新Q表
Q[state, action] += update
(3)注意,简单训练一轮后,Q值就不全是0
4.7多轮训练
(1)多轮简要代码
#(6)多轮训练
for epoch in range(1000):
trainOneEpoch()
if epoch % 100 == 0:
print(epoch, len(pool), play()[-1])
(2)训练过程每100步后的结果
(4)训练后的Q值,随意标注的几个最优动作,马上可以看出来了
{0: "←", 1: "↓", 2: "→", 3: "↑"}
4.8训练结果的使用
(1)训练得到的Q值可以直接使用,简单测试代码
#(7)最后演示10次训练结果的行走
for i in range(10):
play(True)
(2)结果很完美
4.9完整测试代码
(1)完整代码如下
import gymnasium as gym
from matplotlib import pyplot as plt
import numpy as np
import random
from IPython import display
#定义环境
class MyWrapper(gym.Wrapper):
def __init__(self):
#is_slippery控制会不会滑
env = gym.make('FrozenLake-v1',
render_mode='rgb_array',
is_slippery=False)
super().__init__(env)
self.env = env
def reset(self):
state, _ = self.env.reset()
return state
def step(self, action):
state, reward, terminated, truncated, info = self.env.step(action)
over = terminated or truncated
#走一步扣一份,逼迫机器人尽快结束游戏
if not over:
reward = -1
#掉坑扣100分
if over and reward == 0:
reward = -100
return state, reward, over
#打印游戏图像
def show(self):
plt.figure(figsize=(3, 3))
plt.imshow(self.env.render())
plt.show()
#贪婪策略玩一局游戏并记录数据
def play(show=False):
data = []
reward_sum = 0
state = env.reset()
over = False
#(1)如果没结束,一直尝试下去
while not over:
#(2)大部分情况下从Q值获取动作
action = Q[state].argmax()
#(3)贪婪策略,小概率情况下,随机
if random.random() < 0.1:
action = env.action_space.sample()
# print("random.random() env.action_space.sample()")
#(4)输入下一步动作,获取下一步状态state,奖励reward,以及是否结束over
next_state, reward, over = env.step(action)
#(5)把每一步的状态state,动作action,奖励reward,下一状态next_state,是否结束over都记下来
data.append((state, action, reward, next_state, over))
#(6)计算累积的奖励reward_sum
reward_sum += reward
#(7)更新状态
state = next_state
# print(action,over)
if show:
display.clear_output(wait=True)
env.show()
return data, reward_sum
#数据池
class Pool:
#初始化一个空的元组
def __init__(self):
self.pool = []
#返回长度
def __len__(self):
return len(self.pool)
#获取第i个元素
def __getitem__(self, i):
return self.pool[i]
#更新动作池
def update(self):
#每次更新不少于N条新数据
old_len = len(self.pool)
# 下述while中len(pool)至少会增加200条
while len(pool) - old_len < 200:
#下面的操作一下子可能会添加好多元素,
# 比如100条,而且有可能重复的
self.pool.extend(play()[0])
#只保留最新的N条数据
self.pool = self.pool[-1_0000:]
#从Pool中获取一批数据样本
def sample(self):
return random.choice(self.pool)
#训练一轮的函数
def trainOneEpoch( ):
#(1)先更新一下池子Pool,也就是跑了最小N条数据
pool.update()
#(2)每次更新数据后,训练M次,可修改
for i in range(200):
#(3)随机从Pool中抽一条数据
state, action, reward, next_state, over = pool.sample()
#(4)Q矩阵当前估计的state下action的价值
# 最Q开始都是0
value = Q[state, action]
#(5)实际玩了之后得到的reward+下一个状态的价值*0.9
target = reward + Q[next_state].max() * 0.9
#(6)value和target应该是相等的,说明Q矩阵的评估准确
#如果有误差,则应该以target为准更新Q表,修正它的偏差
#这就是TD误差,指评估值之间的偏差,以实际成分高的评估为准进行修正
update = (target - value) * 0.1
#(7)更新Q表
Q[state, action] += update
if __name__ == '__main__':
#(1)创建环境
env = MyWrapper()
env.reset()
# state, reward, over =env.step(2) #先前一步
# print(state, reward, over)
# state, reward, over =env.step(2) #先前一步
# print(state, reward, over)
# env.show()
#(2)初始化Q表,定义了每个状态下每个动作的价值
Q = np.zeros((16, 4))
#(3)贪婪策略往往看
# play(show=True)
# data, reward_sum = play()
# print(data,reward_sum)
#(4)数据池
pool = Pool()
# pool.update()
#(5) 训练1轮
trainOneEpoch()
#print(Q)
#(6)多轮训练
for epoch in range(1000):
trainOneEpoch()
if epoch % 100 == 0:
print(epoch, len(pool), play()[-1])
print(Q)
#(7)最后演示10次训练结果的行走
for i in range(10):
play(True)
5、Q-learning算法的基本原理总结
Q-learning算法的核心思想是通过学习一个Q值函数(Q-value Function)来估计在某个状态下采取某个行动的长期回报。Q值函数记作:Q(s, a),其中s表示状态,a表示行动。
Q-learning算法的更新公式为:
其中: - s:当前状态。 - a:当前行动。 - r:获得的即时奖励。 - s':下一个状态。 - a':下一个行动。 - \alpha:学习率,控制更新的步长。 - \gamma:折扣因子,用于控制未来奖励的重要性。
在每个时刻,智能体(Agent)根据当前状态选择一个行动,并根据环境的反馈获得奖励和下一个状态,然后根据上述公式更新Q值函数。智能体的行动选择可以采用贪婪策略(Greedy Policy)或ε-贪婪策略(ε-Greedy Policy)。
猜你喜欢
- 2024-10-14 开启深度强化学习之路:Deep Q-Networks简介和代码示例
- 2024-10-14 人工智能之机器学习常见算法 人工智能机器学习的三种常用算法
- 2024-10-14 通过Q学习更深入地学习强化学习 持续强化理论学习
- 2024-10-14 基于在线附加Q学习的伺服电机速度最优跟踪控制方法
- 2024-10-14 机器不学习:强化学习之 Deep Q Network (DQN)
- 2024-10-14 算法人生(2):从“强化学习”看如何“活在当下”
- 2024-10-14 使用强化学习和q-learning来玩贪吃蛇的Python实现
- 2024-10-14 技术论文|改进 Q 学习算法在多智能体强化学习中的应用
- 2024-10-14 16种提升效率的机器学习算法! 提高算法效率的关键是什么
- 2024-10-14 探索人工智能中的Q-learning算法:从小白到大师
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)