第1章:智能体的第一次冒险:什么是强化学习?
你有没有想过,自己是如何学会骑自行车,或者打通一款难度很高的电子游戏?你并不会有人拿着“正确答案”手册,一步步告诉你“此刻身体该向左倾斜5度,右手握闸力度为3公斤”。你只是坐上去,尝试,摔倒,再尝试,偶尔成功保持平衡几米,然后奖励——那种自由飞驰的快乐——让你想再来一次。慢慢地,你找到了规律:速度太快时轻捏刹车,转弯时身体内倾。最终,你不再思考这些细节,骑车变成了一种本能。这种通过与环境互动、从结果中学习、最终优化行为序列的能力,正是人工智能领域“强化学习”试图赋予机器的核心智慧。 它不依赖于预先标注好的海量数据(那是监督学习),也不追求从无标签数据中发现固有结构(那是无监督学习),而是让一个“智能体”在动态环境中,通过不断“试错”来学习达成目标的最佳策略。
1.1 机器学习的三大范式:定位强化学习
在深入“迷宫”之前,我们必须先厘清强化学习在整个机器学习版图中的独特位置。想象一下你要教一个孩子认识“猫”。
- **监督学习**:你给他看成百上千张照片,每张都明确标上“这是猫”或“这不是猫”。孩子通过比对这些带标签的样本,学习到猫的视觉特征(尖耳朵、胡须、特定体型)。这是目前最成熟、应用最广的范式,如人脸识别、垃圾邮件过滤。其核心是 **“模仿”**,学习一个从输入到输出的映射函数 $f(x) = y$。
- **无监督学习**:你给他一堆混杂的动物照片,没有任何标签。孩子自己发现这些照片可以分成几簇,一簇都是毛茸茸有四条腿的,另一簇是有翅膀会飞的。他并不知道这些簇对应“猫科”或“鸟类”,但他发现了数据内在的结构和分组。其核心是 **“发现”**,如聚类、降维。
- **强化学习**:你把这个孩子放进一个充满玩具猫和玩具狗的房间,告诉他:“你的任务是在10分钟内尽可能多地找出‘真猫’(可能房间里有几只真的小猫,但混了很多仿制品)。每找到一只真猫,奖励你一颗糖;每误抓一只仿制品,扣除你一颗糖。房间里的东西可能会移动,有些区域灯光昏暗,有些区域有干扰噪音。” 孩子必须自己探索,尝试抓取不同的物体,根据每次获得的糖(奖励)或失去的糖(惩罚)来调整自己的搜索策略:是快速扫视,还是仔细触摸?是优先去光亮处,还是忽略噪音区?他学习的不是“猫的静态特征”,而是 **“在特定环境状态(S)下,采取何种动作(A)能最大化未来累计奖励(G)”** 这一序列决策问题。
强化学习的本质,是学习一个在时间序列中做出最优决策的“策略”。它最适用于顺序决策问题,即当前的动作不仅影响即时奖励,更会改变未来的状态,从而影响所有后续的奖励。游戏、机器人控制、自动驾驶、资源调度、交易策略,都属于此类。
1.2 强化学习的五大核心构件:智能体与世界的对话语言
任何强化学习系统都可以抽象为以下五个核心要素的持续交互,这构成了我们理解所有后续复杂算法的基石。
```mermaid graph LR A[智能体 Agent] -- 选择动作 --> B[环境 Environment]; B -- 反馈新状态与奖励 --> A; subgraph 环境内部 B --> C[状态 State]; C --> D[奖励 Reward]; end A --> E[策略 Policy]; E -- 决定 --> A; ```
1. 智能体:做决策的主体。在游戏中是AI角色,在机器人中是控制器,在推荐系统中是推荐引擎。智能体是“学习者”和“执行者”。
2. 环境:智能体之外的一切,是智能体交互的对象。环境根据智能体的动作, transitioning 到新的状态,并给出奖励。环境对智能体而言通常是部分可观测的,即智能体无法获知环境的全部信息(例如,围棋棋盘对AI是完美信息环境,但自动驾驶汽车无法看穿被遮挡的建筑物)。
3. 状态:环境在某一时刻的描述。它可以是完全可观测的(如棋盘所有格子的黑白子分布),也可以是部分可观测的(如机器人只有自身的摄像头图像,没有全局地图)。状态集合记为 $S$。
4. 动作:智能体在某个状态下可以执行的操作。动作集合记为 $A$。动作可以是离散的(“左转”、“右转”、“前进”),也可以是连续的(方向盘转动角度、油门深度)。
5. 奖励:环境对智能体动作的即时数值反馈。它是标量信号,是指导学习的“指挥棒”。奖励函数 $R(s, a, s')$ 定义了在状态 $s$ 下执行动作 $a$ 并转移到状态 $s'$ 后获得的即时奖励。强化学习的目标是最大化长期累积奖励,而非瞬时奖励。 奖励的设计是强化学习成功与否的关键艺术与难点。一个糟糕的奖励函数会导致智能体学会钻空子,得到意想不到甚至有害的行为(例如,一个旨在“减少能源消耗”的机器人可能学会把自己关进黑暗的柜子里)。
6. 策略:智能体的“行为准则”。它是从状态到动作的映射函数,可以是确定性的 $\pi(s) = a$,也可以是随机性的 $\pi(a|s)$(即在状态 $s$ 下选择动作 $a$ 的概率)。强化学习的过程,就是寻找最优策略 $\pi^*$ 的过程,该策略能使长期累积奖励的期望值最大。
状态转移:环境在智能体执行动作后的状态变化规律,记为 $P(s' | s, a)$,即从状态 $s$ 执行动作 $a$ 后转移到状态 $s'$ 的概率。这个模型通常未知,智能体需要在交互中自行学习。
1.3 首次探险:网格迷宫寻宝游戏
理论是骨架,实践是血肉。让我们用最经典的网格世界迷宫,亲手构建一个强化学习问题,见证智能体如何从懵懂到精通。
游戏设定
- **环境**:一个 $4 \times 4$ 的网格。
- **状态**:每个网格单元是一个状态,共16个状态 $(0,0)$ 到 $(3,3)$。
- **动作**:智能体在每个格子可以执行 **上、下、左、右** 四个动作(如果动作会导致走出网格,则停留在原地)。
- **起点**:左上角 $(0,0)$。
- **终点/宝藏**:右下角 $(3,3)$,到达即获得 **+10** 分奖励,游戏结束。
- **陷阱**:网格中散布着几个“沼泽”格子(例如 $(1,1), (2,2)$),踩上去获得 **-5** 分惩罚,但游戏继续。
- **普通移动**:每走一步(非终点/陷阱),获得 **-0.1** 分的小额惩罚,鼓励智能体尽快找到宝藏,避免无限漫游。
- **目标**:学习一个策略,从起点出发,以最大期望累积奖励到达终点。
```python import numpy as np
class GridMaze: def __init__(self, size=4): self.size = size self.state = (0, 0) # 初始状态 self.end_state = (size-1, size-1) self.trap_states = [(1, 1), (2, 2)] self.actions = ['UP', 'DOWN', 'LEFT', 'RIGHT'] self.action_effects = { 'UP': (-1, 0), 'DOWN': (1, 0), 'LEFT': (0, -1), 'RIGHT': (0, 1) } self.is_terminal = False
def reset(self): self.state = (0, 0) self.is_terminal = False return self.state
def step(self, action): if self.is_terminal: return self.state, 0, True
dx, dy = self.action_effects[action] x, y = self.state new_x, new_y = x + dx, y + dy
边界检查
if not (0 <= new_x < self.size and 0 <= new_y < self.size): new_x, new_y = x, y
self.state = (new_x, new_y) reward = -0.1 # 每步移动的微小惩罚
if self.state == self.end_state: reward = 10 self.is_terminal = True elif self.state in self.trap_states: reward = -5
return self.state, reward, self.is_terminal
示例:运行一步
env = GridMaze() state = env.reset() print(f"初始状态: {state}") next_state, reward, done = env.step('RIGHT') print(f"执行'RIGHT'后: 状态={next_state}, 奖励={reward}, 结束={done}") ```
初始的“白痴”智能体
假设我们的智能体最初是“盲目”的,它没有任何先验知识。它的策略可能是:在每个状态,完全随机地选择一个动作(均匀随机策略 $\pi(a|s) = 1/4$)。让我们模拟一次它的“首次探险”:
1. 起点 `(0,0)`,随机选择 `RIGHT` -> `(0,1)`,奖励 `-0.1`。 2. 状态 `(0,1)`,随机选择 `DOWN` -> `(1,1)`(陷阱!),奖励 `-5`。 3. 状态 `(1,1)`,随机选择 `RIGHT` -> `(1,2)`,奖励 `-0.1`。 4. ... 继续随机游走,可能再次掉入陷阱,也可能兜兜转转几十步才偶然碰到终点 `(3,3)`,获得 `+10`。
一次“回合”(从起点到终点或陷入无法结束的循环)下来,这个随机智能体获得的总回报(所有即时奖励之和)可能是 `+10 - 0.1*50 -5*2 = -1.2`,甚至是负数!它显然不是个好策略。但这次经历,就是它学习的原材料。
1.4 价值函数:评估状态与动作的“远见”
智能体如何从一次次的试错中学习?它需要一种方式来评估:某个状态有多“好”?在某个状态下采取某个动作有多“好”?
状态价值函数 $V_\pi(s)$:在策略 $\pi$ 下,从状态 $s$ 开始,未来所有折扣奖励的期望总和。 $$V_\pi(s) = \mathbb{E}_\pi [ G_t | S_t = s ] = \mathbb{E}_\pi \left[ \sum_{k=0}^{\infty} \gamma^k R_{t+k+1} \bigg| S_t = s \right]$$ 其中 $G_t$ 是时刻 $t$ 的累积折扣奖励,$\gamma$(Gamma)是折扣因子,$0 \leq \gamma \leq 1$。
动作价值函数 $Q_\pi(s, a)$:在状态 $s$ 下,先执行动作 $a$,然后遵循策略 $\pi$,未来所有折扣奖励的期望总和。 $$Q_\pi(s, a) = \mathbb{E}_\pi [ G_t | S_t = s, A_t = a ]$$
核心洞察:最优策略 $\pi^*$ 应该让每个状态的价值 $V^*(s)$ 最大,或者说,在每个状态下,选择能使后续状态价值最大的动作(即 $Q^*(s, a)$ 最大的 $a$)。
为什么需要折扣因子 $\gamma$?
试想,如果 $\gamma = 0$,智能体只关心即时奖励。那么它最优的策略就是:如果眼前有陷阱(-5),就原地不动(每步-0.1),永远不结束游戏,避免最终到达终点前的“最后一搏”可能踩到陷阱的风险。这显然荒谬。
如果 $\gamma = 1$,未来奖励和现在一样重要。在可能无限循环的环境中,累积奖励可能无界,导致价值函数无法收敛。
引入 $\gamma < 1$(通常取0.9或0.99),它表达了两个关键思想: 1. 时间偏好:现在得到的奖励比未来同样数额的奖励更有价值(类似于经济学中的“贴现”)。 2. 数学保证:在有限奖励和 $\gamma < 1$ 时,无限级数 $\sum \gamma^k R$ 必然收敛,使问题有良好定义。
例如,在迷宫中,终点奖励 `+10` 对当前状态的价值贡献,取决于你距离终点的步数 $n$。如果 $\gamma=0.9$,从终点前一步 `(3,2)` 看,$V(3,2) \approx 0.9 \times 10 + (-0.1) = 8.9$。从两步远 `(3,1)` 看,$V(3,1) \approx 0.9 \times 8.9 + (-0.1) \approx 7.9$。奖励会随着距离衰减,这迫使智能体不仅寻找宝藏,还要权衡路径长短。
1.5 从试错到学习:Q-learning 算法初体验
对于我们的迷宫,环境模型 $P(s'|s,a)$ 是未知的。最著名、最直观的无模型算法之一是 Q-learning。它直接学习动作价值函数 $Q(s, a)$。
核心思想:维护一个 $Q$ 表(表格),行是状态 $s$,列是动作 $a$,单元格 $Q(s,a)$ 存储“在状态 $s$ 执行动作 $a$ 的长期价值估计”。智能体通过以下规则更新 $Q$ 值(贝尔曼方程的最优性版本):
$$Q_{new}(s, a) \leftarrow (1 - \alpha) Q(s, a) + \alpha \left[ r + \gamma \max_{a'} Q(s', a') \right]$$
其中:
- $\alpha$(Alpha)是**学习率**(0 < $\alpha$ ≤ 1),控制新信息覆盖旧信息的程度。
- $r$ 是执行动作 $a$ 后获得的**即时奖励**。
- $s'$ 是执行动作后到达的**新状态**。
- $\gamma$ 是**折扣因子**。
- $\max_{a'} Q(s', a')$ 是**基于当前估计的“未来最优价值”**。这是Q-learning“向前看”和“贪婪”的关键:它假设从新状态 $s'$ 开始,未来将采取最优动作。
更新过程解读:新估计值 = 旧估计值 + 学习率 × ( 目标值 - 旧估计值 )。其中目标值 $r + \gamma \max_{a'} Q(s', a')$ 是“当前一步的奖励”加上“对未来最优价值的估计”。这个差值(TD误差)驱动着学习。
动手实验:训练你的第一个智能体
```python import matplotlib.pyplot as plt
def train_q_learning(env, episodes=500, alpha=0.1, gamma=0.9, epsilon=0.1): n_states = env.size * env.size n_actions = len(env.actions) Q = np.zeros((n_states, n_actions)) # Q表初始化 action_to_idx = {a: i for i, a in enumerate(env.actions)} idx_to_action = {i: a for i, a in enumerate(env.actions)} rewards_history = []
for ep in range(episodes): state = env.reset() total_reward = 0 done = False while not done: state_idx = state[0] * env.size + state[1]
ε-贪婪策略:大部分时间选Q最大的动作,偶尔随机探索
if np.random.random() < epsilon: action_idx = np.random.randint(n_actions) else: action_idx = np.argmax(Q[state_idx]) action = idx_to_action[action_idx]
next_state, reward, done = env.step(action) next_state_idx = next_state[0] * env.size + next_state[1]
Q-learning 更新
best_next_Q = np.max(Q[next_state_idx]) td_target = reward + gamma * best_next_Q * (not done) # 终止状态未来价值为0 td_error = td_target - Q[state_idx, action_idx] Q[state_idx, action_idx] += alpha * td_error
state = next_state total_reward += reward rewards_history.append(total_reward)
return Q, rewards_history
训练
env = GridMaze() Q_table, reward