开源
MAMEToolkit:可以在街机游戏中强化学习算法的Python库
来源:元经纪     阅读:643
网站管理员
发布于 2023-01-28 09:57
查看主页

概述

这个 Python 库将允许您在几乎任何街机游戏上训练您的强化学习算法。它目前在 Linux 系统上可用,并作为MAME的包装器工作。该工具包允许您的算法逐步完成游戏过程,同时接收帧数据和内部存储器地址值以跟踪游戏状态,并发送与游戏交互的动作。

要求:

注意:如果您使用的是不常见的 Linux 发行版或具有不同指令集的 CPU,请参阅编译自定义 MAME部分。

安装

[hidecontent type="logged" desc="隐藏内容:登录后可查看"]

您可以使用pip安装库,只需运行:

pip install MAMEToolkit

街头霸王随机特工演示

该工具包目前已应用于 Street Fighter III Third Strike:为未来而战(日本 990608,无 CD),但可以针对 MAME 上可用的任何游戏进行修改。下面演示了如何为街头霸王环境编写随机代理。

import random
from MAMEToolkit.sf_environment import Environment

roms_path = "roms/"  # Replace this with the path to your ROMs
env = Environment("env1", roms_path)
env.start()
while True:
    move_action = random.randint(0, 8)
    attack_action = random.randint(0, 9)
    frames, reward, round_done, stage_done, game_done = env.step(move_action, attack_action)
    if game_done:
        env.new_game()
    elif stage_done:
        env.next_stage()
    elif round_done:
        env.next_round()

该工具包还支持 hogwild 训练:

from multiprocessing import Process
import random
from MAMEToolkit.sf_environment import Environment


def run_env(worker_id, roms_path):
    env = Environment(f"env{worker_id}", roms_path)
    env.start()
    while True:
        move_action = random.randint(0, 8)
        attack_action = random.randint(0, 9)
        frames, reward, round_done, stage_done, game_done = env.step(move_action, attack_action)
        if game_done:
            env.new_game()
        elif stage_done:
            env.next_stage()
        elif round_done:
            env.next_round()


workers = 8
# Environments must be created outside of the threads
roms_path = "roms/"  # Replace this with the path to your ROMs
threads = [Process(target=run_env, args=(i, roms_path)) for i in range(workers)]
[thread.start() for thread in threads]

设置你自己的游戏环境

游戏 ID 要创建游戏的模拟,您必须首先拥有您正在模拟的游戏的 ROM 并知道 MAME 使用的游戏 ID,例如对于这个版本的街头霸王,它是“sfiii3n”。您的游戏 ID 可以通过运行找到:

from src.MAMEToolkit.emulator import see_games
see_games()

这将调出 MAME 模拟器。您可以搜索游戏列表以找到您想要的游戏。游戏 ID 总是在游戏标题末尾的括号中。

内存地址 使用工具包与模拟器本身进行交互并不需要太多,但是挑战来自于找到与您关心的内部状态相关联的内存地址值,并使用您的环境类跟踪所述状态。可以使用MAME Cheat Debugger跟踪游戏的内部内存状态,它允许您跟踪游戏的内存地址值如何随时间变化。

作弊调试器可以使用以下命令运行:

from src.MAMEToolkit.emulator import run_cheat_debugger
roms_path = "roms/" # Replace this with the path to your ROMs
game_id = "sfiii3n"
run_cheat_debugger(roms_path, game_id)

有关使用调试器的信息,请参阅以下教程的内存转储部分

一旦确定了要跟踪的内存地址,就可以使用以下命令开始仿真:

from src.MAMEToolkit.emulator import Emulator
from src.MAMEToolkit.emulator import Address

roms_path = "roms/"  # Replace this with the path to your ROMs
game_id = "sfiii3n"
memory_addresses = {
        "fighting": Address('0x0200EE44', 'u8'),
        "winsP1": Address('0x02011383', 'u8'),
        "winsP2": Address('0x02011385', 'u8'),
        "healthP1": Address('0x02068D0B', 's8'),
        "healthP2": Address('0x020691A3', 's8')
    }
    
emulator = Emulator("env1", roms_path, game_id, memory_addresses)

这将立即启动仿真并在工具包链接到仿真器进程时停止仿真。

步进仿真器 链接工具包后,您可以使用 step 函数步进仿真器:

data = emulator.step([])

frame = data["frame"]
is_fighting = data["fighting"]
player1_wins = data["winsP1"]
player2_wins = data["winsP2"]
player1_health = data["healthP1"]
player2_health = data["healthP2"]

step 函数将帧数据作为 NumPy 矩阵返回,以及该时间步长的所有内存地址整数值。

发送输入 要向模拟器发送操作,您还需要确定游戏支持哪些输入端口和字段。例如,要让街头霸王投币,需要以下代码:

from src.MAMEToolkit.emulator import Action

insert_coin = Action(':INPUTS', 'Coin 1')
data = emulator.step([insert_coin])

要确定哪些端口可用,请使用 list actions 命令:

from src.MAMEToolkit.emulator import list_actions

roms_path = "roms/"  # Replace this with the path to your ROMs
game_id = "sfiii3n"
print(list_actions(roms_path, game_id))

对于街头霸王,它返回列表,其中包含可用于将操作发送到 step 函数的所有端口和字段:

[
    {'port': ':scsi:1:cdrom:SCSI_ID', 'field': 'SCSI ID'}, 
    {'port': ':INPUTS', 'field': 'P2 Jab Punch'}, 
    {'port': ':INPUTS', 'field': 'P1 Left'}, 
    {'port': ':INPUTS', 'field': 'P2 Fierce Punch'}, 
    {'port': ':INPUTS', 'field': 'P1 Down'}, 
    {'port': ':INPUTS', 'field': 'P2 Down'}, 
    {'port': ':INPUTS', 'field': 'P2 Roundhouse Kick'}, 
    {'port': ':INPUTS', 'field': 'P2 Strong Punch'}, 
    {'port': ':INPUTS', 'field': 'P1 Strong Punch'}, 
    {'port': ':INPUTS', 'field': '2 Players Start'}, 
    {'port': ':INPUTS', 'field': 'Coin 1'}, 
    {'port': ':INPUTS', 'field': '1 Player Start'}, 
    {'port': ':INPUTS', 'field': 'P2 Right'}, 
    {'port': ':INPUTS', 'field': 'Service 1'}, 
    {'port': ':INPUTS', 'field': 'Coin 2'}, 
    {'port': ':INPUTS', 'field': 'P1 Jab Punch'}, 
    {'port': ':INPUTS', 'field': 'P2 Up'}, 
    {'port': ':INPUTS', 'field': 'P1 Up'}, 
    {'port': ':INPUTS', 'field': 'P1 Right'}, 
    {'port': ':INPUTS', 'field': 'Service Mode'}, 
    {'port': ':INPUTS', 'field': 'P1 Fierce Punch'}, 
    {'port': ':INPUTS', 'field': 'P2 Left'}, 
    {'port': ':EXTRA', 'field': 'P2 Short Kick'}, 
    {'port': ':EXTRA', 'field': 'P2 Forward Kick'}, 
    {'port': ':EXTRA', 'field': 'P1 Forward Kick'}, 
    {'port': ':EXTRA', 'field': 'P1 Roundhouse Kick'}, 
    {'port': ':EXTRA', 'field': 'P1 Short Kick'}
]

我们建议您创建一个包含所有可能操作的枚举,然后将它们的操作值发送到模拟器,请参阅示例 Actions Enum

还有在标题屏幕和角色选择等不可学习的游戏屏幕之间转换游戏的问题。要了解如何实施,请查看提供的步骤脚本示例街头霸王 III 第三次打击:为未来环境实施而战

模拟器类还有一个 frame_ratio 参数,可用于调整算法看到的帧速率。默认情况下,MAME 以每秒 60 帧的速度生成帧,但是,这对于您的算法来说可能太多了。默认情况下,工具包将使用 frame_ratio 3,这意味着 3 帧中有 1 帧通过工具包发送,这会将帧速率转换为每秒 20 帧。使用更高的 frame_ratio 也会提高工具包的性能。

from src.MAMEToolkit.emulator import Emulator

emulator = Emulator(env_id, roms_path, game_id, memory_addresses, frame_ratio=3)

在没有屏幕的情况下运行库/在 Linux 服务器上

如果您正在运行 linux 服务器或 docker 实例,那么您将需要向 python 脚本添加一些额外的代码以启用 MAME 运行。为此,我们将使用Xvfb 库,它将模拟 X 显示服务器的一个实例。只需Xvfb为您的相关 Linux 发行版安装库。然后将以下两行添加到主 Python 脚本的顶部。

import os
os.system("Xvfb :0 -screen 0 800x600x16 +extension RANDR &")
os.environ["DISPLAY"] = ":0"

这将模拟具有 16 位颜色的 800x600 分辨率屏幕。随意更改参数以满足您的需要。

带 PC 规格的库性能基准

该工具包的开发和测试已在 8 核 AMD FX-8300 3.3GHz CPU 和 3GB GeForce GTX 1060 GPU 上完成。使用单个随机代理,街头霸王环境可以以 600% 以上的正常游戏速度运行。对于 8 个随机代理的 hogwild 训练,环境可以以 300%+ 正常游戏速度运行。

简单的 ConvNet 代理

为确保该工具包能够训练算法,设置了一个简单的 5 层 ConvNet,并进行了最少的调整。该算法能够成功学习街头霸王的一些简单机制,例如连击和格挡。街头霸王的游戏玩法是让玩家在难度递增的 10 个阶段中与不同的对手作战。最初,该算法将平均达到第 2 阶段,但最终在 2200 次训练后平均可以达到第 5 阶段。学习率是使用每集的单个播放过程中造成的净伤害与受到的伤害来跟踪的。

MAME的变化

该库充当修改后的 MAME 实现的包装器。进行了以下更改:

  • 更新了 lua 控制台以允许检索帧数据的格式
  • 更新 lua 控制台以允许检索当前帧数据
  • 禁用游戏开始警告

以下文件受到影响:

  • src/emu/machine.cpp
  • src/emu/video.cpp
  • src/emu/video.h
  • src/frontend/mame/luaengine.cpp
  • src/frontend/mame/ui/ui.cpp
  • src/osd/sdl/window.cpp

可以在 [ https://github.com/MJ-Murray/mame ]找到修改后的 MAME 实现

编译自定义 MAME

不幸的是,这个库并不适用于每个操作系统或 CPU 指令集。这是因为它使用 MAME 的自定义预编译实例,该实例特定于编译它的操作系统和 CPU。但是,如果您使用不同的 linux 发行版或指令集,这并不意味着您没有选择,它只是意味着您使用这个库的路径有点复杂。您唯一剩下的选择是自己编译 MAME 的自定义实例。为此,您只需要一个带有 GUI 的 Linux 发行版。其他操作系统将无法运行,因为该库严重依赖 linux fifo 管道。

编译步骤

要编译您自己的 MAME 自定义实例,请在您的终端中运行以下命令:

git clone git@github.com:M-J-Murray/mame.git
cd mame
make SUBTARGET=arcade -j4

调整j以匹配您的 CPU 支持的虚拟内核数量,因为这可能需要几个小时,具体取决于您的计算机。

编译完成后,您应该有一个名为 的可执行文件mamearcade64,或者类似的东西。现在您可以在模拟器方法调用中使用 binary_path 关键字参数来指向您的自定义二进制文件,或者您可以将所述可执行文件重命名为mame并用新文件替换 python MAMEToolkit 目录中的预编译 MAME 实例。您应该能够通过转到 python 环境目录找到 MAMEToolkit 目录,然后转到site-packages.

故障排除

本节介绍如果您的make命令失败并显示某种描述不正确/缺少库的错误消息时该怎么办。由于不同的 Linux 发行版默认实现不同的库,因此您可能不会默认安装正确的库。这些库还需要特定于您的 CPU 指令集。为所有 Linux 发行版和指令集编写所有库安装命令将非常困难,但是,我可以概述 MAME 需要的库。名单如下:

  • libdl
  • librt
  • libSDL2-2.0
  • libpthread
  • libutil
  • libGL
  • libasound
  • libQt5Widgets
  • libQt5Gui
  • libQt5Core
  • libX11
  • libSDL2_ttf-2.0
  • libfontconfig
  • libstdc++
  • libm
  • libgcc_s
  • libc

您的错误消息应表明至少缺少其中一个库。要安装所述库,您需要在线查看并了解如何为相关的 Linux 发行版和指令集安装/更新库。使用以下内容作为谷歌搜索模板:“{linux distribution} {CPU instruction set} install {missing library}”只需将大括号替换为与您相关的信息即可。希望您应该能够在论坛上找到相关的安装命令。如果缺少的库不适用于您的发行版/cpu,那么 MAMEToolkit 将无法为您工作。

一旦你安装了你的库,只要make再次运行它就会从它停止的地方继续,你不会丢失你的编译进度。

[/hidecontent]

 

[/rihide

免责声明:本文为用户发表,不代表网站立场,仅供参考,不构成引导等用途。 开源
每日元宇宙|苹果公司申请VisionPro商标,Meta计划全面加码AI
男子连续驾车11个小时带着全家翻车 交警提醒:切勿疲劳驾驶
江苏中塑王TPE|热塑性弹性体TPE与橡胶的不同
2023年中国元宇宙营销市场研究报告
全民开发者时代到来:《无锡市元宇宙创新发展三年行动计划》发布

首页

分类

定制方案

消息

我的