1.前言:
学习了DQN有一段时间了,在我接触到的入门教程里,一般都是用它来玩集成好的Gym的游戏比如CartPole-v0,然后复杂一些的就是用它来玩Flappy bird,但是它们的环境都是集成好的,可以通过简单的调用api获得环境信息,奖励,在现实中少有这样准备的很好的api接口。于是,打算自己来设计一个简单的DQN神经网络,玩微信小游戏:
2.环境准备:
所使用的主要Python环境和库:
python = 3.6.6
numpy==1.15.4
Pillow==5.3.0
torch==1.0.0
torchvision==0.2.1
所使用的调试训练运行环境:
夜神模拟器 v6.2.6.3
微信版本 v7.0.0
小游戏名称 乒乓吧同学
执行操作方式 Adb调试工具的虚拟点击
如果想要运行此代码,需要将夜神模拟器设置为(运行时需要将模拟器窗口放于左上角,以方便截图):
1.为什么要用模拟器,而不是用数据线连接接手机通过Adb工具截图?
因为手机不能改分辨率,只能用默认分辨率1920*1080,而且通过adb工具截图后上传到电脑大概需要0.5秒,在进行训练时,这个速度还会变大,而乒乓球这种快节奏游戏,很难忍受这种延迟,所以使用模拟器运行小游戏,然后可以直接通过Pillow库的相关函数截取特定区域获得图片。
2.为什么分辨率设置的这么低?
因为如果分辨率设置的很高,那么传入神经网络的图像参数就会很多,那么计算量就会增加,那么我的笔记本GPU可能就会跑不动。。。
3.为什么设置为双核2048MB内存?
因为对于我的笔记本而言,太高电脑反应变慢尤其是在训练的时候,太低玩微信小游戏都有延迟,所以多次测试后,选择这个配置。
3.代码讲解
A.首先是与调试环境交互相关的代码讲解:
class Handle:
def __init__(self):
self.debug = False
self.box = (3,43,483,823) # 完整截图区域
self.box_view = (0, 120, 460, 580) # 神经网络的视觉区域
self.box_reward = (144, 20, 334, 90)# 比分板区域
self.image = None # 未初始化的截图
self.image_view = None # 未初始化的神经网络视野
self.image_reward = None # 未初始化的分数板区域
self.state = []
self.score_previous = 0 # 之前的分数
def getimage(self):
self.image = ImageGrab.grab(self.box).convert('L')
self.image_view = self.image.crop(self.box_view)
self.image_reward = self.image.crop(self.box_reward)
getimage()
方法用来从电脑屏幕的特定区域进行截图,此截图即为整个游戏界面,在截图之后将会吧图像转换为灰度图,以减少运算量,然后截取image_view
作为神经网络的视野,截取image_reward
比分扳区域用作之后的分数识别,两个截图如下图所示
def getstate(self):
self.state = []
for _ in range(4):
self.getimage()
self.state.append(self.image_view)
self.state = np.stack(self.state,axis=0)
def getscore(self):
image_one = self.image_reward.crop((0,0,72,70))
for _,_,filename in os.walk('./source/one'):
for file in filename:
name = os.path.join('./source/one',file)
image = Image.open(name)
if self.similar(image_one,image)>90:
return int(file.replace('.png',''))
print('No matching')
return None
@staticmethod
def similar(image_1,image_2):
lh, rh = image_1.histogram(), image_2.histogram()
ret = 100 * sum(1 - (0