最近,我投身于一个令人兴奋的项目——利用强化学习技术训练一个能够玩转《超级马里奥》的智能代理。这个项目不仅是对技术的一次挑战,更是对经典游戏的一次全新诠释。
强化学习的魔法
强化学习,这个听起来有些神秘的名词,其实就是一种让机器通过不断尝试和错误来学习如何完成任务的技术。想象一下,你在玩一个新游戏,开始时你可能不知道如何操作,但通过不断尝试,你逐渐掌握了游戏规则并开始游刃有余。强化学习中的智能代理(也就是我们的玩家)也是这样,它通过不断地尝试和探索,学习如何在游戏世界中生存并获得高分。
在强化学习中,代理(agent)通过与环境(environment)的交互来学习。每一次行动(action)后,环境都会给出一个反馈(reward),这个反馈可以是正的(奖励)也可以是负的(惩罚)。代理的目标是最大化长期累积的奖励。这个过程可以用一个数学模型——马尔可夫决策过程(Markov Decision Process, MDP)来描述,它提供了强化学习问题的一个框架。
超级马里奥的新挑战
在这个项目中,我们的主角不再是那个熟悉的胡子水管工,而是一个由深度神经网络驱动的智能代理。这个代理需要在充满敌人、障碍和奖励的马里奥世界中找到生存之道。它的任务是简单而又复杂:最大化奖励,也就是尽可能地活得更久、跳得更远。
技术的魅力
要实现这一目标,我们采用了深度Q学习和双深度Q网络(DDQN)技术。深度Q学习是一种结合了深度学习和Q学习的强化学习方法。它使用一个深度神经网络来近似Q函数,这个函数评估在给定状态下采取某个行动的期望回报。而双深度Q网络(DDQN)进一步改进了DQN,通过使用两个网络来减少估计中的过高估计(bias),从而提高了学习的稳定性和性能。
训练过程的乐趣
训练这个智能代理的过程充满了惊喜和挑战。一开始,它就像是一个游戏新手,总是在同一个地方跌倒,但随着时间的推移,它开始学会了如何跳跃、躲避,甚至是在空中做出华丽的翻转。每一次的尝试都是一次新的探索,每一次的失败都是学习的机会。看着它从一个笨拙的新手变成一个游戏高手,这个过程充满了成就感。
在训练过程中,我们还采用了一些技术来优化学习效率,如经验回放(experience replay)和固定Q目标(fixed Q-targets)。经验回放通过随机抽取过去的经验来打破数据之间的相关性,而固定Q目标则是通过定期更新目标网络来稳定训练。
这是一次技术与乐趣的完美结合,一次对经典的全新演绎。如果你也对强化学习或游戏开发感兴趣,不妨尝试一下,也许你会在这个过程中发现更多的乐趣和可能性。
import torch
from utils.log import MetricLogger
from utils.pro_img import *
from pathlib import Path
from nes_py.wrappers import JoypadSpace
import datetime
import gym_super_mario_bros
from gym.wrappers import FrameStack
from model.agent import Mario
if __name__ == "__main__":
# 初始化 Super Mario 环境
env = gym_super_mario_bros.make("SuperMarioBros-1-1-v0")
# 限制动作空间为:向右走和向右跳
env = JoypadSpace(env, [["right"], ["right", "A"]])
env.reset()
next_state, reward, done, info = env.step(action=0)
# 应用环境包装器
env = SkipFrame(env, skip=4)
env = GrayScaleObservation(env)
env = ResizeObservation(env, shape=84)
env = FrameStack(env, num_stack=4)
use_cuda = torch.cuda.is_available()
print(f"Using CUDA: {use_cuda}")
save_dir = Path("checkpoints") / datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S")
save_dir.mkdir(parents=True)
# 实例化 Mario
mario = Mario(state_dim=(4, 84, 84), action_dim=env.action_space.n, save_dir=save_dir)
logger = MetricLogger()
#train
e=0
while True:
state = env.reset()
# 开始游戏循环
while True:
# 选择动作
action = mario.act(state)
env.render()
# 执行动作
next_state, reward, done, info = env.step(action)
# 记忆当前经历
mario.cache(state, next_state, action, reward, done)
# 学习更新网络
q, loss = mario.learn()
# 记录日志
logger.log_step(reward, loss, q)
# 更新状态
state = next_state
# 检查游戏是否结束
if done:
e += 1
logger.record(episode=e, epsilon=mario.exploration_rate, step=mario.curr_step)
if e % 20 == 0:
mario.save()
break