0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オープンウェイトの音楽生成AI MiniMax-Music3 を RunPod で動かして13曲作った(実測値まとめ)

0
Last updated at Posted at 2026-08-16

オープンウェイトの音楽生成AI MiniMax-Music3 を RunPod で動かして13曲作った(実測値まとめ)

2026年8月14日にオープンウェイト公開された音楽生成モデル MiniMax-Music3 を、RunPodでGPUを借りて動かしてみました。

環境構築から生成まで一通りやって、1.72時間・約137円で13曲できました。VRAMやRAMの実際の使用量、生成にかかる時間、ハマりどころをまとめます。


TL;DR

  • 歌詞+音楽の説明文から、**最長5分のフル楽曲(歌入り)**を生成するモデル
  • 既存曲を参考にしたカバー生成はできない(音声を入力するパラメータが存在しない)
  • 実測: VRAM 23.3GB・システムRAM 26GB・リアルタイム比 0.47倍
  • VRAMは曲の長さに依存しないので、24GBのGPUで足りる
  • ただしシステムRAMは32GB以上必要。ここを見落とすと最安GPUを選んで詰む
  • 出力は 44.1kHz / 16bit / ステレオ(READMEの「32kHz」は誤り)
  • 5分の曲1本あたり 約14円

MiniMax-Music3 とは

約11Bパラメータの音楽生成モデルです。構成が特徴的で、

Global LLM (8B, Qwen3-8B由来)   ← 曲の長期構造・意味を担当
        ↓
Local LLM (0.6B)                ← フレーム内の音響細部を担当
        ↓
   隠れ状態の融合
        ↓
Flow Matching (2.4B)
        ↓
Flow-VAE Decoder (123M)
        ↓
      ステレオ音声

離散トークンだけからデコードするのではなく、Global / Local 両LLMの最終隠れ状態を融合してFlow Matchingに渡します。この連続表現が発声のニュアンスや楽器の質感を保つ、という設計です。

できること

  • 歌詞 + 音楽説明文 → 最長5分のフル楽曲。イントロ〜Aメロ〜サビ〜間奏〜アウトロの構造が崩れない
  • 歌詞に構造タグを書ける: [intro] [verse] [pre-chorus] [chorus] [post-chorus] [bridge] [instrumental] [solo] [outro]
  • 日本語の歌詞も歌う
  • シード指定で再現可能

説明文は3層の Structured Caption で書くと制御が効きます。

  • Global Metadata: ジャンル / BPM / キー / 感情の推移 / 聴取シーン / 音質
  • Vocal Details: 声の性別 / 音色 / 歌い方 / ハモリ / エフェクト
  • Arrangement: 主要楽器 / セクションごとの変化 / グルーヴ / 空間処理

できないこと

既存の曲を読み込んで、それを参考に新しい曲を作ることはできません。

期待している人が多そうなので実装を確認しました。diffusersパイプラインが受け付ける入力は次の4つだけです。

InputParam("prompt",   required=True)   # 音楽の説明文
InputParam("lyrics",   required=True)   # 歌詞
InputParam("audio_duration", default=60.0)
InputParam.template("generator")        # シード

音声を渡すパラメータが存在しません。

紛らわしいのが condition_encoder/config.json で、

{"input_sampling_rate": 24000, "input_hop_length": 960}

いかにも音声を食いそうに見えますが、実装は forward(hidden_states) で、これはLLMのフレームレートを潜在フレームレートに変換するための係数でした。音声入力ではありません。

カバー生成はMiniMaxの商用APIにある music-cover という別モデルの機能(audio_url / audio_base64 / cover_feature_id を受け取る)で、オープンウェイト化されていません。公式クラウドの music-3.0 エンドポイントですら歌詞+説明文のみです。

その他の制約

  • CUDA必須(CPU推論不可)
  • ストリーミング生成は非対応
  • プロンプトは5,000トークンまで、生成は9,000フレーム(6分)まで
  • タグやBPM指定は「誘導」であって「保証」ではない(公式が明記)

なぜRunPodを使ったか

ウェイトが約26GBあり、これがシステムRAMに乗るためです。

公式READMEには「CPUオフロードを使えば8GBのビデオカードでも動く」とありますが、これはVRAMの話です。CPUオフロードはVRAMに載りきらないウェイトをシステムRAMに置く仕組みなので、VRAMを節約した分はそのままRAMの消費になります。

手元のRTX 3060機(VRAM 12GB / システムRAM 30GB)では、RAM側が先に限界に達しました。VRAMではなくシステムRAMがボトルネックになるというのが、このモデルを動かす上での最重要ポイントです。


GPU選定

RunPodの当日価格(VRAM 24GB以上)です。

GPU VRAM RAM vCPU Community Secure
RTX A5000 24GB 25GB 9 $0.16/h $0.27/h
RTX 3090 24GB 125GB 16 $0.22/h $0.50/h
RTX A6000 48GB 50GB 9 $0.33/h $0.53/h
RTX 4090 24GB 41GB 6 $0.34/h $0.74/h
A40 48GB 50GB 9 $0.35/h $0.44/h
L4 24GB 50GB 12 $0.44/h $0.49/h
L40 48GB 94GB 8 $0.69/h $0.82/h

選定条件は2つ。VRAMだけで決めてはいけません。

  1. VRAM ≥ 24GB
  2. システムRAM ≥ 32GB(ウェイト26GBがホストRAMを通過するため)

この2条件を掛けると、最安の RTX A5000 は RAM 25GB なので脱落します。単価だけ見て選ぶと、ウェイトが載らずに詰みます。

第一候補は RTX 4090 Community($0.34/h)にしましたが、当日は 4090 / A6000 / A40 / L40 の Community が全滅していて、実際に取れたのは RTX A6000 / Secure / $0.53/h でした。VRAM 48GBあるのでオフロード設定が一切不要になり、結果的に検証がシンプルになりました。

割り当てリソースは cgroup で確認する

freenprocホスト全体の値を見せてくるので当てになりません。

$ free -g
              total        used        free
Mem:            503          81         139     # ホスト全体の値

$ cat /sys/fs/cgroup/memory.max
49999998976        # = 46.6GiB ← 実際の割り当て
$ cat /sys/fs/cgroup/cpu.max
765000 100000      # = 7.65 vCPU

ディスク速度

コンテナディスク (/)       2.9 GB/s
/workspace(ネットワーク)  535 MB/s

ネットワーク側は5倍遅いですが、27GBのロードで50秒程度の差にしかなりません。そもそも30GBのコンテナディスクには27GBのモデルが入らないので、モデルは /workspace に置きます


環境構築

イメージ

runpod/pytorch:1.1.0-rc.154-cu1281-torch280-ubuntu2204

確定した構成:

パッケージ バージョン
Python 3.12.13
torch 2.8.0+cu128
CUDA 12.8
transformers 5.15.0
diffusers 0.40.0.dev0

インストール

diffusersは未マージのPRブランチが必要です(2026年8月時点)。所要22秒

pip install --no-cache-dir \
  "git+https://github.com/huggingface/diffusers@dafe3733fcfdbf3c48915fe77be3aef65b5d6a2d" \
  transformers accelerate soundfile "huggingface_hub[cli]"

ハマりどころ① pythonpython3 が別物

このイメージには torchが入った /usr/local/bin/python と、素の /usr/bin/python3 が両方あります。pip は前者に紐づいています。

python  -c "import torch"   # OK
python3 -c "import torch"   # ModuleNotFoundError: No module named 'torch'

セットアップスクリプトを python3 で書いていて、「pip installは成功しているのにimportできない」で少し悩みました。

ハマりどころ② リポジトリの半分は diffusers では使わない

素直に全部落とすと 54GB になります。

18G   qwen_7B/                  ← SGLang経路用。diffusersでは不要
16G   language_model/           ← 必要
9.2G  flowmatching_vae.pth      ← SGLang経路用。不要
9.1G  transformer/              ← 必要
1.3G  rvq_depth_decoder/        ← 必要
470M  dav.pth                   ← 不要
209M  vocoder/                  ← 必要
98M   condition_encoder/        ← 必要

modular_model_index.json が参照するのはサブフォルダの7コンポーネントだけなので、除外すれば 54GB → 27GB です。ダウンロード自体は65秒でした。

hf download MiniMaxAI/MiniMax-Music3 --local-dir /workspace/model \
  --exclude "qwen_7B/*" --exclude "*.pth"

--exclude "qwen_7B/*" "*.pth" と続けて書くと、2つ目が「そういう名前のファイル」と解釈されて404になります。--exclude は都度書いてください。

ハマりどころ③ ローカルパスを渡してもHubから再ダウンロードされる

modular_model_index.json7コンポーネント全部に、こうハードコードされています。

"pretrained_model_name_or_path": "MiniMaxAI/MiniMax-Music3"

このため、

pipe = ModularPipeline.from_pretrained("/workspace/model")  # ローカルパスを渡したのに

としても中身はHubを見に行き、27GBを再ダウンロードします。これに気づかずディスクを埋めました。

対策は2つセットで打ちます。

# 1. JSON内のパスをローカルに書き換える
for name, spec in data.items():
    if isinstance(spec, list) and len(spec) == 3 and isinstance(spec[2], dict):
        spec[2]["pretrained_model_name_or_path"] = MODEL_DIR
# 2. 事故ってもHubに出て行かないようにする
export HF_HUB_OFFLINE=1

ハマりどころ④ 公式READMEのサンプルコードが落ちる

READMEにはこう書いてあります。

sf.write("song.wav", audio.T.float().cpu().numpy(), pipe.sampling_rate)

しかし実際に返ってくるのは torch tensorではなくnumpy配列なので、

AttributeError: 'numpy.ndarray' object has no attribute 'float'. Did you mean: 'flat'?

で落ちます。生成を60秒かけて完走した後、最後の1行で死ぬので注意してください。

data = audio.T
if hasattr(data, "cpu"):
    data = data.float().cpu().numpy()
else:
    data = np.asarray(data, dtype=np.float32)

ハマりどころ⑤ サンプリングレートがREADMEと違う

READMEは全編を通して「32 kHz 16-bit stereo」と書いていますが、pipe.sampling_rate が返すのは 44100 です。出力WAVを確認しても、

44100 Hz  2 ch  PCM_16

でした。44.1kHz / 16bit / ステレオが正しい値です。


生成

コード

import os
os.environ["HF_HUB_OFFLINE"] = "1"

import torch, soundfile as sf
from diffusers import ModularPipeline

pipe = ModularPipeline.from_pretrained("/workspace/model")
pipe.load_components(dtype=torch.bfloat16)
pipe.to("cuda")

audio = pipe(
    prompt=prompt,          # 音楽の説明文
    lyrics=lyrics,          # 歌詞(構造タグ付き)
    audio_duration=90.0,
    generator=torch.Generator("cuda").manual_seed(7),
    output="audios",
)[0]

歌詞の書き方

構造タグは必ず単独行に置きます。実装のコメントに明記があります。

Structure tags such as [verse] or [chorus] must each be on their own line; text on the same line as a leading tag is dropped by the checkpoint's input contract.

[verse]
ぼくは まだ ちいさいけれど
ゆめだけは でっかいんだ
[chorus]
はやく おとなに なったなら
どこへだって いけるんだ

[verse] ぼくは まだ... のようにタグと同じ行に書くと、その本文は黙って捨てられます

説明文の書き方(実際に使ったもの)

Global Metadata: Genre modern kids pop anthem for an animated film.
Tempo 150 BPM, driving and danceable. Key D major, bright and upbeat.
Production profile: glossy modern pop mix, punchy drums, wide stereo.

Vocal Details: Lead vocal is a spirited young child, bright and cheeky.
Gang-vocal singalong chorus with children and adults.

Arrangement: Four-on-the-floor kick with loud handclaps. Marimba plays
the main hook. Bouncy synth bass, plucky synth stabs, layered hand
percussion, punchy brass stabs.

BPMやキーは効きますが、あくまで誘導です。厳密に一致するとは限りません。


実測値

ロード時間

工程
from_pretrained 0.2
load_components 5.7
to("cuda") 31.9
合計 37.8

ロード直後で VRAM 21.87GB、ホストRAM 28.64GB。

なおロード時間はページキャッシュの状態で大きく変動します(実測で 10.6秒 〜 91.0秒)。ネットワークストレージから27GBを読むと、それだけで約50秒かかるためです。

生成

ジャンル 指定尺 実際の尺 生成秒 リアルタイム比 VRAMピーク
英語アコースティックポップ 30s 30.02s 62.3 0.482 23.12 GB
日本語J-POPバラード 90s 70.88s 150.1 0.472 23.23 GB
日本語シティポップ 90s 64.76s 138.4 0.468 23.23 GB
Lo-fiインスト 90s 75.69s 160.9 0.470 23.28 GB
ミュージカル 180s 144.9s 321.3 0.451 23.3 GB
ミュージカル 300s 239.7s 553.8 0.433 23.3 GB

ここから3つのことが読み取れます。

① VRAMは曲の長さに依存しない

23.1〜23.3GBでほぼ一定です。Flow Matchingを200フレームの窓に区切ってdenoiseしているため、5分の曲でもVRAMは増えません。

つまり 48GBは過剰で、24GBのGPUで足ります。RTX 3090($0.22/h)や RTX 4090($0.34/h)で同じことができるはずです。ただしシステムRAM 32GB以上は必須です。

audio_duration は「上限」であって「目標」ではない

90秒を指定して出てきたのは 64.76〜75.69秒、300秒指定で 239.7秒でした。公式の説明通りです。

Generation may finish before this limit when the model emits an end-of-audio token.

狙った尺にしたいなら、audio_duration を長めに取った上で歌詞の分量で調整します。 尺の指定だけで曲を伸ばすことはできません。

③ 生成時間は尺にほぼ比例する

リアルタイム比が 0.43〜0.48 に収まっているので、**「欲しい秒数 ÷ 0.47」**で所要時間を見積もれます。

5分(300秒)のフル楽曲なら約640秒 ≒ 10.6分。A6000 なら 約14円/曲です。


費用と後片付け

実費

項目
GPU RTX A6000 / Secure Cloud
単価 $0.53/h
稼働時間 1.72 時間
実費 約 $0.91(約137円)
生成 13曲・合計約24分

環境構築に約6分(pip 22秒 + モデルDL 65秒 + 不要ファイル削除とパス修正)、残りは生成と試行錯誤です。1曲あたり約10円

RunPodは stop では課金が止まらない

ここは要注意です。 停止中のPodもストレージ課金が続き、しかも稼働中の倍単価($0.20/GB/月)になります。以前これでPodを放置して月$121(約18,000円)を発生させたことがあります。

終わったら必ず terminate(DELETE) して、残り0件を確認するまでがセットです。

for pod_id in targets:
    api("DELETE", f"/pods/{pod_id}")

time.sleep(6)
remaining = api("GET", "/pods")
print(f"VERIFIED: {len(remaining)} pod(s) remain")
if remaining:
    sys.exit(2)

セッションが切れても課金が止まるよう、Podの外にタイムアウト強制terminateを置いておくと安心です。Podの中に置くと、terminate時に自分ごと消えて後始末が完了しません。

モデルDLはGPUを借りる前にできるか

できます。ネットワークボリュームを先に作り、CPU専用PodでダウンロードしてからGPU Podに付け替えれば、GPUの課金時計はモデルが揃ってから回り始めます。

ただし単発なら割に合いません。

  • DL 65秒 = $0.53/h × 65s ≒ $0.01
  • ネットワークボリューム 60GB = 月$4.2 が置くだけで発生し続ける
  • ボリュームはデータセンター固定なので、そのDCに空きGPUが無いと詰む(今回まさにCommunityが全滅した)

繰り返し使うならボリューム、単発なら都度DL で良いと思います。


RunPod APIの注意点

新しい rpa_ 形式のAPIキーは GraphQL では 403 になります。 RESTを使ってください。

curl https://rest.runpod.io/v1/pods -H "Authorization: Bearer $RUNPOD_API_KEY"

エンドポイント一覧は GET /v1/openapi.json で取れますが、GPU価格を引くAPIはRESTには無いので、価格は料金ページを見るしかありません。

Pod作成時、条件を厳しくしすぎると落ちます。

{"error":"create pod: This machine does not have the resources to deploy your pod"}

特に minVCPUPerGPU に注意。RTX 4090は6 vCPUしかないので、8を要求すると弾かれます。実用的には、候補GPUを安い順に並べて空きがあるものを順に試すのが確実です。

CANDIDATES = [
    ("NVIDIA GeForce RTX 4090", "COMMUNITY", 0.34),
    ("NVIDIA RTX A6000",        "COMMUNITY", 0.33),
    ("NVIDIA A40",              "COMMUNITY", 0.35),
    ("NVIDIA RTX A6000",        "SECURE",    0.53),
]
for gpu, cloud, price in CANDIDATES:
    try:
        pod = api("POST", "/pods", build(gpu, cloud))
        break
    except urllib.error.HTTPError:
        continue

まとめ

MiniMax-Music3 は「歌詞と説明文からフル楽曲を作る」ことに特化したモデルで、そこはよくできています。日本語の歌詞も歌ってくれました。一方で既存曲を参考にする用途には対応していないので、そこが必要なら商用APIの music-cover を見ることになります。

環境構築で一番効いた知見は、VRAM要件だけを見てGPUを選ばないことでした。CPUオフロード系のモデルはVRAMをシステムRAMに逃がす仕組みなので、ローVRAM構成ほどRAMを食います。「8GBのGPUでも動く」という記述は、RAMが潤沢にあることが暗黙の前提になっています。

実測値をまとめておきます。

項目 実測
必要VRAM 23.3GB(曲の尺に依存しない)
必要システムRAM 26GB+α(32GB以上を推奨)
ロード時間 37.8秒(キャッシュ次第で10〜91秒)
生成速度 リアルタイム比 0.47倍
出力 44.1kHz / 16bit / ステレオ
コスト 5分の曲で約14円

なお商用利用する場合は MiniMax-Music3 COMMUNITY LICENSE により UI上に「MiniMax-Music3」の表示が必要です。ストック素材や動画制作に使う場合は確認してください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?