引言

强化学习(Reinforcement Learning, RL)是人工智能领域的核心技术之一,其 “试错学习” 的特性与游戏场景天然契合。超级马里奥作为经典横版闯关游戏,不仅规则简单、场景直观,还包含了 “避障、前进、得分” 等典型强化学习任务要素,成为入门 RL 的绝佳案例。

本文将从强化学习的核心原理出发,详细拆解 “AI 如何学会玩马里奥” 的完整流程,重点解析 DQN 算法的两大核心优化技术(经验回放、双网络),提供可直接运行的 PyTorch 代码,并逐行解析关键模块,帮助读者彻底理解强化学习在游戏中的落地逻辑。

一、核心原理:AI 玩马里奥的底层逻辑

1.1 强化学习的核心要素

强化学习的本质是 “智能体(Agent)在环境(Environment)中通过试错积累经验,最大化累积奖励(Reward)” 的过程。对应马里奥游戏:

  • 智能体(Agent):AI 控制器,负责根据游戏画面决策按键操作;
  • 环境(Environment):超级马里奥游戏本身,提供画面、角色状态等信息;
  • 状态(State):游戏当前画面(4 帧堆叠的 84×84 灰度图),包含地形、敌人、角色位置等关键信息;
  • 动作(Action):AI 可执行的操作(如左移、右移、跳跃、加速跑);
  • 奖励(Reward):引导 AI 学习的 “评分标准”,如前进加分、死亡扣分、吃金币加分。

1.2 为什么选择 DQN 算法?

DQN(Deep Q-Network)是将深度学习与 Q-Learning 结合的经典算法,由 DeepMind 于 2013 年提出,首次实现了 AI 自主玩 Atari 游戏。选择 DQN 用于马里奥的核心原因的是其解决了传统 Q-Learning 的两大痛点,而这依赖于两个关键优化技术:

  • 经验回放(Experience Replay):打破训练数据的时间相关性,避免模型训练震荡;
  • 双网络(Policy Net + Target Net):稳定 Q 值估计目标,防止训练过程中目标漂移。

1.3 关键设计:4 帧图像堆叠的意义

单张游戏画面是静态的,无法提供运动信息(如敌人移动方向、马里奥跳跃状态)。通过堆叠连续 4 帧图像,AI 能从帧间差异中识别:

  • 敌人是向左还是向右移动;
  • 马里奥处于上升还是下落阶段;
  • 障碍物的相对运动趋势。这一设计是 AI “看懂” 运动的关键,也是 DeepMind 验证的游戏 RL 最优输入格式。

二、DQN 两大核心优化技术:原理与代码体现

DQN 算法之所以能稳定训练并学会玩游戏,核心依赖 “经验回放” 和 “双网络” 两大技术。以下将详细拆解这两个技术的原理、代码位置及作用机制。

2.1 经验回放(Experience Replay):打破数据相关性,避免训练震荡

(1)核心问题:无经验回放的训练痛点

如果直接使用连续的游戏帧训练:

  • 连续帧的画面高度相似(如马里奥连续向右走 10 帧,画面几乎无变化);
  • 训练数据存在强时间相关性,模型会被 “同一类场景” 持续影响;
  • 导致梯度更新方向单一,模型参数剧烈波动(训练震荡),甚至梯度爆炸。
(2)核心原理

经验回放的本质是 “建立 AI 的记忆库”:

  1. 将每次游戏的 “状态 - 动作 - 奖励 - 下一状态 - 结束标志” 存储起来;
  2. 训练时从记忆库中随机采样一批数据,而非使用最新的连续帧;
  3. 随机采样打破了数据的时间顺序和相关性,让模型学习到多样化的场景;
  4. 梯度更新更均衡,避免被单一场景 “带偏”,训练过程更稳定。
(3)代码中的具体体现
① 定义经验回放池(记忆库)

python

运行

self.replay_buffer = deque(maxlen=10000)  # 容量10000,存储最近1万条游戏经验
  • deque(双端队列)实现,超出容量时自动丢弃最早的经验;
  • 每条经验包含(state, action, reward, next_state, done)五个关键信息。
② 存储经验到回放池(每步游戏都存储)

python

运行

# 单回合游戏循环中,执行动作后立即存储经验
agent.store_experience(current_state, action, reward, next_current_state, done)

# 存储逻辑的实现(MarioRLAgent类方法)
def store_experience(self, state, action, reward, next_state, done):
    self.replay_buffer.append( (state, action, reward, next_state, done) )
  • 每次 AI 执行一个动作,环境返回反馈后,就将这一 “交互经历” 存入记忆库;
  • 确保记忆库中积累足够多的多样化场景(掉坑、躲怪、吃金币、通关等)。
③ 训练时随机采样(核心步骤)

python

运行

# 从经验池随机采样32条经验(batch_size=32)
batch = random.sample(self.replay_buffer, self.batch_size)
# 解包数据,用于后续计算损失
states, actions, rewards, next_states, dones = zip(*batch)
  • random.sample()是经验回放的核心:从 1 万条经验中随机挑选 32 条,完全打乱时间顺序;
  • 采样后的数据可能包含 “掉坑”“吃金币”“跳管道” 等完全不同的场景,模型学习更全面。
(4)为什么能避免震荡?
  • 无经验回放:模型反复学习连续相似的场景,梯度方向单一,参数越调越偏;
  • 有经验回放:随机采样让模型同时学习不同场景的规律,梯度方向相互平衡,参数更新更平稳,不会出现剧烈震荡。

2.2 双网络(Policy Net + Target Net):稳定 Q 值目标,防止目标漂移

(1)核心问题:单网络的训练痛点

Q-Learning 的核心是计算 “目标 Q 值”,公式为:目标Q值 = 即时奖励 + gamma * 下一状态的最大Q值如果只用一个网络:

  • 同一网络既负责计算 “当前 Q 值”,又负责计算 “下一状态的最大 Q 值”;
  • 训练过程中网络参数不断更新,导致 “下一状态的最大 Q 值” 也在实时变化;
  • 模型相当于在 “追着一个不断移动的目标跑”,Q 值估计不稳定,训练震荡剧烈。
(2)核心原理

双网络的本质是 “分离预测网络和目标网络”:

  1. 策略网络(Policy Net):实时更新参数,负责根据当前状态选择动作(探索 + 利用);
  2. 目标网络(Target Net):参数固定,仅定期同步策略网络的权重,负责计算稳定的目标 Q 值;
  3. 目标网络的参数不随训练实时变化,确保目标 Q 值在一定周期内是固定的;
  4. 模型训练的目标更稳定,避免了 “目标漂移” 问题。
(3)代码中的具体体现
① 定义两个网络(结构完全一致,权重初始相同)

python

运行

self.policy_net = MarioDQN(self.num_actions)  # 策略网络:实时更新,用于选动作
self.target_net = MarioDQN(self.num_actions)  # 目标网络:固定权重,用于算目标Q值
# 初始同步:让目标网络的权重和策略网络完全一致
self.target_net.load_state_dict(self.policy_net.state_dict())
self.target_net.eval()  # 设为评估模式,禁止梯度更新
  • 两个网络的结构完全相同(3 卷积 + 2 全连接),仅作用不同;
  • target_net.eval()确保目标网络不参与梯度计算和参数更新,仅作为 “固定的目标计算器”。
② 目标网络不参与梯度更新

python

运行

# 计算目标Q值时,使用target_net,且禁用梯度计算
with torch.no_grad():
    next_max_q = self.target_net(next_states_tensor).max(dim=1)[0]
target_q_values = rewards_tensor + (1 - dones_tensor) * self.gamma * next_max_q
  • with torch.no_grad():禁用梯度计算,确保 target_net 的参数不会被更新;
  • 目标 Q 值由 “固定的 target_net” 计算,不会随 policy_net 的训练而实时变化。
③ 定期同步目标网络权重

python

运行

# 每5回合同步一次目标网络和策略网络的权重
if episode % 5 == 0:
    agent.sync_target_net()

# 同步逻辑的实现(MarioRLAgent类方法)
def sync_target_net(self):
    self.target_net.load_state_dict(self.policy_net.state_dict())
  • 目标网络不是永远固定,而是每训练 5 回合,将策略网络的最新权重复制过来;
  • 既保证了目标 Q 值在短期内的稳定性,又能让目标网络逐步跟上策略网络的学习进度。
④ 策略网络单独更新参数

python

运行

# 仅更新策略网络的参数,目标网络不更新
loss.backward()  # 计算梯度(仅对policy_net生效)
self.optimizer.step()  # 优化策略网络的参数
  • 训练过程中,只有 policy_net 的参数会被梯度下降更新;
  • target_net 的参数仅在同步时更新,中间保持固定。
(4)为什么能稳定 Q 值估计?
  • 单网络:目标 Q 值随网络参数实时变化,模型训练目标漂移,Q 值估计波动大;
  • 双网络:目标 Q 值由固定的 target_net 计算,在同步周期内保持稳定,模型训练的目标更明确,Q 值估计更准确,训练过程更平滑。

2.3 两大技术的协同作用

  • 经验回放解决了 “数据相关性” 问题,让训练数据更均衡;
  • 双网络解决了 “目标漂移” 问题,让训练目标更稳定;
  • 两者结合,从数据和目标两个层面保证了 DQN 算法的稳定性,这也是 AI 能顺利学会玩马里奥的核心原因。

三、环境搭建与依赖安装

3.1 核心依赖库

  • gym-super-mario-bros:马里奥游戏环境,提供标准化的状态、动作接口;
  • nes-py:Nintendo 娱乐系统模拟器,支持马里奥游戏运行;
  • torch:PyTorch 深度学习框架,用于构建神经网络和反向传播;
  • numpy:数组处理,用于图像堆叠和数据转换;
  • opencv-python:图像预处理(转灰度、缩放)。

3.2 安装命令

bash

运行

# 安装核心依赖
pip install gym-super-mario-bros==7.3.0 nes-py numpy opencv-python
# 安装PyTorch(根据CUDA版本选择,无GPU则安装CPU版)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu

四、完整代码实现(带超详细注释)

4.1 代码整体结构

python

运行

# 1. 导入依赖库
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import cv2
import random
from collections import deque
from nes_py.wrappers import JoypadSpace
import gym_super_mario_bros
from gym_super_mario_bros.actions import SIMPLE_MOVEMENT

# 2. 神经网络模型(3卷积+2全连接)
class MarioDQN(nn.Module):
    def __init__(self, num_actions):
        super(MarioDQN, self).__init__()
        # 卷积层:提取图像特征(AI的“眼睛”)
        self.conv_layers = nn.Sequential(
            # 输入:4帧84×84灰度图(通道数4),输出32个特征图,卷积核8×8,步长4
            nn.Conv2d(4, 32, kernel_size=8, stride=4),
            nn.ReLU(),  # 激活函数:引入非线性,增强特征表达能力
            # 输入32通道,输出64通道,卷积核4×4,步长2
            nn.Conv2d(32, 64, kernel_size=4, stride=2),
            nn.ReLU(),
            # 输入64通道,输出64通道,卷积核3×3,步长1
            nn.Conv2d(64, 64, kernel_size=3, stride=1),
            nn.ReLU()
        )
        
        # 全连接层:决策动作(AI的“大脑”)
        # 卷积层输出维度计算:(84-8)/4 +1 =20 → (20-4)/2 +1=9 → (9-3)/1 +1=7 → 64×7×7=3136
        self.fc_layers = nn.Sequential(
            nn.Linear(64 * 7 * 7, 512),  # 全连接层1:3136维特征→512维高级特征
            nn.ReLU(),
            nn.Linear(512, num_actions)   # 全连接层2:512维特征→动作数(输出每个动作的Q值)
        )

    # 前向传播:输入状态→输出动作Q值
    def forward(self, x):
        x = self.conv_layers(x)  # 卷积提取特征
        x = x.reshape(x.size(0), -1)  # 展平特征图(batch_size, 64×7×7)
        q_values = self.fc_layers(x)  # 全连接层输出Q值
        return q_values

# 3. 图像预处理函数:将游戏画面转为模型可输入格式
def preprocess_frame(frame):
    """
    输入:游戏原始帧(RGB图像,尺寸通常为256×240)
    输出:预处理后的帧(84×84灰度图,归一化到[0,1])
    """
    # 1. 转为灰度图(减少计算量,保留关键信息)
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
    # 2. 缩放到84×84(统一输入尺寸,加速训练)
    resized_frame = cv2.resize(gray_frame, (84, 84), interpolation=cv2.INTER_AREA)
    # 3. 归一化(将像素值从[0,255]转为[0,1],稳定模型训练)
    normalized_frame = resized_frame.astype(np.float32) / 255.0
    return normalized_frame

# 4. DQN智能体类:整合环境、模型、训练逻辑
class MarioRLAgent:
    def __init__(self):
        # 4.1 初始化游戏环境
        # 加载马里奥游戏(1-1关卡)
        self.env = gym_super_mario_bros.make("SuperMarioBros-1-1-v0")
        # 简化动作空间:从原始多按键组合简化为7个核心动作(如左、右、跳等)
        self.env = JoypadSpace(self.env, SIMPLE_MOVEMENT)
        self.num_actions = len(SIMPLE_MOVEMENT)  # 动作数:7

        # 4.2 初始化神经网络(双网络机制)
        self.policy_net = MarioDQN(self.num_actions)  # 策略网络:实时更新,用于选动作
        self.target_net = MarioDQN(self.num_actions)  # 目标网络:定期同步,用于计算目标Q值
        # 初始时让目标网络权重等于策略网络
        self.target_net.load_state_dict(self.policy_net.state_dict())
        self.target_net.eval()  # 目标网络设为评估模式,不参与梯度更新

        # 4.3 初始化优化器和经验回放池
        self.optimizer = optim.Adam(
            self.policy_net.parameters(),  # 优化策略网络参数
            lr=1e-4  # 学习率:控制参数更新步长
        )
        self.replay_buffer = deque(
            maxlen=10000  # 经验池容量:存储最近10000条经验
        )

        # 4.4 强化学习超参数
        self.gamma = 0.99  # 折扣因子:权衡即时奖励和未来奖励
        self.epsilon = 1.0  # 探索率:初始100%随机动作
        self.epsilon_min = 0.01  # 最小探索率:避免完全不探索
        self.epsilon_decay = 0.999  # 探索率衰减系数:每回合降低0.1%
        self.batch_size = 32  # 批次大小:每次训练采样32条经验

    # 4.5 动作选择函数:epsilon-greedy策略(探索+利用)
    def select_action(self, state):
        """
        输入:当前状态(4帧堆叠的84×84图像,shape=(4,84,84))
        输出:选择的动作(0-6的整数)
        """
        # 探索阶段:随机选择动作(概率epsilon)
        if random.random() < self.epsilon:
            return random.randint(0, self.num_actions - 1)
        # 利用阶段:选择Q值最高的动作(概率1-epsilon)
        # 转换为PyTorch张量(添加batch维度)
        state_tensor = torch.tensor(state, dtype=torch.float32).unsqueeze(0)
        with torch.no_grad():  # 不计算梯度,节省资源
            q_values = self.policy_net(state_tensor)  # 前向传播得到Q值
            action = q_values.argmax(dim=1).item()  # 选择Q值最大的动作
        return action

    # 4.6 经验回放训练函数:从经验池中采样训练
    def train_from_replay(self):
        """
        从经验回放池中采样批次,计算损失并更新策略网络
        """
        # 经验池数据不足时,不训练
        if len(self.replay_buffer) < self.batch_size * 10:
            return

        # 1. 从经验池随机采样批次数据
        batch = random.sample(self.replay_buffer, self.batch_size)
        # 解包批次数据(state, action, reward, next_state, done)
        states, actions, rewards, next_states, dones = zip(*batch)

        # 2. 转换为PyTorch张量(批量处理)
        states_tensor = torch.tensor(states, dtype=torch.float32)  # (32,4,84,84)
        next_states_tensor = torch.tensor(next_states, dtype=torch.float32)  # (32,4,84,84)
        actions_tensor = torch.tensor(actions, dtype=torch.long)  # (32,)
        rewards_tensor = torch.tensor(rewards, dtype=torch.float32)  # (32,)
        dones_tensor = torch.tensor(dones, dtype=torch.float32)  # (32,):1表示游戏结束,0表示继续

        # 3. 计算当前Q值(策略网络预测)
        # gather(1, actions_tensor.unsqueeze(1)):按动作索引提取对应Q值
        current_q_values = self.policy_net(states_tensor).gather(
            dim=1, index=actions_tensor.unsqueeze(1)
        ).squeeze()  # (32,)

        # 4. 计算目标Q值(基于目标网络,贝尔曼方程)
        # 目标Q值 = 即时奖励 + gamma * 下一状态的最大Q值(游戏结束时为0)
        with torch.no_grad():
            # 下一状态的最大Q值(目标网络预测)
            next_max_q = self.target_net(next_states_tensor).max(dim=1)[0]
            # 游戏结束时(dones=1),next_max_q设为0
            target_q_values = rewards_tensor + (1 - dones_tensor) * self.gamma * next_max_q  # (32,)

        # 5. 计算损失(均方误差MSE:预测Q值与目标Q值的差距)
        loss_fn = nn.MSELoss()
        loss = loss_fn(current_q_values, target_q_values)

        # 6. 反向传播更新参数
        self.optimizer.zero_grad()  # 清空梯度(避免累积)
        loss.backward()  # 反向传播计算梯度
        self.optimizer.step()  # 优化器更新策略网络权重

        # 7. 探索率衰减(逐渐减少探索,增加利用)
        if self.epsilon > self.epsilon_min:
            self.epsilon *= self.epsilon_decay

    # 4.7 存储经验到回放池
    def store_experience(self, state, action, reward, next_state, done):
        self.replay_buffer.append( (state, action, reward, next_state, done) )

    # 4.8 同步目标网络权重
    def sync_target_net(self):
        self.target_net.load_state_dict(self.policy_net.state_dict())

# 5. 主训练循环
if __name__ == "__main__":
    # 初始化智能体
    agent = MarioRLAgent()
    # 帧堆叠队列:存储最近4帧图像,构建完整状态
    frame_stack = deque(maxlen=4)
    total_episodes = 10000  # 总训练回合数(可根据需求调整)

    # 遍历每个训练回合
    for episode in range(total_episodes):
        # 5.1 重置游戏环境,获取初始帧
        initial_state = agent.env.reset()
        # 初始化帧堆叠:前4帧均为初始帧(保证初始状态有4帧)
        for _ in range(4):
            frame_stack.append(preprocess_frame(initial_state))
        
        episode_reward = 0  # 本回合总奖励
        done = False  # 游戏是否结束标志

        # 5.2 单回合游戏循环
        while not done:
            # 构建当前状态:4帧图像堆叠(shape=(4,84,84))
            current_state = np.stack(frame_stack)
            # 选择动作
            action = agent.select_action(current_state)
            # 执行动作,获取环境反馈
            next_state, reward, done, info = agent.env.step(action)
            # 累积本回合奖励
            episode_reward += reward

            # 预处理下一帧,加入帧堆叠
            processed_next_frame = preprocess_frame(next_state)
            frame_stack.append(processed_next_frame)
            # 构建下一状态
            next_current_state = np.stack(frame_stack)

            # 存储经验到回放池
            agent.store_experience(current_state, action, reward, next_current_state, done)

            # 从经验池中训练
            agent.train_from_replay()

        # 5.3 每5回合同步一次目标网络
        if episode % 5 == 0:
            agent.sync_target_net()
            print(f"[同步目标网络] 回合:{episode}")

        # 5.4 打印本回合信息
        print(f"回合:{episode:4d} | 总奖励:{episode_reward:6.0f} | 探索率:{agent.epsilon:.3f}")

    # 训练结束,关闭环境
    agent.env.close()

五、关键模块逐行解析(补充两大技术相关细节)

5.1 神经网络模型(MarioDQN 类)

  • 卷积层设计:3 层卷积 + ReLU 激活,核心作用是 “自动提取图像特征”。从底层的 “边缘、颜色块” 到高层的 “敌人、管道、坑洞”,无需人工设计特征,模型自主学习。
  • 全连接层设计
    • 全连接层 1(512 神经元):将卷积层输出的 3136 维特征压缩为 512 维,整合高级语义特征(如 “敌人在前方”“前方有坑”);
    • 全连接层 2(动作数神经元):直接输出每个动作的 “价值评分(Q 值)”,Q 值越高表示该动作在当前状态下越优。
  • 前向传播:输入 4 帧堆叠图像,经过卷积→展平→全连接,最终输出 7 个动作的 Q 值。

5.2 图像预处理(preprocess_frame 函数)

  • 转灰度图:RGB 图像有 3 个通道,转灰度后仅 1 个通道,减少计算量的同时保留关键视觉信息(如敌人轮廓、地形边界);
  • 缩放至 84×84:游戏原始画面(256×240)过大,缩放后可降低模型参数规模,加速训练;
  • 归一化:将像素值从 [0,255] 转为 [0,1],避免因像素值过大导致模型梯度爆炸,稳定训练过程。

5.3 智能体核心逻辑(MarioRLAgent 类)

  • epsilon-greedy 策略:平衡 “探索” 和 “利用”。训练初期(epsilon=1.0)完全随机动作,探索所有可能;随着训练推进(epsilon 衰减),逐渐倾向于选择 Q 值最高的动作,利用已有经验;
  • 反向传播更新:通过 MSE 损失计算预测 Q 值与目标 Q 值的差距,利用loss.backward()自动计算各层梯度,optimizer.step()仅更新策略网络的权重(卷积层、全连接层),目标网络不参与更新。

六、训练过程与预期效果

6.1 训练阶段划分

表格

训练回合 表现特征 核心学习成果
0~100 乱跳、频繁掉坑、原地徘徊 无明确策略,探索所有动作
100~300 开始持续向右前进,偶尔跳坑 学会 “向右前进 = 加分”,规避简单危险
300~500 稳定跳坑、躲避普通敌人(板栗仔) 识别 “坑 = 扣分”“敌人 = 扣分”,形成避障策略
500~1000 跳管道、踩乌龟、接近旗杆 掌握复杂地形处理,理解 “踩敌人 = 加分”
1000+ 稳定通关 1-1 关卡,甚至速通 形成最优策略,最大化总奖励

6.2 关键指标观察

  • 总奖励:随着训练推进,回合总奖励应逐步上升并趋于稳定(通关时奖励通常在 1000 以上);
  • 探索率:从 1.0 逐步衰减到 0.01,表明模型从 “探索” 转向 “利用”;
  • 训练速度:CPU 训练约 1000 回合需 10~15 小时(视配置而定),GPU 可加速 3~5 倍。

七、进阶优化建议

7.1 功能扩展

  • 实时画面显示:在训练循环中添加agent.env.render(),实时观察 AI 的游戏过程;
  • 模型保存 / 加载:训练中定期保存模型权重(torch.save(agent.policy_net.state_dict(), "mario_model.pth")),后续可直接加载模型继续训练或测试;
  • 训练曲线可视化:用matplotlib绘制回合奖励变化曲线,直观观察训练效果。

7.2 算法优化

  • 更换更优算法:将 DQN 改为 PPO(Proximal Policy Optimization),训练更稳定、收敛更快,适合复杂关卡;
  • 优先经验回放(PER):对 “重要经验”(如死亡、通关)赋予更高采样权重,提升训练效率;
  • 多线程训练(A3C):用多线程并行探索不同游戏场景,加速经验积累。

八、常见问题与解决方案

8.1 代码运行报错

  • ImportError: No module named 'nes_py':未安装nes-py,执行pip install nes-py
  • RuntimeError: CUDA out of memory:GPU 显存不足,改用 CPU 训练(安装 CPU 版 PyTorch)或减小批次大小(batch_size=16);
  • 游戏画面无法显示:部分环境不支持render(),可忽略或更换游戏版本(如SuperMarioBros-1-1-v3)。

8.2 训练效果不佳

  • 奖励不上升:检查经验池容量(可增大到 20000)或学习率(调整为 5e-5);
  • AI 一直乱跳:探索率衰减过慢,可增大epsilon_decay(如 0.995);
  • 频繁死亡:奖励函数设计可优化(如死亡惩罚改为 - 200,强化 “存活” 优先级)。

九、总结

本文通过 “原理解析 + 代码实现 + 核心技术拆解” 的方式,完整呈现了强化学习在超级马里奥游戏中的应用,重点突出了 DQN 算法的两大核心优化技术:

  • 经验回放:通过随机采样打破数据相关性,避免训练震荡;
  • 双网络:通过分离策略网络和目标网络,稳定 Q 值估计,防止目标漂移。

这两个技术的协同作用,是 AI 能从 “乱按键盘” 逐步成长为 “通关高手” 的关键。代码中每个模块都对应明确的功能,注释详细,新手可直接运行并修改参数实践。

该案例不仅是强化学习的入门经典,其核心思想(如状态表示、奖励设计、经验回放、双网络)还可迁移到其他游戏(如 Atari、贪吃蛇)或机器人控制场景。通过实际运行代码、调整超参数,读者能更直观地理解强化学习的训练规律,为后续学习更复杂的 RL 算法(如 PPO、SAC)打下基础。

Logo

更多推荐