minhahwang Copilot commited on
Commit
871cd89
·
1 Parent(s): 52dd416

perf: warmup generation, async LFM loading, reduce max_new_tokens

Browse files

- Add warmup_lfm() that triggers torch.compile graphs on a dummy query
- Load LFM model in background thread (app starts faster, Play works immediately)
- Reduce default max_new_tokens from 200 to 100 (shorter answers for kids)
- Add _reset_mimi_streaming_state() helper to flush decoder buffers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Files changed (2) hide show
  1. app.py +15 -4
  2. inference_lfm.py +44 -1
app.py CHANGED
@@ -420,10 +420,21 @@ print("[MomsVoice] Creating stock voice profile (vivian)...")
420
  _ensure_stock_voice_profile()
421
  print("[MomsVoice] Stock voice profile ready.")
422
 
423
- print("[MomsVoice] Preloading LFM2.5-Audio-1.5B Q&A model...")
424
- from inference_lfm import get_lfm_model
425
- get_lfm_model()
426
- print("[MomsVoice] LFM Q&A model ready. All models preloaded.")
 
 
 
 
 
 
 
 
 
 
 
427
 
428
 
429
  # Gradio Application Core setup
 
420
  _ensure_stock_voice_profile()
421
  print("[MomsVoice] Stock voice profile ready.")
422
 
423
+ # Load LFM Q&A model asynchronously — users typically start with Play tab,
424
+ # so LFM can load in the background while they browse stories.
425
+ import threading
426
+
427
+ def _load_lfm_background():
428
+ from inference_lfm import get_lfm_model, warmup_lfm
429
+ print("[MomsVoice] (background) Loading LFM2.5-Audio-1.5B Q&A model...")
430
+ get_lfm_model()
431
+ print("[MomsVoice] (background) LFM loaded. Running warmup generation...")
432
+ warmup_lfm()
433
+ print("[MomsVoice] (background) LFM Q&A model ready (compiled + warmed up).")
434
+
435
+ _lfm_thread = threading.Thread(target=_load_lfm_background, daemon=True)
436
+ _lfm_thread.start()
437
+ print("[MomsVoice] LFM loading in background thread. App starting now.")
438
 
439
 
440
  # Gradio Application Core setup
inference_lfm.py CHANGED
@@ -70,6 +70,16 @@ def _module_device(module, fallback: torch.device) -> torch.device:
70
  return getattr(module, "device", fallback)
71
 
72
 
 
 
 
 
 
 
 
 
 
 
73
  def get_lfm_model():
74
  """Load LFM2.5-Audio-1.5B model. Cached after first call."""
75
  global _processor, _model
@@ -113,11 +123,44 @@ def get_lfm_model():
113
  return _processor, _model
114
 
115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  def answer_question_audio(
117
  question_audio_path: str | None = None,
118
  question_text: str | None = None,
119
  story_context: str = "",
120
- max_new_tokens: int = 200,
121
  ) -> tuple[str, np.ndarray | None, int]:
122
  """
123
  Answer a question about the story using LFM2.5-Audio end-to-end.
 
70
  return getattr(module, "device", fallback)
71
 
72
 
73
+ def _reset_mimi_streaming_state(mimi) -> None:
74
+ """Best-effort reset of Mimi's internal streaming buffers."""
75
+ for attr in ("_streaming_state", "_states"):
76
+ if hasattr(mimi, attr):
77
+ try:
78
+ setattr(mimi, attr, None)
79
+ except Exception:
80
+ pass
81
+
82
+
83
  def get_lfm_model():
84
  """Load LFM2.5-Audio-1.5B model. Cached after first call."""
85
  global _processor, _model
 
123
  return _processor, _model
124
 
125
 
126
+ def warmup_lfm():
127
+ """Run a dummy generation to trigger torch.compile and warm CUDA graphs.
128
+ Call once at startup after get_lfm_model() to eliminate first-query latency.
129
+ """
130
+ try:
131
+ processor, model = get_lfm_model()
132
+ from liquid_audio import ChatState
133
+ device = _module_device(model, _select_device())
134
+ dtype = next(model.parameters()).dtype
135
+ mimi = processor.mimi.eval()
136
+
137
+ _reset_mimi_streaming_state(mimi)
138
+ with GPU_INFERENCE_LOCK, torch.no_grad():
139
+ chat = ChatState(processor, dtype=dtype)
140
+ chat.new_turn("system")
141
+ chat.add_text("You are a helpful assistant.")
142
+ chat.end_turn()
143
+ chat.new_turn("user")
144
+ chat.add_text("Hi")
145
+ chat.end_turn()
146
+ chat.new_turn("assistant")
147
+
148
+ with mimi.streaming(1):
149
+ for t in model.generate_interleaved(
150
+ **chat, max_new_tokens=10, audio_temperature=1.0, audio_top_k=4,
151
+ ):
152
+ pass # Just trigger compilation, discard output
153
+ _reset_mimi_streaming_state(mimi)
154
+ logger.info("LFM warmup complete — torch.compile graphs cached.")
155
+ except Exception as exc:
156
+ logger.warning("LFM warmup failed (non-fatal): %s", exc)
157
+
158
+
159
  def answer_question_audio(
160
  question_audio_path: str | None = None,
161
  question_text: str | None = None,
162
  story_context: str = "",
163
+ max_new_tokens: int = 100,
164
  ) -> tuple[str, np.ndarray | None, int]:
165
  """
166
  Answer a question about the story using LFM2.5-Audio end-to-end.