赛道狂飙中国驿站|Trackmania in china|QQ群9890249

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 661|回复: 1

使用神经网络生成 TrackMania 赛道

[复制链接]
发表于 2022-12-25 14:14:31 | 显示全部楼层 |阅读模式
本帖最后由 hyp7617 于 2022-12-25 14:55 编辑

快速介绍


在这篇文章中,我将展示开发 TMTrackNN(TrackMania 的轨道生成器)的过程和细节。

不久前,当我开始学习机器学习时,我希望我的第一个项目不是玩具问题,也不是已经非常普遍的问题(例如图像分类)。因此,我开始研究为我最喜欢的赛车游戏——TrackMania 生成赛道。

下载地址:https://github.com/donadigo/TMTrackNN/releases

TrackMania 是一款赛车游戏,其目标是在给定的赛道/地图上以最快的速度行驶。除了战役轨迹,您还可以在地图编辑器中构建自己的轨迹。

曲目在风格、难度和长度上可能有很大差异。大多数竞争性赛道都涉及在整个赛道本身保持良好的流动性。赛道“风格”有很多种——最流行的风格之一是技术——它的特点是急转弯和许多漂移。

这是在地图编辑器中构建的此类轨道的示例:


数据是什么?


在进入细节之前,让我们先看看 TrackMania 地图是由什么组成的。

地图由一系列块组成,放置在 32x32x32 单位的可用区域上。

每个块都有它的三个主要属性:
·区块名称
·位置
·回转



街区名称代表街区类型——如果它是起点街区、转弯街区、终点街区等。体育场环境中大约有 300 种街区类型。

位置很简单——它由基于块在地图上的位置的 X、Y、Z 坐标组成。

旋转是 0-3 之间的数字,表示方块面向的方向:

0 - 北
1 - 东
2 - 南
3 - 西
所有这些数据都可以从 TrackMania 在保存曲目时保存的 .Gbx 文件中提取。在为那些 .Gbx 文件编写了整个解析器以提取此信息后,我继续并开始获取实际数据 — 轨道。

获取数据和预处理


这一步有时很难克服,对于 ML 项目来说甚至可能代价高昂。

在这种情况下,过程相对容易。方便的是,已经有一个名为Trackmania Exchange (TMX)的网站,它提供了大量由人们制作的曲目。曲目可以按风格和获奖次数分类。我很快写了一个Chrome 扩展来下载当前页面上的所有曲目,并下载了 ~3500 个 1 分钟的技术曲目。预处理后平均一条轨道有大约 100 个块。

预处理包括读取地图文件并从中提取块。preprocessing.py 使用 gbx.py 执行此操作,然后处理此信息并保存每个轨道的简化结构。下面是训练数据文件中一个条目的示例:
  1. ('1170108.Replay.Gbx’, [(16, 30, 5, 15, 1), (282, 30, 4, 15, 3), (6, 31, 5, 15, 1), (282, 31, 4, 15, 0), (6, 29, 5, 15, 2), (282, 29, 4, 15, 1), (6, 29, 5, 14, 3), (282, 29, 4, 14, 1), (6, 30, 5, 14, 1), (67, 30, 4, 12, 2), (265, 29, 5, 13, 1), …)
复制代码
元组的第一个元素是回放的文件名。第二个是元组列表,每个元组代表地图上的一个块。


可视化数据并陷入困境


我们已经收集了数据,将其预处理为简单的数据结构,现在是可视化数据的时候了。因为轨道是一系列块,所以我们需要一些简单的东西来显示序列的样子。visualization_pygame.py正是这样做的。


(每个图像代表序列中的一个放置块,X 块缺少图像,我懒得为这个可视化收集)
看着它,我们有第一个问题,实际上我花了最多的时间来克服。数据混乱。 该序列并不代表轨道要被驱动的实际路径,这就是我们希望数据看起来的样子。

序列中的第一个方块应该是左边的绿色起始方块,然后是黄色助推器等等,但这里不是这种情况。最终在未来,我们希望将这些数据输入 RNN,例如 LSTM,并一次生成一个块的轨迹。由于游戏保存地图的方式,很多方块是随机放置的,没有任何结构——方块列表是按照玩家放置它们的顺序保存的。因此,如果有人建造了一大块轨道,然后决定返回并“修复”轨道的某些部分,这很常见——这就是数据的样子。

我考虑了很长时间,并在此过程中做了很多实验——从应用深度优先搜索到尝试手动对块进行排序——这显然是一个疯狂的想法——一个会花费太多时间的想法。

相反,我想出了一个更好的主意——从已经可用的回放中提取这些信息。

回放


因为回放以相同的文件格式保存,但是是我的解析器没有处理的新信息——我必须添加支持来解析回放文件,这令人惊讶地没有那么困难并且……下载新数据。

现在,我没有下载原始地图文件,而是下载了回放文件,其中也恰好包含记录回放的地图。再一次,这也意味着我还需要添加一些代码来获取重放数据并跟踪所有块。我再次对它们进行了预处理,然后……成功了!

适当的顺序。一些块重叠,但这是在 3d 空间中的轨道上具有 2d 视图的副作用。

更多数据?


此时我们的数据开始有意义,序列是有序的,并以简单的格式保存。获取更多数据的一种方法是……抓取更多数据,或者使用数据增强——这通常应用于图像分类以提高模型的性能。

轨道本身不能移动(以后不会对训练数据产生影响)或“缩放”,但我们可以相对于地图随机旋转所有块。

例如,这条轨道:

原曲目。
变成:

地图旋转了 1 个基本旋转。
这使得我们的数据集大小增加了 4 倍,因为总共有四种可能的基本旋转。

模型架构


为了能够生成新的轨道,我们需要能够从轨道的可能延续中进行采样。目前 TMTrackNN 使用两个神经网络,一个用于预测给定一系列块的下一个块,第二个预测它在地图中的位置。

块模型接收一系列先前的块放置。每个先前的放置都包含一个单热编码块类型。在输出端,网络简单地预测下一个要放置的块类型。输出的损失函数是 softmax 函数。

位置模型接收有关先前块放置的完整序列信息。该模型输入了先前块的编码。每个编码都包含一个单热编码块类型、来自前一个块的归一化 X、Y、Z 向量,最后是对其旋转的单热编码。

因为我们想要预测序列中的下一个块,所以我们要求块模型预测下一个块类型。然后,我们要求位置模型通过将其编码为提供给位置模型的序列中的最后一个时间步来预测该块类型的位置。因此,序列中的最后一个块仅由块类型的单热编码组成,位置和旋转向量填充 -1。

位置模型的输出是两个特征:添加到最后一个块的位置以获得新块的新位置的向量和新块的旋转。它们的损失函数分别是均方误差和softmax。

模型目前在 Keras 中实现,以下是它们的架构:

·方块模型



·位置模型




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
 楼主| 发表于 2022-12-25 14:46:24 | 显示全部楼层
本帖最后由 hyp7617 于 2022-12-25 14:56 编辑

准备训练数据

为了能够将数据提供给我们的模型,我们需要对其进行归一化并将我们之前看到的块元组转换为向量。

为了对元组进行编码,我们将分别对每个特征进行编码,将它们全部连接起来并将其提供给网络。我们将对块 ID 进行一次性编码,使其14变为:
  1. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
复制代码
在编码位置之前,我们将转换为表示它相对于最后一个块的位置的向量,以便此块序列:
  1. [(14, 15, 5, 15, 0), (6, 14, 5, 16, 0)]
复制代码
变成这样:
  1. [(14, 0, 0, 0, 0), (6, -1, 0, 1, 0)]
复制代码
因为:
  1. [14, 5, 16] — [15, 5, 15] = [-1, 0, 1]
复制代码

最后,旋转也可以很容易地进行单热编码,因此旋转 0(北)变为:
  1. [1, 0, 0, 0]
复制代码

我们连接所有这些数组,例如我们最终的块编码(6, -1, 0, 1, 0)是:
  1. [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, …, 0.47, 0.55, 0.63, 1, 0, 0, 0]
复制代码
对于拆分序列,我使用了回溯为 20 的滑动窗口方法,这意味着序列中的每个块都将具有它的前 20 个块的序列作为输入。我还对短于上述 20 的序列使用了 0 填充。

位置模型的一个样本的最终输入如下所示:

  1. [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, …, 0.39, 0.75, 0.13, 0, 0, 1, 0]

  2. [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, …, 0.45, 0.55, 0.24, 0, 0, 0, 1]

  3. [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, …, 0.09, 0.60, 0.38, 0, 1, 0, 0]
  4. ...
复制代码
对于块模型,我们只需要块 ID 的第一个编码,因为它只预测接下来可能放置的块类型。



生成新曲目

生成新轨道时,我们首先在地图上随机放置一个起始块。我们对这个长度为 1 的序列进行编码,并将其提供给块模型。在输出中,我们得到了下一个要放置的块类型的概率。我们将温度应用于此输出,然后进行采样。

之后,我们再次对位置网络的输入进行编码,通过网络运行它们并接收实值位置向量和旋转概率向量。

之后,我们在代码中执行一系列额外检查(如果轨道不超过地图大小等)以确保输出在一定程度上是正确的(毕竟,网络并不总是完美的)并重复再次处理,直到我们以块为单位达到所需的轨道长度。

在赛道的尽头,我们需要放置一个终点块,这样我们才能真正完成它。这是通过省略下图中的整个“块预测”步骤并仅要求位置网络预测完成块的位置来完成的:



最后,我们将所有位置向量转换为实际地图坐标,以便保存轨迹供游戏读取。



结果

在训练网络并解决我遇到的更多问题之后,生成的轨道通常可以由人类驾驶并且类似于“技术”风格。以下是一些生成的曲目的截图:







结论
我确信还有很大的改进空间(数据清理、更好的模型、超参数调整等等)。这是我的第一个 ML 项目,我学到了很多东西。总的来说,我真的很高兴结果如何。我跳过了这篇文章中的一些细节,以免读得太长,但我希望这至少对您来说是一本有趣的读物。
查看GitHub 上的项目,如果您有机会成为 TrackMania 播放器,请查看发布页面以获取下载使用 TMTrackNN 生成的一些赛道

谢谢阅读!

原文出处https://donadigo.com/tmtracknn



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|赛道狂飙中国驿站|Trackmania in china|QQ群9890249 ( 蜀ICP备20016772号-1 )
赛道狂飙中国驿站 赛道狂飙中国驿站TM2020 点击这里给我发消息

川公网安备 51012202000677号

GMT+8, 2024-4-20 10:14 , Processed in 0.036099 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表