第1章:什么是强化学习?——像玩游戏一样学习
想象你站在一个巨大迷宫入口,手中握着一张空白地图,远处隐约传来宝藏的光芒。你不知道路线,但每次迈出一步,都会有声音提示:“撞墙了!扣10分”或“离宝藏近了!加5分”。你会怎么走?是随机乱撞,还是慢慢记住哪些路通向光明、哪些路是死胡同?这个“通过尝试获取反馈,最终找到最优路径”的过程,正是强化学习(Reinforcement Learning) 的核心思想——让机器像人类玩游戏一样,在环境中通过行动获得奖励,自主学习最优策略。
你可能玩过《超级马里奥》或《原神》,在游戏中,你需要控制角色跳跃、攻击、收集金币。每当你吃到金币,屏幕会显示“+100”;如果掉进岩浆,则会“Game Over”。你并没有人教你“在x坐标多少时按A键”,而是通过无数次失败与成功,逐渐掌握了节奏。这就是强化学习在人类学习过程中的体现:没有标准答案,只有奖励与惩罚的反馈。而我们的目标,就是让计算机也具备这种“从玩中学”的能力。
---
迷宫探险:第一个强化学习智能体
让我们把迷宫游戏搬进计算机。假设有一个5×5的网格迷宫,如下图(`S`是起点,`G`是宝藏,`#`是墙,`.`是安全路径):
``` S . . # G . # . # . . # . . . . . . # .
. . . .
```
你的任务是编写一个程序(我们称它为智能体 Agent),让它自动从起点`S`走到宝藏`G`,同时尽量避免撞墙和走多余的路。这个智能体一开始什么都不知道,它只能: 1. 观察当前位置(状态 State) 2. 选择一个动作(Action):上、下、左、右 3. 执行动作,环境返回:
- 新位置(新状态)
- immediate reward(即时奖励):例如,到宝藏+100,撞墙-10,每走一步-1(鼓励快速到达)
4. 根据奖励更新自己的策略,以便下次做得更好
这就是一个最简化的强化学习循环:智能体与环境交互,通过奖励信号学习。
为什么这不是“监督学习”?
你可能听说过监督学习(Supervised Learning),比如训练一个猫狗图片分类器。你需要准备 thousands of 张已标注的图片(“这是猫”“这是狗”),模型通过学习这些“输入-输出对”来预测新图片。关键点是:训练数据是静态的、有标准答案的。
而迷宫智能体没有“标准答案数据集”。没有人告诉它“在(0,0)时应该向右走”。它只能通过自己探索,根据结果(奖励)来调整。这种“没有标签、只有反馈”的学习方式,正是强化学习与监督学习的根本区别:
| 特性 | 监督学习 | 强化学习 | |------|----------|----------| | 数据 | 静态数据集(输入+正确输出) | 动态环境交互(状态+动作+奖励) | | 目标 | 学习映射函数 f(x)=y | 学习策略 π(s)→a 以最大化累积奖励 | | 反馈 | 即时、明确的标签 | 延迟、稀疏的奖励信号 | | 例子 | 图像分类、房价预测 | 游戏AI、机器人控制、推荐系统 |
用比喻来说:监督学习像有答案的习题册,强化学习像没有答案的探险游戏。习题册每道题都有标准解,而探险中你需要自己摸索规则,从失败中总结教训。
---
强化学习的五大核心要素
要系统理解强化学习,我们需要拆解其核心组件。以上迷宫例子中,其实已经包含了所有关键要素:
1. 智能体(Agent)
智能体是学习者与决策者。在迷宫中,智能体就是你编写的程序;在游戏里,它是控制角色的AI;在推荐系统中,它是决定推送哪个视频的算法。智能体的目标:通过行动,使长期累积奖励最大化。
2. 环境(Environment)
环境是智能体外部世界的模拟器。迷宫本身是环境;围棋棋盘是AlphaGo的环境;真实物理世界是机器人操作的环境。环境接收智能体的动作,返回新状态和奖励。重要的是:环境对智能体而言是黑箱——智能体不知道环境如何工作,只能通过交互猜测。
3. 状态(State)
状态是环境在某一时刻的具体描述。在网格迷宫中,状态就是智能体的坐标(如`(0,0)`);在自动驾驶中,状态可能包括车速、位置、周围车辆信息;在聊天机器人中,状态是当前对话历史。状态必须包含足够信息让智能体做决策,但也不能冗余(“状态应满足马尔可夫性质”:未来只依赖当前状态,与过去无关)。
4. 行动(Action)
行动是智能体可以执行的操作集合。迷宫智能体的行动空间是`{上,下,左,右}`;AlphaGo的行动是棋盘上所有合法落子位置;机械臂的行动是各关节角度。行动空间可以是离散的(有限个选择)或连续的(如方向盘转角0.5°~30°)。
5. 奖励(Reward)
奖励是环境对智能体行动的即时数值反馈,是强化学习的“指南针”。迷宫例子中:
- 到达宝藏:+100(强正奖励)
- 撞墙:-10(负奖励)
- 每走一步:-1(小负奖励,鼓励效率)
奖励设计至关重要:如果只设置到达宝藏+100,没有每步惩罚,智能体可能学会“永远不动”(因为不动不会扣分,但也不会到达)。好的奖励函数应准确反映最终目标。
这五个要素构成一个闭环:智能体观察状态 → 选择行动 → 环境转移状态并给予奖励 → 智能体更新策略 → 下一次决策。这个循环不断进行,直到达到终止状态(如找到宝藏或游戏结束)。
---
交互式迷宫:Python实战
理论不如代码直观。下面是一个完整的Python迷宫强化学习示例,包含:
- 迷宫环境定义
- 随机策略智能体( baseline )
- Q-learning算法智能体(核心强化学习方法)
- 可视化训练过程
> 📱 电子版提示:本代码可在Jupyter Notebook中运行,尝试修改迷宫布局、奖励值或学习率,观察智能体行为变化(示例链接)
环境搭建:迷宫世界
首先,我们用NumPy创建一个网格迷宫。`0`表示安全路径,`1`表示墙,`2`是起点,`3`是宝藏,`4`是陷阱(可选)。
```python import numpy as np import matplotlib.pyplot as plt import time
class MazeEnv: def __init__(self):
5x5迷宫:0=空, 1=墙, 2=起点, 3=宝藏, 4=陷阱
self.maze = np.array([ [2, 0, 0, 1, 3], [0, 1, 0, 1, 0], [0, 1, 0, 0, 0], [0, 0, 0, 1, 0], [1, 0, 1, 0, 0] ]) self.start = (0, 0) self.goal = (0, 4) self.state = self.start self.actions = ['up', 'down', 'left', 'right'] self.action_map = { 'up': (-1, 0), 'down': (1, 0), 'left': (0, -1), 'right': (0, 1) }
def reset(self): """重置环境到起点""" self.state = self.start return self.state
def step(self, action): """执行动作,返回新状态、奖励、是否结束""" dx, dy = self.action_map[action] x, y = self.state nx, ny = x + dx, y + dy
检查边界和墙
if nx < 0 or nx >= 5 or ny < 0 or ny >= 5 or self.maze[nx, ny] == 1: reward = -10 # 撞墙惩罚 next_state = self.state # 状态不变 done = False else: next_state = (nx, ny) if next_state == self.goal: reward = 100 # 到达宝藏 done = True else: reward = -1 # 每步小惩罚,鼓励快速 done = False self.state = next_state return next_state, reward, done
def render(self, mode='human'): """可视化迷宫和智能体位置""" grid = np.copy(self.maze) x, y = self.state grid[x, y] = 9 # 用9标记智能体 plt.imshow(grid, cmap='viridis') plt.title("Maze Explorer") plt.xticks([]) plt.yticks([]) plt.show() time.sleep(0.5) ```
这个`MazeEnv`类定义了环境的所有规则:动作如何改变状态、奖励如何计算。智能体将与之交互。
基线:随机策略智能体
最笨的智能体:完全随机选择动作。它不会学习,只是碰运气。
```python class RandomAgent: def choose_action(self): return np.random.choice(['up', 'down', 'left', 'right'])
def learn(self, *args): pass # 随机策略不学习
测试随机智能体
env = MazeEnv() agent = RandomAgent() state = env.reset() total_reward = 0 steps = 0
for _ in range(100): # 最多100步 action = agent.choose_action() state, reward, done = env.step(action) total_reward += reward steps += 1 if done: break
print(f"随机策略:总步数={steps}, 总奖励={total_reward}")
输出示例:随机策略:总步数=47, 总奖励=-47(几乎找不到路)
```
运行几次,你会发现随机智能体 rarely 找到宝藏(可能100次只有几次成功),因为迷宫有死胡同,纯随机效率极低。这引出了一个问题:如何让智能体从经验中学习?
核心算法:Q-learning
Q-learning是强化学习最经典的算法之一,它让智能体学习一个动作价值函数 Q(s,a),表示在状态`s`下采取动作`a`后,未来能获得的期望总奖励。简单记:Q值越高,说明该动作越好。
Q-learning通过贝尔曼方程更新Q值: $$ Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ r_{t+1} + \gamma \max_{a} Q(s_{t+1}, a) - Q(s_t, a_t) \right] $$ 其中:
- $\alpha$:学习率(0<α≤1),控制新信息覆盖旧信息的程度
- $\gamma$:折扣因子(0≤γ≤1),衡量未来奖励的重要性(γ接近1:重视长远;γ接近0:短视)
- $r_{t+1}$:即时奖励
- $\max_{a} Q(s_{t+1}, a)$:下一步状态的最大Q值(假设未来最优)
直观理解:智能体在状态`s`做动作`a`后,得到奖励`r`并到达`s'`。它比较“实际得到的奖励+r+未来最大Q值”与“当前估计的Q值”,用误差修正当前Q值。重复多次,Q表逐渐收敛到真实值。
下面实现Q-learning智能体:
```python class QLearningAgent: def __init__(self, alpha=0.1, gamma=0.9, epsilon=0.1): self.alpha = alpha # 学习率 self.gamma = gamma # 折扣因子 self.epsilon = epsilon # 探索率:ε-greedy策略
初始化Q表:所有状态-动作对Q值为0
状态空间:5x5网格,共25个状态;动作:4个
self.q_table = np.zeros((5, 5, 4)) self.action_to_idx = {'up':0, 'down':1, 'left':2, 'right':3} self.idx_to_action = {0:'up', 1:'down', 2:'left', 3:'right'}
def choose_action(self, state): """ε-greedy策略:大部分时间选Q值最大的动作,小概率随机探索""" x, y = state if np.random.random() < self.epsilon: return np.random.choice(['up', 'down', 'left', 'right']) else:
取当前状态Q值最大的动作
action_idx = np.argmax(self.q_table[x, y]) return self.idx_to_action[action_idx]
def learn(self, state, action, reward, next_state, done): """Q-learning更新规则""" x, y = state nx, ny = next_state action_idx = self.action_to_idx[action]
当前Q值
current_q = self.q_table[x, y, action_idx] if done: target_q = reward # 终止状态没有未来奖励 else:
下一状态的最大Q值
next_max_q = np.max(self.q_table[nx, ny]) target_q = reward + self.gamma * next_max_q
更新Q值
self.q_table[x, y, action_idx] += self.alpha * (target_q - current_q) ```
训练与可视化
现在,让Q-learning智能体在迷宫中训练1000 episodes(每episode从起点到终点或超时):
```python def train(agent, env, episodes=1000): rewards_history = [] steps_history = []
for ep in range(episodes): state = env.reset() total_reward = 0 steps = 0 done = False
while not done and steps < 100: # 每集最多100步 action = agent.choose_action(state) next_state, reward, done = env.step(action) agent.learn(state, action, reward, next_state, done) state = next_state total_reward += reward steps += 1
rewards_history.append(total_reward) steps_history.append(steps)
if (ep+1) % 100 == 0: print(f"Episode {ep+1}: 步数={steps}, 总奖励={total_reward}")
return rewards_history, steps_history
开始训练
env = MazeEnv(