轻松实现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中bisect模块用法实例
Sep 25 Python
编写Python脚本批量下载DesktopNexus壁纸的教程
May 06 Python
黑科技 Python脚本帮你找出微信上删除你好友的人
Jan 07 Python
Python机器学习算法之k均值聚类(k-means)
Feb 23 Python
python单向循环链表原理与实现方法示例
Dec 03 Python
使用python turtle画高达
Jan 19 Python
django实现HttpResponse返回json数据为中文
Mar 27 Python
Python MOCK SERVER moco模拟接口测试过程解析
Apr 13 Python
基于Tensorflow读取MNIST数据集时网络超时的解决方式
Jun 22 Python
Python Tricks 使用 pywinrm 远程控制 Windows 主机的方法
Jul 21 Python
利用Python优雅的登录校园网
Oct 21 Python
Python爬虫基础讲解之请求
May 13 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
MySQL相关说明
2007/01/15 PHP
php文件服务实现虚拟挂载其他目录示例
2014/04/17 PHP
php文件上传原理与实现方法详解
2019/12/20 PHP
js一组验证函数
2008/12/20 Javascript
js 获取浏览器高度和宽度值(多浏览器)
2009/09/02 Javascript
jquery插件制作 自增长输入框实现代码
2012/08/17 jQuery
13 款最热门的 jQuery 图像 360 度旋转插件推荐
2014/12/09 Javascript
JavaScript实现弹出子窗口并传值给父窗口
2014/12/18 Javascript
前端微信支付js代码
2016/07/25 Javascript
常用原生js自定义函数总结
2016/11/20 Javascript
JS实现“隐藏与显示”功能(多种方法)
2016/11/24 Javascript
jQuery DateTimePicker 日期和时间插件示例
2017/01/22 Javascript
微信小程序 chooseImage选择图片或者拍照
2017/04/07 Javascript
AngularJS实现根据不同条件显示不同控件
2017/04/20 Javascript
jquery append与appendTo方法比较
2017/05/24 jQuery
Vue iview-admin框架二级菜单改为三级菜单的方法
2018/07/03 Javascript
JS表单验证插件之数据与逻辑分离操作实例分析【策略模式】
2020/05/01 Javascript
Django应用程序中如何发送电子邮件详解
2017/02/04 Python
python urllib爬取百度云连接的实例代码
2017/06/19 Python
Python3安装Pillow与PIL的方法
2019/04/03 Python
使用Python实现分别输出每个数组
2019/12/06 Python
Pandas时间序列:重采样及频率转换方式
2019/12/26 Python
Python递归实现打印多重列表代码
2020/02/27 Python
Django用数据库表反向生成models类知识点详解
2020/03/25 Python
Python3创建Django项目的几种方法(3种)
2020/06/03 Python
详解Python中list[::-1]的几种用法
2020/11/16 Python
Python 转移文件至云对象存储的方法
2021/02/07 Python
世界上最大的家庭自动化公司:Smarthome
2017/12/20 全球购物
Amcal中文官网:澳洲综合性连锁药房
2019/03/28 全球购物
GMP办公室主任岗位职责
2014/03/14 职场文书
高校教师岗位职责
2014/03/18 职场文书
厨师个人自我鉴定范文
2014/04/19 职场文书
妇女工作先进事迹
2014/08/17 职场文书
群众路线剖析材料
2014/09/30 职场文书
环境卫生工作汇报材料
2014/10/28 职场文书
mysql中如何用命令创建联合唯一索引
2022/04/20 MySQL