轻松实现TensorFlow微信跳一跳的AI


Posted in Python onJanuary 05, 2018

作为python和机器学习的初学者,目睹了AI玩游戏的各种风骚操作,心里也是跃跃欲试。

然后发现微信跳一跳很符合需求,因为它不需要处理连续画面(截屏太慢了)和复杂的操作,很适合拿来练手。于是…这个东西诞生了,目前它一般都可以跳到100多分,发挥好了能上200。

1.需要设备:

Android手机,数据线
ADB环境
Python环境(本例使用3.6.1)
TensorFlow(本例使用1.0.0)

2.大致原理

使用adb模拟点击和截屏,使用两层卷积神经网络作为训练模型,截屏图片作为输入,按压毫秒数直接作为为输出。

3.训练过程

最开始想的用强化学习,然后发现让它自己去玩成功率太!低!了!,加上每次截屏需要大量时间,就放弃了这个方法,于是考虑用自己玩的数据作为样本喂给它,这样就需要知道每次按压的时间。

我是这样做的,找一个手机写个app监听按压屏幕时间,另一个手机玩游戏,然后两个手指同时按两个手机o(?□?)o

4.上代码

首先,搭建模型:

第一层卷积:5*5的卷积核,12个featuremap,此时形状为96*96*12
池化层:4*4 max pooling,此时形状为24*24*12
第二层卷积:5*5的卷积核,24个featuremap,此时形状为20*20*24
池化层:4*4 max pooling,此时形状为5*5*24
全连接层:5*5*24连接到32个节点,使用relu激活函数和0.4的dropout率
输出:32个节点连接到1个节点,此节点就代表按压的时间(单位s)

# 输入:100*100的灰度图片,前面的None是batch size,这里都为1 
x = tf.placeholder(tf.float32, shape=[None, 100, 100, 1]) 
# 输出:一个浮点数,就是按压时间,单位s 
y_ = tf.placeholder(tf.float32, shape=[None, 1]) 
 
# 第一层卷积 12个feature map 
W_conv1 = weight_variable([5, 5, 1, 12], 0.1) 
b_conv1 = bias_variable([12], 0.1) 
# 卷积后为96*96*12 
 
h_conv1 = tf.nn.relu(conv2d(x, W_conv1) + b_conv1) 
h_pool1 = max_pool_4x4(h_conv1) 
# 池化后为24*24*12 
 
# 第二层卷积 24个feature map 
W_conv2 = weight_variable([5, 5, 12, 24], 0.1) 
b_conv2 = bias_variable([24], 0.1) 
# 卷积后为20*20*24 
 
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) 
h_pool2 = max_pool_4x4(h_conv2) 
# 池化后为5*5*24 
 
# 全连接层5*5*24 --> 32 
W_fc1 = weight_variable([5 * 5 * 24, 32], 0.1) 
b_fc1 = bias_variable([32], 0.1) 
h_pool2_flat = tf.reshape(h_pool2, [-1, 5 * 5 * 24]) 
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1) 
 
# drapout,play时为1训练时为0.6 
keep_prob = tf.placeholder(tf.float32) 
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) 
# 学习率 
learn_rate = tf.placeholder(tf.float32) 
 
# 32 --> 1 
W_fc2 = weight_variable([32, 1], 0.1) 
b_fc2 = bias_variable([1], 0.1) 
y_fc2 = tf.matmul(h_fc1_drop, W_fc2) + b_fc2 
 
# 因输出直接是时间值,而不是分类概率,所以用平方损失 
cross_entropy = tf.reduce_mean(tf.square(y_fc2 - y_)) 
train_step = tf.train.AdamOptimizer(learn_rate).minimize(cross_entropy)

其次,获取屏幕截图并转换为模型输入:

# 获取屏幕截图并转换为模型的输入 
def get_screen_shot(): 
  # 使用adb命令截图并获取图片,这里如果把后缀改成jpg会导致TensorFlow读不出来 
  os.system('adb shell screencap -p /sdcard/jump_temp.png') 
  os.system('adb pull /sdcard/jump_temp.png .') 
  # 使用PIL处理图片,并转为jpg 
  im = Image.open(r"./jump_temp.png") 
  w, h = im.size 
  # 将图片压缩,并截取中间部分,截取后为100*100 
  im = im.resize((108, 192), Image.ANTIALIAS) 
  region = (4, 50, 104, 150) 
  im = im.crop(region) 
  # 转换为jpg 
  bg = Image.new("RGB", im.size, (255, 255, 255)) 
  bg.paste(im, im) 
  bg.save(r"./jump_temp.jpg") 
 
  img_data = tf.image.decode_jpeg(tf.gfile.FastGFile('./jump_temp.jpg', 'rb').read()) 
  # 使用TensorFlow转为只有1通道的灰度图 
  img_data_gray = tf.image.rgb_to_grayscale(img_data) 
  x_in = np.asarray(img_data_gray.eval(), dtype='float32') 
 
  # [0,255]转为[0,1]浮点 
  for i in range(len(x_in)): 
    for j in range(len(x_in[i])): 
      x_in[i][j][0] /= 255 
 
  # 因为输入shape有batch维度,所以还要套一层 
  return [x_in]

以上代码过程大概是这样:

轻松实现TensorFlow微信跳一跳的AI

最后,开始训练:

while True: 
 
  ………… 
 
  # 每训练100个保存一次 
  if train_count % 100 == 0: 
    saver_init.save(sess, "./save/mode.mod") 
 
  …………   
  
  sess.run(train_step, feed_dict={x: x_in, y_: y_out, keep_prob: 0.6, learn_rate: 0.00005})

训练所用数据是直接从采集好的文件中读取的,由于样本有限(目前采集了800张图和对应800个按压时间,在github上train_data文件夹里),并且学习率太大又会震荡,只能用较小学习率反复学习这些图片。

5.总结

1.样本的按压时间大都分布在300ms到900ms之间,刚开始训练的时候发现不论什么输入,输出都一直很谨慎的停留在600左右,还以为这种方法不可行。不过半个小时后再看发现已经有效果了,对于不同的输入,输出值差距开始变大了。所以…相信卷积网络的威力,多给它点耐心。

2.由于我自己最多玩到100多分,后面的数据没法采集到,所以当后面物体变得越来越小时,这个AI也会变得容易挂掉。理论上说让它自己探索不会有这个瓶颈,只是截屏时间实在难以忍受。

3.目前还是初级的版本,有很多可以优化的地方,比如说识别左上角的分数,如果某次跳跃得分较高,那么可以把这次的学习率增大;检测特殊物体,比如超市音乐盒,就停留几秒再进行下一次跳跃,等等。

下面是github地址,源码加注释总共不到300行:
https://github.com/zhanyongsheng/LetsJump

更多内容大家可以参考专题《微信跳一跳》进行学习。

Python 相关文章推荐
Python中使用scapy模拟数据包实现arp攻击、dns放大攻击例子
Oct 23 Python
浅谈Python中函数的参数传递
Jun 21 Python
python实现猜单词小游戏
May 22 Python
详解Python的hasattr() getattr() setattr() 函数使用方法
Jul 09 Python
对Python实现简单的API接口实例讲解
Dec 10 Python
在Python 不同级目录之间模块的调用方法
Jan 19 Python
我就是这样学习Python中的列表
Jun 02 Python
python实现LBP方法提取图像纹理特征实现分类的步骤
Jul 11 Python
django 2.2和mysql使用的常见问题
Jul 18 Python
python kafka 多线程消费者&手动提交实例
Dec 21 Python
Python列表切片常用操作实例解析
Mar 10 Python
Tensorflow tf.tile()的用法实例分析
May 22 Python
OpenCV-Python实现轮廓检测实例分析
Jan 05 #Python
django2 快速安装指南分享
Jan 05 #Python
Python实现改变与矩形橡胶的线条的颜色代码示例
Jan 05 #Python
用python制作游戏外挂
Jan 04 #Python
Python学习之Anaconda的使用与配置方法
Jan 04 #Python
Windows下Anaconda的安装和简单使用方法
Jan 04 #Python
Python+OpenCV让电脑帮你玩微信跳一跳
Jan 04 #Python
You might like
PHP也可以?成Shell Script
2006/10/09 PHP
snoopy PHP版的网络客户端提供本地下载
2008/04/15 PHP
php站内搜索关键词变亮的实现方法
2014/12/30 PHP
php查看网页源代码的方法
2015/03/13 PHP
jQuery EasyUI API 中文文档 - Panel面板
2011/09/30 Javascript
JS Array.slice 截取数组的实现方法
2016/01/02 Javascript
javascript弹性运动效果简单实现方法
2016/01/08 Javascript
如何使用AngularJs打造权限管理系统【简易型】
2016/05/09 Javascript
jquery插件canvaspercent.js实现百分比圆饼效果
2017/07/18 jQuery
Vue slot用法(小结)
2018/10/22 Javascript
vuejs2.0运用原生js实现简单拖拽元素功能
2020/08/21 Javascript
React Native中Mobx的使用方法详解
2018/12/04 Javascript
微信小程序代码上传、审核发布小程序
2019/05/18 Javascript
Jquery动态列功能完整实例
2019/08/30 jQuery
layui radio点击事件实现input显示和隐藏的例子
2019/09/02 Javascript
[42:25]EG vs Spirit Supermajor 败者组 BO3 第二场 6.4
2018/06/05 DOTA
python实现分析apache和nginx日志文件并输出访客ip列表的方法
2015/04/04 Python
Python安装第三方库及常见问题处理方法汇总
2016/09/13 Python
pyhton列表转换为数组的实例
2018/04/04 Python
对python3新增的byte类型详解
2018/12/04 Python
python配置grpc环境
2019/01/01 Python
使用Python正则表达式操作文本数据的方法
2019/05/14 Python
python 判断字符串中是否含有汉字或非汉字的实例
2019/07/15 Python
解决Python在导入文件时的FileNotFoundError问题
2020/04/10 Python
Django路由层URLconf作用及原理解析
2020/09/24 Python
css3旋转木马_动力节点Java学院整理
2017/07/12 HTML / CSS
HTML5 drag和drop具体使用详解
2021/01/18 HTML / CSS
Marks & Spencer爱尔兰:英国马莎百货
2016/04/20 全球购物
安德玛比利时官网:Under Armour比利时
2019/08/28 全球购物
值传递还是引用传递
2015/02/08 面试题
研究生毕业自我鉴定范文
2014/03/27 职场文书
工作批评与自我批评范文
2014/10/16 职场文书
四风问题自查自纠工作情况报告
2014/10/28 职场文书
教师党员自我评价范文
2015/03/04 职场文书
2016廉洁教育心得体会
2016/01/20 职场文书
比较node.js和Deno
2021/04/27 Javascript