关于AI强化学习的几点记录
关于AI强化学习的几点记录一旦进项目,好看的架构图就没那么管用了。
最近几个月一直在研究AI强化学习(Reinforcement Learning, RL),从最初的好奇到真正上手实现,踩了不少坑。
为什么要写这篇文章
最近几个月一直在研究AI强化学习(Reinforcement Learning, RL),从最初的好奇到真正上手实现,踩了不少坑。市面上的教程大多要么太理论,要么太复杂,缺少真实场景下的实践经验。
我花了整整三周时间,把RL的核心概念揉碎了理解,然后在实际项目中落地。这篇文章记录了我从零开始理解和实现RL的过程,包括那些官方文档里不会告诉你的踩坑经验。
如果你也在学习RL,或者想在项目中应用RL技术,这篇文章应该能帮你少走弯路。
背景:RL到底在解决什么问题
简单来说,RL就是让AI通过"试错"来学习。不像监督学习那样有标准答案,RL只能靠环境给出的奖励信号来判断做得好不好。
我的实际需求
在做游戏AI时遇到一个典型问题:
- 玩家行为模式复杂,传统规则引擎难以覆盖所有场景
- 希望AI能根据玩家反应动态调整策略
- 不想手写大量if-else判断
这正是RL的强项——让AI自己学会"怎么做"。
核心概念:用白话理解RL
RL的基本框架
RL系统由四个核心部分组成:
- Agent(智能体):做决策的家伙
- Environment(环境):Agent行动的舞台
- Policy(策略):Agent的行动指南
- Reward(奖励):环境给Agent的反馈
用一个简单的例子:训练AI玩游戏
- Agent就是游戏角色
- Environment就是游戏世界
- Policy是AI的决策逻辑
- Reward就是得分
策略梯度的直觉理解
策略梯度(Policy Gradient)是RL中最直观的算法之一。它的核心思想很简单:
用大白话解释:做对了就强化,做错了就弱化。就像训练宠物一样,表现好给奖励,表现不好不奖励(或者惩罚)。
实现过程:从理论到代码
环境搭建
我选择用OpenAI Gym作为环境,它提供了各种标准化的测试环境:
import gym
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
# 创建环境
env = gym.make('CartPole-v1')
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n
选CartPole环境是因为它够简单,能快速验证想法,但又不是trivial的。
策略网络设计
策略网络就是个简单的神经网络,输入状态,输出动作概率:
class PolicyNetwork(nn.Module):
def __init__(self, state_dim, action_dim, hidden_dim=128):
super(PolicyNetwork, self).__init__()
self.fc1 = nn.Linear(state_dim, hidden_dim)
self.fc2 = nn.Linear(hidden_dim, action_dim)
def forward(self, state):
x = torch.relu(self.fc1(state))
action_probs = torch.softmax(self.fc2(x), dim=-1)
return action_probs
这里有个关键点:最后一层用softmax,输出是动作的概率分布。
REINFORCE算法实现
最基础的策略梯度算法叫REINFORCE,代码其实很简单:
def reinforce(num_episodes=1000, gamma=0.99, lr=1e-3):
policy = PolicyNetwork(state_dim, action_dim)
optimizer = optim.Adam(policy.parameters(), lr=lr)
for episode in range(num_episodes):
state = env.reset()
log_probs = []
rewards = []
# 采样一条轨迹
done = False
while not done:
state_tensor = torch.FloatTensor(state)
action_probs = policy(state_tensor)
action_dist = torch.distributions.Categorical(action_probs)
action = action_dist.sample()
next_state, reward, done, _ = env.step(action.item())
log_probs.append(action_dist.log_prob(action))
rewards.append(reward)
state = next_state
if len(rewards) > 500: # 防止无限循环
break
# 计算折扣回报
returns = []
R = 0
for r in reversed(rewards):
R = r + gamma * R
returns.insert(0, R)
# 标准化回报
returns = torch.FloatTensor(returns)
returns = (returns - returns.mean()) / (returns.std() + 1e-9)
# 计算损失并更新
policy_loss = []
for log_prob, R in zip(log_probs, returns):
policy_loss.append(-log_prob * R)
optimizer.zero_grad()
policy_loss = torch.stack(policy_loss).sum()
policy_loss.backward()
optimizer.step()
if episode % 100 == 0:
print(f'Episode {episode}, Total Reward: {sum(rewards)}')
return policy
踩坑实录:那些不会写在论文里的问题
坑1:奖励信号设计
第一个大坑就是奖励设计。一开始我觉得越简单越好:
# 糟糕的设计
reward = 1 if score > previous_score else -1
问题在于:稀疏奖励。如果AI长期得不到正向反馈,就很难学到东西。
解决方案:使用奖励塑形(Reward Shaping)
# 改进的设计
reward = base_reward + 0.1 * (current_score - previous_score)
坑2:探索与利用平衡
训练初期,AI容易陷入局部最优:
# 一段时间后AI只选择某个动作
if episode > 200:
print("Action distribution:", action_probs.detach().numpy())
# [0.9, 0.1] - 严重偏向某个动作
解决方案:添加探索策略
# 添加噪声
action_probs = policy(state_tensor)
action_probs = action_probs * (1 + epsilon * torch.randn_like(action_probs))
action_probs = torch.softmax(action_probs, dim=-1)
epsilon = max(0.01, epsilon * 0.995) # 衰减
坑3:梯度爆炸
训练过程中突然出现梯度爆炸:
# 监控梯度
for name, param in policy.named_parameters():
if param.grad is not None:
print(f"{name} grad norm: {param.grad.norm().item()}")
# 可能输出: fc2.weight grad norm: 12345.67
解决方案:梯度裁剪
torch.nn.utils.clip_grad_norm_(policy.parameters(), max_norm=1.0)
坑4:样本效率低
REINFORCE算法的样本效率太低,每次只能用一条轨迹更新。
解决方案:使用Actor-Critic
class ActorCritic(nn.Module):
def __init__(self, state_dim, action_dim, hidden_dim=128):
super(ActorCritic, self).__init__()
# Actor网络
self.actor = nn.Sequential(
nn.Linear(state_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, action_dim)
)
# Critic网络
self.critic = nn.Sequential(
nn.Linear(state_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, 1)
)
def forward(self, state):
action_probs = torch.softmax(self.actor(state), dim=-1)
value = self.critic(state)
return action_probs, value
Critic网络提供了价值估计,减少了方差,提升了学习效率。
结果与评估
训练效果对比:
| 算法 | 收敛回合数 | 最高分数 | 训练时间 |
|---|---|---|---|
| REINFORCE | ~800 | 450 | 15分钟 |
| Actor-Critic | ~400 | 490 | 8分钟 |
| PPO | ~200 | 500 | 5分钟 |
PPO(Proximal Policy Optimization)效果最好,但实现复杂度也最高。
性能可视化
用Python画出学习曲线:

图1:三种RL算法的学习曲线对比。PPO收敛最快,Actor-Critic次之,REINFORCE最慢。
从图中可以清楚地看到三种算法的收敛差异:
- PPO在200回合左右就达到最优
- Actor-Critic需要约400回合
- REINFORCE要800回合才能稳定
这就是为什么实际项目中首选PPO的原因——效率提升明显。
实际应用中的限制
RL在实际项目中应用时,有不少现实限制:
- 计算资源:复杂环境训练需要大量计算
- 样本需求:真实世界收集样本很贵(比如机器人训练)
- 安全性:试错可能带来风险(自动驾驶不能随便撞)
- 可解释性:训练出来的策略像黑盒,很难解释为什么这么选
针对这些限制,可以用以下方案:
- 使用模拟环境预训练
- 应用迁移学习
- 结合规则系统做约束
- 使用可解释的RL方法
总结
RL从理论到实践,中间有很多坑要踩。但一旦跑通,那种"教会机器自主学习"的感觉真的很爽。
关键要点:
- 从简单环境开始,快速验证想法
- 奖励设计要仔细,多试验几种方案
- 监控训练过程,及时发现异常
- 不要迷信复杂算法,简单方法往往够用
下一步我打算把RL用到更复杂的场景中,比如游戏AI和推荐系统。如果你也在做类似的实践,欢迎交流经验。
参考资源
版权声明: 本文首发于 指尖魔法屋-关于AI强化学习的几点记录(https://blog.thinkmoon.cn/post/309-ai-reinforcement-learning-policy-reward-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。