
NVIDIA Cosmos Transfer 2.5 で車載映像を霧・雨・夜に変換してみた
こんにちは、製造ビジネステクノロジー部の若槻です。
自動運転やモビリティ領域では、学習データをどう揃えるかが常に問題になります。雨・霧・夜・逆光といった条件は、実際に走って撮ろうとすると手間もコストもかかりますし、そもそも危険な条件ほどデータが集まりません。
そこで出てくるのが、既にある走行映像を別の条件へ変換するアプローチです。NVIDIA Cosmos Transfer は、入力動画の構造を保ったまま天候や時間帯を作り変えられるモデルで、まさにこの用途に当たります。
本記事では Cosmos Transfer 2.5 を NVIDIA Brev の H100 インスタンスで動かし、公式サンプルの車載映像を霧・雨・夜へ変換します。
先に結論
2 点あります。
- 生成が破綻する箇所には法則があります。エッジが検出されない領域は拘束されないため、そこだけモデルが自由に描きます。破綻はランダムではなく、制御信号がどこを覆っているかで決まります
vis制御は入力の輝度構造を運びます。そのため「暗くしたい」「白く覆いたい」というプロンプトと綱引きになることがあります
なお、既定の設定では VRAM を 64GB 以上使います。GPU 選定でつまずきやすいので、そこは検証環境の章で先に書きます。
Cosmos Transfer 2.5 とは
制御信号(エッジ、ブラー、深度、セグメンテーション)で構造を拘束しながら、プロンプトで見た目を作り変えるモデルです。Cosmos-Predict2.5 の上に構築されています。
| 対象 | ライセンス |
|---|---|
| ソースコード | Apache 2.0 |
| モデルウェイト | NVIDIA Open Model License |
制御の種類は 4 つで、それぞれ役割が違います。
| 制御 | 何を拘束するか | control_path 未指定時の生成元 |
|---|---|---|
edge |
輪郭・エッジ | Canny Edge |
vis |
大まかな明暗と色の配置 | Bilateral Gaussian Blur |
depth |
奥行き | VideoDepthAnything |
seg |
領域分割 | GroundingDINO(base) + SAM2 |
edge の生成元にある Canny は、画像から輪郭線を抜き出す古典的なアルゴリズムです。しきい値を境に「ここは輪郭」「ここは違う」と判定するので、後で出てくる preset_edge_threshold はこのしきい値の強さを指します。
vis は入力をぼかした映像を渡している
vis の制御映像は、入力動画に強いブラーをかけたものです。細部は完全に潰れますが、「どこが明るくてどこが暗いか」「全体としてどんな色みか」は残ります。目を細めて景色を見たときに残る情報、と考えると近いです。
本記事の後半で実際の vis 制御映像を載せますが、輪郭がまったく分からないほどぼやけた映像です。それでも空が白く、路面がグレーであることは見て取れます。
この「大まかな明暗と色の配置」を、画像処理では低周波成分と呼びます。細かい模様や輪郭が高周波成分です。vis は高周波を捨てて低周波だけをモデルに渡す制御なので、細部は自由にさせつつ、全体の明るさだけを入力に合わせるという効き方をします。
以降「輝度構造」という言葉が出てきたら、この「大まかな明暗の配置」のことだと思ってください。
制御映像を事前に用意する必要はありません。control_path を書かなければ、入力動画から自動生成されます。この点は後で実際に確認します。
検証環境
NVIDIA Brev で H100 インスタンスを 1 台立てました。
H100 は NVIDIA のデータセンター向け GPU です。ゲーム向けの GeForce とは別系統の製品で、サーバーに載せて生成 AI の学習や推論に使われます。個人の PC に載るような GPU ではないので、こうしたクラウドサービスで時間借りするのが現実的です。
今回借りたのは PCIe 版の 1 枚構成でした。H100 には接続方式の違いで PCIe 版と SXM 版があり、SXM 版のほうが高速で、複数枚をつないで使う用途に向きます。PCIe は拡張カードを挿すおなじみの規格のほうで、1 枚だけ使う今回はこちらで足ります。
搭載メモリは 81,559 MiB(約 80GB) と表示されました。確認に使った nvidia-smi は、NVIDIA のドライバに付属している GPU の状態を見るコマンドです。GPU 名・メモリ量・使用率・消費電力などが分かるので、この記事でも何度か登場します。
Brev の使い方は同僚の田中が詳しく書いているので、インスタンスの作り方と接続方法はそちらをご覧ください。
- NVIDIA Brev CLI で GPU インスタンスを起動してみた
- NVIDIA Brev の GPU インスタンスに VS Code Remote SSH と JupyterLab で接続してみた
Brev のコンソールで GPU を選びます。

構成は以下のとおりです。
| 項目 | 値 |
|---|---|
| GPU | NVIDIA H100 PCIe 80GB(81,559 MiB) |
| CPU / RAM | 28 CPU / 180GB |
| ドライバ | 570.195.03(CUDA 12.8) |
| OS | Ubuntu 22.04.5 LTS |
| Python | 3.10.12 |
| 料金 | $3.00/hr(ストレージ込み) |
CUDA は、NVIDIA の GPU に計算をさせるための土台となるソフトウェア群です。PyTorch のような機械学習ライブラリは、この上で動いて GPU を使います。バージョンが合っていないとライブラリが GPU を認識できないので、環境構築ではここを揃えるのが要点になります。
後で出てくる cu128 という表記は「CUDA 12.8 向けにビルドされたもの」という意味です。
なぜ H100 にしたか
当初は L40S 48GB($1.74/hr)で足りると考えていました。公式ドキュメントの要件がこうなっているためです。
| 用途 | 最小 GPU 数 | GPU あたり VRAM |
|---|---|---|
| 単一ビュー推論 | 1 | 24GB+ |
| マルチコントロール推論 | 1 | 40GB+ |
| マルチビュー / auto | 7 | 24GB+ |
| ポストトレーニング | 8 | 80GB+ |
ところが、同僚の森茂が DGX Spark で試した際の記事に、気になる記述がありました。
DGX Spark で NVIDIA Cosmos 世界基盤モデルを動かしてみた
制御信号(エッジマップ、深度マップなど)からリアルな映像を生成する Transfer 2.5 も試みましたが、2B モデルでも 65.4GB の VRAM を必要とし
公称 24GB に対して実測 65.4GB。2.7 倍です。DGX Spark は unified memory の ARM 環境(CPU と GPU が 1 つのメモリを共有する構成で、GPU 専用の VRAM を積む H100 とはメモリの使われ方が違います)なので、そのまま比べられる数字ではありません。それでもこの差を無視して 48GB を選ぶのは危険だと判断し、H100 80GB に変更しました。
結論から言うと、この判断は正解でした。後述しますが、実測は 65,679 MiB です。48GB では収まりません。
なお、インスタンスを選ぶ画面には料金の内訳と重要な注意書きが出ます。見落としやすいので枠で囲みました。

① ストレージの課金条件(Configure Storage の説明文)
Storage is billed based on the amount provisioned and continues to accrue even when your instance is stopped.
確保した容量に対して課金され、インスタンスを停止していても課金され続けます。
② インスタンスの制約(Instance Attributes)
プロバイダによっては次の 2 点が付きます。
- This instance cannot be stopped or restarted(停止・再起動ができない)
- If your organization runs out of credits, Brev deletes the instance and all data on it(クレジットが尽きるとインスタンスごと削除され、データは復旧できない)
共有のクレジットを使っている場合は、後者が地味に効いてきます。
③ 料金の内訳(Cost Breakdown)
Compute と Storage が別建てで表示されます。今回選んだ構成では Storage が Included ですが、プロバイダによってはここに別途金額が乗ります。
起動するとこうなります。

セットアップ
手順そのものはリポジトリの Setup ドキュメントに書かれているので、ここではなぞりません。書かれていないところでつまずいた 5 点を中心に記録します。
- ディスクの置き場所(コンソールの表示と実体が違う)
- Python のバージョン(リポジトリの指定どおりだと入らない)
- Hugging Face のゲート同意(1 つ見落としやすい)
- ゲート状態の確認方法(API の応答が当てにならない)
- トークン登録(失敗しても原因が分からない)
いずれも解決すれば数分ですが、知らないと合計で数時間は溶けます。実際、私は 1 と 2 で作り直しになりました。
ディスクの置き場所に注意
Brev のコンソールは 850GB と表示しますが、ルートディスクは 97GB しかありません。
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 97G 21G 76G 22% /
/dev/vdb 738G 180M 700G 1% /ephemeral
実体は /ephemeral 側です。後述のとおりチェックポイントだけで 34GB あるので、HF_HOME を明示的に逃がしておきます。
export HF_HOME=/ephemeral/hf
Python は 3.10 を明示する
ここが最初の落とし穴でした。リポジトリの .python-version には 3.13 と書かれています。素直に従うと失敗します。
error: Distribution `flash-attn==2.7.3+cu128.torch27` can't be installed
because it doesn't have a source distribution or wheel for the current platform
hint: You're using CPython 3.13 (`cp313`), but `flash-attn` (v2.7.3+cu128.torch27)
only has wheels with the following Python ABI tag: `cp310`
依存インデックスを確認したところ、flash-attn の cp313 ホイールは cu128・cu130 のどちらにも存在しませんでした。用意されているのは cp310 と一部 cp312 だけです。.python-version がリポジトリ自身の依存インデックスと矛盾しています。
uv venv --python 3.10 を明示すれば通ります。
sudo apt-get update
sudo apt-get install -y git-lfs curl ffmpeg libx11-dev tree wget
git lfs install
git clone https://github.com/nvidia-cosmos/cosmos-transfer2.5.git
cd cosmos-transfer2.5
git lfs pull
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
uv python install 3.10
uv venv --python 3.10 .venv
uv sync --extra=cu128 --python 3.10
source .venv/bin/activate
確認します。
$ python -c "import torch; print(torch.__version__, torch.version.cuda, torch.cuda.get_device_name(0))"
2.7.0+cu128 12.8 NVIDIA H100 PCIe
$ python -c "import flash_attn; print(flash_attn.__version__)"
2.7.3
やり直した後の uv sync は 66 秒で完了しました。venv は 12GB です。
Hugging Face のゲート同意は 3 つ必要
Cosmos のモデルは gated です。gated とは、Hugging Face でモデルの配布に制限がかかっている状態を指します。ページでライセンスに同意しないとファイルをダウンロードできません。同意が必要なリポジトリは以下の 3 つあります。
| リポジトリ | 用途 |
|---|---|
nvidia/Cosmos-Transfer2.5-2B |
本体 |
nvidia/Cosmos-Guardrail1 |
ガードレール |
nvidia/Cosmos-Predict2.5-2B |
Wan2.1 VAE / tokenizer |
3 つ目を忘れがちです。Transfer なのになぜ Predict が要るのかというと、VAE と tokenizer を Predict 側のリポジトリから取得するためです。
- VAE(Variational Autoencoder、変分オートエンコーダ)— 動画を「小さくて情報が詰まった数値の並び」に圧縮し、また元に戻す変換器です。動画をそのままの画素で扱うと重すぎるので、モデルはこの圧縮された空間で生成し、最後に VAE で画素へ戻します
- tokenizer — ここではプロンプトの文章をモデルが扱える数値の並びに変換する部品です
どちらも生成の土台になる部品なので、欠けると動きません。同意を忘れると、実行がここで止まります。
Error: Access denied. This repository requires approval.
uvx 'hf>=1.3.5' download nvidia/Cosmos-Predict2.5-2B --repo-type model --revision ... tokenizer.pth
いずれも gated: auto なので、モデルページで "Agree and access repository" を押せば即座に使えるようになります。承認待ちは発生しません。
なお depth や seg の制御を自動生成する場合、さらに depth-anything/Video-Depth-Anything-Large、facebook/sam2-hiera-large、IDEA-Research/grounding-dino-base が必要ですが、これらは gated ではないので手続きは不要です。
ゲートの状態は API の 200 では判断できない
同意状況を確認しようとして、最初は次のようにしていました。
curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $HF_TOKEN" \
"https://huggingface.co/api/models/nvidia/Cosmos-Predict2.5-2B/tree/main"
# => 200
これは同意前でも 200 を返します。ファイル一覧のメタデータは見えても、実ファイルの取得は別扱いだからです。実際の可否を見るなら resolve を叩く必要があります。
curl -s -o /dev/null -w "%{http_code}" -I -L -H "Authorization: Bearer $HF_TOKEN" \
"https://huggingface.co/nvidia/Cosmos-Predict2.5-2B/resolve/main/tokenizer.pth"
hf auth login は入力が見えない
トークンの入力は画面に表示されません。貼り付けが空でも次のようにしか出ないため、トークンが無効なのか貼り付け事故なのか判別できません。
requests.exceptions.HTTPError: Invalid user token.
先に curl で切り分けると早いです。
read -rs -p "token: " T; echo
curl -s -H "Authorization: Bearer $T" https://huggingface.co/api/whoami-v2 | head -c 300
ユーザー情報が返ればトークンは有効です。なお Fine-grained トークンでも、追加の権限設定なしで gated リポジトリを読めました。
動かしてみる
題材
公式サンプルの assets/car_example/ を使います。付属の car_prompt.txt によれば、こういう映像です。
ダッシュカムから撮影した都市部の走行シーン。多車線道路、前方に黒い車、歩道に街路樹と歩行者、ロードコーンでの車線規制、晴天

1280×720 / 29.97fps / 121 フレーム / 約 4 秒です。
まず最小構成で
car_vis_spec.json は 6 行しかありません。
{
"name": "car_vis",
"prompt_path": "../car_prompt.txt",
"video_path": "../car_input.mp4",
"vis": {
"control_weight": 1
}
}
control_path がありません。制御映像を渡していないので、入力動画から自動生成されるはずです。
python examples/inference.py -i assets/car_example/vis/car_vis_spec.json -o outputs/car_vis
ログを見ると、制御パスがすべて None のまま生成が進んでいます。
Processing the following paths: {'edge': None, 'edge_mask': None, 'edge_mask_prompt': None,
'vis': None, 'vis_mask': None, 'vis_mask_prompt': None}
出力ディレクトリにはこうなりました。
car_vis.mp4
car_vis_control_vis.mp4 ← 自動生成された制御映像
car_vis.json
config.yaml
console.log
debug.log
car_vis_control_vis.mp4 が生成されています。制御映像は自動で作られ、しかも保存されます。この挙動が後で効いてきます。
VRAM の実測
VRAM(Video RAM、ビデオメモリ)は GPU が持つ専用のメモリです。モデルの重みや計算の途中結果はここに載るので、足りないと処理が途中で止まります。
厄介なのは、使用量が生成の進み具合につれて増えたり減ったりすることです。一度見ただけでは、いちばん多いときにどれだけ使ったのかが分かりません。
そこで nvidia-smi に -l 2 を付けました。これは 2 秒ごとに現在値を出力し続けるオプションです。生成が終わるまで記録し続け、あとからその中の最大値を拾いました。本記事で「ピーク」と書いているのはこの最大値です。
nvidia-smi --query-gpu=timestamp,memory.used,utilization.gpu --format=csv,noheader -l 2 > vram.csv
memory.used が使用中の VRAM、utilization.gpu が GPU の使用率です。結果をファイルに書き出しておくと、あとから最大値を計算できます。
結果です。
| 構成 | VRAM ピーク |
|---|---|
vis のみ |
65,679 MiB |
edge + vis |
67,517 MiB |
vis ひとつだけの最小構成で 64GB です。制御を 2 つにするとさらに増えます。森茂が DGX Spark で測った 65.4GB という数字が、別環境でほぼそのまま再現された形になりました。
公式ドキュメントの「単一ビュー推論 24GB+」とは大きく開きがありますが、この記述が誤りだと断定はできません。今回試したのは 720p・121 フレーム・num_steps 35 という条件だけで、解像度やフレーム数を落とせば収まる可能性は潰していないためです。
ここで 2 つ用語を補足します。
num_steps— ノイズを取り除いて絵にしていく工程を何回に分けるかの指定です。既定は 35 で、多いほど丁寧に作る代わりに時間がかかります- Distilled モデル — 蒸留(distillation)という手法で軽量化された派生モデルです。大きいモデルの出力を教師にして小さいモデルを訓練したもので、Cosmos Transfer 2.5 では
num_stepsを 4 まで減らせる Distilled Edge モデルが公開されています
つまり Distilled モデルを使えば工程が 35 回から 4 回に減るので、速度もメモリの使い方も変わってくるはずです。こちらは未検証です。
言えるのは次の範囲にとどめます。
既定の設定で 720p の動画を生成するなら、24GB では足りない。
所要時間
| 項目 | 値 |
|---|---|
| 初回総所要(チェックポイント取得込み) | 1,017 秒(約 17 分) |
| うちチェックポイント取得(34GB) | 約 90 秒 |
| サンプリング | 13.47 s/it × 35 ステップ = 約 7 分 52 秒 |
ここで注意が必要です。サンプリング時間だけを見ていると、実際の所要時間を大きく見誤ります。
3 本をまとめて生成したときのログから、フェーズごとの時刻を拾いました。
| フェーズ | 時刻 | 所要 |
|---|---|---|
| プロセス開始 | 10:51:30 | — |
| 1 本目 生成開始 | 10:53:13 | モデルロード 1 分 43 秒 |
| 2 本目 生成開始 | 11:10:09 | 1 本目 16 分 56 秒 |
| 3 本目 生成開始 | 11:26:57 | 2 本目 16 分 48 秒 |
| 終了 | 11:43:47 | 3 本目 16 分 50 秒 |
1 本あたり約 17 分で、ばらつきはほとんどありません。サンプリングが 7 分 52 秒なので、残りの約 9 分が別の処理です。制御入力の自動生成(Canny・ブラー)、プロンプトとネガティブプロンプト双方のガードレール判定、VAE デコード、動画エンコードがここに入ります。
num_steps から所要時間を見積もると倍以上外すので、パラメータ探索の計画を立てるときは注意してください。4 秒の動画 1 本に 17 分です。
依存モデルは 4 つ、キャッシュは 34GB
「2B モデル」という名前から受ける印象より、実際はずっと重いです。
| リポジトリ | 用途 |
|---|---|
nvidia/Cosmos-Transfer2.5-2B |
本体 |
nvidia/Cosmos-Guardrail1 |
ガードレール |
nvidia/Cosmos-Predict2.5-2B |
Wan2.1 VAE / tokenizer |
nvidia/Cosmos-Reason1-7B |
Qwen2.5-VL-7B-Instruct ベース |
ここでいうガードレールは、危険な内容や不適切な内容を生成しないよう入出力を検査する仕組みです。Cosmos では専用モデル(Cosmos-Guardrail1)が用意されていて、通らないと生成が止まります。
このガードレールはネガティブプロンプトに対しても実行されます。
Passed guardrail on negative prompt
霧・雨・夜に変換する
本題です。プロンプトを差し替えて 3 パターン作ります。spec はこういう形です。
{
"name": "car_fog",
"video_path": "/path/to/car_input.mp4",
"prompt": "A driving scene through a modern urban environment, captured from a dashcam inside a vehicle. Dense fog fills the air, heavily reducing visibility. ...",
"negative_prompt": "Clear sunny weather, high visibility, crisp sharp horizon, cloudless sky, bright sunshine, transparent air.",
"guidance": 7,
"num_steps": 35,
"seed": 42,
"edge": { "control_weight": 0.35, "preset_edge_threshold": "medium" },
"vis": { "control_weight": 0.24, "preset_blur_strength": "very_high" }
}
preset_edge_threshold と preset_blur_strength は、制御入力を自動生成するときの強さを決めるプリセットです。どちらも very_low / low / medium / high / very_high の 5 段階で、既定は medium です。
| フィールド | 何を決めるか |
|---|---|
preset_edge_threshold |
Canny のしきい値。低いほど細かいエッジを拾います(ノイズも拾います) |
preset_blur_strength |
ブラーの強さ。強いほど細部が落ち、大まかな輝度だけが残ります |
control_weight が「その制御をどれだけ強く効かせるか」なのに対し、こちらは「そもそもどんな制御映像を作るか」を決めます。効き方が違うので、混同しないほうがよいです。
-i は複数指定できる
-i に複数の spec を渡すと、モデルを 1 回だけロードして順次実行されます。
python examples/inference.py \
-i specs/car_fog.json specs/car_rain.json specs/car_night.json \
-o outputs/weather
3 本で 3,151 秒(52 分 31 秒)でした。モデルロードは重い処理なので、パラメータを振って比較したいときはこの形が効きます。
guidance は 0〜7 の整数
spec を書くときに気づいた点です。ソースを見ると上限が決まっています。
Guidance = Annotated[int, pydantic.Field(ge=0, le=7)]
公式サンプルは 3 なので、7 はかなり強めです。これ以上は上げられないので、変換を強めたい場合は control_weight の配分やプロンプト側で調整することになります。
結果
4 分割で並べた比較映像がこちらです。左上が入力、右上が霧、左下が雨、右下が夜です。
天候表現そのものは、かなりよく出ます。
- 霧: 路面が濡れて光を反射し、前走車のテールランプが滲み、ビルが霞に溶けていきます
- 雨: 路面の照り返し、飛沫、そしてプロンプトに書いた「歩道の傘」まで再現されました
- 夜: 建物の窓が橙色に灯り、ネオンや信号機が光ります



そして、車線、矢印マーキング、前走車 2 台の位置は 3 本とも保存されています。
破綻には法則がある
ここからが本記事の肝です。
出力をよく見ると、入力に無いものが足されている箇所があります。
- 画面下部にダッシュボードとボンネットが出現(霧と雨)
- 左手前の高層ビルが別の建物に描き替えられる
- 中央奥のビルが曲面タワーとネオン看板に変わる(雨)
なぜここだけなのか。自動生成されたエッジ制御映像を見ると、答えが書いてあります。

| 領域 | エッジマップ | 出力での挙動 |
|---|---|---|
| 車線・矢印マーキング | くっきり検出 | 保存 |
| 前走車 2 台 | 輪郭あり | 保存 |
| 右手のビル群 | 窓枠まで検出 | 保存 |
| 左手前の高層ビル | ほぼ無検出(一様なガラス面) | 描き替え |
| 画面下部 | ほぼ無検出(空の路面) | 捏造 |
エッジが検出されない領域は拘束されないので、モデルが自由に描きます。低コントラストで一様な面ほどエッジが立たず、不安定になります。
ここで注意したいのは、毎回同じものが出るわけではないことです。ダッシュボードは霧と雨では出ましたが、夜では出ませんでした。正確には、毎回同じ結果になるのではなく、毎回どうなるか分からないということです。
対処としては preset_edge_threshold を下げる方向が考えられます。very_low から very_high の 5 段階があり、低いほど細かいエッジを拾います(ノイズも拾います)。
制御信号がプロンプトに勝つことがある
夜の結果で、もう 1 つ興味深いことが起きました。
プロンプトには「空は暗い」と書いています。建物の窓は灯り、ネオンも信号機も出ているので、モデルは「夜」を理解しています。それなのに、空だけが入力の明るい灰色のままです。

原因は vis 制御だと考えられます。vis は入力映像の低周波の輝度構造を運ぶ制御なので、control_weight: 0.24 で「元の明るい空」を引っ張り続けます。プロンプトの「暗い空」と綱引きになり、制御側が勝っている状態です。
自動生成された car_night_control_vis.mp4 を見ると、空が明るいまま保持されているのが確認できます。
空や海面のような低周波の一様面が画面を占める映像では、この綱引きが起きやすいと考えられます。「白く覆いたい」「暗くしたい」という指示が効きにくくなります。
診断の手順
以上をまとめると、生成結果がおかしいときに見るべきものがはっきりします。
<name>_control_edge.mp4を見る → 黒い領域が破綻の候補<name>_control_vis.mp4を見る → 保持されている輝度構造がプロンプトと矛盾していないか- 出力と並べて、どこが拘束されどこが自由だったかを確認する
制御映像は自動生成され、指定しなくても出力ディレクトリに保存されます。追加の作業は要りません。パラメータを闇雲に振る前に、この 3 つを見るだけで当たりがつきます。
なお、show_control_condition と show_input というフラグがあり、コードのコメントによれば制御映像や入力を出力動画に連結してくれるようです。
show_control_condition: Concatenate control videos and masks to the output video.
ファイルを個別に開いて見比べるより手軽なはずですが、今回は使っていません。先にこちらを試すほうが早いかもしれません。
おまけ: 出力動画を後段で加工するときの注意
比較用に 4 分割動画を作ろうとしたところ、ffmpeg が終わらなくなり、4 秒のはずの出力が 123MB まで膨れました。
ffprobe にかけると、フレーム数が 121 と 174 の 2 つ報告され、片方は r_frame_rate=0/0 を返します。xstack は最長入力に合わせるため、この不正な尺に引きずられていました。
-t で尺を、fps フィルタでフレームレートを明示すると解決します。
ffmpeg -y -t 4 -i input.mp4 -t 4 -i fog.mp4 -t 4 -i rain.mp4 -t 4 -i night.mp4 \
-filter_complex "[0:v]scale=640:360,fps=30[a];[1:v]scale=640:360,fps=30[b]; \
[2:v]scale=640:360,fps=30[c];[3:v]scale=640:360,fps=30[d]; \
[a][b][c][d]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0,format=yuv420p[out]" \
-map "[out]" -c:v libx264 -crf 20 -t 4 compare.mp4
まとめ
Cosmos Transfer 2.5 で車載映像の天候・時間帯変換を試しました。持ち帰っていただきたいのは 3 点です。
1. 破綻する場所は決まっている
エッジが検出されない領域は制御信号に縛られないので、そこだけモデルが自由に描きます。ガラス張りのビルや均一な路面が描き替えられるのはこのためです。おかしな出力が出たら、まず自動生成された制御映像を見てください。
2. vis はプロンプトと衝突することがある
vis は入力の明暗の配置を運ぶ制御です。「暗くしたい」「白く覆いたい」という指示と正面から綱引きになります。空や海面のような一様な面が画面を占める映像ほど起きやすいはずです。
3. 試すこと自体が高い
4 秒の動画 1 本に約 17 分、VRAM は 65,679 MiB。GPU も時間も要るので、当てずっぽうにパラメータを振るのは現実的ではありません。1 と 2 のように、制御信号を見て当たりを付けてから振るほうが早く着きます。
セットアップでつまずいた 5 点は本文に書いたとおりです。Python のバージョンとゲート同意の 2 つは、知らないとまず踏みます。
次回は、preset_edge_threshold や control_weight を振って、本記事で見つけた 2 つの仮説を検証してみます。
- エッジの閾値を下げると、描き替えを抑えられるのか
visの重みを下げると、空は暗くなるのか
参考にしたページ
Cosmos Transfer 2.5
- nvidia-cosmos/cosmos-transfer2.5 — 本体のリポジトリ。本記事のコード引用はここから
- Cosmos ドキュメント — Quickstart とシステム要件
- NVIDIA Open Model License — モデルウェイトのライセンス
NVIDIA Brev
- NVIDIA Brev
- NVIDIA Brev CLI で GPU インスタンスを起動してみた(同僚の田中)
- NVIDIA Brev の GPU インスタンスに VS Code Remote SSH と JupyterLab で接続してみた(同僚の田中)
Cosmos の他モデルの検証
- DGX Spark で NVIDIA Cosmos 世界基盤モデルを動かしてみた(同僚の森茂) — 本記事の VRAM の議論はこの記事の実測値が出発点です
- NVIDIA Cosmos 3 ファミリーの使い分けマップを整理してみた(同僚の森茂)
どなたかの参考になれば幸いです。






