@@ -103,7 +103,7 @@ def _detect_gpu_arch() -> str:
103103DIT_ENGINE_FILES = {
104104 "sm-music" : ["sa3-sm-music/dit_fp16mixed.trt" ],
105105 "sm-sfx" : ["sa3-sm-sfx/dit_fp16mixed.trt" ],
106- "medium" : ["sa3-m/dit_fp16mixed .trt" ],
106+ "medium" : ["sa3-m/dit_bf16 .trt" ], # bf16 (FMHA-fused) is the medium default
107107}
108108DECODER_FILES = {
109109 "same-s" : [
@@ -129,7 +129,7 @@ def _detect_gpu_arch() -> str:
129129 "default_decoder" : "same-s" },
130130 "sm-sfx" : {"engine" : ARCH_DIR / "sa3-sm-sfx" / "dit_fp16mixed.trt" ,
131131 "default_decoder" : "same-s" },
132- "medium" : {"engine" : ARCH_DIR / "sa3-m" / "dit_fp16mixed .trt" ,
132+ "medium" : {"engine" : ARCH_DIR / "sa3-m" / "dit_bf16 .trt" , # bf16 = medium default
133133 "default_decoder" : "same-l" },
134134}
135135DECODER_PATHS = {
@@ -144,51 +144,94 @@ def _detect_gpu_arch() -> str:
144144
145145# ─── Precision-keyed engine maps ─────────────────────────────────────────
146146#
147- # The canonical engines are FP16-mixed (FP16 trunk + FP32 islands around
148- # RMSNorm / Softmax / RoPE). Pure-FP32 variants are also published — same
149- # numerical behavior as PyTorch eager FP32. Use `--precision fp32` on the
150- # CLI to pick them; default is `fp16mixed`.
147+ # Three DiT precisions:
148+ # bf16 — medium ONLY. Same dit.onnx as fp32, built with BuilderFlag.BF16
149+ # (EXPLICIT_BATCH). bf16 carries fp32's range, so the FP32-softmax
150+ # islands vanish and TRT 10.15's FMHA fuser fires (0 → 96 fused
151+ # _gemm_mha_v2 nodes) → 1.76×@256 / 4.70×@4096 vs fp16-mixed,
152+ # within the perceptual re-seed floor (FAD 0.59× floor, n=128).
153+ # NOT seed-reproducible vs fp16-mixed (differential attention is
154+ # cancellation-sensitive → a different-but-equal take per seed).
155+ # THE MEDIUM DEFAULT. (sm-music/sm-sfx use standard attention and
156+ # already fuse in fp16-mixed — no bf16 engine for them.)
157+ # fp16mixed — canonical (FP16 trunk + FP32 islands around RMSNorm/Softmax/
158+ # RoPE). Kept selectable for bit-reproducibility / max per-step
159+ # fidelity. The sm-music / sm-sfx default.
160+ # fp32 — pure-FP32, bit-equivalent to PyTorch eager. ~2× size/latency.
151161#
152162# The lookup tables below resolve the engine filename per (dit/decoder,
153- # precision). Encoders are FP16-mixed only.
163+ # precision). The bf16 DiT recipe is a build-time precision change only (no new
164+ # ONNX): reuse sa3-m/dit.onnx, build with BF16. Decoders/encoders are unchanged
165+ # by bf16 (it's a DiT-trunk fusion recipe), so decoder "bf16" reuses the
166+ # canonical decoder engine. Encoders are FP16-mixed only.
154167DIT_ENGINE_FILENAME = {
168+ "bf16" : "dit_bf16.trt" , # medium only (FMHA-fused; medium default)
155169 "fp16mixed" : "dit_fp16mixed.trt" ,
156170 "fp32" : "dit_fp32.trt" ,
157171}
172+ # DiT precisions actually built per model. bf16 is medium-only.
173+ _DIT_PRECISIONS = {
174+ "sm-music" : ("fp16mixed" , "fp32" ),
175+ "sm-sfx" : ("fp16mixed" , "fp32" ),
176+ "medium" : ("bf16" , "fp16mixed" , "fp32" ),
177+ }
178+ # Per-DiT default precision (bf16 for medium, fp16mixed elsewhere).
179+ DIT_DEFAULT_PRECISION = {"sm-music" : "fp16mixed" , "sm-sfx" : "fp16mixed" , "medium" : "bf16" }
158180_DIT_SUBDIR = {"sm-music" : "sa3-sm-music" , "sm-sfx" : "sa3-sm-sfx" , "medium" : "sa3-m" }
159181DECODER_ENGINE_FILENAME = {
160182 "same-l" : {
183+ # bf16 is a DiT-only recipe → decoder reuses its canonical fp16-mixed engine.
184+ "bf16" : "dec_dynamic_triton_swa.trt" ,
161185 "fp16mixed" : "dec_dynamic_triton_swa.trt" ,
162186 "fp32" : "dec_dynamic_fp32.trt" ,
163187 },
164188 "same-s" : {
189+ "bf16" : "dec_dynamic_bf16.trt" ,
165190 "fp16mixed" : "dec_dynamic_bf16.trt" ,
166191 "fp32" : "dec_dynamic_fp32.trt" ,
167192 },
168193}
169- PRECISIONS = ("fp16mixed" , "fp32" )
194+ PRECISIONS = ("bf16" , "fp16mixed" , "fp32" )
195+
196+
197+ def default_precision (dit_name : str ) -> str :
198+ """Default DiT precision for a model: bf16 for medium (FMHA-fused speed
199+ default), fp16-mixed otherwise."""
200+ return DIT_DEFAULT_PRECISION .get (dit_name , "fp16mixed" )
170201
171202
172- def get_dit_engine_path (dit_name : str , precision : str = "fp16mixed" ) -> Path :
203+ def get_dit_engine_path (dit_name : str , precision : str = None ) -> Path :
173204 if dit_name not in _DIT_SUBDIR :
174205 raise ValueError (f"unknown dit={ dit_name !r} ; valid: { list (_DIT_SUBDIR )} " )
206+ if precision is None :
207+ precision = default_precision (dit_name )
175208 if precision not in DIT_ENGINE_FILENAME :
176209 raise ValueError (f"unknown precision={ precision !r} ; valid: { PRECISIONS } " )
210+ if precision == "bf16" and dit_name != "medium" :
211+ raise ValueError (
212+ f"precision='bf16' is only available for --dit medium (FMHA-fused); "
213+ f"{ dit_name } uses standard attention and already fuses in fp16mixed. "
214+ f"Valid for { dit_name } : { _DIT_PRECISIONS .get (dit_name )} " )
177215 return ARCH_DIR / _DIT_SUBDIR [dit_name ] / DIT_ENGINE_FILENAME [precision ]
178216
179217
180- def get_decoder_engine_path (decoder_name : str , precision : str = "fp16mixed" ) -> Path :
218+ def get_decoder_engine_path (decoder_name : str , precision : str = None ) -> Path :
181219 if decoder_name not in DECODER_ENGINE_FILENAME :
182220 raise ValueError (f"unknown decoder={ decoder_name !r} ; valid: { list (DECODER_ENGINE_FILENAME )} " )
221+ if precision is None :
222+ precision = "fp16mixed" # decoders have no bf16-specific engine; canonical
183223 if precision not in DECODER_ENGINE_FILENAME [decoder_name ]:
184224 raise ValueError (f"unknown precision={ precision !r} ; valid: { PRECISIONS } " )
185225 return ARCH_DIR / decoder_name / DECODER_ENGINE_FILENAME [decoder_name ][precision ]
186226
187227
188- def get_engine_files (dit_name : str , decoder_name : str , precision : str = "fp16mixed" ,
228+ def get_engine_files (dit_name : str , decoder_name : str , precision : str = None ,
189229 with_encoder : bool = False ) -> list [str ]:
190230 """Relative paths (under ARCH_DIR) needed for the chosen pipeline. Pass this
191- list to _ensure_files() to auto-download anything missing from HF."""
231+ list to _ensure_files() to auto-download anything missing from HF.
232+ precision=None resolves to the per-model default (bf16 for medium)."""
233+ if precision is None :
234+ precision = default_precision (dit_name )
192235 files = list (SHARED_FILES )
193236 files .append (f"{ _DIT_SUBDIR [dit_name ]} /{ DIT_ENGINE_FILENAME [precision ]} " )
194237 files .append (f"{ decoder_name } /{ DECODER_ENGINE_FILENAME [decoder_name ][precision ]} " )
@@ -903,14 +946,22 @@ def _arrow_pick(prompt: str, options: list[str], default: str | None = None) ->
903946
904947
905948def prompt_user_if_missing (args ):
906- """Fill in --dit / --decoder / --seed interactively if missing."""
949+ """Fill in --dit / --decoder / --precision / -- seed interactively if missing."""
907950 if args .dit is None :
908951 args .dit = _arrow_pick ("Choose DiT model:" , list (DIT_CHOICES .keys ()), default = "medium" )
909952 print (f" → { args .dit } " )
910953 if args .decoder is None :
911954 suggested = DIT_CHOICES [args .dit ]["default_decoder" ]
912955 args .decoder = _arrow_pick ("Choose audio decoder:" , list (DECODER_PATHS .keys ()), default = suggested )
913956 print (f" → { args .decoder } " )
957+ # Resolve DiT precision default per model: bf16 for medium (FMHA-fused speed
958+ # default), fp16-mixed for sm-music/sm-sfx. bf16 is medium-only (sm-music/
959+ # sm-sfx use standard attention and already fuse in fp16mixed).
960+ if getattr (args , "precision" , None ) is None :
961+ args .precision = default_precision (args .dit )
962+ if args .precision == "bf16" and args .dit != "medium" :
963+ sys .exit ("error: --precision bf16 is only available for --dit medium "
964+ "(sm-music / sm-sfx already fuse in fp16mixed)." )
914965 if args .seed is None :
915966 args .seed = random .randint (0 , 2 ** 31 - 1 )
916967 return args
@@ -958,10 +1009,14 @@ def main():
9581009 ap .add_argument ("--decoder" , choices = list (DECODER_PATHS .keys ()), default = None ,
9591010 help = "Audio decoder. 'same-s' pairs with sm-* (110 MB engine). "
9601011 "'same-l' pairs with medium (1.2 GB engine). Interactive picker if omitted." )
961- ap .add_argument ("--precision" , choices = list (PRECISIONS ), default = "fp16mixed" ,
962- help = "Engine precision. 'fp16mixed' (default) = FP16 trunk + FP32 islands, "
963- "fastest. 'fp32' = pure FP32, matches PyTorch eager bit-for-bit but ~2× "
964- "slower and ~2× the VRAM. Engines auto-download from HF if missing." )
1012+ ap .add_argument ("--precision" , choices = list (PRECISIONS ), default = None ,
1013+ help = "DiT engine precision (default resolves per model: 'bf16' for medium, "
1014+ "'fp16mixed' for sm-music/sm-sfx). 'bf16' (MEDIUM ONLY) = FMHA-fused, "
1015+ "~1.8-4.7× faster than fp16mixed, within the perceptual floor, but not "
1016+ "seed-reproducible vs fp16mixed (differential attention). 'fp16mixed' = "
1017+ "FP16 trunk + FP32 islands (canonical, bit-reproducible). 'fp32' = pure "
1018+ "FP32, matches PyTorch eager bit-for-bit but ~2× slower and ~2× the VRAM. "
1019+ "Engines auto-download from HF if missing." )
9651020 ap .add_argument ("--models-dir" , default = str (MODELS_DIR ),
9661021 help = f"Directory containing the TRT engines. Default: { MODELS_DIR } " )
9671022 # ── Sampling ──
@@ -1165,8 +1220,12 @@ def _stage_vram(label): return 0
11651220 _w_m = torch .zeros (1 , T5_MAX_LEN , device = "cuda" )
11661221 _w_l = torch .zeros (1 , 257 , T_lat , device = "cuda" )
11671222 _w_lat = torch .zeros (1 , IO_CHANNELS , T_lat , device = "cuda" )
1168- _w_audio = torch .zeros (1 , 2 , T_lat * SAMPLES_PER_LATENT , device = "cuda" ) \
1169- if "enc" in runners else None
1223+ # Encoder warmup is at the chunk_lat shape that encode_chunked actually
1224+ # uses; encoding at the full T_lat shape diverges past T_lat≈100-200 on
1225+ # both encoders (see encoder_encode docstring), so we never feed the
1226+ # engine that shape — encode_chunked stitches chunk_lat=50 windows.
1227+ _w_audio = torch .zeros (1 , 2 , DEFAULT_ENCODER_CHUNK_LAT * SAMPLES_PER_LATENT ,
1228+ device = "cuda" ) if "enc" in runners else None
11701229 # Optional: pre-allocate a pinned-memory destination buffer for the
11711230 # Stage-5 narrow + DtoH path. With pinned dst + non_blocking=True the DMA
11721231 # goes straight from GPU into RAM without the usual pageable→pinned
@@ -1275,7 +1334,7 @@ def _stage_vram(label): return 0
12751334 audio_t = torch .from_numpy (audio_np ).unsqueeze (0 ).cuda () # (1, 2, T)
12761335 sub (f"read+prep ({ init_action } ) { (time .time () - t0 ) * 1000 :.0f} ms" )
12771336 t0 = time .time ()
1278- init_latents = encoder_encode (runners ["enc" ], audio_t )
1337+ init_latents = encode_chunked (runners ["enc" ], audio_t )
12791338 sub (f"encode { (time .time () - t0 ) * 1000 :.0f} ms latents { tuple (init_latents .shape )} " )
12801339 if args .free_models :
12811340 runners ["enc" ].free (); del runners ["enc" ]
0 commit comments