轻松实现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 相关文章推荐
django自定义Field实现一个字段存储以逗号分隔的字符串
Apr 27 Python
python实现斐波那契递归函数的方法
Sep 08 Python
零基础写python爬虫之神器正则表达式
Nov 06 Python
Django中实现点击图片链接强制直接下载的方法
May 14 Python
import的本质解析
Oct 30 Python
Python实现的井字棋(Tic Tac Toe)游戏示例
Jan 31 Python
python 创建一维的0向量实例
Dec 02 Python
logging level级别介绍
Feb 21 Python
浅谈pandas.cut与pandas.qcut的使用方法及区别
Mar 03 Python
python读取yaml文件后修改写入本地实例
Apr 27 Python
详解如何在PyCharm控制台中输出彩色文字和背景
Aug 17 Python
python删除csv文件的行列
Apr 06 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的安全策略
2006/10/09 PHP
利用PHP和AJAX创建RSS聚合器的代码
2007/03/13 PHP
php下intval()和(int)转换使用与区别
2008/07/18 PHP
PHP字符串的递增和递减示例介绍
2014/02/11 PHP
ThinkPHP自定义Redis处理SESSION的实现方法
2016/05/16 PHP
网上应用的一个不错common.js脚本
2007/08/08 Javascript
JS 自动安装exe程序
2008/11/30 Javascript
WEB 浏览器兼容 推荐收藏
2010/05/14 Javascript
ECMAScript 创建自己的js类库
2012/11/22 Javascript
JS打印gridview实现原理及代码
2013/02/05 Javascript
jQuery setTimeout()函数使用方法
2013/04/07 Javascript
js Select下拉列表框进行多选、移除、交换内容的具体实现方法
2013/08/13 Javascript
Javascript基础教程之argument 详解
2015/01/18 Javascript
javascript实现仿腾讯游戏选择
2015/05/14 Javascript
jQuery实现鼠标经过弹出提示信息的地图热点效果
2015/08/07 Javascript
使用jQuery判断浏览器滚动条位置的方法
2016/05/30 Javascript
原生js封装二级城市下拉列表的实现代码
2016/06/16 Javascript
Javascript 5种方法实现过滤删除前后所有空格
2016/06/22 Javascript
JS给Array添加是否包含字符串的简单方法
2016/10/29 Javascript
javascript中的深复制详解及实例分析
2016/12/29 Javascript
ztree实现权限横向显示功能
2017/05/20 Javascript
vue 实现特定条件下绑定事件
2019/11/09 Javascript
python进阶教程之动态类型详解
2014/08/30 Python
Python中使用支持向量机(SVM)算法
2017/12/26 Python
python实现诗歌游戏(类继承)
2019/02/26 Python
python Tensor和Array对比分析
2020/01/08 Python
Django的CVB实例详解
2020/02/10 Python
通过css3的filter滤镜改变png图片的颜色的示例代码
2020/05/06 HTML / CSS
在线购买澳大利亚设计师手拿包和奢华晚装手袋:Olga Berg
2019/03/20 全球购物
外贸实习生自荐信范文
2013/11/24 职场文书
教学质量评估实施方案
2014/03/17 职场文书
餐厅感恩节活动策划方案
2014/10/11 职场文书
员工离职通知函
2015/04/25 职场文书
请客吃饭开场白
2015/06/01 职场文书
创业计划书之餐饮
2019/09/02 职场文书
go类型转换及与C的类型转换方式
2021/05/05 Golang