先に結論
- 自動運転AIチャレンジ2026 の End to End AI 部門に高専生1人のチーム KSK で出場し、決勝戦2位(準優勝)でした。選抜戦は組で1位、選抜戦と発表の総合2位で決勝戦に進みました。
- ハンドルを決めるモデルが見ているのは、2D LiDAR の距離750個だけです。自分の位置(GNSS)は使っていません。ネットワークの形は公式サンプルの TinyLidarNet(約15万パラメータ)のままで、重みは自分で学習しました。アクセルとブレーキは、モデルの外に置いた位置を使わないルールで決めています(LiDAR と車速を使います)。
- 最終モデルは、乱数で作ったコース80本の上で先生役の制御器をまねさせて作りました。本番コースの走行データは学習に入れていません。公式シミュレータ AWSIM では、単独6周を罰(接触などのペナルティ)0件・合計278.9秒で走りました。
- 一番苦労したのはモデルの学習ではなく「測り方」でした。舵の倍率を確かめていなかっただけで、開発途中のモデルの1周が93秒かかっていました(直すと同じモデルで43秒)。

左が AWSIM の走行画面、右が同じ瞬間の 2D LiDAR 750点とモデルの舵(最終モデル、手元の AWSIM で収録)。見えている壁の形が変わると舵も変わります。
同じ内容を図と走行映像で説明した動画(9分43秒)もあります。
30秒でわかる自動運転AIチャレンジと E2E 部門
自動運転AIチャレンジ2026(主催:自動車技術会)は、レーシングカートを自動運転のソフトウェアで走らせて競う大会です。全チームが出る Sim to Real 部門は、公式シミュレータ AWSIM と自動運転ソフトウェアの Autoware で制御を作り、勝ち上がると実機のカートで走ります。End to End AI 部門(以下 E2E 部門)は、センサーの入力から少なくともハンドル操作(横方向の制御)までを学習モデルで行う部門で、走行はすべてシミュレータの上です。E2E 部門に出るチームは Sim to Real 部門にも出る決まりで、私は Sim to Real 部門では SIM 選抜戦で敗退しました(そちらは別の動画で話しています)。
E2E 部門の決まりのうち、設計に効いたものを表にしました(公式ドキュメントの End to End 部門の説明、Sim to Real 部門の説明(罰の決まり)、SIM 決勝特設ページ から)。
| 項目 | 内容 |
|---|---|
| 使えるセンサー | カメラ、LiDAR、舵角、車輪の回転(車速)、ギア |
| 使えないもの | GNSS(自分の位置)など Sim to Real 部門で使えたセンサー |
| 学習モデルの担当 | 入力から横方向の制御(ハンドル)まで |
| 罰(ペナルティ) | 壁や他の車に接触したときなどに科され、一定の時間、速度が 5 km/h に制限される(Sim to Real 部門と同じ)。この記事の「罰の合計○秒」は、公式の結果ファイルに出る罰が続いた時間の合計で、タイムに足される秒数ではない |
| 予選 | 取り組みのスライドと走行動画を審査。上位16チームが SIM 決勝へ |
| SIM 決勝 | 4台同時・6周のレース。選抜戦の走行と書類・プレゼンの総合で4チームが決勝戦へ。決勝戦は完走順だけで順位が決まる |
公式の予選の案内には「入力から横方向制御まではMLで行うことを前提」と書かれています。そこで私は、ハンドル(横方向)は学習モデル、アクセルとブレーキ(縦方向)は自分の位置を使わないルール、と役割を分けました。
関連する動画と記事です。
| 内容 | リンク |
|---|---|
| E2E 部門の解説動画(9:43) | https://youtu.be/S32a94bqrxg |
| Sim to Real 部門の解説動画:MPC と Pure Pursuit(13:33) | https://youtu.be/uafowqYt4PU |
| Sim to Real 部門のリール(86秒) | https://youtube.com/shorts/QVWpWwyTFUA |
結果:選抜戦は組で1位、総合2位で決勝戦へ、決勝戦2位
SIM 決勝は 2026年9月19日に東京国際交流館で行われました。E2E 部門は、4台ずつ走る選抜戦の走りと、書類・5分間のプレゼンの総合点で上位4チームが決勝戦に進みます。KSK は選抜戦の自分の組で1位、選抜戦と発表の総合2位で決勝戦に進み、決勝戦は2位(準優勝)でした。

選抜戦のプレゼンで会場の画面に映った発表スライド。発表タイトルは「コース専用の教師からコース非依存の蒸留へ」(スライド上の所属と名前の部分は消しています)。
会場では持参した PC で Autoware 側だけを起動し、AWSIM とスタートは運営が操作します。持ち込んだのは最終モデルと、この記事の後半で説明するモデルの外の安全装置(ルール)です。当日のレースの記録は手元に無いので、この記事の数字はすべて手元の AWSIM と自作シミュレータで測った値です。社会人のチームが多いと感じた大会で、高専生1人のチームで準優勝できたのは素直にうれしかったです。
全体の流れ
先に全体を1枚にまとめます。学習は自作の GPU シミュレータの上で行い、採用するかどうかは本番と同じシミュレータ AWSIM で決めました。
モデルの入力を LiDAR だけにした理由
モデルの入力にはカメラを使わず、2D LiDAR(レーザーで周りまでの距離を測るセンサー)だけを使いました(車速はモデルの外のルールでだけ使います)。AWSIM で測った諸元は次のとおりです。
| 2D LiDAR | カメラ(公式サンプル PilotNet の入力) | |
|---|---|---|
| モデルに入る数 | 750 | 66×200×3 = 39,600 |
| 届く頻度 | 20回/秒 | 9.52回/秒 |
入力は約50分の1で、届く頻度は2倍以上です。前方およそ180度を0.24度おきに測り、25 m まで届きます。隣にカートを止めて撮り比べると、750本のうち126本が手前で返ってきました。他の車も「壁と同じように近い点のかたまり」として見えるので、他車を避けるためにカメラを足す必要はないと判断しました。
一番の理由は、決勝間近まで、E2E部門でもサーキットで実機走行があると想定していました。
そのため、カメラ入力は不安定だと考えて、不採用としました。
ロボコンの経験的に、LiDARだけでいけそうだなとある程度わかっていたので、初期からLiDARのみ採用しました。
モデル:公式サンプルの TinyLidarNet の形を変えずに使う

TinyLidarNet の構成。1次元の畳み込み5層と全結合4層で、パラメータは150,286個です。
モデルは、大会の公式サンプルに入っている TinyLidarNet(元論文 arXiv:2410.07447)です。750個の距離を畳み込み(隣り合う角度のかたまりを見る層)5層で読み、全結合4層で「加速度」と「舵」の2つを出します。私は舵だけを使いました。
ネットワークの形は一切変えていません(重みは自分で学習しました)。モデルに入れるのは LiDAR のスキャンだけで、時刻・自分の位置・周回数・カメラは入れていません。車速は、モデルの外に置いたルール(後で説明する減速ガードと壁からの後退)でだけ使います。工夫したのは「何を学ばせるか」と「モデルの周りに何を置くか」の2つです。
最初の版:本番コース専用の先生をまねた
学び方は蒸留(distillation)です。うまく走れる「先生」を走らせて、その瞬間の LiDAR の見え方と先生の舵を組にして記録し、生徒(TinyLidarNet)が LiDAR だけから同じ舵を出せるように学ばせます。先生は位置を使ってよく、位置を使うのはデータを集めるときだけです。
最初の版(以下「初期版」)の先生は、私が Sim to Real 部門用に作った制御器でした。自分の位置と地図、コース専用の走行ラインや壁までの余裕のデータを使って走ります。データ集めのときだけ AWSIM で位置のセンサーを残し、本番コースを走らせて記録しました。
初期版は、本番コースではとてもよく走りました。
| 初期版の成績(AWSIM・本番コース・単独) | 最速ラップ | 平均ラップ |
|---|---|---|
| 先生(自分の位置を使う。10分間の連続走行) | 39.65秒 | 40.25秒 |
| 生徒(LiDAR だけ。スタート位置を変えた6周×5本、5本とも完走) | 39.77秒 | 40.85秒 |
最速ラップの差は0.3%です。ところが、別のコース(kashiwanoha)に置くと、その場で止まったまま動きませんでした。後で説明する自作シミュレータで、乱数で作った初めて見るコースに256台を置くと、66.4% がぶつかりました(ぶつからなかった台が走ったのは130.5 m)。先生が本番コースでしか走れないので、学習データも本番コースだけになり、生徒もそのコース専用の運転を覚えていたのだと考えています。
寄り道:公式サンプルの出力は1.37に届かない

初期版のために本番コースで収録した教師データ(全48,960サンプル。学習にはこの一部を使用)の加速度ラベルは、すべて1.37 m/s² でした。
公式サンプルの出力層は tanh(出力を −1〜+1 に収める関数)なので、先生の加速度 1.37 m/s²(配布された車両設定の最大加速度)には学習でどうやっても届きません。公式サンプルの説明にある「アクセルの学習がうまく行かなかった」の理由の一つは、これかもしれません。ほかにも、推論側の固定加速度の既定値が0.6だったこと、距離を30 m で割って正規化しているのにセンサーは25 m までしか測れないことに気づきました。詳しくは公式サンプル TinyLidarNet で詰まったところ(近日公開)の記事にまとめます。私はモデルの加速度出力を使わず、アクセルは一定、ブレーキはルールで作りました。
方針転換:本番コースの走行データを学習に入れない
ここで方針を変えました。本番コースの走行データは学習に入れない、そして他の車が写ったスキャンで学習し直すの2つです。汎化できていないモデルは、本番コースの成績がよくても、その理由が「コースを覚えたから」なのか区別できないからです。
最初に手元のコースの置き場を調べると、12か所の置き場のうち10か所に本番コースのファイルがありました(本番コース専用の置き場と評価専用の置き場を含みます。学習に使う置き場では5か所)。学習用のスクリプトはファイル名順に先頭から使うので、気をつけるだけでは防げません。そこで、学習の入口で名前を見て弾くようにしました。
BANNED_TRACK_KEYS = ("city", "kashiwanoha")
# (中略)
tracks = sorted(Path(args.tracks_dir).glob("*.npz"))
# (中略)
banned = [t for t in tracks if any(k in t.stem.lower() for k in BANNED_TRACK_KEYS)]
if banned:
print(f"[除外] 本番コースを学習から外した: {[t.name for t in banned]}")
tracks = [t for t in tracks if t not in banned]
先生のデータを作るスクリプトにも、本番コースを渡すとエラーで止まる入口を付けました。
ただし、本番コースをまったく見ずに作ったわけではありません。自作シム上の本番コースでの完走率を、モデル・先生の設定・コースの本数を選ぶ指標に使いました。記事を書く段階で調べ直すと、学習中にモデルを選ぶための検証コースにも、本番コースが1本入っていたと見られます。経緯は乱数コースと他車の学習の記事(近日公開)に書きます。ランダムコースを作る範囲(曲がりのきつさなど)も本番コースの寸法に合わせ、後で出てくる舵の倍率0.80と減速ガードの0.45秒は、AWSIM の本番コースを走らせて決めています。「本番コースの走行データを学習に入れていない」が正確な言い方です。
自作 GPU シミュレータとランダムコース80本
AWSIM は1回に最大4台、しかも実際の時間でしか進みません。そこで、PyTorch で多数の車を一度に動かす簡単なシミュレータを自作しました(以下「自作シム」)。Sim to Real 部門のために作ったカートのシミュレータに、GPU でまとめて計算する 2D LiDAR、ランダムなコースの生成、E2E 用の環境、先生役の Pure Pursuit を足したものです。
256台を同時に走らせたときの処理量は、合計で毎秒1万3100ステップでした。AWSIM 1台(毎秒20ステップ)の約655倍です。ただしこれは全台の合計の処理量で、学習全体が655倍速くなるという意味ではありません。

最終モデルの学習に使ったランダム生成コース80本(右。学習スクリプトの選び方から特定)と、走行データを学習に入れていない本番コース(左)。
先生は Pure Pursuit(先の1点を目がけて舵を切る、古典的な経路追従の方法)にしました。コースの中心線さえあれば走れるので、コースごとの準備が要りません。さらに、半径0.85 m の円で表した他車を3台、中心線に沿って一定の速さで走らせ、先生にも避けさせました。先生の避け方は3回作り直しました。避けない先生では、他車のいる条件で完走35.2%・他車との接触83台でしたが、最後の版は完走99.2%・他車との接触0台になりました。

自作シムで最終モデルを、学習の80本に入っていないランダムコースで走らせたところ(学習スクリプトの選び方から特定)。右の橙の点は LiDAR が当たった位置、灰色の円は他車です。このシムには減速ガードなどのルールは入れていません。
BC と DAgger
学習は2段階です。まずBC(Behavior Cloning)で、先生の舵をそのまままねます。先生の走りだけをまねると、生徒が少しずれた瞬間に見たことのない景色になり、ずれがどんどん広がります。そこでDAggerで、生徒を走らせてずれた場面を集め、「先生ならここでどう切るか」を聞き直してデータに足し、学び直します。本番で走るのは生徒だけです。
最終モデルの DAgger は2回です。自作シムの検証コースで45秒間ぶつからなかった割合は、BC 92.2% → 1回目 92.8% → 2回目 92.2% で、いちばん悪いコースの値が最も良かった2回目を採用しました。回数は多ければよいわけではなく、開発途中の版で4回まで回したときは、85.0 → 90.1 → 90.7 → 84.6 → 83.7% と3回目から下がりました。
コースの本数の結論は撤回した
最終モデルの学習コースが80本なのは、開発中の判断の結果です。他車を入れていなかった頃は、コースの本数を増やしても自作シム上の本番コースの完走率が変わらなかったので、本数を増やすのを一度あきらめました。その後、他車3台を入れて測ると本数で大きな差が出たように見えたので、開発ログには「他車ありではコースの本数が効いた」と書き、80本を選びました。
記事にするために同じ重みで測り直すと、他車の有無で値はほとんど変わらず、同じ40本で学習した別のモデルどうしでも 81〜98% と開きました(自作シム・本番コースで45秒間ぶつからなかった割合)。学習1回ずつの値では本数の効果は言えないので、この結論は撤回しました。80本が最適だという根拠もありません。測り直しの手順と値は乱数コースと他車の学習の記事(近日公開)にまとめます。
モデルの外に置いた安全装置
ハンドルはモデルが出しますが、それだけでは本番で困る場面がありました。そこで、位置を使わないルールをモデルの外に4つ置きました。見るのは LiDAR と車輪の回転(車速)だけです。
| 部品 | 中身 |
|---|---|
| 舵の倍率 | モデルの舵出力に0.80を掛けてから指令にする |
| 一定の加速 | 1.37 m/s² で踏み続ける |
| 減速ガード | 前方 ±10° の一番近い距離 ÷ 車速 が0.45秒を切ったらブレーキ |
| 壁からの後退 | 車速 0.8 m/s 未満が1秒続いたら、左右の空きを見て舵を切りながら2秒バック |
減速ガードは、前方の一番近い距離 $d$ を車速 $v$ で割った「ぶつかるまでの時間の目安」(TTC)を使います。
\mathrm{TTC} = \frac{d}{\max(|v|,\ 0.3)},\qquad a = -2.0\left(1-\frac{\mathrm{TTC}}{0.45}\right)\quad(\mathrm{TTC} < 0.45\ \text{のとき})
0.45秒は、1台だけで普通に走ったときの TTC の分布(初期版の単独走行で、下位1%が0.33秒、下位5%が0.44秒、中央値0.87秒)から選んだ値です。単独走行でも時間の5%ほどは0.45秒を下回るので、ふだんも作動はします。ただ、しきい値の近くではブレーキは式のとおりごく弱く、単独のタイムはほぼ変わりませんでした(初期版の単独6周で、最速ラップはガードなし40.57秒、ガードあり40.35秒)。
steer *= self.steer_scale
# (中略)
# 曲がりきれていないなら落とす。復帰より先に評価して、復帰中は触らない。
if bg_on:
front = self._sector_min(ranges, angles, -self.bg_half, self.bg_half, rmax)
ttc = front / max(abs(self._velocity), 0.3)
if ttc < self.bg_ttc:
accel = -self.bg_brake * (1.0 - ttc / self.bg_ttc)
壁からの後退は、自分の位置が分からないので、左右どちらの壁が近いかで向きを決めます。バックのときに詰まっている側へ舵を切ると、車の鼻先は反対側(空いている側)へ逃げます。1秒下がっても前が開かなければ舵を逆にします。
elif now - self._slow_since >= self.rec_stuck_s:
left = self._sector_min(ranges, angles, 25, 90, rmax)
right = self._sector_min(ranges, angles, -90, -25, rmax)
# 詰まっている側へ舵を切る = 鼻先は反対側へ逃げる
self._rec_sign = 1.0 if left < right else -1.0

最終モデルが、4台で走らせたときの1周目に壁に当たり、自分でバックして走りに戻るところ(手元の AWSIM。4台とも自分のモデル)。
効き目は、AWSIM で4台×3本(のべ12台)を走らせて比べました。この2つの比較は、本番コースで学習した初期版で測った値で、最終モデルでは測り直していません。
- 壁からの後退:なしでは、ゴールできなかった5台がすべて0周で終わっていました(壁に当たったまま押し続けるため)。ありにすると、ゴールできなかった4台も5周まで走れました。完走の台数(7/12→8/12)より、0周で終わるか5周走れるかの差のほうが大きいです。
- 減速ガード:速さの違う車を混ぜた4台(初期版2台と、自作シムで学習した開発途中の版2台)で比べると、完走が8/12台から12/12台に、罰の合計が558.4秒から190.1秒に減りました。車どうしの接触は17回から6回に減りましたが、0にはなりませんでした。

減速ガードのあり・なし(初期版2台と開発途中の版2台の混走、4台×3本)。
全車が同じモデルだと、追いつく場面が起きないので、減速ガードは「少し遅くなるだけ」に見えていました。速さの違う車を混ぜて、はじめて差が見えました。
sim-to-sim の罠:自作シムの数字を信じすぎた
ここが一番時間を使ったところです。自作シムでの良し悪しが、そのまま AWSIM での良し悪しになりませんでした。
舵の倍率を一度も確かめていなかった

同じ重み(先生を MPC に替えて蒸留した中間版。MPC は、先の動きを予測して操作を選ぶ制御)で、舵の倍率だけを変えて AWSIM を1台で走らせた最速ラップ。
自作シムで学んだ開発途中のモデルを AWSIM に載せると、1周の最速が93.04秒でした。原因は、モデルの出力を舵角に直す倍率です。0.448 という値を自作シムの定数から計算して使っていましたが、AWSIM で合っているか確かめたことはありませんでした。倍率を振って測り直すと、0.80 で43.02秒。同じモデルが2倍以上速くなりました。この倍率で取った過去の AWSIM での比較は、すべて疑わしくなりました(測り直すと結論が変わらないものもありました)。
「現実っぽい」相手を入れたら壊れた
AWSIM の相手は罰(5 km/h の速度制限)で急に遅くなるはずだと考え、自作シムの他車に「ときどき5 km/h まで落ちる」「横に揺れる」動きを入れて学習しました。自作シムでは当時の最高の90.2% が出ましたが、AWSIM の4台走行では4台とも完走できず、罰は23件でした。後で相手役の車(自分の開発途中の版のモデル)の速さを測ると、2 m/s 未満だった時間は2.4%で、しかもスタートのときだけでした。私が入れた25%は、実際の10倍以上だったわけです。等速で走る円の他車のほうが、もとから実際に近かったことになります。
同じ日に、自作シムでの順位が AWSIM で逆転したことが4回ありました。それからは、自作シムの数字は自作シムの中の比較だけに使い、採用するかどうかは必ず AWSIM で決めています。
4台で走ると完走しない車が出た:大きな原因は CPU だった
4台で走らせると、なぜか完走しない車が出ました。自作シムで学習した開発途中の版は、AWSIM の4台走行で1台も完走しませんでした。学習が足りないと思い込み、先生を替えたりデータの混ぜ方を変えたりして丸一日使いましたが、AWSIM の4台走行では変わりませんでした。
大きな原因はモデルではなく、NumPy が行列の計算に使うライブラリ(BLAS)のスレッド数でした。推論ノードは NumPy で書いていて、既定では1台がコア数と同じ24本のスレッドを使おうとします。4台ぶんが24コアを取り合っていました。
import os
# BLAS のスレッド数を絞る。numpy を import する前でないと効かない。
# (中略)
_TH = os.environ.get('E2E_NUM_THREADS') or '1'
for _v in ('OMP_NUM_THREADS', 'OPENBLAS_NUM_THREADS', 'MKL_NUM_THREADS',
'NUMEXPR_NUM_THREADS', 'VECLIB_MAXIMUM_THREADS'):
os.environ[_v] = _TH
import math
import time
import numpy as np
スレッドを1本にすると、推論4台ぶんの CPU 使用率が943%から99.5%に、load average(実行を待っている処理の数の目安)が84から13に下がりました。初期版の4台×3本で、完走は8/12台から12/12台になりました(上の減速ガードの「8/12→12/12」とは別の実験で、数字が偶然そろっています)。モデルの計算の中身は同じで、計算が間に合うようになっただけです。
開発途中の版の一つ(等速で走る他車を入れて学習した版)も、スレッド数だけを直し、ほかは前と同じ条件(舵の倍率0.80・減速ガードなし)で測り直すと、4台中0台→3台完走になり、罰は22件から3件に減りました(どちらも1本)。それまでの判定の多くは、PC の混み具合に左右されていた可能性があります。ただし、これで全部が片づいたわけではありません。丸一日直していた版には壁への接触など別の原因も重なっていたので、どの版もスレッド数を直せば完走した、とまでは言えません。測り直したこの版も、残る1台は1周目の出遅れで時間切れで、速さもまだ足りていませんでした。詳しくは BLAS のスレッド数の記事(近日公開)と sim-to-sim の罠の記事(近日公開)に書きます。
最終モデルは本当に壁を見ているか
「LiDAR を見ているように見えて、実は走り方の並びを覚えているだけ」ではないかを、入力を壊して確かめました。初期版の先生が本番コースを走ったときの AWSIM のスキャン2,923枚を最終モデルに通し(このデータは学習に使っていません)、先生の舵との相関を見ました。

最終モデルの入力アブレーション(入力は AWSIM のスキャン。値は先生の舵との相関)。そのままなら +0.85、左右反転で −0.82、角度の並びをシャッフルすると −0.04。
左右を反転した入力では舵もほぼ逆になり(反転前と反転後のモデル自身の出力どうしの相関は −0.968)、並びを崩すと相関はほぼ0になりました。少なくとも、スキャンの形と左右の違いを見て舵を決めていることは確かめられました。手順と、初期版との違いは入力アブレーションの記事(近日公開)にまとめます。
最終モデルの AWSIM での成績
| 条件(すべて手元の AWSIM) | 結果 |
|---|---|
| 単独6周 | 合計278.9秒・罰0。各周 47.63 / 46.39 / 46.41 / 46.99 / 46.16 / 45.33秒 |
| 4台混走6周(1本) | 4台とも6周完走、車どうしの接触0件、壁2件(1周目)。4台とも自分のモデル(最終モデル×2+開発途中の版×2)、制限時間400秒 |
きれいに走れた周だけで比べると、最終モデル(最速45.33秒)は初期版(最速39.77秒)より1周あたり5〜6秒遅いです。コースを覚えない代わりに、速さを払った形です。
できなかったこと
止まっている車には間に合いませんでした。最終モデルの3台と、動かない車1台を並べて6周走らせると、止まった車の横を18回通り、7回接触しました(車速の急な落ち込みから数えた回数。公式の結果ファイルでは、接触の罰は6件)。減速ガードは作動していましたが、計算すると、ブレーキを始めるのは残り2.9〜3.7 m、その速さ(時速約23〜30 km)で止まるには10.7〜17.1 m 必要です(停止距離は $v^2/(2a)$、減速 $a = 2.0$ m/s²)。学習でも制御でも、止まっている車の場面は入れていませんでした。先生の練習相手の車は、いつも走っていたからです。

接触1件の直前1.4秒。青が前方の一番近い距離、橙がガードの作動する距離、赤の点線が止まるのに必要な距離。
大きくぶつかって向きが反転すると、逆走を続けることがあるのも見ています(発生率は測っていません)。このモデルは、どちらが前かを知りません。壁から抜け出すことと、正しい向きに戻ることは別の問題でした。ほかにも、AWSIM で他車が写った状態のデータは集められていません。自作シムでは他車を円で近似しているので、AWSIM の車とは LiDAR への写り方が違います。
測定の条件
| 項目 | 内容 |
|---|---|
| シミュレータ | AWSIM(大会の配布版)を手元の PC で実行。自作シムは PyTorch で自作 |
| AWSIM の版 | 決勝の前に、手元の AWSIM を新しい配布版へ入れ替えました。本文の値は、入れ替える前の配布版で測ったものです |
| 学習と推論 | 学習は PyTorch 2.9.1+cu128、GPU は RTX PRO 5000 Blackwell(ノート PC 用)。推論ノードは NumPy 実装 |
| モデルの版 | 最終モデル(決勝で使用)と、本番コースで学習した初期版。本文ではどちらの値かを書いています |
まとめ
- 2D LiDAR 750点だけを見る約15万パラメータのモデルで、E2E 部門の準優勝までたどり着けました。手を入れたのはモデルの形ではなく、何を学ばせるか(乱数で作ったコースと他車、BC と DAgger)と、モデルの外に置いた簡単なルール(舵の倍率・減速ガード・壁からの後退)でした。ルールの効き目は初期版で測ったもので、コースの本数の効果は測り直して撤回しました。
- 本番コースの走行データを学習に入れないと決め、コードで弾くようにしました。その代わり、1周は初期版より5〜6秒遅くなりました。
- 一番時間を使ったのは、数字が何を測っているかを確かめる作業でした。舵の倍率、「現実っぽい」相手、CPU の取り合いは、どれもモデルを疑う前に測り方を疑えば早く見つかったものです。
来年出る人へ一言
- 公式サンプルは、出力の範囲とセンサーの範囲を最初に確かめてください。
- 自作シムや速い評価の数字は、候補を絞るのに使い、採用は本番に近い環境で決めるのがおすすめです。シムから持ってきた定数は、本番の環境で一度振ってから使ってください。
- モデルが悪いと決める前に、PC の混み具合(CPU・スレッド数)を見てください。
- 持ち込むパッケージは、公式の決勝と同じ条件と起動手順で一度動かしてください。私は決勝の2日前に公式と同じ手順で起動してみて、自分のパッケージの既定の制御器が TinyLidarNet になっていない(手元の起動方法でだけ TinyLidarNet が選ばれていた)ことに気づき、既定を直した版を作りました。手元の起動方法だけで試していたら気づけませんでした。
参考
- 自動運転AIチャレンジ2026 公式ドキュメント「End to End部門 説明」:https://automotiveaichallenge.github.io/aichallenge-documentation-racingkart/competition/ai-class.html
- 同「Sim to Real部門 説明」(速度とペナルティ):https://automotiveaichallenge.github.io/aichallenge-documentation-racingkart/competition/sw-class.html
- 同「SIM決勝特設ページ(2026/9/19)」:https://automotiveaichallenge.github.io/aichallenge-documentation-racingkart/competition/sim-finals.html
- TinyLidarNet: 2D LiDAR-based End-to-End Deep Learning Model for F1TENTH Autonomous Racing(arXiv:2410.07447):https://arxiv.org/abs/2410.07447