Repository navigation
Support Audio Flamingo Next checkpoints #44830
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
116 commits
Select commit
Hold shift + click to select a range
caf33f1
Music flamingo
lashahub b69a9d1
Fix pos embeddings
lashahub b4acc17
Merge branch 'huggingface:main' into main
lashahub cf1e9bc
Method arg docstrings
lashahub 44e801b
Add tests & docs
lashahub f0956e3
Merge branch 'huggingface:main' into main
lashahub c973445
Fix AF3 dtype bug
lashahub e3a17fb
Fix the MF performance issue
lashahub 627dee8
Fix pos embeddings
lashahub e9df30d
Merge branch 'main' of https://github.com/lashahub/transformers
lashahub 4c48132
Fix embeddings & format
lashahub d67c114
Remove external deps
lashahub aedd341
Update processor token names
lashahub 87d55a9
Cleanup
lashahub be22746
Simplify RotaryEmbedding to lang-only
lashahub e5b4677
Reuse AF3 config classes
lashahub d7e0bcb
Trim+rename rotary embedding
lashahub 74af4fa
Call parent _init_weights first and drop rotary einsum
lashahub d622368
Precompute rotary cache at init
lashahub cab3937
Use modular processor pattern for MusicFlamingo
lashahub 9dd94a0
Remove audio-only inference example
lashahub 767a1d5
Refactor Audio Feature Casting Path
lashahub 9119660
Clarify private source repo
lashahub fc8ab3a
Clean up modular
lashahub 5159745
Move config to modular
lashahub 4aae4ff
Formatting
lashahub ffef7db
Remove dummy
lashahub 90148ed
Derive musicflamingo timing and rotary config
lashahub 87cb03f
Llama style rotary embeddings
lashahub 5abac95
Added reproducer comments
lashahub f4a1b68
Expose _init_weights for modular.
ebezzam 3b9290f
Satisfy repo checks
ebezzam 82ab1ef
Align MusicFlamingo rotary with Llama style
lashahub e993dea
Move MusicFlamingo _init_weights to encoder
lashahub 2d88557
Keep old behavior
lashahub 27024f1
Move MusicFlamingo rotary settings into encoder rope_parameters
lashahub 10797b9
Use AutoConfig in AF3/MF
lashahub f49014f
Align MusicFlamingo RoTE with Llama RoPE conventions
lashahub f465d3d
Update outdated fixtures
lashahub 4224af5
init_weights without changing others
ebezzam 2cbf219
FIx import
ebezzam a25c8a6
Remove backward compat
lashahub 3ed73a8
Merge branch 'main' into modular-mf
lashahub f2e7d3f
Regenerate modeling for MF
lashahub 445cd24
Fix AF3 batch inference bug
lashahub fc25c48
Simplify config and nit.
ebezzam 664e7b1
Conform more to transformers convention, e.g. removing unused code pa…
ebezzam bbca79a
Add another possible AF3 prefix.
ebezzam 69c9bee
Merge branch 'main' into modular-mf
ebezzam 17846d9
Use auto_docstring and update docstrings.
ebezzam 24fbaa7
Nits
ebezzam e25d377
Nit for review
ebezzam c99fc0a
Shift RoTE to main model so that encoder can be directly used from AF3.
ebezzam 9bb0c53
Refactoring nit.
ebezzam e9528a6
Fix init
lashahub 13af64d
Fix some failing tests
lashahub a34e981
Fix AF3 & MF and add batching tests
lashahub 702eb27
Fix audio embedding masking (bad post length)
ebezzam a32520c
Nits and remove since same as GLM was bug in post length computation
ebezzam 7750bb5
Simplify MF as AF3, and style checks.
ebezzam 74417f6
Merge branch 'main' into modular-mf
ebezzam 54bfecc
New config after merge and modular update.
ebezzam 2f2b552
Merge branch 'main' into modular-mf
ebezzam 612840f
Address music flamingo tests, and some cleanup.
ebezzam 2c3e583
style check
ebezzam a20e163
Regenerate config.
ebezzam fdb849a
Update fixtures.
ebezzam 057ad88
Nits
ebezzam 0442a67
Merge branch 'modular-mf' of github.com:lashahub/transformers into mo…
ebezzam 7f04d2d
Nit
ebezzam 63a135c
Add AudioFlamingoNext alias model
lashahub 7125e05
Merge branch 'modular-mf' into add_AudioFlamingoNext
lashahub 7c94fb5
Regenerate AF-Next files
lashahub 66ce201
Merge branch 'huggingface:main' into modular-mf
lashahub 7e06d27
Improve RoTE config
lashahub d423510
Refine MusicFlamingo rotary time handling
lashahub e79475b
Simplification, and update AF3 processor for better modular
ebezzam 6a1add4
Fix torch export
ebezzam e05b767
Simplify modular, including upstreaming input_ids input to get_audio_…
ebezzam edcffef
Remove upstreaming of input_ids to get_audio_features, and remove aud…
ebezzam e986996
Switch to MoonshineRotaryEmbedding, and cleanup.
ebezzam ad76e28
Remove hardcoded MusicFlamingo partial_rotary_factor
lashahub 8e0dc3b
Update fixtures
lashahub a46aa1c
Compile re.sub
ebezzam 836da94
Merge branch 'modular-mf' of github.com:lashahub/transformers into mo…
ebezzam 1089477
Update src/transformers/models/musicflamingo/modular_musicflamingo.py
ebezzam 2ea5574
Update src/transformers/models/musicflamingo/modular_musicflamingo.py
ebezzam 999737e
Style
ebezzam 1533bec
Merge branch 'main' into modular-mf
ebezzam 6857af9
Update fixtures.
ebezzam cd693fc
Merge branch 'main' into modular-mf
ebezzam 35fc31f
Conditional torch import for processor.
ebezzam a62e7d9
Merge branch 'modular-mf' of github.com:lashahub/transformers into mo…
ebezzam d0d18f2
Merge branch 'main' into modular-mf
ebezzam 47fa938
Merge branch 'main' into modular-mf
ebezzam dd2cc52
Merge branch 'modular-mf' into add_AudioFlamingoNext
lashahub c6f4213
Merge MF & convert modular
lashahub fd63719
30 mins in AF-Next
lashahub 6d5948e
Merge branch 'main' into add_AudioFlamingoNext
lashahub a44c774
Regen
lashahub 3c7f582
Fix AF-Next converter
lashahub 8f33aeb
AF-Next readme
lashahub d323d1f
Add tests
lashahub 9735a5f
Update AF-Next docs
lashahub 548e646
Fix MusicFlamingo and AFNext context metadata and rope defaults
lashahub e771363
Merge branch 'huggingface:main' into add_AudioFlamingoNext
lashahub 8c17076
Update fixtures
lashahub d79fb29
Address reviews
lashahub 205f8c8
Add reproducer
lashahub 7e63ddd
Update AF-Next converter
lashahub e38b6ac
Remove AF-Next
lashahub 8771a9f
Keep AF-Next converter
lashahub 7091a2a
Merge branch 'main' into add_AudioFlamingoNext
lashahub da61fd3
Merge branch 'main' into add_AudioFlamingoNext
ebezzam 88e9644
Update src/transformers/models/musicflamingo/modular_musicflamingo.py
eustlb 3f1219d
make
eustlb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
300 changes: 300 additions & 0 deletions
300
src/transformers/models/musicflamingo/convert_audioflamingonext_to_hf.py
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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() |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI checkpoint is actually using this: https://huggingface.co/nvidia/audio-flamingo-3-hf/blob/main/config.json#L66