编者按:近年来,虽然关于强化学习进展的新闻屡见报端,对强化学习感兴趣的人也很多,但对普通学习者来说,真正做一个自己感兴趣的强化学习项目还是太麻烦了。今天论智给大家推荐的是一名网友开源的python库,它提供了一个可以玩任何旧版街机游戏的api,操作方式非常亲民。
这是一个允许你在几乎任何街机游戏中训练你的强化学习算法的python库,它目前在linux系统上可用。通过这个工具包,你可以定制算法逐步完成游戏过程,同时接收每一帧的数据和内部存储器地址值以跟踪游戏状态,以及发送与游戏交互的动作。
安装
github地址:github.com/m-j-murray/mametoolkit/blob/master/readme.md
你可以用pip安装这个库,只需运行以下命令:
pip install mametoolkit
演示示例:街霸
在街机爱好者心中,街霸是史上最经典的游戏之一。现在工具包内包含的街霸版本是街头霸王3:三度冲击(japan 990608, no cd),我们以此为例,用以下代码写一个随机智能体:
import random
frommametoolkit.sf_environment importenvironment
roms_path = roms/
env = environment(env1, roms_path)
env.start()
whiletrue:
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!训练:
什么是hogwild!?niu等人引入了一个叫做 hogwild! 的更新策略,可以使 sgd 可以在多 cpu 上并行更新。处理器在无需对参数加锁的情况下就可以访问共享内存。但仅在输入的是稀疏数据时才有效,因为每次更新仅修改所有参数的一小部分。他们展示了在这种情况下,更新策略几乎可以达到一个最优的收敛率,因为处理器不太可能覆盖掉有用的信息。
from threading importthread
import random
frommametoolkit.sf_environment importenvironment
def run_env(env):
env.start()
whiletrue:
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()
def main():
workers = 8
# environments must be created outside of the threads
roms_path = roms/
envs = [environment(fenv{i}, roms_path) for i in range(workers)]
threads = [thread(target=run_env, args=(envs[i], )) for i in range(workers)]
[thread.start() for thread in threads]
建立自己的游戏环境
这个工具包之所以易于上手,是因为它和模拟器本身不需要太多交互,只需注意两点——一是查找你关注的内部状态相关联的内存地址值,二是用选取的环境跟踪状态。你可以用mame cheat debugger,它会反馈游戏的内存地址值如何随时间变化。如果要创建游戏模拟,你得先获得正在模拟的游戏的rom,并知道mame使用的游戏id,比如街霸的id是'sfiii3n'。
游戏id
你可以通过运行以下代码找到游戏的id:
frommametoolkit.emulator importemulator
emulator = emulator(env1, , , memory_addresses)
这个命令会打开mame仿真器。你可以搜索游戏列表以找到想要的游戏,游戏的id位于游戏标题末尾的括号中。
内存地址
如果获得了id,也有了想要跟踪的内存地址,你可以开始模拟:
frommametoolkit.emulator importemulator
frommametoolkit.emulator importaddress
roms_path = 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, sfiii3n, memory_addresses)
这会启动仿真器,并在工具包连接到模拟器进程时暂停。
分步运行仿真器
连接工具箱后,你可以分步运行仿真器:
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矩阵返回,同时,它也会返回该时间步长的所有内存地址整数值。
如果要向仿真器输入动作,你还需要确定游戏支持的输入端口和字段。比如玩街霸需要先投币,这个代码是:
frommametoolkit.emulator importaction
insert_coin = action(':inputs', 'coin 1')
data = emulator.step([insert_coin])
要确定哪些端口可用,请使用list actions命令:
frommametoolkit.emulator import list_actions
roms_path = roms/
game_id = sfiii3n
print(list_actions(roms_path, game_id))
下面这个返回的列表就包含街霸环境中可用于向步骤函数发送动作的所有端口和字段:
[
{'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'}
]
仿真器类还有一个frame_ratio参数,可用于调整算法所见的帧速率。默认情况下,mame以每秒60帧的速度生成帧,如果你觉得这太多了,想把它改成每秒20帧,可以输入以下代码:
frommametoolkit.emulator importemulator
emulator = emulator(roms_path, game_id, memory_addresses, frame_ratio=3)
mame性能基准测试
目前这个工具包的开发和测试已在8核amd fx-8300 3.3ghz cpu以及3gb geforce gtx 1060 gpu上完成。在使用单个随机智能体的情况下,街头霸王环境可以以正常游戏速度的600%+运行。而如果是用8个随机智能体进行hogwild!训练,环境可以以正常游戏速度的300%+运行。
convnet智能体
为了确保工具包能够训练算法,作者还设置了一个简单的5层convnet,只需少量调整,你就可以用它进行测试。在街霸实验中,这个算法能够成功学习到游戏的一些简单技巧,比如连击(combo)和格挡(blocking)。街霸本身的游戏机制是分成10个关卡(难度递增),玩家在每个关卡都要迎战不同的对手。刚开始的时候,这个智能体平均只能打到第2关。但在经过2200次训练后,它平均能打到第5关。
至于智能体的学习率,它是用每一局智能体所造成的净伤害和所承受的伤害来计算的。
苹果A11处理器曝光?苹果对iPhone8守口如瓶,售价走高果粉一点不介意?
消防疏散通道CS余压监控系统设计规范原则说明
分析储能的三大应用场景
SiC助益电动汽车发展,英飞凌与意法半导体加速布局
电容152是多少uf?换算规律是这样的
给大家推荐一名网友开源的Python库
富士康高雄电池工厂开工建设,正式进军电动汽车电池行业
HarmonyOS:何为一生万物,万物归一
电解液行业的普罗米修斯什么时候会降临?
pcb制板的规则你值得一看
采用模块化架构应用处理器扩展手机功能
5g共建共享网络的规划与设计方案
NS32F103CBT6软硬件通用STM32F103CBT6
iphone8什么时候上市?iphone8最新消息:苹果手机要打翻身仗?市值再次创下新高,疲软出现转机
基于linux下自定义一个脚本来替代rm命令
电磁流量计校准装置的原理及设计
三星C5 Pro/C7 Pro跳票 延迟至明年1月发布
贸泽电子赞助同济大学DIAN Racing车队
飞思卡尔ARM平台MCU引领嵌入式技术发展新趋势
ADC/DAC精度计算器教程