Linux 之父出席、干货分享、圆桌讨论,精彩尽在 OpenCloudOS 社区开放日,报名戳 了解详情
写点什么

以王者农药为例,入 tensorflow 之门

  • 2019 年 9 月 20 日
  • 本文字数:4596 字

    阅读完需:约 15 分钟

以王者农药为例,入tensorflow之门

本文写给想入门机器学习又苦于大学高数基本不会,高中数学基本忘光,就想入门中一窥的普通程序员们。能够帮助有工程经验的程序员(非算法工程师)快速上手 TensorFlow。

机器学习亦或是深度学习一直是大热话题,网上各式教程林林总总层出不穷。大多上来就讲 CNN、RNN、gradient descent。概念太多,可能一个简单的求导就会你让的想不起是怎么考上大学的。所以本文尽量少讲或者不讲知识点和理论零公式纯实战入门 Tensorflow 的 hello world,所以很多地方只会给结论不会讲为什么。


准备


正文

机器学习类似于要解一个数学题,题目的条件固定,求一个答案。解法可能非常非常多,但是只要做出来就能得分。我们今天要解的题目是王者荣耀中的攻击和最终伤害的关系。是每多增加一点攻击就多增加一点伤害吗?如果大家有 dota 类的 moba 游戏经验会知道,防御力的减伤效果并不是等比例增加的,下图是我网上随便找的 dota2 的物理伤害和护甲关系曲线。



大概意思就说你在出了一件物理防御大件的时候效果会非常明显,再出第二件第三件的时候效果不会有第一件那么明显。所以今天的题目就是,王者荣耀攻击和伤害会有类似关系吗?


接下来我们会做一个监督学习中的最简单最简单的线性回归( linear regression)来解这个问题。接下来分 3 步来分解这个问题。第一步,定义 model。第二步,定义 lost function。第三步,寻找最 match 的 model 的参数。这个步骤类似把大象装冰箱,或是开发个网站需要 MVC 分层,套路相对固定。


当然还有个定 0 步,收集数据。我这边使用姜子牙训练营模式站撸木桩韩信的方法收集了 30 条数据。收集的方法是不断的切换无特效的纯攻击装和升级。



攻击:289., 389., 409., 569., 649., 659., 739., 759., 779., 799., 819., 169., 264., 291., 311., 324., 331., 344., 351., 411., 431., 511., 591., 691., 791., 209.0,159.0, 169.0, 189.0, 891.


伤害:175., 236., 247., 348., 395., 397., 446., 460., 470., 486., 499., 102., 160., 175., 189., 196., 201., 208., 211., 250., 260., 310., 358., 420., 480., 126.0,96.0, 102.0, 114.0, 540.


下面贴上数据的分布可以看到还是比较均匀的,同时通过比较直观的感受也可以指导我们定义 model。



python 
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
复制代码


好了,我们现在开始一段一段的来写 tensorflow 的 hello world。


第一段 import3 个必要类库


1,numpy 一个数组处理库。


2,tensorflow 我们今天的主角。


3,matplotlib 绘图库用来最后验证结论。


python
# 再看这里先定义两个猜测存在的变量w、b,tf.Variable([初始值], dtype=变量类型),Variable就是tf中的定义变量的封装了
w = tf.Variable([1.0], dtype=tf.float64)
b = tf.Variable([0.0], dtype=tf.float64)
# 最后看这里我们再定义两个变量x(攻击)、y(伤害),因为我们这个地方还没导入数据,但是又要提前定义,所以tf为我们贴心的设计了placeholder用于解决这种情况
x = tf.placeholder(tf.float64)
y = tf.placeholder(tf.float64)
# 先看这里,我们先假设最终的答案是 伤害 = 攻击力 * w + b 其中w和b是我们猜测可能存在的影响变量
linear_model = x * w + b
复制代码


第二段的内容比较多,我把解释直接写在了注释里。


python
#training & testing data
atk_train = np.array( [289., 389., 409., 569., 649., 659., 739., 759., 779., 799., 819., 169., 264., 291., 311., 324., 331., 344., 351., 411., 431., 511., 591., 691., 791., 209.0]).astype(np.float32) / 100
damage_train = np.array( [175., 236., 247., 348., 395., 397., 446., 460., 470., 486., 499., 102., 160., 175., 189., 196., 201., 208., 211., 250., 260., 310., 358., 420., 480., 126.0]).astype(np.float32) / 100
atk_test = np.array([159.0, 169.0, 189.0, 891.]).astype(np.float32) / 100 damage_test = np.array([96.0, 102.0, 114.0, 540.]).astype(np.float32) / 100
复制代码


第三段导入了训练数据和验证数据,这个地方我们取了 4 条数据作为 testing data,剩下 26 条数据作为 training data。这里有个知识点,我们一般大概抽样 20%左右的数据用于验证模型正确性,80%的数据用于训练。这个比例当然不是绝对的,根据场景选择合适的。机器学习的模型都是训练出来的,这个不用再解释了非常好理解。注意到这里在最后我们所有的数据都一个除以 100 的操作,这里是因为我们在后续训练的过程中过大的数会导致 float 溢出,所以同意缩小 100 倍再进行后面的运算。


python
#loss function
loss = tf.reduce_sum(tf.square(linear_model - y))
#optimizer
optimizer = tf.train.GradientDescentOptimizer(0.001)
train = optimizer.minimize(loss)
#accuracy
correct_prediction = tf.abs(tf.cast(linear_model, tf.int32) - tf.cast(y, tf.int32)) < 2
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
复制代码


第四段代码会稍微难以理解,一般的机器学习教程可能这个地方要讲一个小时。


我们刚才定义了一个 linear_model 也给他初始化了一些参数,但是我们怎么样去衡量某个参数是否是好的呢?所以我们需要一个评分标准,这个标准就是 loss function。这个函数返回的数字越小那么意味着参数越优秀。


tf.reduce_sum(tf.square(linear_model - y))是什么意思呢,linear_model 是我们预测的答案,y 是标准答案。我们用(linear_model - y)的平方来表示是否最接近标准答案,很明显 0 是最完美的情况。然后 reduce_sum 是什么意思呢,是分别拿所有的 training data 的最终反馈一一相加。这就是我们定义的 loss function。


optimizer 是优化器,我们已经定义好了 model 和 loss,怎么样去优化参数呢,就需要一个优化器就是 optimizer,这个地方直接使用 tf 已经封装好的 tf.train.GradientDescentOptimizer(0.001),这个优化器用到的算法是梯度下降。这个算法是怎么来的,又有哪些问题,教程很多这里就略过不讲了,目标就就是知其然。


我们只需要知道 GradientDescentOptimizer 就是可以用来优化参数,0.001 是所谓的 learning rate 学习的速率,这里也是需要根据你的模型定义一个合适的值,过大过小都会出问题。


再下面一行我们定义真正要训练的目标,train = optimizer.minimize(loss)目标就是用 optimizer 求 loss 的最小的结果。


再后面的 accuracy 是算最终的正确率,这里我们把正确率定义为预测的伤害值在正负 2 就算预测准确。


python
#初始化所有变量
init = tf.global_variables_initializer()
#训练的时候,tf规定必须运行在一个session里。所以我们new一个session
sess = tf.Session()
并且初始化他
sess.run(init)
#开始训练,循环1W次
for i in range(100000): # 传入要训练的train, 和需要的训练数据
data = sess.run(train, {x: atk_train, y: damage_train})
复制代码


第五段代码,终于开始模型训练行数比较多又比较简单,所以也写在了注释里。


python
#evaluate training accuracy
curr_w, curr_b, curr_loss, curr_accuracy = sess.run([w, b, loss, accuracy], {x: atk_train, y: damage_train})
print("w: %s b: %s loss: %s accuracy: %s" % (curr_w, curr_b, curr_loss, curr_accuracy))


curr_w, curr_b, curr_loss, curr_accuracy = sess.run([w, b, loss, accuracy], {x: atk_test, y: damage_test})
print("w: %s b: %s loss: %s accuracy: %s" % (curr_w, curr_b, curr_loss, curr_accuracy))
复制代码


第六段代码,之前训练的每次循环都会改变我们最开始定义的 w 和 b 变量的值。一万次之后会发生什么呢?所以需要打印验证一下我们训练的结果。第一行输出传入的 training_data,第二行传入的是 testing data 已验证参数是否 overfitting。


output:
w: [ 0.6076637] b: [-0.00811569] loss: 0.00450731719102 accuracy: 1.0 w: [ 0.6076637] b: [-0.00811569] loss: 4.32571875675e-05 accuracy: 1.0
复制代码


后记

哇,我们可以看到最终 w 在约等于 0.6 b 约等于 0 的时候,预测的正确率无论在 testing set 上面还是在 training set 上到表现很好。我们可以得出结论 伤害=攻击力 x 0.6。这个结论和防御力的减伤关系完全不一样。大概意思就是你每加一点攻击就可以得到多一点的伤害。为什么会有这个 0.6 呢,是因为木桩韩信的减伤。所以 ADC 在对手肉盾减伤比例已经非常高的了的时候,需要出一件破甲弓(按百分比减少防御)效果会比再出一件输出装效果要好。如果对手没有肉择不需要再出破甲弓。


做到这里我们终于用机器学习的方法获得了打王者荣耀的小 tips!


如果有下期,我可能会尝试用 Logistic Regression 做一下王者荣耀中的英雄分类问题。


下面是完整可以运行代码


python 
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
#Model parameters
w = tf.Variable([1.0], dtype=tf.float64)
b = tf.Variable([0.0], dtype=tf.float64)
#Model input and output
x = tf.placeholder(tf.float64)
y = tf.placeholder(tf.float64) linear_model = x * w + b
#training data
atk_train = np.array( [289., 389., 409., 569., 649., 659., 739., 759., 779., 799., 819., 169., 264., 291., 311., 324., 331., 344., 351., 411., 431., 511., 591., 691., 791., 209.0]).astype(np.float32) / 100
damage_train = np.array( [175., 236., 247., 348., 395., 397., 446., 460., 470., 486., 499., 102., 160., 175., 189., 196., 201., 208., 211., 250., 260., 310., 358., 420., 480., 126.0]).astype(np.float32) / 100
atk_test = np.array([159.0, 169.0, 189.0, 891.]).astype(np.float32) / 100
damage_test = np.array([96.0, 102.0, 114.0, 540.]).astype(np.float32) / 100
#loss function
loss = tf.reduce_sum(tf.square(linear_model - y))
#optimizer
optimizer = tf.train.GradientDescentOptimizer(0.001)
train = optimizer.minimize(loss)
#accuracy
correct_prediction = tf.abs(tf.cast(linear_model, tf.int32) - tf.cast(y, tf.int32)) < 2
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
#training loop
init = tf.global_variables_initializer()
sess = tf.Session() sess.run(init)
for i in range(100000):
data = sess.run(train, {x: atk_train, y: damage_train})
#evaluate training accuracy
curr_w, curr_b, curr_loss, curr_accuracy = sess.run([w, b, loss, accuracy], {x: atk_train, y: damage_train})
print("w: %s b: %s loss: %s accuracy: %s" % (curr_w, curr_b, curr_loss, curr_accuracy))


curr_w, curr_b, curr_loss, curr_accuracy = sess.run([w, b, loss, accuracy], {x: atk_test, y: damage_test})
print("w: %s b: %s loss: %s accuracy: %s" % (curr_w, curr_b, curr_loss, curr_accuracy))
复制代码


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/d14Qip_NN2eWAelLpNViKg


2019 年 9 月 20 日 18:03615

评论

发布
暂无评论
发现更多内容

打破 Serverless 落地边界,阿里云 SAE 发布 5 大新特性

Serverless Devs

阿里云 Serverless 函数计算

PaddlePaddle:在 Serverless 架构上十几行代码实现 OCR 能力

Serverless Devs

AISWare AntDB亚信科技数据库产品特性解读——平滑弹性扩展(一)

亚信AntDB数据库

亚信科技

网易云音乐音视频算法的 Serverless 探索之路

Serverless Devs

阿里云 Serverless 算法 音视频

先行一步,7 大技术创新和突破,阿里云把 Serverless 领域的这些难题都给解了

Serverless Devs

阿里云 gpu VPC 函数计算

云原生体系下 Serverless 弹性探索与实践

Serverless Devs

云原生 无服务器 弹性计算

万圣节也是节,准备好Trick or Treat了么?

气气

话题讨论

Serverless 工程实践 | 自建 Apache OpenWhisk 平台

Serverless Devs

Python代码阅读(第47篇):从列表右边开始执行给定函数

Felix

Python 编程 Code Programing 阅读代码

永不落幕的世界智能盛会:天津市工业和信息化局与工商银行天津分行举行对接交流活动

InfoQ 天津

英特尔全面升级开发者专区(Developer Zone),携手开发者共塑科技未来

科技新消息

三轮融资笔笔过亿,来画如何实现弯道超车?

ToB行业头条

Android平台如何使用RSA算法进行加解密?

Changing Lin

10月日更

OCR+NLP 提取信息并分析,这个开源项目火了!

百度开发者中心

最佳实践 开源技术

北森CEO纪伟国:深耕HR SaaS,聚焦场景一体化

海比研究院

第 24 章 -《Linux 一学就会》- shell中色彩处理和awk使用技巧

学神来啦

Linux linux运维 linux云计算 linux一学就会

安全漏洞的复现与总结

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 漏洞挖掘

瑜伽CRM系统使老师再也不用教学分心

低代码小观

CRM 管理工具 CRM系统 瑜伽 瑜伽馆管理

WorkPlus数字化办公解决方案,打造企业高效协同生态!

WorkPlus Lite

直面Z级计算挑战,英特尔携手生态合作伙伴加速开发者工具和软件部署

科技新消息

阿里最新春招面经,腾讯/美团/字节1万道Java中高级面试题

收到请回复

Java 程序员 面试 职场 后端

Serverless 工程实践 | 零基础上手 Knative 应用

Serverless Devs

[2021年新鲜出炉]K8s工程师资料合辑,书籍推荐,面试题,精选文章,开源项目,PPT,视频,大厂资料

奔着腾讯去

golang Docker Kubernetes 容器 云原生

用建造者模式实现一个防SQL注入的ORM框架

Tom弹架构

一文详解从云计算到 Serverless

Serverless Devs

云计算 Serverless

【浪潮云说】直播间第十期将于今晚19:30准时开播

浪潮云

云计算

公关CRM软件助你培养长期客户关系

低代码小观

CRM 管理系统 管理工具 管理软件 公关

给JSONObject添加自定义遍历方法

FunTester

单元测试 Fastjson JSON库 spock FunTester

架构实战营毕业总结

maybe

如何成为一个更好的职业人?

石云升

学习笔记 职场经验 10月日更

递推算法与递推套路(手撕算法篇)

有道技术团队

学习 编程 算法

GPU容器虚拟化:用户态和内核态的技术和实践详解

GPU容器虚拟化:用户态和内核态的技术和实践详解

以王者农药为例,入tensorflow之门_文化 & 方法_苏冲_InfoQ精选文章