📃

高品質音楽生成AI【ACE-Step-1.5】で「破綻の微修正」に特化した新機能を提案する【Retake】

に公開

ACE-Step-1.5で使える新機能を考案しました。

高品質音楽生成AI【ACE-Step-1.5】で「破綻の微修正」に特化した新機能【Retake】を開発しました。
ぜひ、既存のRepaint機能との違いを確認してください。最後がRetakeです。
記事の後半でも、別の曲で比較していますので、ぜひご覧ください。
https://youtu.be/FgBosNFs4VY

はじめに

前回、ACE-Step-1.5のText2MusicとRepaintをPythonスクリプトから使う話を書きました。

あれはあれでかなり便利だったのですが、実際に曲を作っていると、どうしても最後に残る不満がありました。

  • 曲全体はかなり気に入っている
  • でも、数秒だけ歌い回しや発音を直したい
  • しかも、できれば原曲とほとんど同じ空気感のまま直したい

音楽生成AIを使っているとこういう課題は必ず付きまとう課題です。
曲自体の良さと破綻が一箇所もないという二つの要素でのガチャを要求されるため、ひたすら生成して注意深く曲を聞く必要があります。

ACE-Step-1.5ではRepaintの機能が公式から提供されており、それで破綻を治すことができるようになっています。とても素晴らしい機能です。
ただ、実際にやってみると「ちゃんと直ってはいるが、そこだけ少し別テイク感がある」ということが割とあります。

そこで、今回は、なぜRepaint機能で生成した編集箇所は、別テイク感があるのかという部分の説明と、破綻の微修正に特化した機能である「Retake」という機能を提案します。

一言でいうと、元曲の設計図と空気感をできるだけ残したまま、指定区間だけを録り直すための機能です。

悲しいですが、この2~3ヶ月間の唯一の成果です。

実際に比較をしてみる。

では、前回の記事の最後でも提示しましたが、実際に原曲の破綻部分を、公式Repaint機能と提案手法であるRetake機能を用いて修正した比較を行います。

この動画では、一部の歌詞が正しく読めていない部分の微修正を行うことを想定しています。
https://youtu.be/FgBosNFs4VY

Repaintでもかなり綺麗に修正できているように思うと思いますが、イヤホンなどできくと、編集箇所がわかる程度には違和感があると思います。
さらにいうと、Repaintに関しては違和感のない出力になるまで何度も何度も再生成をさせて一番良いものを利用しています。
対して提案するRetake機能に関しては、多くても4回ほどの再生成をすれば違和感ないトラックが生成されます。
4トラック程度であれば、RTX3060程度のGPUでも並列で一発で生成ができます。

また、Retake機能は後述しますが、その特性上、複数の編集区間を無劣化で同時に修正できます。
Repaint機能では一箇所しか修正できないのと、特性上Repaintを繰り返すと曲の品質が劣化するため、ここも大きな優位性です。

実際に、原曲のすべての破綻部分を微修正したものが以下です。
わかりやすいように比較で提示します
https://youtu.be/1QV36l8u7eI

聞いてみるとかなりわかりやすいのですが、Retakeは「全部作り直した別曲」ではなく、本当にその数秒だけ歌い直した感じにかなり近いです。
個人的には、ACE-Step-1.5の使い方の中でもかなり実用度が高い方法だと思っています。

実際に、Retake機能で微修正を施した曲全体も以下に置いておきます。
興味があればぜひ聴いてください。
https://www.youtube.com/watch?v=LJI3ZZMOmjg

実行結果の章では、また別の曲を使って比較をします。

ACE-Step-1.5とは

ACE-Step-1.5は、ACE StudioとStepFunが共同開発したオープンソースの音楽生成モデルです。
詳細な説明は以下の記事に譲ります。過去記事をご覧ください。
https://zenn.dev/asap/articles/6a717d7a68ec02

前回までは主にText2MusicとRepaintを扱いました。
今回は、そこからさらに一歩進めて、Repaintの違和感をさらに減らすために、既存の機能をどう組み合わせるかという話になります。

公式Repaint機能とは

現状のRepaint機能の特徴

今回の記事の立ち位置的に、公式のRepaint機能ではできないから、Retakeを提案するという流れになってしまっていますが、大前提として、Repaint機能自体が悪いわけではありません。

単純に、破綻の微修正に利用することを想定した機能ではないのと、ACE-Step-1.5で生成した曲だけでなく既存の曲や別のAIが生成した曲に対しても同じように使えることを優先した機能であることから、破綻の微修正とは相性が悪いだけです。

Repaint機能を図で解説すると以下です。

Repaintでは、原曲に対してVAE Encoderを適用して、潜在表現を得ます。
その潜在表現をベースに、DiTにてユーザが指定した歌詞、キャプションに合わせて潜在表現を再生して、VAE Decoderには波形化します。
この時、編集区間以外の部分が、大きく変更されないように、編集区間以外は、原曲にVAE Encoderを適用して得られた潜在表現に置き換えます。(単純に置き換えると、境界部分で違和感が大きくなるので、周囲のフレームを馴染ませる形で置き換えられます)
このようにして編集区間の編集を達成しています。

ちなみに、通常のText2Music機能を図で解説すると以下になります。

ユーザが指定した歌詞やメタ情報をもとに、LLMがaudio codesを生成し、それをベースに擬似潜在表現を得ます。
その擬似潜在表現をベースに、DiTにてユーザが指定した歌詞、キャプションに合わせてVAEに入力する潜在表現を生成して、VAE Decoderには波形化します。

Repaint機能が破綻の微修正と相性が悪い理由


問題点というとあれですが、理由は主に二点です。

理由①:原曲にVAE Encoderを適用して、潜在表現を取得している


公式のRepaint機能ではACE-Step-1.5で生成された曲に限らず、別のAIで生成した曲や、既存の曲の全てで適用できる機能です。
これらすべての曲で、一部の範囲の歌詞を変更したり、曲の雰囲気を変更することができる素晴らしい機能になります。

しかしながら、そのために、DiTに入れるsrc_latentsが、原曲をVAE Encoderに適用して得られた潜在表現を利用しています。
このsrc_latentsはDiTがノイズ除去をする上で重要なガイド役の役割を果たします。
直感的にいうと、DiTは間違いなくこのsrc_latentsに近づくようにノイズ推論をしていると予想できます。

しかしながら、Repaint機能ではVAEのEncoderを間に挟んでいるため、VAEを通すたびに「劣化」することになります。

加えて、Text2Musicの場合、DiTはLLMが生成したaudio codesから作成される潜在表現がsrc_latentsとなります。
この潜在表現は、VAE Encoderの出力に近付くようにLLMやAudioTokenDetokenizerは学習されていますが、本質的に違うものがDiTに入力される以上、得られる出力を原曲に近づけるのは難しいです。
曲の破綻の微修正に利用する場合は、破綻箇所以外の部分は、原曲の流れを完全に踏襲する必要があります。この部分が課題になります。

理由②:src_latentsの編集区間部分がsilence latentsに置き換えられている

公式のRepaint機能は、破綻部分の修正のためだけの機能ではなく、
例えば

  • サビ全体を別案にしたい
  • 雰囲気を結構変えたい
  • かなり大胆に作り直したい
    のような場合にも利用できる汎用性の高い機能です。

先ほど説明しましたが、src_latentsというのはDiTに伝えるガイド役であり、DiTはこのsrc_latentsに近付くようにノイズを除去するような挙動をする傾向があります。
しかしながら、Repaint機能において、編集区間に関しては「曲の雰囲気を原曲から大きく変えたい場合」、原曲の潜在表現をsrc_latentsに利用するのは、デメリットにもなり得ます。

すなわち、編集区間の雰囲気や歌詞を原曲から大きく変えたいにも関わらず、原曲の潜在表現がsrc_latentsに入っていると、それに生成する潜在表現が引っ張られてしまい、大きな雰囲気の変更が達成されない可能性が高いです。
そこで、公式Repaint機能では編集区間のsrc_latentsがsilence latentsという別物に完全に置き換わっています。

silence latentsは、その特徴は全く公開されていない、謎のファイルsilence_latents.ptから得られる特殊な潜在表現です。
公式Repaint機能では、編集区間に該当するsrc_latentsの値を、このsilence_latents.ptに格納されている600秒分の潜在表現に最初から置き換えていきます。
これにより、編集区間においては、原曲の情報を消去することで、よりバリエーション高い表現の生成が可能になります。
加えて潜在表現以外に関しては、原曲の潜在表現がガイドとして機能します。
さらに、DiTのステップごとに、編集区間以外に関しては、原曲のVAE潜在表現に適切なノイズをかけたものに毎回置き換えながら生成を進めることになっています。
これにより、編集区間外の状況に合わせるように編集区間内が再構成される、とても頭のいい設計になっています。

しかしながら、この設計こそが、破綻の微修正に向いていない最大の理由です。
破綻部分を修正する際に、編集区間の原曲の情報がないため、歌詞だけでなく、背景のBGMの情報や楽器の情報などが完全に消えてしまいます。
結果として、原曲の編集区間内のBGMの雰囲気が、DiTに引き継がれないため、若干の違和感が生じてしまいます。

前回のRepaint記事でも、かなり保守的な設定にして違和感を減らしました。
それでも、よく聞くと「完全に自然」とまでは言い切れませんでした。

提案手法「Retake」機能

ここまででRepaint機能というのがどういうものかわかっていただけたと思います。
つまりRepaint機能というのは、「ACE-Step-1.5」で生成された曲の「破綻を微修正」するためだけに存在するわけでなく、「あらゆる曲」で「さまざまな変更」を行う汎用的な機能です。

したがって、「ACE-Step-1.5」で生成された曲の「破綻を微修正」するという点に関しては今ひとつな性能と感じてしまいます。
そこで、私はこの「破綻の微修正」に特化した機能を提案します。それが「Retake」機能です

まずは、図解を提示します。

以下で解説します。

Retake機能の理論的な解説

ではRetakeは何をやっているのかというと、Repaintのように編集区間を一旦ほぼ空白にするのではなく、原曲の設計図と原曲のlatentの両方を使うようにしています。
また、「ACE-Step-1.5で生成された曲の破綻を微修正する」という前提のため、Text2Audioの段階で出力された中間出力(CoT情報やaudio_codes、最終的な潜在表現)を利用します。

1. 元曲の設計図をそのまま使う

Retake機能では、原曲のaudio codesからText2Musicパイプラインと同様にAudioTokenDetokenizerで25Hzにアップサンプリングした擬似潜在表現をそのまま再利用します。

つまり原曲が生成された時と同じsrc_latentsをDiTに入力することになるため、原曲を最も再現しやすい入力となります。

つまり、原曲を作ったときにDiTが見ていた条件をなるべくそのまま再構成しています。

2. 初期ノイズ状態を原曲寄りにする

Retakeの自然さに効いているのがここです。
DiTは初期のガウスノイズから複数のstepを経て、潜在表現を復元します。

この時、手元には、原曲の潜在表現を持っているため、初期ノイズに10%~30%ほど原曲の潜在表現を混ぜることで、より編集区間内の出力が原曲の方向性に近づきます。

ここで何をしているかというと、編集区間の初期状態を完全な白紙ノイズから始めるのではなく、原曲寄りの状態から始めるようにしています。
これにより、Repaint機能ではsilence latentsの影響で、「真っ白なキャンバスに描き直す」ように生成していましたが、Retake機能では「元絵をかなり薄く残したトレーシングペーパーの上で描き直す」ような挙動になります。
後者の方が、より原曲に馴染んだ編集が可能になります。

3. 原曲の真latentを利用して、編集区間外を復元する

これがRepaintとの大きな違いです。
上記の設定でDiTによって生成された潜在表現に関して、編集区間以外を保存している原曲の潜在表現に置き換えます。
VAE Encoderから得られた潜在表現では、Decoderに入れた後の波形が劣化してしまいますが、原曲を生成した潜在表現に置き換えることで、原理的に劣化しません。

したがって、Repaint機能のように波形による上書きの処理が不要になります。
音声波形がmp3などの非可逆圧縮を利用している場合などは、音声波形の処理のたびに劣化してしまいますが、Retake機能ではその心配はありません。
また音声波形を直接組み替えると、波形自体がどれだけ似ていても、音量の差などの影響もモロに受けてしまうため、区間境界での違和感を感じやすくなってしまいます。
これを実施しなくて良いのは、Repaint機能の明確な強みです。

4. DiTのtask_typeText2Musicで運用する

Instructionを原曲の生成時に合わせる

細かい話なので、図には反映させていないですが、ACE-Step-1.5では、マルチタスク学習が行われており、タスクごとにInstructionが自動で設定され、モデルに入力されます。

公式Repaint機能を利用する場合、DiTのtask_typerepaintになります。
実は、ACE-Step-1.5は、このtask_typeが変わると、モデルの挙動が変更されます。

具体的には、DiTのCross Attention層に入力されるEmbeddingsに関連するTask Instructionが変更されます。

ここには大きな罠があります
実は、Text2Musicを実施したとしても、DiTに入力されるInstructionがText2Musicのものとは限りません。
分岐点は、audio codesを利用するかどうかです。
利用しない場合はtext2musictask_typeが利用されます。
一方で、audio codesを利用する場合のtask_typeはなぜかcoverになります。

つまり、Text2Musicにおいて、LLMを利用してcaptionからaudio codesを生成し、DiTのsrc_latentsに利用する場合は、必ず内部的なtask_typecoverに変わります。
そして、このtask_typeの違いは、DiTのcross_attentionに入力されるInstructionに影響します。
したがって、Retake機能においても、保存したaudio codesを利用するため、内部的なtask_typecoverを利用します。

さて、Coverの場合のInstructionは

"Generate audio semantic tokens based on the given conditions:"

となっています。
このテキストの後に、主にCaptionの内容やMeta情報の内容が記述されているテキストをQwen3-Embedding-0.6Bによって、Embeddingsして、DiTのCross Attentionにて条件付けしています。

しかし、task_typerepaintの場合のInstructionは

"Repaint the mask area based on the given conditions:"

となっており、若干異なります。
なので、Repaint機能を利用するよりも、Text2Music機能でDiTを動作させる方が、原曲を生成した時と同じ条件で動作させることができます。

Instructionの詳細

以下で、タスクごとにハードコードされている。

ACE-Step-1.5/acestep/constants.py
TASK_INSTRUCTIONS = {
    "text2music": "Fill the audio semantic mask based on the given conditions:",
    "repaint": "Repaint the mask area based on the given conditions:",
    "cover": "Generate audio semantic tokens based on the given conditions:",
    "extract": "Extract the {TRACK_NAME} track from the audio:",
    "extract_default": "Extract the track from the audio:",
    "lego": "Generate the {TRACK_NAME} track based on the audio context:",
    "lego_default": "Generate the track based on the audio context:",
    "complete": "Complete the input track with {TRACK_CLASSES}:",
    "complete_default": "Complete the input track:",
}

編集区間をモデル内で利用しない。

Retake機能では、編集区間はDiTモデルに影響を与えていません。
編集区間はDiTの実行が完了した後に、原曲に潜在表現に対してOverwritingを行う際にのみ利用されています。

ここも多少公式Repaint機能と異なる部分です
task_typerepaintの場合、編集区間が設定されると、DiTの入力の一つであるchunk_masksが変更されます。
このchunk_masksの値は、潜在表現(生成したい曲の秒数x25Hz)の長さと全く同じ長さのマスクとなっており、このマスクの値が1である箇所は、DiTに新規で生成を要求したい位置を表します。

具体的には、Text2Audioの場合は、曲全体を新規で生成してほしいため、chunk_masksは全ての位置で1(True)となっています。
一方でRepaintの場合は、編集区間の内部のみを新規で生成してほしい(その他の部分はsrc_latentsと入れ替えるので、力を入れる必要はない)ため、編集区間の内部の位置のみが1(True)となっています。

しかしながら、今回わざわざ、原曲を生成した時の潜在表現やaudio codesやメタ情報を保存して、それをDiTに入力することで、原曲になるべく寄せるような形にしています。
そこで、chunk_masksに関しても全て1(True)となるようにしています。

以下にRepaint機能とRetake機能における、chunk_masks付近の図を再掲します。

公式Repaint機能

提案Retake機能

このように、提案するRetake機能では、編集区間の情報はDiTに入力されておらず、chunk_masksに関しても影響を受けていないことがわかります。
これらの変更により、Retake機能でのDiTは、完全にText2Audio時と同等の挙動をするように設計されているため、かなり原曲に近い値が生成されます。

実際に実行する

実行環境

今回も、基本的には前回記事と同じ環境です。

  • OS: Ubuntu 22.04
  • GPU: RTX 3060 12GB
  • Memory: 64GB
  • Python: 3.11.7
  • uv: 0.10.4

リポジトリ

以下を利用します。
https://github.com/personabb/acestep15_cli

環境構築

以下のコマンドで必要なリポジトリをクローンして、環境構築します。

git clone https://github.com/personabb/acestep15_cli.git
git submodule update --init --recursive
uv sync

もしうまく実行できなかった場合は、サブモジュールのcommitを以下に合わせてください

cd ./ACE-Step-1.5  
git checkout 82252c2418de6cb8b3ca99b05592aaf539cc7fb3

フォルダ構成

最終的には以下のようになります。
outputs/フォルダは実行後に生成されます。

(作業ディレクトリ)/
├── cli_exe_infer_sft.py
├── cli_exe_infer_repaint.py
├── cli_exe_infer_retake.py
├── cli_exe_infer_utils/
│   ├── retake_latents.py
│   ├── retake_runtime.py
│   ├── retake_seed_utils.py
│   ├── task_type_fix.py
│   ├── sft_lm.py
│   ├── sft_rng.py
│   ├── sft_workflow.py
│   ├── task_type_fix.py
│   ├── audio_input_compat.py
│   └── session.py
├── ACE-Step-1.5/
│   └── checkpoints/ (そのほかもある)
├── inputs/
└── output/

元曲をcli_exe_infer_sft.pyで作ると、output/配下にsessionができます。
Retakeでは、このsessionを再利用します。

backend/output/20260413_004941/
├── session.json
├── lm_metadata.json
├── 01.wav
├── 01_params.json
├── 01_latents.npy
└── ...

ここで重要なのは以下です。

  • lm_metadata.json
    • CoTで解決されたcaptionやBPMなど
  • 01_params.json
    • audio_codesを含むさまざまな設定情報
  • 01_latents.npy
    • 25Hz latentのnumpy保存データ
  • session.json
    • session全体の情報
      • 一回の生成で実行された全ての曲情報の概要が格納されています。

cli_exe_infer_retake.pyは、これらをload_source_track()でまとめて読み込みます。
Retakeは、WAVだけを見ているのではなく、元曲を作った時の中間情報ごと持ち込み実行をします。

実行

基本的な流れは以下です。

1. 元曲を作る

cd backend
uv run python cli_exe_infer_sft.py

まずは原曲を作ります。
Retakeは、原曲のaudio_codesとlatentを前提にするので、ここが出発点です。

2. cli_exe_infer_retake.pyの先頭変数を設定する

最初に主に触るのは以下です。

  • SOURCE_SESSION_DIR
    • 原曲の出力パス
  • SOURCE_TRACK_INDEX
    • 複数の原曲の何曲目を使うか
      • batch_sizeを1より大きい値を設定すると、一つのフォルダに複数の曲が生成されるため、その中のどの曲に対して微修正するかを選択します。
  • REPAINTING_REGIONS
    • どこを直したいか
  • RETAKE_SEED
    • Seed値を設定できます。リストで設定すると複数の微修正トラックのseedを固定できます。
  • SOURCE_LATENT_MIX_RATIO
    • どの程度、初期ノイズに原曲ノイズを混ぜるかを設定するパラメータ

3. Retakeを実行する

cd backend
uv run python cli_exe_infer_retake.py

出力はOUTPUT_DIR/YYYYMMDD_HHMMSS/に保存されます。
Retake結果も、また次のRetakeの原曲として使えるようになっています。

最初に触る変数

backend/cli_exe_infer_retake.pyの先頭に、だいたい重要な設定がまとまっています。
最初は全部触る必要はなくて、まずは以下だけ見れば十分です。

source選択

  • SOURCE_SESSION_DIR = "./output/20260413_004941"
    • 元曲sessionの場所です
  • SOURCE_TRACK_INDEX = 1
    • session内の何曲目を使うかです

編集内容

  • REPAINTING_REGIONS = [{"start": 107.0, "end": 111.0}]
    • どこを直すかです
    • listなので、複数区間をそのまま入れられます
  • RETAKE_CAPTION = None
    • Noneなら元曲のCoT拡張captionを継承します
    • 雰囲気まで少し変えたいときだけ上書きします
  • RETAKE_LYRICS = None
    • Noneなら元曲の歌詞を継承します
    • 読み直しや歌詞差し替えをしたいときだけ変更します
      • 特に漢字の読み間違いを修正したい場合は、ひらがなやカタカナに変更した歌詞全文を投入することをお勧めします

変化量の調整

  • RETAKE_SEED = -1
    • DiTの初期ノイズに関わるSeedを設定します。
    • -1ならランダムです。
  • SOURCE_LATENT_MIX_RATIO = 0.3
    • 初期ノイズに対して、原曲の潜在表現を何割混ぜ合わせるか決定します。
    • 大きいほど原曲寄り、小さいほど変化しやすいです
  • LATENT_CROSSFADE_FRAMES = 25
    • 境界をどれだけ滑らかにつなぐかです
    • 25Hz latentなので、25フレームはだいたい1秒です

共通生成条件

  • DIT_MODEL = "acestep-v15-sft"
  • LM_MODEL = "acestep-5Hz-lm-1.7B"
  • INFERENCE_STEPS = 64
  • GUIDANCE_SCALE = 7.0
  • BATCH_SIZE = 4
  • DIT_OFFLOAD_TO_CPU = True
  • LLM_OFFLOAD_TO_CPU = True

このあたりは、まずはデフォルトで良いと思います。
最初に本当に触るべきなのは、以下の5つくらいです。

実行結果

冒頭にも一部提示しましたが、せっかくなので新曲で提示します。
では実際にRetake機能も利用して、微修正を施した後の曲を以下に提示します。
https://www.youtube.com/watch?v=v5lXL2v9gwE

続いて、上記の曲の原曲での破綻部分(読み間違いなど)をRepaint機能で修正した場合との比較を以下で行います。

https://youtu.be/zJUDKxsTuF8

実際に聞いてみると、かなり印象が違います。
発音修正や数秒の歌い直しのような用途では、

  • そこだけ少し別テイクっぽい
  • 境界を意識すると、ほんの少しだけ浮いて聞こえる

ということが、やはりあります。
また、src_latentsがsilence latentsになっていることもあり、音が抑えられていることもあるなどで、「破綻の微修正」という用途では違和感を感じます。
(ちなみにこれでも20回以上の再生成を繰り返して、もっとも違和感がなかったものを採用しています)

一方で提案するRetake機能では、

  • 原曲の設計図(audio codes)を共有している
  • 原曲のlatentをそのまま参照している
  • 編集区間外の潜在表現を戻している

ので、かなり自然です。

特に以下のような修正では強いです。

  • 1単語だけ気になる
  • 読み間違いだけ直したい

こういうとき、Retakeは本当にちょうどよいです。
大げさに作り直しすぎないのが良いです。
さらにフル尺で聞いても、Retakeのほうが「編集したこと自体が目立ちにくい」と感じました。

また、原曲全体において、破綻があった箇所を全て提案したRetake機能で修正した比較動画を以下に示します。
https://youtu.be/889Vp3-xVUY

ちなみに、RTX3060では、一度の実行で4トラック分seedを変えて、Retake機能による曲修正を行うことができます。
4曲生成された修正トラックを以下のような自作アプリを利用して、比較を行い、最も自然なトラックの潜在表現を組み換えに利用することで、一発で完全に修正することができます。

youtubeに挙げている曲はそのようにして作成されております。

まとめ

今回は、高品質音楽生成AI【ACE-Step-1.5】で「破綻の微修正」に特化した新機能【Retake】を提案しました。

Retakeがやっていることを要約すると、以下です。

  • 元曲のaudio_codesを再利用する
  • 元曲のsource latentも再利用する
  • 編集区間だけ新しいseedで揺らす
  • 編集区間外は原曲へ戻す

既存の公式Repaint機能よりも、微修正するという用途では圧倒的に使いやすい機能ができたと自負しております。
ぜひ参考にしてみてください。

ACE-Step-1.5はText2Musicだけでも十分面白いですが、こういう使い方をすると、さらに実用的で楽しいです。

Discussion