この記事は、自動運転AIチャレンジ2026で、VLMを使った実況システムを試したメモです。
完成したシステムの紹介というより、かなり試行錯誤の記録です。
「VLMに車載カメラを見せれば、いい感じに実況してくれるのでは?」と思って始めましたが、実際には遅延、音声生成、画像理解の粗さ、言い回しの単調さなど、いろいろな問題が出ました。
私自身もVLMやローカルLLMに詳しいわけではないので、調べながら少しずつ整理していきます。
目的
VLMが面白そうだったから試してみたい、ただそれだけです。
VLMは Vision-Language Model の略で、ざっくり言うと「画像を見て、言葉で説明できるAIモデル」です。
最近は画像を渡して「何が写っている?」「この場面を説明して」と聞けるモデルが増えています。
自動運転AIチャレンジでは、AWSIMというシミュレータ上で車両を走らせます。そこには車載カメラ映像や車両状態があります。
これをVLMに見せると、走行中の状況を説明してくれるのではないかと思いました。
うまくいけば、例えば次のような応用につながりそうです。
- 自動運転の挙動を説明してくれる助手席AI
- エンドツーエンドAI開発の一部に使える観察・説明モジュール
- 走行ログをあとから見返すときの自動解説
- チーム内で走行の良し悪しを共有するための動画生成
特に興味があったのは、クラウドAPIではなく、ローカルVLM/LLMでどこまで低遅延にできるかです。
やったこと
今回やったことを先にまとめると、AWSIM上を走る車両のカメラ画像と車両状態を取り出し、ローカルのVLM/LLMとVOICEVOXをつないで、準リアルタイムに日本語実況を出す実験です。
最終的に試した構成は、ざっくり次の流れです。
- 車載カメラ画像を小さくしてVLMへ渡す
- VLMで「前回から何が変わったか」を短く説明する
- 速度・操舵・加速度などの車両履歴を数秒ぶん要約する
- Text LLMで、画像変化と車両履歴を合わせて日本語実況文にする
- VOICEVOXで音声化する
- 古くなった音声は捨てて、なるべく最新の実況だけをリアルタイムに再生できる状態にする
- 現時点では評価のために、音声が再生可能になった時刻を使って録画映像へ後から合成している
実験したPC環境は、だいたい次のようなものです。
| 項目 | 内容 |
|---|---|
| CPU | 13th Gen Intel Core i7-13700HX |
| GPU | NVIDIA GeForce RTX 4070 Laptop GPU |
| VRAM | 約8GB |
| 実行環境 | Windows + WSL2 + Docker |
| LLM/VLM実行 | Ollama |
| 音声合成 | VOICEVOX |
AWSIM、Autoware、Ollama、VOICEVOXを同時に動かすので、単に「モデル単体が速いか」だけではなく、GPUメモリに乗るか、モデル切り替えが起きないかも効いてきました。
▼ このPCを使ってます。
最初に考えた構成
最初の発想は単純でした。
- 車載カメラ画像をVLMに渡す
- VLMが状況を説明する
- LLMが日本語の実況文にする
- VOICEVOXで音声にする
- 音声をリアルタイムに再生し、その様子を録画して実況付き動画にする
構成としては次のようなものです。
AWSIM / Autoware
├─ 車載カメラ画像
├─ 速度・操舵・加速度
↓
Realtime VLM Commentary Node
├─ Ollama VLM
├─ Ollama Text LLM
└─ VOICEVOX
↓
リアルタイム再生される実況音声
↓
録画して実況付き動画として確認
ここでやりたいのは、後処理で動画に音声を貼るだけではなく、「走っている最中に音声が鳴る」構成です。
そのために低遅延化しています。
ただし現時点では、まだOSの音声デバイスへリアルタイム再生するところまでは実装していません。
代わりに、走行中に実況音声wavを生成し、音声が再生可能になった時刻を audio_ready として記録しています。
その後、録画映像に audio_ready 基準で音声を合成し、「リアルタイム再生できていたら、どのくらい遅れて聞こえるか」を評価しています。
前提: AWSIMの画面ではなく車両センサを見る
VLMに何を見せるかですが、自動運転の文脈で意味があるのは、車両が実際に持っているセンサ情報です。
そのため、VLMには車載カメラ画像を渡すことにしました。
また、カメラ画像だけでなく、車両状態も使うことにしました。
- 速度
- 目標速度
- 操舵角
- 加速度
- 速度追従誤差
画像だけでは「何が見えるか」は分かっても、「車が加速しているのか」「減速しながら曲がっているのか」は分かりにくいからです。
試行錯誤1: VLMにそのまま実況させると遅い
最初は、VLMに画像を渡して、そのまま説明や実況を作らせようとしました。
しかし、これはリアルタイム実況にはかなり厳しかったです。
問題は主に2つありました。
- 遅い
- 今の場面とコメントのタイミングがずれる
例えば、最初のカーブを曲がっているのに、音声ではスタート時のコメントが流れるような状態になりました。
これは生成が遅いだけでなく、音声生成待ちのキューが溜まって、古いコメントが順番に再生されてしまうのが原因でした。
そこで、次のような方針に変えました。
- 古い音声は捨てる
- 再生待ちが詰まったら最新だけ残す
- コメントは短くする
- 音声は少し速く再生する
このあたりから、「常時しゃべる」よりも「短く、遅れず、今の状況に近いことを話す」方が大事だと分かってきました。
この時点で分かったボトルネックは、主に次の3つです。
| ボトルネック | 起きたこと | 対応 |
|---|---|---|
| VLM推論 | 重いVLMだと画像1枚の説明だけで数秒かかる | 軽量VLMを試す |
| Text LLM推論 | 大きいLLMだと日本語文は自然だが遅い | 小さいLLMへ変更 |
| 音声キュー | 音声が長いと再生待ちが溜まり、古い実況が流れる | 古い音声を捨てる、VOICEVOXの再生速度を速める |
特にキュー詰まりは体感上かなり大きかったです。
ある実験では、生成そのものの中央値は約2.4秒でも、再生待ちまで含めると画像から音声再生までの遅れが中央値で約5.2秒になりました。これだと、映像ではすでにカーブを曲がっているのに、音声では少し前の場面を話しているように聞こえます。
その後、短文化、VOICEVOXの1.35倍速、古い音声の破棄を入れることで、キュー遅延はほぼ0秒まで減らせました。
試行錯誤2: ローカルLLM環境と候補モデル
ローカル環境では、Ollamaでいくつかのモデルを試しました。
Ollamaは、ローカルPC上でLLMやVLMを動かすための実行環境です。
自分のPCスペックや目的に合わせてモデルをダウンロードし、ローカルAPIとして呼び出せます。
今回の最初の発想は、あくまで「VLMだけで実況できるのでは?」でした。
最初からVLMとText LLMの組み合わせをきれいに設計していたわけではありません。
まず候補として触ったモデルやツールは次の通りです。
| モデル | サイズ | 役割 | 試した理由 | 所感 |
|---|---|---|---|---|
| llava:7b | 4.7GB | VLM | 画像対応で、まず動かしやすい | 画像説明はできるが、実走中は重め |
| moondream | 1.7GB | VLM | 軽量VLMとして低遅延を期待 | かなり速いが、説明は粗い |
| qwen3:8b | 5.2GB | Text LLM | 日本語文の自然さを期待 | 文は比較的よいが、8GB VRAM環境では重い |
| qwen2.5:1.5b | 986MB | Text LLM | 速度と文章品質のバランス狙い | 今回のText LLMでは一番使いやすかった |
| qwen2.5:0.5b | 397MB | Text LLM | さらに軽くするため | 速いが、指示漏れや文章品質が気になった |
qwen3:8b は日本語の文としては良くなりますが、AWSIMと同時に動かすには重すぎました。
qwen2.5:0.5b も試しましたが、プロンプトの指示漏れや文章品質が気になりました。
そのため、Text LLMは qwen2.5:1.5b がバランスの良いところでした。
軽量VLM: moondream
moondream は軽くて速いですが、万能ではありません。
最初はJSONタグのような構造化出力を期待しましたが、空応答になったり、安定しなかったりしました。
一方で、自然文で「この画像を短く説明して」と聞くと、比較的うまく返ります。
そこで、moondreamには複雑な実況文を作らせるのではなく、視覚情報をざっくり説明させるだけにしました。
このあたりで、VLMには「面白い実況文」まで求めず、見えているものや変化を短く取る役割に寄せた方がよいと分かってきました。
試行錯誤3: VLMだけで実況するのではなく、視覚センサの一つとして使う
ここが大きな方針転換でした。
最初は、VLMだけで実況してもらおうとしていました。
しかし実際には、VLMは車載カメラ画像を見て「青白いバリアがある」「建物がある」「街中コースっぽい」といった大まかな説明をするのが得意でした。
逆に、走行状態まで含めて面白い実況を作るのは苦手です。
そこで、役割を分けました。
- VLM: 画像から見えるものをざっくり説明する
- 車両データ: 速度、操舵、加速度の変化を見る
- Text LLM: VLMの説明と車両データを合わせて、日本語実況文にする
- VOICEVOX: 生成した実況文を音声にする
この分解の方が安定しました。
この方針にしてから、VLMとText LLMの組み合わせを変えて遅延と文章のバランスを見ました。
ここで初めて「どのVLMで画像を見るか」と「どのText LLMで実況文にするか」を分けて考えるようになりました。
実際に試した構成は次のような傾向でした。
| 構成 | 狙い | 遅延の目安 | 所感 |
|---|---|---|---|
llava:7b + qwen3:8b
|
画像説明と日本語文の品質を優先 | total median 約13.8秒 | 文章は比較的自然だが、8GB VRAM環境では重すぎる |
llava:7b + qwen2.5:1.5b
|
VLM品質を残しつつText LLMを軽くする | total median 約4.4秒 | 成立はするが、リアルタイム実況にはまだ遅い |
llava:7b + template |
Text LLMを外して低遅延化 | total median 約2.5秒 | 速いが、ルールベース寄りで面白さが落ちる |
moondream + qwen2.5:1.5b
|
軽量VLMで低遅延化 | total median 約2.0秒 | かなり速いが、画像理解は粗い |
moondream + qwen2.5:1.5b + 前後フレーム比較 |
速さを保ちつつ変化を実況する | total median 約1.8秒 | 現時点では低遅延でベター |
※ templateはLLMを使わずに文章を作る比較用のルール処理をする場合です。ルールベースでテキストのテンプレを選択します。
llava:7b + template は、Text LLMを使わない比較条件です。
LLMらしい面白さは減りますが、遅延を詰めるうえでは重要なベースラインになりました。
流暢性は上がりました。ただ、ビルの間を走行していると勘違いしているので、まだまだ改善の余地はあります。
試行錯誤4: 画像を小さくしても、思ったほど速くならない
低遅延化のために、入力画像を小さくすることも試しました。
例えば次のようなサイズです。
| 前処理 | 狙い |
|---|---|
full_320x180 |
そこそこ情報を残す |
full_256x144 |
さらに軽くする |
結果として、full_256x144 は速くなりました。
ただし、期待したほど劇的ではありませんでした。
これは、チーム内でもコメントをもらったのですが、モデル内部で画像がさらに縮小・パッチ化されている可能性があります。
こちらで少し縮小しても、モデル内部の処理が支配的なら、速度はあまり変わらないかもしれません。
一方で、小さくしすぎると認識が粗くなります。
今回の比較では、ざっくり次の傾向でした。
| 前処理 | VLM空応答 | total latency median | 所感 |
|---|---|---|---|
full_256x144 |
2/8 | 約1.8秒 | 速いが少し不安定 |
full_320x180 |
0/8 | 約2.3秒 | 安定するが遅い |
低遅延デモとしては full_256x144 が良さそうでした。
ただし安定性を重視するなら full_320x180 です。
次にやるなら、256 でVLMが空応答になったときだけ 320 で再試行するhybrid構成がよさそうです。
試行錯誤5: 1枚画像だけだと、実況が単調になる
VLMに1枚画像だけを見せると、説明が似てきます。
実際に出てきた文は、例えば次のようなものです。
- ビルの間から、コースが右へ続きます
- 青白いバリア沿いに走行しています
- 建物のある街中コースを進みます
間違いではないのですが、何度も聞くと単調です。
そこで、前回画像も保存して、前回と現在を比較させることにしました。
最初はVLMに2枚の画像をそのまま渡しましたが、moondreamでは空応答が増えました。
そこで、前回画像と現在画像を左右に連結し、1枚の比較画像として渡しました。
実装上の「前回画像」は、前回VLMを呼んだときのフレームです。
低遅延版では約4秒ごとに実況を出していたので、だいたい4秒前のフレームと現在フレームを比較するイメージです。
左: 前回フレーム
右: 現在フレーム
この候補画像は12秒差のフレームで作っています。実際の低遅延版では、前回VLM実行から現在までの約4秒差を見る想定です。
この1枚に対して、
左が前回、右が現在です。何が変わりましたか?
と聞く形です。
これで「今見えているもの」だけでなく、「何が変わったか」をVLMに聞けるようになりました。
ただし、自動運転AIチャレンジのコースでは、下半分はあまり変わり映えがなく、上半分しか意味がないかもしれません。
試行錯誤6: 車両データは時系列で持つ
車両データも、1点だけを見ると情報が足りません。
例えば、ある瞬間の速度が22km/hだったとしても、それだけでは次のことが分かりません。
- 加速中なのか
- 減速中なのか
- 旋回から戻っているのか
- 目標速度に近づいているのか
そこで、車両データを数秒ぶん保持するようにしました。
今回の実装では、車両データは約8秒ぶん保持しました。
実況は4秒ごとに出していたので、直近1〜2回分の挙動を見ながら話せるくらいの長さです。
保持するトピックは、だいたい次のようなものです。
- 速度が上がっているか、下がっているか
- 目標速度に近づいているか
- 操舵角が大きくなっているか、戻っているか
- 加速度が正か負か
- 直近でカーブに入ったのか、抜けたのか
- 車両が安定しているのか、変化が大きいのか
保持した履歴から、LLMに渡す要約を作ります。
- 速度のstart/end/delta
- 速度のmin/max
- 目標速度
- 操舵角のstart/end/max
- 加速度のstart/end/min/max
- 加速中/減速中/安定などのmotion trend
これにより、LLMが「今この瞬間」だけではなく、「ここ数秒でどう動いたか」を踏まえて文を作れるようになります。
試行錯誤7: 出力タイプをローテーションする
同じ入力から毎回自由に文を作らせると、似た表現に寄ってつまらないです。
そこで、出力タイプを5種類に分けて、順番に切り替えるようにしました。
| タイプ | 役割 |
|---|---|
visual_change |
前回画像から変わった見た目を話す |
vehicle_motion |
加速、減速、旋回、安定などを話す |
course_shape |
直線、カーブ、バリア、縁石などを話す |
scene_detail |
建物、看板、空、工事中の景色などを話す |
sport_commentary |
少し実況者っぽく話す |
これに加えて、直近の実況履歴もLLMに渡し、同じ文を繰り返さないようにしました。
最後のほうで、「建設中の工場が見えます」など、風景に言及するようになりました。
現時点の評価構成
現時点では、低遅延版の評価は次のような構成です。
最終的にやりたいのはリアルタイム音声再生です。
ただし今は、音声が完成した時刻 audio_ready を記録し、あとから録画動画に合成して、リアルタイム再生時の遅延を評価しています。
この図では、現時点の評価構成を示しています。
やりたいのはリアルタイム音声再生ですが、現時点では評価のために audio_ready 基準で後から動画に合成し、遅延を評価しています。
注意点として、VLMに入れるのは画像だけです。
速度・操舵・加速度などの車両データは、VLMではなくText LLMへ渡します。
AWSIM / Autoware
├─ 車載カメラ画像
├─ 速度・操舵・加速度
↓
Realtime VLM Commentary Node
├─ 前回画像と現在画像を比較
├─ 車両データを8秒ぶん保持
├─ moondreamでvisual_changeを生成
├─ qwen2.5:1.5bで日本語実況文を生成
└─ VOICEVOXで音声化
↓
audio_ready基準で動画に合成
使っているモデルは次の通りです。
| 役割 | モデル/ツール |
|---|---|
| VLM | moondream |
| Text LLM | qwen2.5:1.5b |
| 音声合成 | VOICEVOX |
GPUは8GB VRAMクラスのローカル環境で試しています。
現時点の結果
低遅延版では、だいたい次の結果になりました。
| 項目 | 結果 |
|---|---|
| VLM latency median | 約0.7秒 |
| Text LLM latency median | 約0.4秒 |
| VOICEVOX latency median | 約0.7秒 |
| Total latency median | 約1.8秒 |
最初は、音声がかなり遅れて「いま何に対するコメントなのか分からない」状態でした。
そこから、古い音声を捨てる、短文にする、VOICEVOXを速める、モデルを軽くする、といった調整で、だいぶ準リアルタイムに近づいてきました。
ただし、まだ課題はあります。
- VLMの説明が空になることがある
- moondreamの画像理解はかなり粗い
- 実況の言い回しはまだ単調になる
- 面白いコメントと低遅延の両立が難しい
やってみて分かったこと
何も考えずにVLMをそのまま「実況者」として使うのは難しいということがわかりました。
VLMは、画像から見えるものをざっくり拾うのには使えます。
しかし、走行の意味づけや面白い実況文は、車両データや履歴と組み合わせないと厳しいです。
今回の実験では、VLMは賢い実況者ではなく、画像を言葉に変えるセンサと捉えると扱いやすくなりました。
そのうえで、実況文を作るには次の情報を組み合わせる必要があります。
- 画像から見えるもの
- 前回からの見た目の変化
- 車両の速度や操舵の変化
- 最近しゃべった内容
- 今回どんな種類のコメントを出したいか
この分解をすると、ローカルVLM/LLMでも少し現実的になります。
これからやりたいこと
次にやるなら、次のあたりです。
0. リアルタイム音声再生へつなぐ
この実験の目的は、最終的にはリアルタイムに音声生成して、そのまま再生できるようにすることです。
現時点では、遅延のため audio_ready 基準で後から合成して評価しています。
次は、音声ができた瞬間に再生キューへ渡すWorkerを追加したいです。
- VOICEVOXでwavが生成されたら即座に再生対象へ渡す
- 再生待ちが詰まっていたら古い音声を捨てる
- 最新の短い実況だけを再生する
- 実スピーカー録音に依存せず、再生開始時刻をログとして残す
- 必要なら、後から同じ時刻で動画に合成して検証する
VLMが安定して返す条件を探す
full_256x144 は速いですが、VLMの空応答が少し出ました。一方で full_320x180 は安定します。
まず、空応答が出にくい条件を探します。
- 画像サイズ
- プロンプトの聞き方
- 前回/現在フレームの見せ方
- VLM APIの呼び方
- 生成パラメータ
このあたりを変えながら、安定して返る条件を探すのが先です。
そのうえで、どうしても空応答が出たときの保険として、320で再試行する、現在フレーム単体に切り替える、直近のvisual descriptionを使う、といったfallbackを入れるなど、対応を考えていきたいです。
イベント駆動に寄せる
今は4秒ごとに実況しています。
ただ、実際には常にしゃべる必要はありません。
- 加速開始
- 減速開始
- 旋回開始
- 旋回終了
- 目標速度到達
- 風景変化
遅延が小さくなってリアルタイム性が高ければ、こういうイベントでしゃべる方が、実況として自然になりそうです。
面白さの評価を考える
遅延は数値で見られます。しかし「実況として面白いか」はまだ主観です。
- 今の映像と合っているか
- 同じことを繰り返していないか
- 車両の動きに触れているか
- 見ていて楽しいか
このあたり、考えていきたいです。
ほかの実況AIとの比較
今回の実装は、VLM、Text LLM、VOICEVOXを自分で組み合わせたものです。
一方で、LiveCCのように、動画を見ながら実況すること自体を目的にしたVideo LLMもあります。
こうした実況AIと比較すると、今の構成の良いところと弱いところが見えそうです。
- 映像の流れをどれくらい自然に読めるか
- コメントのタイミングが映像と合っているか
- 同じ言い回しを繰り返さないか
- 実況として聞いていて面白いか
- 車両状態や制御情報を入れたときに、どこまで説明が良くなるか
LiveCCのようなモデルは、動画そのものから実況らしい文章を出す方向に強そうです。
一方で、自動運転の文脈では、映像だけでなく、速度、操舵、加速度、目標速度との差といった車両データも重要です。
そのため、単純に置き換えるというより、まずは同じ走行動画を入力して、今の構成と出力を比べてみたいです。
そこで得られた「実況らしい言い回し」や「話すタイミング」の作り方を、今のパイプラインに取り込めると面白そうです。
マルチモーダルモデルを制御に使えるか試す
今回は、VLMを「走行状況を説明するためのセンサ」として使いました。
次の興味としては、VLMやVideo LLMのようなマルチモーダルモデルを、車両制御の一部に使えるかも試してみたいです。
ただし、いきなりVLMにハンドルやアクセルを任せるのではなく、まずはルールベースの制御を主にして、限定的な場面だけマルチモーダルモデルを補助的に使うのが現実的だと思います。
例えば、次のような使い方です。
- 通常走行はルールベースや既存の制御で行う
- 異常っぽい状況をVLMで検出する
- 「前方に障害物がありそう」「コースが見えにくい」といった状態を言語化する
- その結果をもとに、減速、停止、慎重走行などの候補を出す
- 最終的な制御判断は、安全側のルールで制限する
つまり、VLMに直接運転させるというより、まずは「制御判断の補助」や「異常検知の説明」に使うイメージです。
実況で作った仕組みは、画像、車両状態、時系列の履歴を扱うので、この方向にもつなげられるかもしれません。
おわりに
まだまだキャプションの精度は低いですが、車載カメラ映像、車両データ、ローカルVLM、ローカルLLM、音声合成をつないで、準リアルタイムに実況付き動画を作るところまでは来ました。
一口にVLMといっても、何をルールベースで判断して、どんな画像の文脈をVLMに拾ってほしいのか。それらを限られた計算リソースの中でどのように実現するのか。工夫できそうな点がありそうです。
自動運転AIチャレンジでは、制御や経路計画の話が中心になりますが、走行をどう観察するか、どう説明するか、どうチームで共有するかも面白いテーマだと思いました。
VLMやローカルLLMは、そういう「走行を理解しやすくするための道具」として使える可能性も感じました。
まだ試行錯誤中ですが、この方向はもう少し掘ってみたいです。





