1. 原理讲解
Q-learning算法实际上相当简单,仅仅维护一个Q值表即可,表的维数为(所有状态S,所有动作A),表的内容称为Q值,体现该状态下采取当前动作的未来奖励期望。智能体每次选择动作时都会查询Q值表在当前状态下采取何种动作得到的未来奖励可能最多,当然也会添加一些随机性,使智能体可能选择别的可能当前认为未来奖励并不多的动作,以便跳出局部最优解,尽量得到全局最优解。
2.Q表更新公式
Q-learning算法的核心是通过不断更新Q表来学习最优策略。Q表是一个二维数组,其中Q(s, a)表示在状态s下采取动作a的预期回报(或价值)。更新公式如下:
Q(s,a) ← Q(s,a) + α * [r + γ * max(Q(s’,a’)) - Q(s,a)]
Q(s,a):当前状态s下采取动作a的价值估计(来自Q-table)
α:学习率(0 < α ≤ 1),学习率 α 的作用是控制Q值更新的幅度。具体来说:
如果 α=1,Q值会完全更新为新的目标值,即 Q(s,a)=TD Target。
如果 α=0,Q值不会更新,即 Q(s,a) 保持不变。
对于 0<α<1,Q值会部分更新为新的目标值,即 Q(s,a) 会逐渐向目标值靠拢。
r:执行动作a后获得的即时奖励
γ:折扣因子(0 ≤ γ < 1),衡量未来奖励的重要性
max(Q(s',a')):在新状态s'下所有可能动作中的最大Q值
这个公式实际上是在说:“新的Q值 = 旧的Q值 + 学习率 × (目标值 - 旧Q值)”,其中:目标值 = 即时奖励r+ 未来奖励的折现(γ * max(Q(s’,a’)))
(目标值 - 旧Q值) 是所谓的"时序差分误差"(Temporal Difference Error)
TD Error(时间差分误差):
这个误差表示当前Q值与目标值之间的差距。
如果TD误差为正,说明当前Q值低估了实际回报,需要增加。
如果TD误差为负,说明当前Q值高估了实际回报,需要减少。
3.代码实现部分:
在CartPole环境中,状态由4个连续值组成:
Q-learning传统实现需要有限的状态空间(即状态是可数的),但连续状态有无限可能,所以需要把连续值"分桶"变成离散值。
什么是bins?
想象把连续的数值范围切成若干个"桶"(bins):
温度计例子:
[0°C - 10°C) → 低温桶
[10°C - 20°C) → 中温桶
[20°C - 30°C] → 高温桶
`# 把-2.4到2.4的范围切成20个等分区间
position_bins = np.linspace(-2.4, 2.4, 20)`
离散化代码:
def discretize_state(state, bins):
"""将连续状态转换为离散索引"""
discretized = []
for i in range(4): # CartPole有4个状态维度
# 将值限制在bin范围内
clipped = np.clip(state[i], bins[i][0], bins[i][-1])
# 找到最近的bin索引
discretized.append(np.digitize(clipped, bins[i]) - 1) # -1使索引从0开始
return tuple(discretized)

4.训练过程:

ε-贪婪策略:
是Q-learning中平衡探索(Exploration)和利用(Exploitation)的核心机制。
1. 基本概念
什么是ε-贪婪策略?以概率 ε 随机选择动作(探索新可能),以概率 1-ε 选择当前已知最优动作(利用已有知识)。纯贪婪策略(总是选最优)可能导致陷入局部最优,纯随机策略(总是随机选)学习效率低下,ε-贪婪策略在两者间取得平衡
简单例子:1. 想象你在选择午餐
假设你每天都要选择午餐:
A餐厅:你知道很好吃(已知最优选择)
B餐厅:你没吃过(未知选择)
纯贪婪策略(总是选最优)
👉 每天都去A餐厅
优点:永远不会吃到难吃的
缺点:可能错过更好吃的B餐厅
纯随机策略
👉 抛硬币决定去A或B
优点:可能发现新美食
缺点:经常吃到难吃的
ε-贪婪策略(聪明人的选择)
👉 大多数时候(比如90%)去A餐厅,偶尔(10%)尝试B餐厅
平衡了"吃得好"和"发现新选择"`
可视化理解
训练过程:
[随机][随机][随机]... (初期完全随机探索)
↓
[最优][随机][最优][最优][随机]... (中期混合)
↓
[最优][最优][最优][最优][最优]... (后期基本固定)
ε是个概率值(0-1之间)
算法会生成一个随机数跟ε比较
随机数 < ε → 探索(随机选)
随机数 ≥ ε → 利用(选已知最优)
ε会随着训练逐渐减小
动态调整参数:
epsilon = 1.0 # 初始值(100%探索)
for 每次训练:
epsilon = max(0.01, epsilon*0.995) # 每次衰减0.5%
代码理解:
import random
# 设置ε=0.1(10%概率随机探索)
epsilon = 0.1
if random.random() < epsilon: # 10%的情况
action = 随机选左或右 # 探索新动作
else: # 90%的情况
action = 当前已知最好的动作 # 用已知最好的
完整代码
import gym
import numpy as np
# 初始化环境
env = gym.make('CartPole-v1', render_mode="human")
print("动作空间:", env.action_space) # 0:左, 1:右
print("状态空间:", env.observation_space) # 4个值: [车位置, 车速度, 杆角度, 杆角速度]
# 离散化设置
num_bins = 20
# 手动设置合理的边界值(避免过大值)
pos_bins = np.linspace(-2.4, 2.4, num_bins)
vel_bins = np.linspace(-3.0, 3.0, num_bins)
angle_bins = np.linspace(-0.5, 0.5, num_bins)
ang_vel_bins = np.linspace(-2.0, 2.0, num_bins)
bins = [pos_bins, vel_bins, angle_bins, ang_vel_bins]
def discretize_state(state, bins):
"""将连续状态转换为离散索引"""
discretized = []
for i in range(4): # CartPole有4个状态维度
# 将值限制在bin范围内
clipped = np.clip(state[i], bins[i][0], bins[i][-1])
# 找到最近的bin索引
discretized.append(np.digitize(clipped, bins[i]) - 1) # -1使索引从0开始
return tuple(discretized)
# 初始化Q表
q_table = np.zeros((num_bins, num_bins, num_bins, num_bins, env.action_space.n))
# 训练参数
episodes = 5000
epsilon = 1.0 # 初始探索率
epsilon_min = 0.01
epsilon_decay = 0.995
alpha = 0.1 # 学习率
gamma = 0.99 # 折扣因子(应该接近1)
# 测试训练结果
for episode in range(episodes):
state, _ = env.reset()
state = discretize_state(state, bins)
done = False
total_reward = 0
while not done:
# ε-贪婪策略
if np.random.random() < epsilon:
action = env.action_space.sample() # 随机探索
else:
action = np.argmax(q_table[state]) # 利用已知最优
# 执行动作
next_state, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
next_state = discretize_state(next_state, bins)
total_reward += reward
# Q-learning更新
current_q = q_table[state][action]
max_next_q = np.max(q_table[next_state])
# 如果游戏结束,没有下一个状态的最大Q值
target_q = reward if done else reward + gamma * max_next_q
q_table[state][action] = current_q + alpha * (target_q - current_q)
state = next_state
# 衰减探索率
epsilon = max(epsilon_min, epsilon * epsilon_decay)
print(f"测试回合 {episode}, 奖励 {total_reward},贪心:{epsilon}")
env.close()
1万+



被折叠的 条评论
为什么被折叠?



