强化学习入门二(Q-Learning)
Q-Learning是强化学习中最经典的无模型(model-free)算法之一,核心思想是通过学习"状态-动作价值函数"(即Q函数)来指导智能体的决策。它不需要对环境建模,直接从与环境的交互经验中学习最优策略。在实际复杂的机器人控制任务中,通常会使用Q-Learning的扩展算法,如Deep Q-Network (DQN),它用神经网络替代Q表,能够处理高维状态空间。让我们以机器人在迷宫中寻找目标
Q-Learning算法详解
Q-Learning是强化学习中最经典的无模型(model-free)算法之一,核心思想是通过学习"状态-动作价值函数"(即Q函数)来指导智能体的决策。它不需要对环境建模,直接从与环境的交互经验中学习最优策略。
Q-Learning的核心概念
-
Q函数(Q-Value Function)
- 定义:Q(s,a)表示在状态s下执行动作a的长期价值(即未来可能获得的累积奖励总和)
- 作用:智能体通过比较不同动作的Q值,选择Q值最高的动作
-
Q值更新公式
Q(s,a) ← Q(s,a) + α[r + γ·maxₐ'Q(s',a') - Q(s,a)]其中:
- α是学习率(0 < α ≤ 1),控制更新幅度
- γ是折扣因子(0 ≤ γ ≤ 1),表示未来奖励的重要程度
- r是执行动作a后获得的即时奖励
- s’是执行动作a后到达的新状态
- maxₐ’Q(s’,a’)表示新状态s’下所有可能动作的最大Q值
-
ε-贪婪策略(ε-greedy)
- 以ε的概率随机选择动作(探索)
- 以1-ε的概率选择当前Q值最高的动作(利用)
- 平衡探索(发现新策略)和利用(获取已知奖励)
Q-Learning算法流程
- 初始化Q表(Q(s,a)),通常初始化为0或随机小值
- 对于每个回合(episode):
a. 初始化状态s
b. 当s不是终止状态时:
i. 基于ε-贪婪策略,在状态s选择动作a
ii. 执行动作a,获得奖励r和新状态s’
iii. 使用Q值更新公式更新Q(s,a)
iv. 将状态更新为s’ - 重复步骤2,直到Q表收敛
机器人控制实例:迷宫导航
让我们以机器人在迷宫中寻找目标为例,具体说明Q-Learning的应用。
假设机器人需要在一个5x5的迷宫中找到目标位置,机器人可以向上、下、左、右四个方向移动:
- 碰到墙壁或边界时,不能移动且获得-1惩罚
- 每移动一步获得-0.1惩罚(鼓励最短路径)
- 到达目标位置获得+10奖励
- 到达目标后 episode 结束
代码解析
import numpy as np
import matplotlib.pyplot as plt
class MazeEnv:
"""迷宫环境"""
def __init__(self):
# 5x5的迷宫,0表示空地,1表示墙壁,2表示目标
self.maze = [
[0, 1, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 0, 0, 1, 0],
[1, 1, 0, 1, 1],
[0, 0, 0, 0, 2]
]
self.rows = 5
self.cols = 5
self.reset()
def reset(self):
"""重置环境,回到起点"""
self.robot_pos = [0, 0] # 机器人初始位置
return tuple(self.robot_pos)
def step(self, action):
"""执行动作,返回新状态、奖励和是否结束"""
# 动作:0-上,1-右,2-下,3-左
row, col = self.robot_pos
new_row, new_col = row, col
done = False
if action == 0: # 上
new_row -= 1
elif action == 1: # 右
new_col += 1
elif action == 2: # 下
new_row += 1
elif action == 3: # 左
new_col -= 1
# 检查是否撞墙或越界
if (new_row < 0 or new_row >= self.rows or
new_col < 0 or new_col >= self.cols or
self.maze[new_row][new_col] == 1):
# 撞墙,位置不变,给予惩罚
reward = -1
else:
# 移动成功
self.robot_pos = [new_row, new_col]
new_row, new_col = self.robot_pos
# 检查是否到达目标
if self.maze[new_row][new_col] == 2:
reward = 10 # 到达目标,给予奖励
done = True
else:
reward = -0.1 # 每步轻微惩罚,鼓励最短路径
done = False
return tuple(self.robot_pos), reward, done
def render(self):
"""绘制迷宫和机器人位置"""
for i in range(self.rows):
for j in range(self.cols):
if [i, j] == self.robot_pos:
print("R", end=" ") # 机器人
elif self.maze[i][j] == 1:
print("#", end=" ") # 墙壁
elif self.maze[i][j] == 2:
print("G", end=" ") # 目标
else:
print(".", end=" ") # 空地
print()
print()
class QLearningRobot:
"""基于Q-Learning的机器人"""
def __init__(self, env, learning_rate=0.1, gamma=0.9, epsilon=0.1):
self.env = env
self.learning_rate = learning_rate # 学习率α
self.gamma = gamma # 折扣因子γ
self.epsilon = epsilon # ε-贪婪策略的ε值
# 初始化Q表,状态是位置(row, col),动作是0-3
self.q_table = {}
for i in range(env.rows):
for j in range(env.cols):
self.q_table[(i, j)] = [0.0, 0.0, 0.0, 0.0] # 上下左右四个动作
def choose_action(self, state):
"""基于ε-贪婪策略选择动作"""
if np.random.uniform(0, 1) < self.epsilon:
# 随机选择动作(探索)
return np.random.choice(4)
else:
# 选择Q值最大的动作(利用)
return np.argmax(self.q_table[state])
def learn(self, state, action, reward, next_state):
"""更新Q值"""
# 当前Q值
current_q = self.q_table[state][action]
# 新状态的最大Q值
max_next_q = max(self.q_table[next_state])
# Q值更新公式
new_q = current_q + self.learning_rate * (reward + self.gamma * max_next_q - current_q)
self.q_table[state][action] = new_q
def train(self, episodes=1000):
"""训练机器人"""
rewards = [] # 记录每回合的总奖励
steps = [] # 记录每回合的步数
for episode in range(episodes):
state = self.env.reset()
total_reward = 0
step = 0
done = False
while not done:
action = self.choose_action(state)
next_state, reward, done = self.env.step(action)
self.learn(state, action, reward, next_state)
total_reward += reward
state = next_state
step += 1
# 防止无限循环
if step > 1000:
break
rewards.append(total_reward)
steps.append(step)
# 每100回合打印一次进度
if (episode + 1) % 100 == 0:
print(f"Episode {episode+1}/{episodes}, Total Reward: {total_reward:.2f}, Steps: {step}")
return rewards, steps
def test(self):
"""测试训练好的机器人"""
state = self.env.reset()
self.env.render()
done = False
step = 0
while not done and step < 100:
action = np.argmax(self.q_table[state]) # 只使用利用,不探索
state, _, done = self.env.step(action)
self.env.render()
step += 1
# 主程序
if __name__ == "__main__":
# 创建环境和机器人
env = MazeEnv()
robot = QLearningRobot(env, learning_rate=0.1, gamma=0.9, epsilon=0.1)
# 训练机器人
print("开始训练...")
rewards, steps = robot.train(episodes=1000)
# 绘制训练曲线
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.plot(rewards)
plt.title("每回合总奖励")
plt.xlabel("回合数")
plt.ylabel("总奖励")
plt.subplot(1, 2, 2)
plt.plot(steps)
plt.title("每回合步数")
plt.xlabel("回合数")
plt.ylabel("步数")
plt.tight_layout()
plt.show()
# 测试训练好的机器人
print("测试训练好的机器人:")
robot.test()
上述代码实现了一个完整的Q-Learning机器人迷宫导航系统,主要包含两个类:
-
MazeEnv类:定义了迷宫环境
- 5x5的网格世界,包含墙壁、空地和目标
- 提供reset()方法重置环境
- 提供step()方法执行动作并返回新状态、奖励和是否结束
- 提供render()方法可视化当前状态
-
QLearningRobot类:实现Q-Learning算法
- 维护一个Q表存储每个状态-动作对的价值
- choose_action()方法基于ε-贪婪策略选择动作
- learn()方法使用Q值更新公式更新Q表
- train()方法进行多回合训练
- test()方法验证训练效果
算法执行过程说明
-
初始化阶段:
- 创建5x5的迷宫环境,设置起点(0,0)和终点(4,4)
- 初始化Q表,所有状态-动作对的Q值都为0
- 设置超参数:学习率α=0.1,折扣因子γ=0.9,探索率ε=0.1
-
训练阶段:
- 机器人从起点开始,根据ε-贪婪策略选择动作
- 每次移动后,根据获得的奖励和新状态更新Q值
- 随着训练进行,机器人逐渐学习到哪些动作能带来更高的长期奖励
- 训练曲线显示:总奖励逐渐增加,到达目标所需步数逐渐减少
-
测试阶段:
- 关闭探索(ε=0),只根据Q值选择最优动作
- 机器人能够找到从起点到目标的最短路径
Q-Learning的特点与适用场景
-
优点:
- 算法简单易懂,实现难度低
- 收敛性有保证,理论上能找到最优策略
- 不需要环境模型,适用范围广
-
缺点:
- 当状态空间和动作空间很大时,Q表会变得非常庞大
- 对高维状态空间(如视觉输入)处理困难
-
适用场景:
- 小型机器人控制任务(如迷宫导航、简单机械臂控制)
- 游戏AI(如小型网格游戏)
- 简单的决策系统
在实际复杂的机器人控制任务中,通常会使用Q-Learning的扩展算法,如Deep Q-Network (DQN),它用神经网络替代Q表,能够处理高维状态空间。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)