如何让AI像NBA球星一样投篮?
消息来源:baojiabao.com 作者: 发布时间:2026-05-12

本文旨在使用 Unity3D 和 TensorFlow 来教 AI 怎样玩一个简单的游戏:把球投进篮筐。
游戏介绍
我们说的这个游戏里玩家只有一个主要目标:把球投进篮筐里。听起来貌似不难,但当你血液上涌、心跳加速、观众们呐喊时,嗯,想投进还是挺困难的。这是不是北美的经典游戏——篮球?不是,没听说过。我说的是 Midway 出品的经典街机游戏 NBA Jam。
如果你玩过 NBA Jam 或任何受到它启发的游戏(包括真实世界中的 NBA 大联盟,我记得应该是在 NBA Jam 之后诞生的),那你肯定知道从玩家的角度来看,投篮的原理是非常简单的。只需按住投球键,然后在正确的时机松开即可。但你有没有想过,从游戏的角度来看,投篮的过程是什么?球的弧线怎样确定?投球的力度多大?计算机怎样知道投球的角度?
聪明并且喜欢数学的你肯定能用纸笔得到答案,但笔者八年级的代数不及格……所以这种“聪明人”的答案就免了吧。我需要用更难的办法解决。
我不想用简单、快捷、有效的方式,用数学解决投篮的问题,而是想学一些简单的 TensorFlow,然后试着投篮就好了。
让我们开始吧!
我们需要一堆东西来完成这个项目。
Unity 模拟篮球和物理运动;
Node.js 和 TensorFlow.js 用于训练模型;
TensorFlowSharp 用于将模型通过 ML-Agents asset 包集成到 Unity 中;
tsjs-converter(https://github.com/tensorflow/tfjs-converter)将 TensorFlow.js 模型转换为图,以便在 Unity 使用;
Google Sheets(http://sheets.google.com/)用于将线性回归可视化。
你不懂某个技术也完全没关系!(其实我也不是完全懂!)我会尽力解释这些东西怎样合作的。使用这么多技术的缺点之一就是我没法详细解释每一种技术,但我会尽可能多地提供资源供大家学习。
下载项目
我不想手把手建立这个项目,所以我建议从 GitHub 上下载(https://github.com/abehaskins/tf-jam)代码,然后随着我的解释一步步做。
注意:你需要下载并导入 ML-Agents(https://github.com/Unity-Technologies/ml-agents)这个 Unity asset 包,才能在 C# 中使用TensorFlow。如果在 Unity 中看到任何 TensorFlow 找不到的错误,请确保你按照 Unity 的 TensorflowSharp 文档(https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Using-TensorFlow-Sharp-in-Unity.md)完成了设置。
目标是什么?
简单来说,我们希望的输出很简单。我们想要解决的问题是:如果投篮者与篮筐的距离为 X,那么就以力度 Y 投篮。就这么简单!我们不考虑瞄准或其他任何东西。我们只想找出要多大力气投篮才能命中。
如果你想知道怎样才能在 Unity 中制作更复杂的 AI,可以参考 Unity 的更完整的 ML-Agents(https://github.com/Unity-Technologies/ml-agents)项目。我这里介绍的项目本身非常简单易行,而且不一定使用了最佳实践(我也在学习呀!)。
我有限的关于 TensorFlow、机器学习和数学的知识并不是障碍。所以就把这个项目当做娱乐吧。
篮筐和篮球
我们已经说过这个项目的目标了——投篮。要把球投进篮筐里,首先我们需要一个篮筐,还有一个球。这就该 Unity 上场了。
如果你不熟悉 Unity,那只需要记住它是个游戏引擎,可以在任何平台上制作二维和三维游戏。它有内置的物理引擎,基本的三维建模,和一个非常好用的脚本运行时(Mono:https://www.mono-project.com/),所以我们可以利用它用 C# 来写游戏。
我不是艺术家,所以我简单地拖了几个立方体放在了场景里。
红色立方体显然是玩家。篮筐上有个看不见的触发器(https://unity3d.com/learn/tutorials/topics/physics/colliders-triggers),用于检测物体(篮球)通过篮筐。
在 Unity 编辑器中可以看到隐形的触发器的绿色边框。你可以看到我们放了两个触发器。这样可以保证我们只统计那些从顶部一直落到底部的球。
看一下 /Assets/BallController.cs(这个文件是每个篮球上的脚本)中的 OnTriggerEnter方法,会发现这两个触发器是同时使用的。
这个函数做了几件事情。首先,它确保顶部和底部的两个触发器都触发了,然后改变球的材质,这样我们就能直观地看到球进了篮筐,最后输出我们关 心的两个变数:distance 和 force.y。
投篮
打开 /Assets/BallSpawnerController.cs。这个脚本运行在投篮运动员上,负责生成篮球,并尝试投篮。看一下末尾处的 DoShoot() 方法。
在这段代码中,Instantiates 初始化一个新的篮球实例,然后设置投篮的力度,以及与篮筐的距离(这样后面输出就会更容易,如前一段代码所示)。
如果你还没关 /Assets/BallController.cs,你可以看看它的 Start() 方法。每次创建新的篮球时都会调用这个方法。
换句话说,我们建立一个新的球,给它一些力量,然后在 30 秒之后自动销毁这个球,因为我们要处理很多很多球,我们希望场景能干净一些。
试着运行一下项目,看看我们的全明星投篮运动员投得怎么样。点击 Unity 编辑器中的 Play 按钮,我们就会看到……
玩家(我们叫他“小红”)要向斯蒂芬·库里挑战了!
为啥小红投篮这么差?答案是 Assets/BallController.cs 中的一行,float force = 0.2f。这一行说每次投篮都应该是完全一样的力度。我们发现 Unity 忠实地执行了这个“完全一样”。同一个对象,同样的力度,不断重复,弹跳方式都完全一样。真棒。
当然这并不是我们希望的结果。不尝试新的东西就永远不可能成为詹姆斯。所以我们来尝试下吧。
随机投篮,收集数据
我们简单地改变力度为随机数,来引入一些随机的噪声。
这样投篮就是随机的了,我们终于看到有球命中的样子了,尽管需要花上好长一段时间才能命中。
小红很笨,他偶尔会投进,但完全是靠蒙。不过没关系。现在,任何投进的球都是我们需要的数据点。我们一会儿就会用到。
同时,我们不想从一个固定的位置投篮。我们希望小红能从任意距离投进篮筐(如果他运气足够好的话)。在 Assets/BallSpawnController.cs 中找到这几行,然后去掉 MoveToRandomDistance() 前面的注释。
运行之后,我们会发现小红充满活力地一边投篮一边跳来跳去。
随机运动和随机力度的组合能创建出非常有用的东西:数据。看看Unity的控制台,就会看到每次投进后都会显示出数据。
每次成功投进都会输出目前的投中次数、到篮筐的距离,和投篮的力度。这个模拟很慢,我们来加快一些。回到我们添加 MoveToRandomDistance()的地方,把 0.3f(两次投篮之间300毫秒延迟)改成 0.05f(50毫秒延迟)。
再点击 Play 按钮看看能投中多少。
这个训练不错!我们可以从后面的计数器看到,成功投中的次数大概是 6.4%。库里也做不到这么高吧?不过说起训练,我们从这里学到什么了吗?说好的 TensorFlow 呢?这有什么意思?好吧,TensorFlow 是下一步的十二。我们现在要把 Unity 中的数据拿出来,建立一个模型来预测力度。
预测,模型和回归
看看 Google Sheets 里收集到的数据。
在进入 TensorFlow 之前,我想先看看数据,所以我让 Unity 一直运行,直到小红投中 50 个球。这会在 Unity 项目的根目录下生成一个文件 successful_shots.csv。这是从 Unity 中保存下的投篮命中的原始数据!我让 Unity 导出这些数据,这样就可以在工作表中进行分析了。
.csv 文件只有三列:index、distance 和 force。我把这个文件(https://support.google.com/docs/answer/40608?co=GENIE.Platform%3DDesktop&hl=en)导入到 Google Sheets 中,然后建了个散点图(https://support.google.com/docs/answer/190718?hl=en)并画上趋势线(https://support.google.com/docs/answer/6075154?hl=en&co=GENIE.Platform%3DDesktop),这样就能大概知道数据的分布。
哇!看这个图。我是说,看图中的那条线。嗯,好吧,我承认,一开始我也不知道这条线是啥意思。来一步步看看。
这张图显示的是一系列点,Y 轴是投篮力度,X 轴是投篮距离。我们可以看到力度和距离之间有很明显的相关性(除了一些不正常的弹跳引起的随机异常之外)。
用正常的话说就是“TensorFlow很会处理这种数据”。
虽然这个例子很简单,但 TensorFlow 很棒的一点就是,如果有需要,我们可以用极其简单的代码做出非常复杂的模型。例如,在完整的游戏中,我们可以包含许多特征——如其他玩家的位置,以及他们以前的阻挡投篮的频率等,来确定玩家应该选择投篮还是传球。
用 TensorFlow.js 建立模型
用你喜欢的编辑器打开 tsjs/index.js 文件。这个文件跟 Unity 没关系,它只是用来根据 successful_shots.csv 的数据训练模型的。
下面是所有训练并保存模型的代码。
可以看到,代码没多少。首先从 .csv 文件中载入数据,然后建立一系列 X 和 Y 点(就像 Google Sheets 一样)。然后我们要求模型去“拟合”数据。之后把模型存下来供以后使用。
很可惜,TensorFlowSharp 要求的模型的格式跟 Tensorflow.js 能保存的格式不一样。所以我们得做一些转换才能把模型导入到 Unity。我用了一些工具来做这项工作。基本的流程就是把模型从 TensorFlow.js 格式转换成 Keras 格式,这样我们就能设置保存点(https://www.tensorflow.org/get_started/checkpoints),然后将Protobuf图形定义(https://www.tensorflow.org/extend/tool_developers/)合并进去,得到冻结的图形定义(https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/tools/freeze_graph.py),这样就能导入到 Unity 中了。
幸运的是,你可以跳过这一切,只需运行 tsjs/build.sh,如果一切正常,它会自动完成所有步骤,然后把冻结的模型导入到 Unity 中。
在 Unity 中,看看 Assets/BallSpawnController.cs 文件中的 GetForceFromTensorFlow(),看看怎样使用我们的模型。
在制作图形定义时,需要定义一个包含多个步骤的复杂系统。在这个例子中,我们把模型定义成单密集层(以及一个隐含的输入层),意思就是我们的模型接受一个输入,然后给出一个输出。
如果在 TensorFlow.js 中调用model.predict(https://js.tensorflow.org/api/0.11.7/#tf.Model.predict),它会自动把输入放到正确的输入图节点上,然后在计算完成之后,从正确的节点上拿到输出。但 TensorFlowSharp 的工作原理不同,需要你自己去根据节点名称操作节点。
知道这些之后,我们只需把输入转换成图期待的格式,然后把输出发回给小红即可。
游戏时间!
使用上面的系统,我根据模型做了几个不同的版本。下面是小红在一个根据 500 次命中数据训练过的模型上的投篮结果。
我们看到命中率提高了 10 倍!如果我们训练小红几个小时,收集一万条,或者十万条命中数据会怎样?肯定会让他提高更多!这个工作就留给读者了。
我强烈推荐你看看 GitHub 上的源代码
https://github.com/abehaskins/tf-jam
如果能超过 60% 的命中率,欢迎在 Twitter 上告诉我:
https://twitter.com/abeisgreat
(剧透:超过 60% 是完全可能的,回到本文开头看看那张图,小红能被训练得很好!)
原文:https://medium.com/tensorflow/tf-jam-shooting-hoops-with-machine-learning-7a96e1236c32?linkId=54634097
作者:TensorFlow
译者:弯月,责编:屠敏
相关文章
B站怎么炸崩了哔哩哔哩服务器今日怎么又炸挂了?技术团队公开早先原因2023-03-06 19:05:55
苹果iPhoneXS/XR手机电池容量续航最强?答案揭晓2023-02-19 15:09:54
华为荣耀两款机型起内讧:荣耀Play官方价格同价同配该如何选?2023-02-17 23:21:27
google谷歌原生系统Pixel3 XL/4/5/6 pro手机价格:刘海屏设计顶配版曾卖6900元2023-02-17 18:58:09
科大讯飞同传同声翻译软件造假 浮夸不能只罚酒三杯2023-02-17 18:46:15
华为mate20pro系列手机首发上市日期价格,屏幕和电池参数配置对比2023-02-17 18:42:49
小米MAX4手机上市日期首发价格 骁龙720打造大屏标准2023-02-17 18:37:22
武汉弘芯遣散!结局是总投资1280亿项目烂尾 光刻机抵押换钱2023-02-16 15:53:18
谷歌GoogleDrive网云盘下载改名“GoogleOne” 容量提升价格优惠2023-02-16 13:34:45
巴斯夫将裁员6000人 众化工巨头裁员潮再度引发关注2023-02-13 16:49:06
人手不足 韵达快递客服回应大量包裹派送异常没有收到2023-02-07 15:25:20
资本微念与李子柒销声匿迹谁赢? 微念公司退出子柒文化股东2023-02-02 09:24:38
三星GalaxyS8 S9 S10系统恢复出厂设置一直卡在正在检查更新怎么办2023-01-24 10:10:02
华为Mate50 RS保时捷最新款顶级手机2022多少钱?1.2万元售价外观图片吊打iPhone142023-01-06 20:27:09
芯片常见的CPU芯片封装方式 QFP和QFN封装的区别?2022-12-02 17:25:17
华为暂缓招聘停止社招了吗?官方回应来了2022-11-19 11:53:50
热血江湖手游:长枪铁甲 刚猛热血 正派枪客全攻略技能介绍大全2022-11-16 16:59:09
东京把玩了尼康微单相机Z7 尼康Z7现在卖多少钱?2022-10-22 15:21:55
苹果iPhone手机灵动岛大热:安卓灵动岛App应用下载安装量超100万次2022-10-03 22:13:45
苹果美版iPhone可以在中国保修 从哪看怎么查询iPhone的生产日期?2022-09-22 10:00:07










