基于TensorFlow的端到端模仿学习:马里奥赛车自动驾驶入门实战

发布时间:2026/10/25 18:44:33
基于TensorFlow的端到端模仿学习:马里奥赛车自动驾驶入门实战 1. 项目缘起与整体设计思路1.1 为什么选马里奥赛车做自动驾驶入门很多人一听到“自动驾驶”四个字第一反应是激光雷达、多传感器融合、高精地图那一套重资产方案觉得离自己太远。但如果你只是想入门人工智能在自动驾驶方向的应用完全没必要一上来就啃那些工业级系统。马里奥赛车这类竞速游戏其实是一个被严重低估的练手场景。原因很简单它把自动驾驶的核心问题压缩到了一个极简的闭环里。你需要的输入只有屏幕画面输出只有方向、油门、刹车这几个连续或离散的控制量中间不需要考虑行人、红绿灯、复杂路口博弈。换句话说它是一个端到端模仿学习的绝佳沙盒——你喂给它“人怎么开”的数据它学着“自己怎么开”。我当初选这个项目就是因为它能让我在一台普通带独显的笔记本上把“数据采集→模型训练→实时推理→闭环控制”这条链路完整跑通一遍。这条链路跑通了你再去看那些真实的自动驾驶数据集和论文会发现底层逻辑是相通的只是规模和复杂度不同而已。这个项目适合谁适合已经会一点 Python、想找个具体项目把 TensorFlow 用起来的人适合上完人工智能导论课但不知道知识能干嘛的学生也适合想给自己的孩子演示“AI 到底怎么学会开车的”的家长。你不需要有深度学习调参经验但需要有一点耐心因为数据采集这一步会占用你不少时间。1.2 整体技术方案选型与考量整个项目的架构可以拆成四块游戏环境、数据采集、模型训练、实时推理控制。我逐一说说选型背后的逻辑。游戏环境这块我用的是一个开源的马里奥赛车模拟环境。选它的理由很实际它提供了 Python 接口能直接读取屏幕帧、能程序化地注入按键省去了我自己去截屏和模拟键盘的麻烦。如果你用的是其他竞速游戏理论上也能做但你需要自己解决“怎么拿到画面”和“怎么发按键”这两个工程问题入门阶段没必要给自己加难度。数据采集环节核心思路是人类示范。我用手柄或者键盘自己开若干圈程序在后台以固定频率同时记录“当前画面”和“我此刻的按键”。这里有个关键决策记录频率选多少我实测下来每秒 10 到 15 帧比较合适。太低了画面变化跨度大模型学不准太高了相邻帧几乎一样数据冗余严重训练还慢。我最后定的是每 100 毫秒采一帧也就是 10Hz。模型这块我用的是卷积神经网络。为什么不用循环网络或者强化学习因为模仿学习的本质是“看到什么画面就输出什么动作”这是一个典型的图像到向量的映射问题CNN 天生适合干这个。循环网络更适合处理时序依赖强的任务而在这个场景里单帧画面其实已经包含了足够的信息来判断该往哪打方向。强化学习当然也能做但它需要设计奖励函数、需要大量试错入门门槛高得多不适合作为第一个项目。推理控制环节我用了一个滑动窗口平滑的技巧。模型每一帧都会输出一个预测动作但如果你直接把每一帧的预测原样发给游戏车子会抖得厉害因为相邻帧的预测可能有细微跳变。我的做法是取最近 5 帧预测的众数对于离散动作或均值对于连续动作这样控制信号就稳多了。这个技巧在后面会详细讲。1.3 环境搭建TensorFlow 安装的坑与解法说到 TensorFlow 安装这可能是劝退新手的第一道坎。我见过太多人卡在版本不匹配、CUDA 装不上、import 报错这些问题上。这里我把我的安装路径完整说一遍。首先明确一点如果你没有 NVIDIA 显卡直接装 CPU 版就行别折腾 GPU。CPU 版训练这个项目虽然慢一点但完全能跑通。安装命令就一行pip install tensorflow但如果你有 NVIDIA 显卡想用 GPU 加速那就需要关注版本匹配。截至我写这篇东西的时候TensorFlow 2.5.0 是一个比较稳定的选择它对应的 CUDA 是 11.2cuDNN 是 8.1。你需要先确认自己的显卡驱动版本足够新然后按顺序装 CUDA Toolkit 和 cuDNN最后再装 TensorFlow。注意千万不要先装 TensorFlow 再装 CUDA因为 TensorFlow 安装时会检查 CUDA 是否存在顺序反了容易出问题。装完之后用这段代码验证 GPU 是否可用import tensorflow as tf print(tf.config.list_physical_devices(GPU))如果输出是一个非空列表说明 GPU 认到了。如果是空列表说明要么没装好要么驱动版本不对。这时候别急着重新装先检查nvidia-smi命令能不能正常输出如果能说明驱动没问题那就是 CUDA 或 cuDNN 的版本对不上。关于 PyTorch 和 TensorFlow 的区别顺便说一句我的看法。PyTorch 在学术界更流行动态图写起来更顺手TensorFlow 在工业部署上生态更成熟尤其是 TensorFlow Lite 和 TensorFlow Serving 这套工具链。这个项目用 TensorFlow主要是因为它对新手更友好一些Keras 高层 API 几行代码就能搭一个 CNN。你要是已经习惯 PyTorch用 PyTorch 复现这个项目也完全没问题逻辑是一样的。2. 核心细节解析与实操要点2.1 数据采集怎么采、采多少、采什么样数据采集这个环节看似简单其实决定了模型效果的上限。我踩过的坑基本都集中在这里。采多少我一开始只开了 5 圈大概采了 3000 多帧训练出来的模型在直道上还行一到弯道就冲出去。后来加到 20 圈接近 15000 帧效果明显好转。我的经验是至少 15 圈最好 30 圈而且要有意识地多跑弯道因为直道的数据模型很容易学会弯道才是难点。采什么样这里有个关键原则数据分布要覆盖你希望模型学会的所有场景。如果你采集的时候总是贴着内道走模型就学不会外道过弯如果你从来不刹车模型就不知道刹车是什么。所以采集的时候要刻意多样化有时候走内线有时候走外线有时候提前刹车有时候晚刹车。这样模型才能学到更鲁棒的控制策略。怎么采我写了一个采集脚本核心逻辑是一个循环读当前帧→存下来→读当前按键→存下来→等待 100 毫秒→重复。按键的存储格式要注意我用的是 one-hot 编码比如“左油门”是一个向量“右油门”是另一个向量。这样模型输出层用 softmax 激活就能直接对应到各个动作组合的概率。实操心得采集的时候最好把画面缩小再存。原始画面如果是 1280x720存下来又占空间又拖慢训练。我统一缩到 200x150 左右既保留了足够的视觉信息又大大降低了计算量。这个尺寸是我试出来的再小就看不清弯道了再大就浪费算力。还有一个细节画面要转灰度。彩色画面有三个通道灰度只有一个通道计算量直接降到三分之一而且对于判断赛道位置来说颜色信息其实没那么重要。我实测灰度图和彩色图的训练效果差别很小但训练速度快了很多。2.2 模型结构设计为什么这么搭模型结构这块我用的是一个比较经典的 CNN 架构参考了 NVIDIA 那篇著名的端到端自动驾驶论文的思路但做了简化。整体结构是这样的第一层是卷积层32 个 5x5 的卷积核步长 2激活函数用 ReLU。第二层也是卷积层64 个 5x5 的卷积核步长 2ReLU。第三层还是卷积层64 个 3x3 的卷积核步长 1ReLU。然后接一个 Flatten 层把特征图拉平再接一个 128 维的全连接层最后输出层的大小等于动作组合的数量。为什么这么设计卷积层的作用是提取画面里的空间特征比如赛道边缘、弯道方向。第一层用大步长是为了快速降维减少计算量后面的层用小步长是为了提取更精细的特征。全连接层的作用是把提取到的特征映射到具体的控制动作上。注意输出层不要用 softmax 如果做的是回归任务。我这里把动作离散化了所以用 softmax 输出各个动作的概率。如果你想做连续控制比如方向盘角度那输出层就不用激活函数损失函数也要换成均方误差。损失函数我用的是交叉熵优化器用 Adam学习率设 0.001。这些参数都是比较常规的选择没有特别调。训练的时候我留了 20% 的数据做验证集用来监控过拟合。如果验证集损失开始上升而训练集损失还在下降那就是过拟合了需要加 Dropout 或者减少模型复杂度。2.3 训练过程中的参数计算与调整训练轮数epoch设多少这个没有标准答案要看你的数据量和模型复杂度。我的做法是设一个比较大的轮数比如 50然后开 EarlyStopping当验证集损失连续 5 轮不下降就自动停。这样既不会欠拟合也不会浪费时间。Batch size 设多少我用的 32。这个值太小了训练不稳定太大了内存吃不消。32 是一个比较折中的选择。如果你显卡内存大可以试试 64 或 128训练会快一些。学习率要不要调我一开始用 0.001后来发现训练后期损失下降很慢就加了一个学习率衰减策略每 10 轮把学习率乘以 0.5。这样前期学得快后期学得细。这个技巧在大多数训练任务里都适用。实操心得训练的时候一定要把训练集和验证集的损失曲线画出来看。我见过太多人只看最终准确率不看曲线结果模型过拟合了都不知道。曲线图能告诉你很多信息如果两条曲线都还在下降说明可以继续训练如果训练集下降但验证集上升说明过拟合了如果两条曲线都平了说明训练到头了。3. 实操过程与核心环节实现3.1 完整实操流程概览整个项目的实操流程可以分成六步环境搭建→游戏环境接入→数据采集→模型训练→推理控制→效果调优。我按顺序把每一步的关键操作说清楚。第一步环境搭建前面已经讲过了核心就是装好 TensorFlow 和必要的依赖库。除了 TensorFlow你还需要装 numpy、opencv-python、pillow 这几个库分别用来做数值计算、图像处理和图像读取。第二步游戏环境接入你需要找到你所用模拟环境的 Python 接口文档搞清楚怎么读画面、怎么发按键。这一步因环境而异但通常都有现成的示例代码可以参考。第三步数据采集这是最耗时间的一步。我写了一个采集脚本运行之后你就开始开车脚本在后台默默记录。采集完成后你会得到一个包含画面和按键的数据集通常存成 numpy 的 .npy 文件或者 hdf5 文件。第四步模型训练把采集到的数据喂给模型训练若干轮保存效果最好的模型权重。第五步推理控制加载训练好的模型实时读取游戏画面预测动作发给游戏。第六步效果调优根据实际表现调整模型结构、训练参数、控制策略。3.2 数据采集脚本的关键实现数据采集脚本的核心是一个循环我把它简化成伪代码给你看import cv2 import numpy as np import time frames [] actions [] while True: frame get_screen() # 读取当前画面 frame cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 转灰度 frame cv2.resize(frame, (200, 150)) # 缩放 action get_current_key() # 读取当前按键 frames.append(frame) actions.append(action) time.sleep(0.1) # 等待100毫秒这里有几个细节要注意。get_screen()和get_current_key()这两个函数需要根据你的具体环境来实现。time.sleep(0.1)保证了采集频率是 10Hz这个值可以根据实际情况调整。采集完成后把 frames 和 actions 存成文件np.save(frames.npy, np.array(frames)) np.save(actions.npy, np.array(actions))注意采集的时候要确保画面和按键是同步的。如果你的读取画面和读取按键之间有延迟会导致标签错位模型学出来的东西就是错的。我的做法是先读画面再读按键两者之间的时间差控制在几毫秒以内。3.3 模型训练脚本的关键实现训练脚本的核心是搭模型、编译、fit。我把关键代码列出来import tensorflow as tf from tensorflow.keras import layers, models model models.Sequential([ layers.Conv2D(32, (5, 5), strides2, activationrelu, input_shape(150, 200, 1)), layers.Conv2D(64, (5, 5), strides2, activationrelu), layers.Conv2D(64, (3, 3), strides1, activationrelu), layers.Flatten(), layers.Dense(128, activationrelu), layers.Dense(num_actions, activationsoftmax) ]) model.compile(optimizertf.keras.optimizers.Adam(0.001), losscategorical_crossentropy, metrics[accuracy]) history model.fit(X_train, y_train, validation_split0.2, epochs50, batch_size32, callbacks[tf.keras.callbacks.EarlyStopping(patience5)])这段代码里num_actions是你的动作组合数量。input_shape要和你的画面尺寸匹配。validation_split0.2表示留 20% 做验证。训练完成后保存模型model.save(mario_kart_model.h5)3.4 推理控制脚本的关键实现推理控制脚本的核心是加载模型、读画面、预测、发按键model tf.keras.models.load_model(mario_kart_model.h5) action_history [] while True: frame get_screen() frame cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) frame cv2.resize(frame, (200, 150)) frame frame.reshape(1, 150, 200, 1) / 255.0 prediction model.predict(frame, verbose0) action np.argmax(prediction) action_history.append(action) if len(action_history) 5: action_history.pop(0) smoothed_action max(set(action_history), keyaction_history.count) send_key(smoothed_action) time.sleep(0.05)这里我用了滑动窗口平滑取最近 5 帧预测的众数作为最终动作。这个技巧能有效减少抖动。time.sleep(0.05)表示推理频率是 20Hz比采集频率高一些这样控制更及时。实操心得推理的时候画面预处理要和训练时完全一致。我见过有人训练时用了灰度缩放推理时忘了转灰度结果模型完全跑偏。这种低级错误一定要避免。4. 常见问题与排查技巧实录4.1 训练不收敛怎么办训练不收敛是最常见的问题表现是损失一直很高或者损失震荡不下降。排查思路是这样的先检查数据。把几张训练画面和对应的标签打印出来看看确认画面和按键是对应的。如果标签错了模型当然学不会。再检查数据量如果只有几百帧那肯定不够至少要几千帧。再检查模型。如果模型太复杂而数据太少会过拟合如果模型太简单会欠拟合。可以试试减少或增加层数。学习率也是一个常见问题太大了会震荡太小了会下降很慢。可以试试 0.0001 到 0.01 之间的几个值。最后检查预处理。画面有没有归一化标签有没有做 one-hot 编码这些细节都会影响训练。4.2 模型在直道上表现好但弯道冲出去这是最典型的问题根本原因是弯道数据不足。模型在直道上看到的画面多学得好弯道数据少学得差。解决办法很简单多采集弯道数据。你可以专门找一条弯道多的赛道反复跑把弯道数据补上来。另一个可能的原因是模型容量不够。如果模型太小它可能学不会弯道这种复杂的视觉模式。可以试试增加卷积层的通道数或者加一层全连接层。还有一个原因是控制延迟。如果你的推理频率太低模型看到弯道的时候已经来不及打方向了。可以试试提高推理频率或者用预测未来几帧的方式做提前量。4.3 车子抖动厉害怎么办抖动的原因是相邻帧的预测不一致。解决办法就是我前面说的滑动窗口平滑。窗口大小可以调我用的 5你可以试试 3 到 10 之间的值。窗口越大越平滑但响应也越慢。这是一个权衡。另一个减少抖动的方法是在训练数据里加入平滑。比如采集的时候如果连续几帧的按键是一样的就只保留一帧。这样模型学到的动作会更稳定。4.4 常见问题速查表问题现象可能原因排查方法解决办法损失不下降学习率不当打印损失曲线调整学习率损失震荡学习率太大观察损失波动减小学习率过拟合数据太少或模型太复杂对比训练/验证损失加数据或加Dropout欠拟合模型太简单训练损失也很高增加模型复杂度弯道冲出去弯道数据不足统计弯道数据量补采弯道数据抖动厉害预测不稳定观察连续预测滑动窗口平滑推理跑偏预处理不一致对比训练/推理预处理统一预处理流程GPU 用不了CUDA版本不匹配检查nvidia-smi重装匹配版本4.5 独家避坑技巧第一个技巧采集数据时开一个计时器。我一开始采集的时候没计时开了多少圈完全凭感觉结果数据量忽多忽少。后来我加了一个计时器每采集 5 分钟就提醒自己休息一下顺便检查数据量。这样采集过程更可控。第二个技巧训练时保存每个 epoch 的模型。不要只保存最终模型因为最终模型可能过拟合了。保存每个 epoch 的模型然后拿几个不同的模型去实测选效果最好的那个。我实测下来验证集损失最低的那个模型不一定实际表现最好有时候中间某个 epoch 的模型反而更稳。第三个技巧推理时加一个“紧急刹车”逻辑。如果模型输出的动作置信度很低比如最高概率不到 0.5说明模型不确定该怎么做这时候可以强制刹车或者保持上一帧的动作。这个逻辑能避免模型在陌生场景下做出离谱的操作。第四个技巧用多个赛道训练。如果你只用一条赛道训练模型会记住这条赛道的特征换一条赛道就废了。用多条赛道训练模型才能学到更通用的驾驶策略。这个道理和真实自动驾驶一样训练数据要多样化。5. 项目扩展与进阶方向5.1 从模仿学习到强化学习模仿学习的上限是你的驾驶水平你开得好模型就好你开得烂模型就烂。如果你想突破这个上限可以试试强化学习。强化学习的思路是让模型自己试错通过奖励函数来引导它学会更好的驾驶策略。具体到这个项目你可以设计这样的奖励每前进一米加一分撞墙扣十分跑完全程额外加一百分。然后让模型自己跑跑得多了它就能学会比人类更好的路线。当然强化学习的训练时间比模仿学习长得多可能需要跑几万圈才能收敛。5.2 从单帧到时序模型现在的模型只看单帧画面没有利用时序信息。如果你把连续几帧画面叠在一起作为输入模型就能感知到速度、加速度这些动态信息控制会更精准。具体做法是把输入从(150, 200, 1)改成(150, 200, 4)四个通道分别是最近四帧的灰度图。更进一步你可以用 LSTM 或 GRU 来处理时序。把 CNN 提取的特征按时间顺序喂给 LSTMLSTM 的输出再接全连接层。这样模型就能记住之前几帧的信息做出更合理的决策。5.3 从游戏到真实场景的迁移思考这个项目虽然是在游戏里做的但它的技术栈和真实自动驾驶是相通的。真实自动驾驶也是“感知→决策→控制”这个链路只是感知用的传感器更多摄像头、激光雷达、毫米波雷达决策用的模型更复杂多任务学习、规划算法控制更精细油门、刹车、转向的连续控制。如果你想往真实自动驾驶方向发展这个项目是一个很好的起点。你可以把它当作一个“最小可行系统”理解了它的每一个环节再去学真实的自动驾驶系统会容易很多。真实系统里那些复杂的部分本质上都是在解决这个最小系统里没有覆盖到的边缘情况。实操心得我在做完这个项目之后最大的收获不是学会了 TensorFlow而是理解了“数据质量决定模型上限”这个道理。你喂给模型什么样的数据模型就学成什么样。这个认知在我后来做其他 AI 项目的时候反复被验证。最后再分享一个小技巧如果你想让模型学得更快可以在训练前对数据做增强。比如把画面稍微左右平移、调整亮度、加一点噪声。这样相当于变相增加了数据量模型会更鲁棒。我实测下来加了数据增强之后模型在陌生赛道上的表现明显更好。这个技巧在数据量不足的时候特别有用你可以试试。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询