debug logs + tweaks

This commit is contained in:
Fill
2025-12-30 23:00:49 -08:00
parent 4d19d98cd2
commit 7eb5fd41fa
8 changed files with 95 additions and 8 deletions
+10
View File
@@ -7,8 +7,18 @@ Generate complete songs with vocals and instrumentals from lyrics!
import sys
import os
import warnings
import importlib.util
# Suppress cosmetic warnings from transformers about GenerationMixin and checkpointing format
# These need to be set early, before transformers is imported
warnings.filterwarnings("ignore", message=".*GenerationMixin.*")
warnings.filterwarnings("ignore", message=".*old version of the checkpointing format.*")
warnings.filterwarnings("ignore", message=".*doesn't directly inherit from.*")
warnings.filterwarnings("ignore", message=".*will NOT inherit from.*")
warnings.filterwarnings("ignore", message=".*_set_gradient_checkpointing.*")
warnings.filterwarnings("ignore", category=FutureWarning, module="transformers.*")
# Get current directory
current_dir = os.path.dirname(os.path.abspath(__file__))
+8
View File
@@ -139,6 +139,14 @@ class CodecLM:
bgm_wavs = list(bgm_wavs)
texts, audio_qt_embs = self._prepare_tokens_and_attributes(lyrics=lyrics, melody_wavs=melody_wavs, vocal_wavs=vocal_wavs, bgm_wavs=bgm_wavs, melody_is_wav=melody_is_wav)
# Debug: Log what's being passed to _generate_tokens
print(f"\n[CodecLM DEBUG] ========== _generate_tokens INPUT ==========")
print(f"[CodecLM DEBUG] texts (lyrics): {texts}")
print(f"[CodecLM DEBUG] descriptions: {descriptions}")
print(f"[CodecLM DEBUG] audio_qt_embs shape: {audio_qt_embs.shape if audio_qt_embs is not None else 'None'}")
print(f"[CodecLM DEBUG] ================================================\n")
tokens = self._generate_tokens(texts, descriptions, audio_qt_embs)
if (tokens == self.lm.eos_token_id).any():
+7 -1
View File
@@ -233,7 +233,13 @@ class LmModel(StreamingModule):
if descriptions is not None:
attr["text"]["type_info"] = descriptions[i]
conditions.append(attr)
print("conditions", conditions)
# Enhanced debug logging for lyrics/descriptions
print(f"\n[LmLevo DEBUG] ========== CONDITION ATTRIBUTES ==========")
print(f"[LmLevo DEBUG] Available conditioners: {list(self.condition_provider.conditioners.keys())}")
print(f"[LmLevo DEBUG] attr['text']['description'] (LYRICS): {repr(attr.text.get('description', 'NOT SET'))[:200]}")
print(f"[LmLevo DEBUG] attr['text']['type_info'] (DESCRIPTION): {repr(attr.text.get('type_info', 'NOT SET'))[:200]}")
print(f"[LmLevo DEBUG] Has prompt_audio: {'prompt_audio' in attr.audio}")
print(f"[LmLevo DEBUG] =============================================\n")
if prepare_null_condition:
cfg_inference = ClassifierFreeGuidanceDropoutInference()
null_conditions = cfg_inference(conditions, condition_types=["audio", "text"],
+13
View File
@@ -133,9 +133,22 @@ class QwTokenizerConditioner(TextConditioner):
print("all structure tokens: ", {self.text_tokenizer.convert_ids_to_tokens(i):i for i in self.struct_token_ids})
def tokenize(self, x: tp.List[tp.Optional[str]]) -> tp.Dict[str, torch.Tensor]:
# Debug: Log input before tokenization
print(f"\n[QwTokenizerConditioner DEBUG] ========== TOKENIZE INPUT ==========")
print(f"[QwTokenizerConditioner DEBUG] Input text (first item, first 300 chars): {repr(x[0][:300]) if x and x[0] else 'None/Empty'}")
print(f"[QwTokenizerConditioner DEBUG] Number of inputs: {len(x)}")
x = ['<|im_start|>' + xi if xi is not None else "<|im_start|>" for xi in x]
# x = [xi if xi is not None else "" for xi in x]
inputs = self.text_tokenizer(x, return_tensors="pt", padding=True)
# Debug: Log tokenization result
print(f"[QwTokenizerConditioner DEBUG] Tokenized shape: {inputs['input_ids'].shape}")
print(f"[QwTokenizerConditioner DEBUG] First 20 token IDs: {inputs['input_ids'][0][:20].tolist()}")
decoded = self.text_tokenizer.decode(inputs['input_ids'][0][:50])
print(f"[QwTokenizerConditioner DEBUG] Decoded first 50 tokens: {repr(decoded)}")
print(f"[QwTokenizerConditioner DEBUG] ===========================================\n")
return inputs
def forward(self, inputs: tp.Dict[str, torch.Tensor]) -> ConditionType:
+22 -4
View File
@@ -3,8 +3,21 @@ FL Song Gen Lyrics Formatter Node.
Helps users build properly formatted lyrics with section tags.
"""
import re
from typing import Tuple
# Regex to filter lyrics - keeps letters, numbers, whitespace, brackets, hyphens, and CJK characters
# Removes punctuation like commas, apostrophes, quotes, etc.
LYRICS_FILTER_REGEX = re.compile(
r"[^\w\s\[\]\-\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af\u00c0-\u017f]"
)
def clean_lyrics_line(line: str) -> str:
"""Clean a single lyrics line by removing unsupported punctuation."""
cleaned = LYRICS_FILTER_REGEX.sub("", line)
return cleaned.strip()
class FL_SongGen_LyricsFormatter:
"""
@@ -228,9 +241,14 @@ class FL_SongGen_LyricsFormatter:
"""
Convert multiline text to SongGen format.
Newlines become periods to separate phrases.
Punctuation is removed to match model training data format.
"""
# Split by newlines, strip each line, filter empty
lines = [line.strip() for line in text.strip().split("\n") if line.strip()]
# Split by newlines, clean each line, filter empty
lines = []
for line in text.strip().split("\n"):
cleaned = clean_lyrics_line(line)
if cleaned:
lines.append(cleaned)
# Join with period-space (matches original SongGeneration training data format)
return ". ".join(lines)
# Join with period only (matches official SongGeneration format)
return ".".join(lines)
+4
View File
@@ -19,6 +19,10 @@ from omegaconf import OmegaConf
# Suppress cosmetic warnings from transformers about GenerationMixin and checkpointing format
warnings.filterwarnings("ignore", message=".*GenerationMixin.*")
warnings.filterwarnings("ignore", message=".*old version of the checkpointing format.*")
warnings.filterwarnings("ignore", message=".*doesn't directly inherit from.*")
warnings.filterwarnings("ignore", message=".*will NOT inherit from.*")
warnings.filterwarnings("ignore", message=".*_set_gradient_checkpointing.*")
warnings.filterwarnings("ignore", category=FutureWarning, module="transformers.*")
# Get the fl_utils directory (same directory as this file)
_FL_UTILS_DIR = os.path.dirname(__file__)
+30 -2
View File
@@ -5,6 +5,7 @@ Encapsulates the inference logic from SongGeneration's generate.py.
import gc
import os
import re
import sys
import tempfile
import importlib.util
@@ -15,6 +16,12 @@ import torch
import torchaudio
import soundfile as sf
# Regex to filter lyrics - keeps letters, numbers, whitespace, brackets, hyphens, and CJK characters
# Removes punctuation like commas, apostrophes, quotes, etc. that the model wasn't trained on
LYRICS_FILTER_REGEX = re.compile(
r"[^\w\s\[\]\-;\.\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af\u00c0-\u017f]"
)
# Get the fl_utils directory (same directory as this file)
_FL_UTILS_DIR = os.path.dirname(__file__)
@@ -112,8 +119,9 @@ class SongGenWrapper:
print(f"[FL SongGen] Duration {duration}s exceeds max {self.max_duration}s, clamping.")
duration = self.max_duration
# Clean lyrics
lyrics = lyrics.replace(" ", " ")
# Clean lyrics - remove unsupported punctuation and normalize spaces
lyrics = LYRICS_FILTER_REGEX.sub("", lyrics)
lyrics = re.sub(r"\s+", " ", lyrics) # Normalize multiple spaces to single space
if self.low_mem:
return self._generate_lowmem(
@@ -193,6 +201,16 @@ class SongGenWrapper:
'melody_is_wav': melody_is_wav,
}
# Debug: Log what we're passing to the model
print(f"\n[FL SongGen DEBUG] ========== GENERATION INPUT ==========")
print(f"[FL SongGen DEBUG] Lyrics (first 200 chars): {repr(lyrics[:200]) if lyrics else 'None'}")
print(f"[FL SongGen DEBUG] Description: {repr(description) if description else 'None'}")
print(f"[FL SongGen DEBUG] melody_wavs shape: {pmt_wav.shape if pmt_wav is not None else 'None'}")
print(f"[FL SongGen DEBUG] vocal_wavs shape: {vocal_wav.shape if vocal_wav is not None else 'None'}")
print(f"[FL SongGen DEBUG] bgm_wavs shape: {bgm_wav.shape if bgm_wav is not None else 'None'}")
print(f"[FL SongGen DEBUG] melody_is_wav: {melody_is_wav}")
print(f"[FL SongGen DEBUG] ======================================\n")
print(f"[FL SongGen] Generating tokens for {duration}s song...")
with torch.autocast(device_type="cuda", dtype=torch.float16, enabled=self.device == "cuda"):
@@ -359,6 +377,16 @@ class SongGenWrapper:
'melody_is_wav': melody_is_wav,
}
# Debug: Log what we're passing to the model (low mem path)
print(f"\n[FL SongGen LowMem DEBUG] ========== GENERATION INPUT ==========")
print(f"[FL SongGen LowMem DEBUG] Lyrics (first 200 chars): {repr(lyrics[:200]) if lyrics else 'None'}")
print(f"[FL SongGen LowMem DEBUG] Description: {repr(description) if description else 'None'}")
print(f"[FL SongGen LowMem DEBUG] melody_wavs shape: {pmt_wav.shape if pmt_wav is not None else 'None'}")
print(f"[FL SongGen LowMem DEBUG] vocal_wavs shape: {vocal_wav.shape if vocal_wav is not None else 'None'}")
print(f"[FL SongGen LowMem DEBUG] bgm_wavs shape: {bgm_wav.shape if bgm_wav is not None else 'None'}")
print(f"[FL SongGen LowMem DEBUG] melody_is_wav: {melody_is_wav}")
print(f"[FL SongGen LowMem DEBUG] ======================================\n")
print(f"[FL SongGen LowMem] Generating tokens...")
with torch.autocast(device_type="cuda", dtype=torch.float16):
with torch.no_grad():
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui_fl-songgen"
description = "FL Song Gen - AI-powered song generation nodes for ComfyUI. Generate complete songs with vocals and instrumentals from lyrics using Tencent's SongGeneration (LeVo) model. Features style transfer, auto style presets, dual-track output, and up to 4m30s song generation."
version = "1.0.8"
version = "1.0.9"
license = "Apache-2.0"
dependencies = [
"torch>=2.0.0",