第4章:Q-Learning与表格方法:Q表更新原理、ε-贪婪策略、在简单栅格环境中的无人机导航

各位同学,欢迎来到第四章。这一章我们终于要动手了——让无人机学会自己找路。

前面几章我们聊了强化学习的基本框架,马尔可夫决策过程,还有贝尔曼方程。说实话,那些都是理论铺垫。今天我们要讲的,是强化学习里最经典、最直观的算法之一:Q-Learning

我个人觉得,Q-Learning 就像强化学习的「Hello World」。你把这个搞懂了,后面那些深度网络、策略梯度什么的,理解起来会顺畅很多。

4.1 什么是Q表?

先问大家一个问题:如果你是一个无人机,在栅格环境里飞行,你怎么知道下一步该往哪走?

最简单的办法——记笔记。

你每到一个格子,就掏出小本本,记下:「在这个格子,往东走能得多少分?往西走呢?」

这个「小本本」,就是Q表

Q表本质上是一个二维表格:

  • :所有可能的状态(比如无人机所在的栅格坐标)
  • :所有可能的动作(上、下、左、右、悬停等)
  • 单元格的值:Q(s, a),表示在状态s下执行动作a的「长期回报期望」

我刚开始做无人机项目时,环境是20×20的栅格,状态数400个,动作5个。Q表就是400行×5列,一共2000个格子。手动初始化全零,然后一点点填满。

核心思想:Q表就是无人机的「经验手册」。它告诉无人机:在每一个位置,每一个动作到底值不值得做。

4.2 Q表更新原理

好,现在无人机有了小本本。但它怎么往本子上记东西呢?

这就是Q-Learning的核心公式了。别怕,我拆开讲:

Q(s, a) ← Q(s, a) + α [ r + γ * max_a' Q(s', a') - Q(s, a) ]

这个公式看着唬人,其实就三部分:

  1. 当前估计:Q(s, a) —— 你原来觉得这个动作值多少
  2. 实际收获:r + γ * max_a' Q(s', a') —— 你执行完动作后,实际拿到了奖励r,再加上未来能拿到的最大价值
  3. 误差修正:两者相减,乘以学习率α,然后加回去

说白了就是:用实际经验来修正你的估计

举个例子。无人机在格子(2,3),它选择「向右走」。执行后:

  • 它拿到了即时奖励 r = -1(因为移动一步有能耗惩罚)
  • 它到了新格子(2,4),发现这个格子未来最好动作的价值是 max Q(s', a') = 0.8
  • 假设 γ = 0.9,那么实际收获 = -1 + 0.9 × 0.8 = -0.28
  • 原来它觉得向右走值 0.5,现在发现实际只有 -0.28
  • 于是它把Q值往下调一点:新Q = 0.5 + α × (-0.28 - 0.5)

嗯,这里要注意:学习率α不能太大也不能太小。我踩过这个坑——α设成0.9,结果Q值震荡得像过山车,无人机永远不收敛。后来我习惯设0.1到0.3之间,稳得很。

我的经验:α = 0.1 适合大多数场景。如果环境变化剧烈(比如障碍物会移动),可以适当调大到0.3。但别超过0.5,否则你会后悔的。

4.3 ε-贪婪策略:探索与利用的平衡

现在无人机有了Q表,也知道怎么更新了。但有个问题:它该不该每次都选Q值最大的动作?

你想想看,如果每次都选最好的,那它永远不知道有没有更好的路。这就是经典的探索-利用困境

解决方案?ε-贪婪策略。

做法很简单:

  • 以概率 ε 随机选一个动作(探索)
  • 以概率 1-ε 选Q值最大的动作(利用)

我习惯把ε设成0.1,也就是90%的时间利用经验,10%的时间探索新路。

但这里有个技巧:ε可以随时间衰减

刚开始训练时,无人机啥都不懂,多探索探索。训练到后期,经验丰富了,就少探索多利用。

# ε衰减策略示例
epsilon = 1.0
epsilon_min = 0.01
epsilon_decay = 0.995

for episode in range(total_episodes):
    # 训练...
    epsilon = max(epsilon_min, epsilon * epsilon_decay)

我曾经在一个复杂迷宫里试过固定ε=0.1,结果无人机绕了5000个回合还没找到最优路径。后来改成衰减策略,1500回合就收敛了。差距就这么大。

避坑指南:ε衰减太快也不行。我试过decay=0.9,结果ε从1.0掉到0.01只用了50个回合,无人机还没探索够就「固化」了,最后找到的是次优解。建议decay设在0.995到0.999之间。

4.4 在简单栅格环境中的无人机导航

理论讲完了,咱们来实战。下面是一个完整的Q-Learning无人机导航示例。

环境设定:

  • 10×10的栅格世界
  • 起点:左上角 (0, 0)
  • 终点:右下角 (9, 9),到达得+100分
  • 障碍物:随机分布,撞上得-50分并回到起点
  • 每走一步:-1分(鼓励走最短路径)

动作空间:上、下、左、右

import numpy as np
import random

# 环境参数
GRID_SIZE = 10
START = (0, 0)
GOAL = (9, 9)
OBSTACLES = [(3,3), (3,4), (3,5), (7,7), (8,7)]

# Q表初始化
Q = np.zeros((GRID_SIZE, GRID_SIZE, 4))  # 4个动作

# 超参数
alpha = 0.1
gamma = 0.9
epsilon = 1.0
epsilon_min = 0.01
epsilon_decay = 0.995
episodes = 2000

# 动作映射
actions = [(-1,0), (1,0), (0,-1), (0,1)]  # 上、下、左、右

def get_next_state(state, action_idx):
    dx, dy = actions[action_idx]
    nx, ny = state[0] + dx, state[1] + dy
    # 边界检查
    if nx < 0 or nx >= GRID_SIZE or ny < 0 or ny >= GRID_SIZE:
        return state  # 撞墙,原地不动
    return (nx, ny)

def get_reward(state, next_state):
    if next_state == GOAL:
        return 100
    if next_state in OBSTACLES:
        return -50
    return -1

# 训练循环
for ep in range(episodes):
    state = START
    done = False
    
    while not done:
        # ε-贪婪选择动作
        if random.random() < epsilon:
            action = random.randint(0, 3)
        else:
            action = np.argmax(Q[state[0], state[1], :])
        
        # 执行动作
        next_state = get_next_state(state, action)
        reward = get_reward(state, next_state)
        
        # Q表更新
        best_next = np.max(Q[next_state[0], next_state[1], :])
        td_target = reward + gamma * best_next
        td_error = td_target - Q[state[0], state[1], action]
        Q[state[0], state[1], action] += alpha * td_error
        
        # 状态转移
        state = next_state
        
        if state == GOAL or state in OBSTACLES:
            done = True
    
    # ε衰减
    epsilon = max(epsilon_min, epsilon * epsilon_decay)
    
    if ep % 200 == 0:
        print(f"Episode {ep}, Epsilon: {epsilon:.3f}")

print("训练完成!")

这段代码跑完,Q表就训练好了。你可以用训练好的Q表来规划路径:从起点开始,每一步都选Q值最大的动作,直到到达终点。

4.5 Q-Learning的局限与思考

Q-Learning很强大,但它有硬伤。

第一个问题:状态空间爆炸

刚才的例子是10×10的栅格,状态数100个。如果换成100×100呢?10000个状态。再考虑连续坐标?无穷多个状态。Q表根本存不下。

这就是为什么后来有了深度Q网络(DQN)——用神经网络代替Q表。

第二个问题:收敛速度

Q-Learning是逐状态更新的。你想想看,100个状态,每个状态4个动作,每个动作要反复更新几十次才能收敛。如果状态多了,训练时间会指数级增长。

我做过一个实验:50×50的栅格,Q-Learning跑了整整一个晚上才收敛。换成DQN,两个小时就搞定了。

总结一下:Q-Learning适合状态空间小、离散动作的场景。它是理解强化学习的基础,但实际工程中,我们更多用它的进阶版本。

4.6 本章核心知识图谱

下面这张图,是我自己画的Q-Learning核心流程。你看一遍,应该就能把整个逻辑串起来了。

Q-Learning无人机导航核心流程 1. 感知当前状态 s 2. ε-贪婪选择动作 a 以ε概率随机探索 3. 执行动作 a 4. 获得奖励 r 5. 到达新状态 s' 6. 更新Q表 Q(s,a) += α[r+γmaxQ(s')-Q(s,a)] 循环直到到达终点或最大步数 关键参数说明: • α (学习率):控制每次更新的步长,通常取0.1~0.3 • γ (折扣因子):控制未来奖励的重要性,通常取0.9~0.99 • ε (探索率):控制探索与利用的平衡,可随时间衰减

这张图把整个流程串起来了。你从左上角开始看,顺着箭头走一遍,就能理解无人机是怎么一步步学会导航的。

4.7 写在最后

Q-Learning虽然简单,但它是强化学习的基石。我到现在做项目,遇到小规模离散状态空间的问题,第一反应还是用Q表试试——因为它快、稳、好调试。

下一章我们会聊深度Q网络,也就是DQN。到时候你会发现,DQN的核心思想和Q-Learning一模一样,只是把Q表换成了神经网络。所以,把这一章吃透,后面会轻松很多。

好了,去动手写代码吧。记住:纸上得来终觉浅,绝知此事要coding