Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
caf33f1
Music flamingo
lashahub Dec 24, 2025
b69a9d1
Fix pos embeddings
lashahub Dec 26, 2025
b4acc17
Merge branch 'huggingface:main' into main
lashahub Jan 6, 2026
cf1e9bc
Method arg docstrings
lashahub Jan 6, 2026
44e801b
Add tests & docs
lashahub Jan 8, 2026
f0956e3
Merge branch 'huggingface:main' into main
lashahub Jan 8, 2026
c973445
Fix AF3 dtype bug
lashahub Jan 10, 2026
e3a17fb
Fix the MF performance issue
lashahub Jan 10, 2026
627dee8
Fix pos embeddings
lashahub Jan 10, 2026
e9df30d
Merge branch 'main' of https://github.com/lashahub/transformers
lashahub Jan 10, 2026
4c48132
Fix embeddings & format
lashahub Jan 12, 2026
d67c114
Remove external deps
lashahub Jan 23, 2026
aedd341
Update processor token names
lashahub Jan 23, 2026
87d55a9
Cleanup
lashahub Feb 10, 2026
be22746
Simplify RotaryEmbedding to lang-only
lashahub Feb 13, 2026
e5b4677
Reuse AF3 config classes
lashahub Feb 14, 2026
d7e0bcb
Trim+rename rotary embedding
lashahub Feb 14, 2026
74af4fa
Call parent _init_weights first and drop rotary einsum
lashahub Feb 14, 2026
d622368
Precompute rotary cache at init
lashahub Feb 14, 2026
cab3937
Use modular processor pattern for MusicFlamingo
lashahub Feb 15, 2026
9dd94a0
Remove audio-only inference example
lashahub Feb 15, 2026
767a1d5
Refactor Audio Feature Casting Path
lashahub Feb 15, 2026
9119660
Clarify private source repo
lashahub Feb 21, 2026
fc8ab3a
Clean up modular
lashahub Feb 22, 2026
5159745
Move config to modular
lashahub Feb 22, 2026
4aae4ff
Formatting
lashahub Feb 23, 2026
ffef7db
Remove dummy
lashahub Feb 23, 2026
90148ed
Derive musicflamingo timing and rotary config
lashahub Feb 23, 2026
87cb03f
Llama style rotary embeddings
lashahub Feb 23, 2026
5abac95
Added reproducer comments
lashahub Feb 23, 2026
f4a1b68
Expose _init_weights for modular.
ebezzam Feb 25, 2026
3b9290f
Satisfy repo checks
ebezzam Feb 25, 2026
82ab1ef
Align MusicFlamingo rotary with Llama style
lashahub Feb 25, 2026
e993dea
Move MusicFlamingo _init_weights to encoder
lashahub Feb 26, 2026
2d88557
Keep old behavior
lashahub Feb 26, 2026
27024f1
Move MusicFlamingo rotary settings into encoder rope_parameters
lashahub Feb 26, 2026
10797b9
Use AutoConfig in AF3/MF
lashahub Feb 26, 2026
f49014f
Align MusicFlamingo RoTE with Llama RoPE conventions
lashahub Feb 26, 2026
f465d3d
Update outdated fixtures
lashahub Feb 26, 2026
4224af5
init_weights without changing others
ebezzam Feb 27, 2026
2cbf219
FIx import
ebezzam Feb 27, 2026
a25c8a6
Remove backward compat
lashahub Feb 27, 2026
3ed73a8
Merge branch 'main' into modular-mf
lashahub Feb 27, 2026
f2e7d3f
Regenerate modeling for MF
lashahub Feb 27, 2026
445cd24
Fix AF3 batch inference bug
lashahub Mar 6, 2026
fc25c48
Simplify config and nit.
ebezzam Mar 10, 2026
664e7b1
Conform more to transformers convention, e.g. removing unused code pa…
ebezzam Mar 10, 2026
bbca79a
Add another possible AF3 prefix.
ebezzam Mar 10, 2026
69c9bee
Merge branch 'main' into modular-mf
ebezzam Mar 10, 2026
17846d9
Use auto_docstring and update docstrings.
ebezzam Mar 10, 2026
24fbaa7
Nits
ebezzam Mar 11, 2026
e25d377
Nit for review
ebezzam Mar 11, 2026
c99fc0a
Shift RoTE to main model so that encoder can be directly used from AF3.
ebezzam Mar 11, 2026
9bb0c53
Refactoring nit.
ebezzam Mar 11, 2026
e9528a6
Fix init
lashahub Mar 17, 2026
13af64d
Fix some failing tests
lashahub Mar 17, 2026
a34e981
Fix AF3 & MF and add batching tests
lashahub Mar 17, 2026
702eb27
Fix audio embedding masking (bad post length)
ebezzam Mar 17, 2026
a32520c
Nits and remove since same as GLM was bug in post length computation
ebezzam Mar 17, 2026
7750bb5
Simplify MF as AF3, and style checks.
ebezzam Mar 17, 2026
74417f6
Merge branch 'main' into modular-mf
ebezzam Mar 17, 2026
54bfecc
New config after merge and modular update.
ebezzam Mar 17, 2026
2f2b552
Merge branch 'main' into modular-mf
ebezzam Mar 18, 2026
612840f
Address music flamingo tests, and some cleanup.
ebezzam Mar 18, 2026
2c3e583
style check
ebezzam Mar 18, 2026
a20e163
Regenerate config.
ebezzam Mar 18, 2026
fdb849a
Update fixtures.
ebezzam Mar 18, 2026
057ad88
Nits
ebezzam Mar 18, 2026
0442a67
Merge branch 'modular-mf' of github.com:lashahub/transformers into mo…
ebezzam Mar 18, 2026
7f04d2d
Nit
ebezzam Mar 18, 2026
63a135c
Add AudioFlamingoNext alias model
lashahub Mar 18, 2026
7125e05
Merge branch 'modular-mf' into add_AudioFlamingoNext
lashahub Mar 18, 2026
7c94fb5
Regenerate AF-Next files
lashahub Mar 18, 2026
66ce201
Merge branch 'huggingface:main' into modular-mf
lashahub Mar 20, 2026
7e06d27
Improve RoTE config
lashahub Mar 22, 2026
d423510
Refine MusicFlamingo rotary time handling
lashahub Mar 23, 2026
e79475b
Simplification, and update AF3 processor for better modular
ebezzam Mar 23, 2026
6a1add4
Fix torch export
ebezzam Mar 23, 2026
e05b767
Simplify modular, including upstreaming input_ids input to get_audio_…
ebezzam Mar 23, 2026
edcffef
Remove upstreaming of input_ids to get_audio_features, and remove aud…
ebezzam Mar 24, 2026
e986996
Switch to MoonshineRotaryEmbedding, and cleanup.
ebezzam Mar 24, 2026
ad76e28
Remove hardcoded MusicFlamingo partial_rotary_factor
lashahub Mar 24, 2026
8e0dc3b
Update fixtures
lashahub Mar 24, 2026
a46aa1c
Compile re.sub
ebezzam Mar 30, 2026
836da94
Merge branch 'modular-mf' of github.com:lashahub/transformers into mo…
ebezzam Mar 30, 2026
1089477
Update src/transformers/models/musicflamingo/modular_musicflamingo.py
ebezzam Mar 30, 2026
2ea5574
Update src/transformers/models/musicflamingo/modular_musicflamingo.py
ebezzam Mar 30, 2026
999737e
Style
ebezzam Mar 30, 2026
1533bec
Merge branch 'main' into modular-mf
ebezzam Mar 30, 2026
6857af9
Update fixtures.
ebezzam Mar 30, 2026
cd693fc
Merge branch 'main' into modular-mf
ebezzam Mar 30, 2026
35fc31f
Conditional torch import for processor.
ebezzam Mar 30, 2026
a62e7d9
Merge branch 'modular-mf' of github.com:lashahub/transformers into mo…
ebezzam Mar 30, 2026
d0d18f2
Merge branch 'main' into modular-mf
ebezzam Mar 30, 2026
47fa938
Merge branch 'main' into modular-mf
ebezzam Mar 30, 2026
dd2cc52
Merge branch 'modular-mf' into add_AudioFlamingoNext
lashahub Mar 31, 2026
c6f4213
Merge MF & convert modular
lashahub Mar 31, 2026
fd63719
30 mins in AF-Next
lashahub Apr 4, 2026
6d5948e
Merge branch 'main' into add_AudioFlamingoNext
lashahub Apr 4, 2026
a44c774
Regen
lashahub Apr 4, 2026
3c7f582
Fix AF-Next converter
lashahub Apr 4, 2026
8f33aeb
AF-Next readme
lashahub Apr 4, 2026
d323d1f
Add tests
lashahub Apr 5, 2026
9735a5f
Update AF-Next docs
lashahub Apr 5, 2026
548e646
Fix MusicFlamingo and AFNext context metadata and rope defaults
lashahub Apr 7, 2026
e771363
Merge branch 'huggingface:main' into add_AudioFlamingoNext
lashahub Apr 13, 2026
8c17076
Update fixtures
lashahub Apr 13, 2026
d79fb29
Address reviews
lashahub Apr 25, 2026
205f8c8
Add reproducer
lashahub Apr 25, 2026
7e63ddd
Update AF-Next converter
lashahub May 12, 2026
e38b6ac
Remove AF-Next
lashahub May 12, 2026
8771a9f
Keep AF-Next converter
lashahub May 12, 2026
7091a2a
Merge branch 'main' into add_AudioFlamingoNext
lashahub May 13, 2026
da61fd3
Merge branch 'main' into add_AudioFlamingoNext
ebezzam May 13, 2026
88e9644
Update src/transformers/models/musicflamingo/modular_musicflamingo.py
eustlb May 14, 2026
3f1219d
make
eustlb May 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def write_processor(src_root: Path, dst_root: Path):
tokenizer=AutoTokenizer.from_pretrained(str(llm_dir), chat_template=tokenizer_chat_template, use_fast=True),
chat_template=processor_chat_template,
)
processor.tokenizer.model_max_length = 32768

@ebezzam ebezzam May 13, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

processor.save_pretrained(str(dst_root))

logger.info("processor (tokenizer + preprocessor)")
Expand Down Expand Up @@ -167,7 +168,7 @@ def merge_and_shard_weights(src_root: Path, dst_root: Path, processor: AudioFlam
vocab_size=len(tok),
hidden_size=3584,
intermediate_size=18944,
model_max_length=8192,
model_max_length=32768,
num_attention_heads=28,
num_hidden_layers=28,
num_key_value_heads=4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ class MusicFlamingoConfig(PreTrainedConfig):
rope_parameters: dict | None = None

def __post_init__(self, **kwargs):
if self.rope_parameters is None:
self.rope_parameters = {
"rope_type": "default",
"rope_theta": 1200.0,
"partial_rotary_factor": 0.2,
}
if isinstance(self.audio_config, dict):
if self.audio_config["model_type"] in [None, "musicflamingo_encoder"]:
self.audio_config["model_type"] = "audioflamingo3_encoder"
Expand All @@ -87,8 +93,6 @@ def __post_init__(self, **kwargs):
elif self.text_config is None:
self.text_config = CONFIG_MAPPING["qwen2"]()

if self.rope_parameters is None:
self.rope_parameters = {"rope_type": "default", "rope_theta": 1200, "partial_rotary_factor": 0.2}
self.max_position_embeddings = self.rope_parameters["rope_theta"]
self.head_dim = self.audio_config.hidden_size
super().__post_init__(**kwargs)
Expand Down

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eustlb ok to add the conversion script for the new checkpoint? https://huggingface.co/nvidia/audio-flamingo-next-hf

Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
# Copyright 2026 NVIDIA CORPORATION and the HuggingFace Inc. team. All rights
# reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Convert AudioFlamingoNext checkpoints into the MusicFlamingo Hugging Face layout."""

from __future__ import annotations

import argparse
import json
import logging
from collections import defaultdict
from pathlib import Path
from typing import Any

import torch
from safetensors.torch import safe_open

from transformers import (
AutoTokenizer,
GenerationConfig,
MusicFlamingoConfig,
MusicFlamingoForConditionalGeneration,
MusicFlamingoProcessor,
Qwen2Config,
WhisperFeatureExtractor,
)


logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")


def _load_json(p: Path):
if not p.is_file():
raise FileNotFoundError(f"Missing JSON: {p}")
with p.open("r", encoding="utf-8") as f:
return json.load(f)


def write_processor(src_root: Path, dst_root: Path):
llm_dir = src_root / "llm"

system_prompt = (
"You are Audio Flamingo-Next, a multimodal assistant for language and audio. "
"On each turn you receive an optional audio clip which may contain speech, music, or ambient sounds "
"and optional text, you will receive at least one or both; use your world knowledge and reasoning "
"to help the user with any task. Interpret the entirety of the content of any input audio—regardless "
"of whether the user calls it audio, speech, music, or sound."
)

# fmt: off
tokenizer_chat_template = (
"{% if messages[0]['role'] != 'system' %}"
"{{ '<|im_start|>system\\n" + system_prompt + "<|im_end|>\\n' }}"
"{% endif %}"
"{% for message in messages if message['content'] is not none %}"
"{{ '<|im_start|>' + message['role'] + '\\n' + message['content'] + '<|im_end|>' + '\\n' }}"
"{% endfor %}"
"{% if add_generation_prompt %}"
"{{ '<|im_start|>assistant\\n' }}"
"{% endif %}"
)
# fmt: on

# fmt: off
processor_chat_template = (
"{% if messages[0]['role'] != 'system' %}"
"<|im_start|>system\n" + system_prompt + "<|im_end|>\n"
"{% endif %}"
"{% for m in messages if m['content'] is not none %}"
"<|im_start|>{{ m['role'] }}\n"
"{% if m['content'] is string %}"
"{{ m['content'] }}"
"{% else %}"
"{% set audio = namespace(found=False) %}"
"{% set text_buf = namespace(v='') %}"
"{% for c in m['content'] %}"
"{% if c.get('type') == 'audio' or 'audio' in c %}"
"{% set audio.found = True %}"
"{% elif c.get('type') == 'text' or 'text' in c %}"
"{% set text_buf.v = text_buf.v + c['text'] %}"
"{% endif %}"
"{% endfor %}"
"{% if audio.found %}{{ '<sound>' }}{% endif %}{{ text_buf.v }}"
"{% endif %}"
"<|im_end|>\n"
"{% endfor %}"
"{% if add_generation_prompt %}"
"<|im_start|>assistant\n"
"{% endif %}"
)
# fmt: on

processor = MusicFlamingoProcessor(
feature_extractor=WhisperFeatureExtractor(feature_size=128, return_attention_mask=True),
tokenizer=AutoTokenizer.from_pretrained(str(llm_dir), chat_template=tokenizer_chat_template, use_fast=True),
chat_template=processor_chat_template,
max_audio_len=1800,
)
processor.tokenizer.model_max_length = 131072
processor.save_pretrained(str(dst_root))

logger.info("processor (tokenizer + preprocessor)")
return processor


PREFIX_MAP = {
"llm": "language_model",
"sound_tower": "audio_tower",
"sound_mm_projector": "multi_modal_projector",
}


def _resolve_component_dir(dirpath: Path):
if not dirpath.is_dir():
return None
idx = dirpath / "model.safetensors.index.json"
mono = dirpath / "model.safetensors"
if idx.exists():
wm = _load_json(idx).get("weight_map") or {}
by_shard: dict[str, list[str]] = defaultdict(list)
for k, shard in wm.items():
by_shard[shard].append(k)
return ("sharded", dirpath, {k: sorted(v) for k, v in sorted(by_shard.items())})
if mono.exists():
return ("file", mono)
cands = sorted([x for x in dirpath.iterdir() if x.suffix == ".safetensors"])
return ("file", cands[0]) if len(cands) == 1 else None


def merge_and_shard_weights(src_root: Path, dst_root: Path, processor: MusicFlamingoProcessor):
state: dict[str, Any] = {}
for tag in PREFIX_MAP.keys():
comp = _resolve_component_dir(src_root / tag)
if not comp:
continue

out_prefix = PREFIX_MAP.get(tag, tag)

if comp[0] == "file":
fp: Path = comp[1]
with safe_open(str(fp), framework="pt", device="cpu") as f:
for k in f.keys():
if k == "__metadata__":
continue
state[f"{out_prefix}.{k}"] = f.get_tensor(k)
else:
base: Path = comp[1]
shard_map: dict[str, list[str]] = comp[2]
for shard, keys in shard_map.items():
sp = base / shard
with safe_open(str(sp), framework="pt", device="cpu") as f:
for k in keys:
state[f"{out_prefix}.{k}"] = f.get_tensor(k)

if not state:
raise FileNotFoundError("No tensors found in llm/, sound_tower/, or sound_mm_projector/.")

tok = processor.tokenizer
text_config = Qwen2Config(
bos_token_id=tok.bos_token_id,
eos_token_id=tok.eos_token_id,
pad_token_id=tok.pad_token_id,
vocab_size=len(tok),
hidden_size=3584,
intermediate_size=18944,
model_max_length=131072,
max_position_embeddings=131072,
num_attention_heads=28,
num_hidden_layers=28,
num_key_value_heads=4,
rope_theta=15300000.0,
use_cache=False,
)

vocab = tok.get_vocab()
config = MusicFlamingoConfig(
text_config=text_config,
audio_token_id=vocab["<sound>"],
audio_bos_token_id=vocab.get("<|sound_bos|>"),
audio_eos_token_id=vocab.get("<|sound_eos|>"),
)
model = MusicFlamingoForConditionalGeneration(config).to(dtype=torch.bfloat16)

# Update state dict to new key names if necessary
projector_key_mapping = {
"multi_modal_projector.layers.0.weight": "multi_modal_projector.linear_1.weight",
"multi_modal_projector.layers.0.bias": "multi_modal_projector.linear_1.bias",
"multi_modal_projector.layers.2.weight": "multi_modal_projector.linear_2.weight",
"multi_modal_projector.layers.2.bias": "multi_modal_projector.linear_2.bias",
}
for old_key, new_key in projector_key_mapping.items():
if old_key in state:
state[new_key] = state.pop(old_key)

# Llama-style rotary caches `inv_freq` as a non-persistent buffer, so we do not load/save it in the checkpoint.
state.pop("audio_tower.sound_tower.pos_emb.freqs", None)

# Load weights into the instantiated model so we can push via `push_to_hub` later.
load_res = model.load_state_dict(state, strict=True)
# Enforce a clean load
if getattr(load_res, "missing_keys", None) and load_res.missing_keys:
mk = load_res.missing_keys
raise ValueError(f"Missing keys when loading: {mk[:10]}{' ...' if len(mk) > 10 else ''}")
if getattr(load_res, "unexpected_keys", None) and load_res.unexpected_keys:
uk = load_res.unexpected_keys
raise ValueError(f"Unexpected keys when loading: {uk[:10]}{' ...' if len(uk) > 10 else ''}")

model.generation_config = GenerationConfig(
bos_token_id=tok.bos_token_id,
eos_token_id=tok.eos_token_id,
pad_token_id=tok.pad_token_id,
max_new_tokens=2048,
)

model.save_pretrained(save_directory=str(dst_root))
logger.info("model.safetensors index and shards")
return model


"""
Reproducible Usage
==================

1) Download the original AudioFlamingoNext weights from NVIDIA (requires Git LFS and private repo access):

```
git lfs install
git clone https://huggingface.co/nvidia/audio-flamingo-next
```

This creates a folder `audio-flamingo-next/` containing the original components:
`llm/`, `sound_tower/`, and `sound_mm_projector/`.

2) Convert to the Hugging Face Transformers format (locally):

```
python src/transformers/models/musicflamingo/convert_audioflamingonext_to_hf.py \
--src_dir audio-flamingo-next \
--dst_dir audio-flamingo-next-hf
```

3) Convert and push directly to the Hub (requires `huggingface-cli login` or `HF_TOKEN`):

```
python src/transformers/models/musicflamingo/convert_audioflamingonext_to_hf.py \
--src_dir audio-flamingo-next \
--dst_dir audio-flamingo-next-hf \
--push_to_hub <username-or-org>/audio-flamingo-next-hf
```
"""


def main() -> None:
ap = argparse.ArgumentParser(description="Convert AudioFlamingoNext to the MusicFlamingo Hugging Face format.")
ap.add_argument("--src_dir", required=True, help="Source model root directory")
ap.add_argument("--dst_dir", required=True, help="Destination directory for converted model")
ap.add_argument(
"--push_to_hub",
default=None,
type=str,
help=(
"Optional repository ID to push the converted assets to the Hugging Face Hub, "
"e.g. 'username/audio-flamingo-next-hf'."
),
)
args = ap.parse_args()

src_root = Path(args.src_dir).resolve()
if not src_root.is_dir():
raise FileNotFoundError(f"Source directory not found: {src_root}")

dst_root = Path(args.dst_dir).resolve()
if dst_root.exists():
raise FileExistsError(f"Destination already exists: {dst_root}")

processor = write_processor(src_root, dst_root)
model = merge_and_shard_weights(src_root, dst_root, processor)

if args.push_to_hub:
logger.info("Pushing processor to the Hub ...")
processor.push_to_hub(args.push_to_hub)
logger.info("Pushing model to the Hub ...")
model.push_to_hub(args.push_to_hub)


if __name__ == "__main__":
main()
Loading
Loading