跳到主要内容
AI教程

使用 JavaScript 构建、训练并评估进化式自动驾驶汽车

了解如何运行这个无依赖的 JavaScript 项目,检查其神经网络和驾驶规划器,在浏览器或 Node.js 中训练新的大脑,并评估它们在未见过的道路上的表现。

使用 JavaScript 构建、训练并评估进化式自动驾驶汽车

本项目的功能

self-driving-car 是一个使用原生 JavaScript 编写的紧凑型自动驾驶模拟器。一个小型神经网络通过进化学习,在弯曲的三车道高速公路上行驶,保持车道、为交通减速、打转向灯、超越较慢车辆,并在适当时返回右侧车道。

没有示例驾驶员展示正确行为。相反,每一代都会将一组神经网络送上同一条道路。行驶距离最远的网络会获得更高的适应度分数,并成为下一代的父代。

项目包含约 1,300 行 ES 模块代码,涵盖道路、车辆物理、感知、交通、神经网络、遗传算法、规划器、渲染和用户界面。项目没有运行时依赖,同一组模拟模块可以在浏览器和 Node.js 中运行。

你可以打开在线演示,观看预训练驾驶员、在浏览器中进化种群,或亲自控制车辆。

驾驶系统的工作方式

模拟器以每秒 60 步的固定速率运行。在每一步中,车辆都会扫描附近车道,将观测结果转换为 19 个神经网络输入,并生成两个输出:踏板指令和请求车道。

感知与神经网络

网络不会处理摄像头像素或原始距离射线,而是接收类似感知系统提供给驾驶规划器的结构化信息:

  • 左侧、当前和右侧车道是否存在。
  • 每条相关车道中前方和后方最近的车辆。
  • 每个间距缩小的速度。
  • 学习车辆的当前速度。
  • 未来 100 米内最急的弯道。
  • 车道变更规划器的当前状态。

网络架构为 19 · 12 · 8 · 2,使用 tanh 激活函数,包含 362 个权重。一个输出控制踏板,另一个选择车道:高于 +0.5 的值请求向左侧车道变更,低于 -0.5 的值请求向右侧车道变更。

规划器与车辆模型

神经网络决定何时以及向哪里移动,但不会直接控制转向。手写规划器会将车道请求转换为安全、平顺的操作。车辆会打转向灯 0.7 秒,检查目标车道,沿五次 S 曲线行驶 2.6 秒,并使用纯追踪转向来跟随规划路径。

如果另一辆车与本车并行,或即将进入本车盲区,规划器会继续打转向灯并等待间距扩大。在打灯阶段释放请求会取消该操作。

车辆本身使用国际单位制下的运动学自行车模型。其参数接近家用两厢车:车长 4.4 米,0 到 100 km/h 加速时间为 9.8 秒,最高速度为 115 km/h,最大制动能力为 8 m/s²。可用的弯道抓地力会限制车辆通过弯道的速度。

交通、适应度与进化

背景交通遵循智能驾驶员模型。车辆的期望速度在 61 至 94 km/h 之间,会从左侧超车,超车后返回右侧,变道前打转向灯,并对学习车辆做出反应。

适应度主要取决于行驶的米数。如果车辆发生碰撞,或被沿道路追赶而来的慢车队赶上,则会扣除 300 分。如果车辆处于左侧车道且右侧车道明显空闲,每停留一秒还会扣除四米。超车没有直接奖励;超车之所以有用,是因为它能让车辆行驶更远。

进化使用四项主要技术:

  • 精英保留:在命令行训练中,最优秀的四个网络会原样保留。
  • 锦标赛选择:更强的网络更有可能成为父代。
  • BLX-0.25 交叉:混合父代权重以创建后代。
  • 高斯突变:突变率和突变幅度以 40 代为半衰期逐渐衰减。

安装与本地设置

克隆仓库并启动本地静态服务器:

git clone https://github.com/Stxqq/self-driving-car.git
cd self-driving-car
npm run serve

serve 命令会在 5101 端口启动 Python HTTP 服务器。在浏览器中打开 http://localhost:5101。

无需安装任何软件包。项目可以由任意静态 Web 服务器托管,但直接通过 file:// 打开页面将无法运行,因为浏览器会限制该环境中的 ES 模块。

测试和命令行脚本需要 Node.js 22 或更高版本。使用以下命令运行测试套件:

npm test

使用浏览器界面

观看预训练驾驶员

使用观看模式,观察随附的网络在交通中驾驶。页面会显示其输入、输出、规划路线、车道变更状态和车辆统计数据。蓝色带状线表示规划器生成的路径。

手动驾驶

在驾驶模式中,你可以替代神经网络,同时保留相同的规划器。车辆开始时的巡航控制设定为 70 km/h。

  • 按住 ↑ 提高设定速度。
  • 按下 ↓ 制动并降低设定速度。
  • 按下 ← 请求向左变道。
  • 按下 → 请求向右变道。

网络卡片会继续显示预训练网络原本会采取的操作,因此这种模式适合将你的决策与它的决策进行比较。

在浏览器中训练

训练模式会用随机网络权重启动 60 辆汽车。在一个世代内,所有汽车共用同一条道路,交通会在前 15 个世代逐渐增加。早期轮次从 45 秒开始。当汽车坚持到终点时,后续轮次的时长会增加一半,直到达到五分钟的最长时长。

浏览器训练很快就能发现保持车道和跟车行为,但超车要困难得多。项目测试表明,随机初始化的种群通常在第 15 代之前每公里只能完成 0.1 到 0.5 次变道。原始预训练驾驶器需要约 170 个世代、每代 200 个个体,变道才开始产生收益。

如果你想基于随附大脑进行温和变异,而不是从随机权重开始,请选择基于预训练。在页面中训练的大脑可以导出为 JSON,之后再通过“导入”控件加载。

从命令行训练

命令行训练会以无头模式跨工作线程运行。以下示例使用 120 个网络的种群训练 10 个世代,并在三条带种子的道路上评估每个网络,每次运行 60 秒:

node scripts/train.mjs --generations 10 --population 120 --seeds 3 --seconds 60

默认情况下,生成的大脑会写入 runs/brain.json。这样可以将实验与随附网络 src/brains/pretrained.json 分开。

训练器会报告最佳距离和平均距离、存活汽车数量、变异率以及耗时等统计数据。由于规划器会让汽车保持在车道中央,第 0 代可能已经有汽车能够完成整个短时运行。因此,与单个最佳结果相比,观察种群平均值的上升通常更容易看出进展。

实用训练选项

  • --density 更改交通量。
  • --resume 从 --out 指定路径中的大脑开始,并使用更温和的变异。
  • --generations 控制进化轮次。
  • --population 控制每个世代评估的大脑数量。
  • --seeds 控制使用的道路种子数量。
  • --seconds 设置每次运行的时长。

随附大脑所使用的训练流程记录在 scripts/curriculum.sh 中。流程从全交通环境下的两分钟运行开始,逐步扩展到更多道路上的五分钟运行,最后以靠右行驶微调阶段结束。根据项目文档,该课程在一台 14 核笔记本电脑上耗时约一小时。

评估训练后的大脑

评估会在训练期间未使用过的确定性道路上测试大脑。使用道路种子列表运行评估器:

node scripts/evaluate.mjs --seeds 9001,9002,9003,9004,9005

输出会报告距离、耗时、平均速度、变道次数,以及每次运行是因时间耗尽还是汽车碰撞而结束。它还会计算平均距离和中位距离等汇总值。

若要评估导出的网络或新训练的网络,而不是随附大脑,请通过 --brain 传入其 JSON 文件:

node scripts/evaluate.mjs --brain runs/brain.json --seeds 9001,9002,9003

可以使用以下命令重新生成官方结果:

npm run evaluate -- --write

该命令会写入 scripts/results.json,浏览器界面也会读取此文件。

理解已发布的结果

随附的 362 权重网络在全交通环境下使用 30 个留出种子进行了五分钟测试。它达到了 6.90 km 的平均距离、7.23 km 的中位距离和 87 km/h 的平均速度。30 次运行中有 28 次在五分钟后仍在进行,汽车平均每公里变道 5.1 次。

项目将该系统与早期直接根据 14 个射线传感器进行转向的版本进行了比较。旧网络的平均距离为 4.05 km,平均速度为 56 km/h,30 次运行中有 20 次在五分钟后仍在进行。由于交通模型也发生了变化,这并不是受控基准测试,但它说明了为什么将学习到的决策与规划转向分离后,更容易发现超车行为。

网络选择踏板和目标车道;规划器负责信号灯、间距检查和平顺转向。

高级技巧

使用多个种子减少过拟合

在一条道路上表现良好的大脑,可能会在另一条道路上失败。增加训练种子的数量,并为验证和最终评估预留单独的种子。无头训练器会让每个大脑单独在其道路上评估,因为交通会对学习中的汽车作出反应;这样可以防止某个候选者的行为改变另一个候选者的得分。

先恢复训练,再从头开始

如果训练后的大脑已经能够保持车道并避开交通,请使用 --resume 或浏览器中的预训练选项。从随机权重开始适合观察从零开始的进化过程,但复杂的超车行为可能需要更多世代和更大的种群。

逐步提高难度

遵循代码库中的课程方法:从易于管理的运行时长开始,然后逐步增加时长、道路多样性和评估深度。更长的运行能更充分地证明驾驶的稳健性,但会让每个世代的成本更高。

保持确定性

该模拟精确到固定时间步长,具有相同种子和大脑的运行会产生相同的轨迹。速度控制会让每个渲染帧运行更多个 1/60 秒的模拟步长,而不是改变物理步长。这样就能加速训练,同时不改变结果。

了解项目中的修改位置

  • src/sim/ 包含道路、车辆、感知、规划器、交通、世界、神经网络和进化代码,且不依赖 DOM。
  • src/render/ 包含画布舞台、网络可视化、解剖结构显示和图表。
  • src/ui/ 包含观察、训练和驾驶会话、存储以及键盘处理。
  • src/brains/ 包含预训练网络。
  • scripts/ 包含训练、课程、评估和结果文件。
  • test/ 包含 Node.js 测试,包括留出回放检查。

结论

本项目展示了一个非常小的神经网络如何学习高层驾驶决策,同时由传统规划器处理精确转向和变道执行。请先运行浏览器演示,比较手动决策与神经网络决策,然后使用 Node.js 脚本训练和评估你自己的神经网络。其无依赖实现和确定性模拟也使其成为研究进化学习、车辆模型、交通行为和规划的实用代码库。