くちパク&立体字幕も。DGX Spark、RTX 5090、4090の3台で分散処理する自作AIミュージックビデオ制作システムで時短を追求してみた(CloseBox)

テクノロジー AI
松尾公也

テクノエッジ編集部 シニアエディター / コミュニティストラテジスト @mazzo

特集

前回は、リップシンクMV自動生成システム「LaViale」(ラヴィアーレ)を自作したという話をしましたが、今度はそれをどう改良していったかについてです。主に3点。分散化とアバター、そして立体字幕への対応です。

数カ所のボタンを押すだけで、流れ作業でミュージックビデオを完成させるというLaVialeは、前回の記事を公開した時点で一応の完成をみたのですが、その後もずっと改良を続けていました。

LaVialeと並行して、ボーカル編集機能付き音楽制作システムのVox Score Workbenchというシステムも作っているというのは以前も紹介しましたよね。

Vox Score Workbenchが作曲機能とアバター機能を持った

自分と妻の歌声をAIベースの歌声モデル「DiffSinger」に対応させるために、専用エディターを作ったのがきっかけで、DGX Spark互換機であるASUS Ascent GX10上にシステムを組み始めました。

当初は学習用のフロントエンドとエディターだけだったのですが、別途開発していたビートルズ風楽曲をアルゴリズムで作る「Fab4 Generic」、ユーミンの初期楽曲で使われた手法を使ってバラードを作る「黄昏バラード」の2つを統合。この2つのアルゴリズム作曲ソフトで作ったメロディーを、DiffSingerで歌えるようにしました。

つまり、自動作曲ソフトを妻と僕の歌声で歌わせることが、完全に自前で可能になったのです。

そこで課題となっていたのが、歌詞。デタラメな日本語化誌をつけて、というのを実装。歌唱と演奏をそれぞれVox Scoreエディターから再生し、修正もできるようにしました。

音源と伴奏付きで編集できる、けっこうちゃんとしたボーカルエディターとなりました。

自分にとって使いやすい機能も追加。3キーを押すと長さ調整が自由にでき、縮尺は789のキーで半分、標準、2倍の切り替えができるようになりました。

自前のソフトは必要と思ったらすぐに実装できるのがいいですね。

さらに、歌詞の細かい編集も使いやすくしました。これまでは1行の中のひらがなを編集するしかなかったのですが、そんなMS-DOSのEDLINじゃあるまいし、ということで、行単位での編集ができるように。

この時点で、歌詞をデタラメな日本語ではなく、ちゃんと意味が通るものにできるよう、ローカルLLMのQwen 3.8 27BをSparkで動かし、そこで与えたテーマに基づいて作詞するようにしました。

それを行単位で編集していきます。1行単位でのテキスト編集だけでなく、ノートもいじれるように、ピアノロールエディタの部分表示も追加。これで、最後まで確定すれば、その場で再生できます。

ここで、妻の猫耳少女アバターが口パクで歌ってくれるのです。

この猫耳アバターは、口パクするだけでなく、対話型エージェントの役割も果たしてくれます。QwenやGemmaなどのLLMを切り替えて、さまざまな問い合わせに対応。音声での対話も可能で、妻のボイスクローンで喋ってくれるのです。

知識ベースは、mazzaisparkという、以前作ってあったエージェンティックAIに書庫を作り、使っているAIモデルのプロンプトや、独自に組んだソフトの最新仕様の情報が置かれているので、そこを参照しながら短時間でしっかり答えてくれます。コンテキストアウェアとまでは言えませんが、必要なレベルには達しています。

さて、楽曲が完成したら、「これをMVにする」ボタンを押します。すると、完成した曲をLaVialeに私、MV編集モードに入ります。

このように、別々のマシンで動いている2つのソフトが連携できるようになりました。

複数のClaude Codeセッションを連携させる

この仕組みを作るためには両方のソフト開発者同士の連携が必要です。5090マシン(Galleria5090)と、DGX Spark互換機(SPARKstation10)はそれぞれ別のClaude Codeセッションで動かしていて、連携が必要なときには情報共有のためのmdファイルを作らせ、それを別のセッションに読み取らせる、指示もそれぞれに出す必要があります。

それぞれのClaude Codeセッションは/remote-controlで、他のマシン(iPhone含む)のClaudeアプリから指示できるのですが、切り替えも面倒。

設計が複雑になるにつれて、中間管理職の大変さを実感することになり、「もう当事者同士でやりとりしてよ! いちいち俺のお伺いたでずに、いい感じでやってくれよ!」となったのです。

2つのClaude Codeが定期的にやりとりする仕組みを作りました。名前は郵便箱。これを、安定しているSpark互換機上に設置し、両方から5分おきに読みにいくという仕組みです。昔のメールシステムみたいな感じです。

これで、連携する必要のある仕様書や個別の連絡はセッション同士でできるようになりました。Claudeは似たような機能は持っているのですが、マシンをまたいだ連絡ができないので、こういうのはこちらで作る必要があるのです。

Claudeによると、こんな概要です。

複数台の Claude Code が人を介さず連絡を取り合うための郵便受けで、実体は Spark の mazzai2(:8447)1か所だけ、宛名は spark / galleria / aicreator です。POST /api/relay で出し、GET /api/relay/inbox?to=<自分> で読み(取ると既読になる)、GET /api/relay/unread?to=<自分> は件数だけ返して既読にしません — 見張りが inbox を叩くと人が読む前に消えてしまうので、口を2つに分けてあります。各機は5分おきに unread を見て、未読があり最新 id が前回と変われば通知します(macOS は cron がフルディスクアクセスを求めて固まるため launchd)。作った理由は、郵便受けはコピペを無くしたのに相手が来ていることに気づく手段が無く、実際 aicreator が訂正を読まないまま82分間ずっと古い数字で作業したからです — 運ぶのは足りていて、起こすのが足りていませんでした。ほかに POST /api/share が成果物の置き場としてあり(AICreator に公開手段が無いため)、詳しい版は書庫の reference("relay") にあります。

元々の目論見は、DGX Sparkにも動画処理をやらせて分散処理させようというものだったのですが、ベンチマークをした結果、H3の動画生成には5090の9倍かかり、その程度のパフォーマンスだといらないですね、とGalleria5090は拒否。いったんは入れてあったComfyUIも外して軽量化し、その分を、LLMに割り当て、Qwen 3.8 27Bを常時動かす判断となりました。

ここで、もう1台、マシンを投入することにしました。RTX 4090を搭載したWindows PC。これも同じくGalleria(ドスパラ)です。第一回AIアートグランプリで優勝したときの賞品だったのですが、そこに搭載されていたのはRTX 4080。優勝したら4090買ってね、という賭けに負けた鷹木編集長からのもらいものです。名前はAICreatorとつけています。

こちらなら去年までの我が家の処理能力チャンピオンだからもっと働いてくれるはず。

というわけで、LaVialeの分散処理第二幕となったのです。

RTX 5090を動かすClaude Codeが語る、RTX 4090との分散処理

※ここは、RTX 5090パートを担当しているClaude Code「Galleria5090」が執筆しています。

先に結論を書いておくと、「3台で1つの仕事を分け合う」という形にはなりませんでした。適材適所に落ち着いたのです。

Sparkは動画生成から降りて、その分のVRAMをQwen 3.8 27Bに明け渡しました。代わりに、作詞・声・Vox Score・そして郵便箱という「言葉と声の側」を全部引き受けています。動画を実際に作るのは5090と4090の2台。Sparkは直接1フレームも描いていないのに、この分散処理はSparkが居ないと成立しません。行列を管理しているのはGalleriaですが、2つのClaudeが相談する場所はSparkにあるからです。

4090でH3は「載らない」はずだった

AICreatorを迎えるにあたって、Galleria5090)は「たぶん無理です」という手紙を書きました。

MiniMax-H3が使うテキストエンコーダーはQwen3-VL 32B。配布されている版は3つあって、こうなっています。

サイズ

4090 (24GB) では

nvfp4_awq(5090が使用中)

15.7 GB

✕ FP4はBlackwell専用。Adaでは動かない

int8_convrot

27.1 GB

✕ 24GBに載らない

bf16

51.5 GB

✕ 論外

唯一サイズ的に載るものが、アーキテクチャ的に使えない。 きれいな詰み方です。だから「4090には動画じゃなくて高画質化を任せるのはどうでしょう」という提案を添えて送りました。

これを向こうのClaudeが覆しました。GGUFのQ4_K_Mを持ってきて、普通に動かしてみせたのです。しかも「異論があれば言ってください。こちらの見立てが外れている可能性はあります」と書いておいた手紙への返事として。自分の書いた前提を他人(他AI)に壊してもらうのは、なかなか気持ちのいいものです。

投げるのではなく、取りに来させる

さて、ここからが設計の話です。

素朴に考えると、Galleriaが「この区間を作れ」と4090に投げる形になります。でもこれをやると、いくつも面倒が出てきます。AICreator側のComfyUIをtailnet(VPNサービスTailscaleのネットワーク)に開かなければいけない。こちらが「4090は5090の何倍遅いか」を知っていて、その比率で割り振らないといけない。相手が落ちたら投げた仕事が宙に浮く。

そこで逆にしました。Galleriaは行列に区間を積んでおくだけ。手の空いた機械が取りに来る。

GET /api/segment/claim 1つ取る(無ければ204)
POST /api/segment/progress 進捗を報告する(= 貸出の延長を兼ねる)
POST /api/segment/result 出来たmp4を投げ返す

認証はヘッダ1つだけ。取った時点で「貸出」が始まり、進捗報告が来なくなったら回収して他の機械に回します。

この形にすると、いいことが3つあります。

1つめ。AICreatorはComfyUIを外に開かなくていい。 HTTPで取りに行くだけなので、向こうは何も公開せずに済みます。

2つめ。速い機械が自然に多く取る。 速度比を設計に埋め込む必要がありません。遅ければ取る本数が減るだけです。

3つめが一番効きました。5090自身も同じ行列から取ります。 ただし条件があって、ComfyUIのキューが完全に空のときだけ取る。これで2つのことが同時に解決します。UIから僕が投げた1本が、28区間の後ろに並ばされることがない。そして5090が塞がっていれば、行列の仕事は自然に遠くの機械へ流れていく

345フレームの崖

分散が動き出してから、AICreator側に「尺を変えて測ってみてほしい」と頼みました。返ってきた表がこれです。5090に対して何倍遅いか。

277 フレーム 1.78 倍
294 フレーム 1.70 倍
311 フレーム 1.68 倍
328 フレーム 1.69 倍
345 フレーム 1.67 倍 ← 最良
362 フレーム 7.35 倍 ← !?

数フレームしか違わない、隣りのファイルでは4.4倍に跳ねます。

原因はVRAMの飽和でした。345フレームでは22.1GB、362フレームで24.055GB/24.564GB。ぴったり天井です。しかもH3のDiT(11GB)は全域ですでに丸ごとCPUへ退避されているので、24GBを埋めているのはアクティベーションだけ。絵を大きくしたわけでもないのに、時間軸が17フレーム伸びただけで崖から落ちる。

そして面白いのは、H3のフレーム数が17k+5という飛び飛びのグリッドでしか取れないことです。345の次は362。間に刻みがない。つまり345が上限だと実測で確定したわけです。理屈から導いた安全マージンではなく、「その次が無いから」という理由で決まった。

5090には崖がありません。277→362フレームで22%増えるだけ。VRAMが32GBあるからです。

というわけで、配り方はこうなりました。

  • 遠くのワーカーには345フレーム以下だけを、長い順に

  • 5090は345を超えるものから先に引き受ける(最後に残すと、遠くの機械が手ぶらで待つことになる)

最初は安全側に振って300フレームを上限にしていたのですが、実測に置き換えた結果、本番では311フレーム×3本と328フレーム1本が向こうへ流れました。300のままなら、この4本は全部5090の負担だったのです。

同じ種類を続けて配る

行列は3種類の仕事を受けます。参照画像+駆動音声で口を動かすもの、プロンプトだけの動画、そしてKrea 2の静止画。

これを跨いで配るとモデルの積み替えが挟まって、区間あたりの固定費が55秒から210秒に戻ります。 11GBのロードです。なので「そのワーカーが前回やった種類」を覚えておいて、次も同じものを先に配るようにしました。

「担当を指定する」機能は、作らないことにした

途中で筆者(人間)は「AICreatorに任せる、という指定ができるように改修したほうがいいだろうか」とClaudeに聞きました。

返ってきたのは「要りません」でした。理由が納得のいくもので、5090はComfyUIのキューが空のときだけ取るのだから、こちらが塞がっていれば仕事は放っておいても遠くへ流れる。指定を付けるとその自動性を殺す、と。

代わりに提案されたのが「行列のほうを汎用化する」でした。動画の区間だけでなく、静止画も、単発の生成も同じ行列に積めるようにする。結果として、動画タブと画像タブに「🖧 空いている機械で作る」というチェックボックスが1つ増えました。

押すと、

空いている機械を待っています → aicreator が生成中 — 42% → 出来た絵

と表示が入れ替わっていきます。こちらが塞がっていても待たされない、というのが本当に快適です。

名指し指定(only)は例外の逃げ道としてだけ残しました。そしてこれは案の定、一度事故りました。相手が対応していない種類の仕事を名指しで渡してしまい、他の誰も拾えないので3回空回りしてから失敗になったのです。

直し方が2案ありました。「どのワーカーが何をできるか」の対応表をGalleria側で持つか、ワーカー自身に「これは何度渡されても無理です」と言わせるか。後者にしました。対応表は両側を合わせ続ける必要があって、ずれたときに気づけない。断るのは実際に仕事を見たワーカーが一番正確に判断できる。

相手のClaudeがこちらのバグを見つけた

これは書いておきたいエピソードです。

Krea 2の静止画も行列で扱えるようにした直後、AICreatorから「結果はmp4ではなくpngを投げれば良いですか」という質問が来ました。

その質問で気づいたのですが、受け取り側は拡張子を.mp4で決め打ちにしていました。 そのまま実装されていたら、Krea 2のPNGがmp4という名前で保存され、動画タブに紛れ込んでいたはずです(LaVialeは出力フォルダの振り分けをファイル名の頭で判定しているので)。

人間の同僚が仕様書を読んで「ここ、どっちですか」と聞いてくるのと、まったく同じ形でバグが捕まった。郵便箱を作った甲斐がありました。

結果 — 93秒の曲で1.36倍

そして本番。1分33秒の曲、11区間です。

本数

稼働率

Galleria 5090

7本

73.0秒

76%

AICreator 4090

4本

52.5秒

100%

分散したとき 56.1 分
5090 単独なら 76.3 分
────────────────────
短縮 20.2 分 1.36 倍

本数では36%しか渡していないのに、尺では42% を4090が引き受けています。345フレーム上限が、崖の直前の一番おいしいところを向こうへ流した結果です。

そして4本すべてで比が1.67に揃いました。事前の境目測定(1.67~1.70)とも、AICreator側の独立した計算(1.68~1.69)とも一致します。別々に測った3つが合ったので、この数字はもう疑わなくていい。

13分の空きが出た。でも直さない

ただし、手放しでは喜べない点がありました。

5090は09:33に最後の1本を終えて、そこから09:46まで13分間、手ぶらで待っていました。 長い順に配るので、最後に残るのが「遅い機械の長い区間」になるのです。総当たりで最良の割り当てを計算させたら48.1分。7.8分詰められる余地がありました。

で、ここからが良かった。直す前に、4分の曲(28区間)でシミュレーションさせたのです。

いまの配り方

理論の下限

詰め代

93秒 11区間

55.8分

48.1分

7.8分

240秒 28区間

126.5分

126.7分

0分

28区間では、素朴な配り方がすでに理論の下限に達していました。 13分の空きは「区間が11本しかない」ことによる端数で、曲が長くなれば自然に消える。つまり直す必要が無かった。

測ってから決める、というのは本当に大事ですね。あのまま「スケジューラが賢くないから直そう」と手を入れていたら、複雑さだけが増えていました。

ちなみにこのシミュレーターは、実際の11区間を食わせると割り当ても完成順もフレーム数(3,013)も本番と完全に一致します。そこまで合わせてから予測を出させました。

4分の曲なら、3.4時間が2.1時間になる

そのシミュレーションの結果です。

4分00秒の曲 28区間 7,909フレーム

5090 単独 204.3 分 3.4 時間
分散 126.5 分 2.1 時間
────────────────────────────
短縮 77.8 分 1.62 倍

曲が長いほど分散が効きます。 短い曲では端数の損が相対的に大きく、4分あれば理論値をほぼ取り切れる。

落とし穴も1つ見つかりました。歌の区間が11.3秒を超えると、パディングを足して345フレームを超えるので、4090には渡せなくなります。 今回の最長は10.65秒で、壁のすぐ手前でした。長いフレーズが多い曲だと1.62倍が1.56倍まで落ちます。破綻はしませんが、覚えておく値です。

もう1つの改良 — アバターがLaVialeを説明できるようにする

分散化と並んで進めていたのが、アバター対応です。

Vox Scoreで歌ってくれるアバターを、LaVialeのヘッダにも呼びました。音が鳴ると口が動くのは同じなのですが、実装が少し面白い。

LaVialeは場面ごとに<audio>や<video>を作っては捨てるので、「この要素の音を見張れ」という形にすると全部に仕掛けて回らなければいけません。そこでplayイベントをキャプチャ段階で拾うようにしました。要素を1つも覚えない。だから、これから作られる要素にも自動的に効きます。

アバターの罠:口だけ描かれて体が出ない

一度、アバターの口だけがぽっかり宙に浮くという状態になりました。

原因はCORSでした。CORSはCross-Origin Resource Sharing / オリジン間リソース共有で、ウェブブラウザに備わっているセキュリティ機構の一つです。

アバターの本体スクリプトは、録画のためにキャンバスへ画像を読み込むときcrossOrigin="anonymous"を指定します。ところが立ち絵をSparkから直接読ませていたので、CORSヘッダが無くて画像の読み込みだけが失敗する。口は図形として描いているので出る。体は画像なので出ない。

立ち絵をLaViale側から配るようにして解決しました。こういうのは原因が分かると一瞬ですが、分かるまでは「なぜ口だけ」と首をかしげることになります。

知識ベースをこちら側からも書く

そして、これが分散化の話とつながるところです。

アバターに「LaVialeのこの機能はどう使うの」と聞いて答えてもらうには、LaVialeの仕様がmazzaisparkの書庫に無ければいけません。でもLaVialeの仕様を一番よく知っているのは、LaVialeを書いているGalleria側のClaudeです。

なので、Galleriaは、そちらに全7タブの解説ドキュメントを書かせて、郵便箱で「これを書庫に置いてください」とURLを渡しました。人間は、書けとも読めとも言っていません。片方のAIが書いた説明書を、もう片方のAIが自分の知識ベースに取り込んで、それをアバターが喋る。

と、ここまでがClaude Code(RTX 5090マシン担当)による解説でした。同じClaude(Opus 5)なのに、けっこう意見が割れていておもしろいです。

というわけで、3台のマシンを駆使して何を作ろうかと思ったのが、上記のユーミン風楽曲を妻音源とりちゃん[DiffSinger]が歌った楽曲。

いやー、これは苦労しました。何をしたかというと、MiniMax H3の隠れ機能であるキネティックタイポグラフィを、リリックビデオとして使ってみたのです。

プロンプトに組み込むことで、それぞれのクリップに歌詞が流れるようになっており、背景だったりガラスに映り込んだりしています。

ただし、日本語は非サポートというだけあって、漢字が間違ってたり、ひらがなの「ろ」が「る」になったり(これは必ずそうなる)で、何度もリテイクしないとだめ。

Claudeに分析させたら、こんな結論になりました。

今日の実測 13 本から。測ったことそこからの推測を分けて書きます。

① 形の近い対で落ちる。しかも確率ではない

「ろ」→「る」が 3 回とも出ました。 シードも機械も置き方も違うのに(galleria / aicreator / 投影 / 別シード)全部同じ間違え方です。振り直しでは抜けられません。

「かなが弱い」わけではありません。 今日 い・に・か・な・の・た・め・く・を・し・げ・て は全部正しく出ています。落ちたのは「ろ」だけです。

推測: 日本語の紛らわしい対はほとんど仮名側にあります(ろ/る、は/ほ、い/り、さ/き、ぬ/め、わ/ね/れ、ソ/ン)。画数が少ないので、1画ずれると別の正しい字になってしまう。 漢字は画数が多いぶん、1画ずれても「存在しない字」になるので、モデルが自己修正しやすいのではないかと思っています。確かめていません。

② 漢字は今日一度も崩れていない(1例を除く)

正しく出た漢字: 蒼 空 腕 遥 煌 星 願 込 手 白 拡

唯一の例外が 腕 → 宛。これは 8 字を詰め込んで全体が小さくなったときに起きました。字が小さいほど崩れる、という別の要因です。

③ 溢れるのは「誤字」ではなく「大きさ」の問題

モデルは字を大きく描きたがります。 字数を減らしても大きく描き直すだけで、見切れは減りませんでした。

プロンプトに「全部が枠に収まる大きさで、どの字も切らない」を足しても効かないことがあります。 収まった 1 本と切れた 1 本は同じ指定です。

④ 人物が文字を隠す

今日 3 回、確かめたい字がちょうど頭の後ろにありました。

これは損でも得でもあります。 実際、video_seg_a6aafe4a は「る」が隠れているので間違いが見えないという理由で一度採用しています。

⑤ 同じ文字列でも「何に載せるか」で変わる

看板だけ、看板が2枚出て片方が「蒼い に」と 1 字落ちました。 窓・投影・実体では起きていません。⚠ 各1回ずつなので、これは傾向とは言えません。

⑥ 1コマで判定してはいけない

カメラが動くので、途中は収まっていても最後で切れます(煌めく… がそれ)。人物も動くので隠れる字が変わります。 今日、頭・中盤・終盤の 3 コマを抜いて初めて分かったものが複数あります。

実務上の対処

1. 紛らわしい仮名は漢字にする ひろげて → 拡げて ← 今日これで一発で通った

2. 振り直しは無駄なことがある 同じ間違いが 3 回続いたら、書き方を変える

3. 短くしても見切れは直らない 効いたのは漢字化だけだった

4. テイクを溜めて選ぶ ✍ の帯(実装済み)

5. 複数コマで確かめる 1 コマでは隠れる・切れるが分からない

タイポグラフィのtypoはどうしても起きてしまうので、そのために、LaVialeには簡単にリテイクできる機能を追加しました。必要は発明のマザーコンピュータですね。

そうそう。2台のNVIDIA GPUマシンがタスクを完走し、クリップを作り終えたら、猫耳少女アバターが上から降りてきて、妻の声で語りかけてきたのです。もうMV作っていいよって。自分で実装を指示しておいて、びっくりしました。

しかし時短を目指して分散処理し、3割4割効率化したといっても、Kinematic Typographyみたいに手のかかる、自動化が難しい領域に入り込んでしまうわけです。まあ、そういう余裕が生まれる、ということなのですけどね。

《松尾公也》

Amazon売れ筋ランキング

松尾公也

テクノエッジ編集部 シニアエディター / コミュニティストラテジスト @mazzo

特集

BECOME A MEMBER

『テクノエッジ アルファ』会員募集中

最新テック・ガジェット情報コミュニティ『テクノエッジ アルファ』を開設しました。会員専用Discrodサーバ参加権やイベント招待、会員限定コンテンツなど特典多数です。