File size: 4,467 Bytes
4fe4e70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9c8f79c
 
4fe4e70
 
 
 
9c8f79c
4fe4e70
 
 
 
9c8f79c
 
4fe4e70
79dd8dc
 
4fe4e70
 
 
 
 
 
79dd8dc
9c8f79c
 
79dd8dc
4fe4e70
 
 
 
9c8f79c
4fe4e70
 
79dd8dc
9c8f79c
79dd8dc
 
 
9c8f79c
 
4fe4e70
 
9c8f79c
4fe4e70
 
 
 
 
 
 
 
9c8f79c
4fe4e70
 
 
 
 
 
 
9c8f79c
 
 
 
5fda8fd
 
 
 
9c8f79c
 
 
 
4fe4e70
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"""
ViuAI_TTS_200M Model Verification Script.
Checks architecture parameter budget, Human Prosody Engine, CFG support, and Voice Prompting.
"""

import sys
import os
import torch

# Fix Windows console encoding if needed
if sys.platform == "win32":
    try:
        sys.stdout.reconfigure(encoding="utf-8")
    except Exception:
        pass

# Ensure local package path is recognized
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from models import ViuAITTS200M


def run_verification():
    print("=" * 65)
    print("[*] Initializing ViuAI_TTS_200M Architecture...")
    print("=" * 65)

    # Instantiate model
    model = ViuAITTS200M()
    model.eval()

    # 1. Check parameter counts
    param_counts = model.count_parameters()
    print("\n[+] Model Parameter Budget Breakdown:")
    print("-" * 55)
    for name, count in param_counts.items():
        million_params = count / 1e6
        print(f"  {name:.<40} : {million_params:>6.2f} Million ({count:,} params)")
    print("-" * 55)

    # 2. Test Training Step (Flow Matching + Human Prosody Losses + Masking)
    print("\n[+] Testing Training Step (Flow Matching + Human Prosody Losses + Masking)...")
    batch_size = 2
    text_len = 15
    mel_len = 80

    dummy_tokens = torch.randint(0, 200, (batch_size, text_len))
    dummy_mels = torch.randn(batch_size, 80, mel_len)
    dummy_durations = torch.randint(2, 8, (batch_size, text_len))
    dummy_pitch = torch.randn(batch_size, text_len)
    dummy_energy = torch.randn(batch_size, text_len)
    dummy_text_lens = torch.tensor([15, 10], dtype=torch.long)
    dummy_mel_lens = torch.tensor([80, 60], dtype=torch.long)

    dummy_ref_mel = torch.randn(batch_size, 80, 40)

    losses = model.forward_train(
        text_tokens=dummy_tokens,
        mel_target=dummy_mels,
        durations=dummy_durations,
        pitch_target=dummy_pitch,
        energy_target=dummy_energy,
        ref_mel=dummy_ref_mel,
        text_lengths=dummy_text_lens,
        mel_lengths=dummy_mel_lens,
        train_vocoder=False,
    )

    print(f"  [OK] Flow Matching Loss : {losses['flow_loss'].item():.4f}")
    print(f"  [OK] Prosody Loss       : {losses['prosody_loss'].item():.4f}")
    print(f"  [OK] Duration Loss      : {losses['duration_loss'].item():.4f}")
    print(f"  [OK] Total Loss         : {losses['total_loss'].item():.4f}")

    # Gradient verification on DiT and Text Encoder
    losses["total_loss"].backward()
    dit_grads = sum(1 for p in model.dit.parameters() if p.grad is not None and p.grad.abs().sum() > 0)
    total_dit = len(list(model.dit.parameters()))
    print(f"  [OK] DiT Gradients      : {dit_grads}/{total_dit} parameters actively updated")
    model.zero_grad()

    # 3. Test Inference Pass with CFG and Reference Voice Prompting
    print("\n[+] Testing Human-like Inference Pass (with CFG=2.0 & Voice Prompting)...")
    single_token_input = torch.randint(0, 200, (1, 10))
    dummy_ref_audio = torch.randn(1, 80, 50)  # 50 frames of reference audio (like Adam)

    with torch.no_grad():
        audio_out, mel_out = model.generate(
            text_tokens=single_token_input,
            ref_mel=dummy_ref_audio,
            num_steps=10,
            cfg_scale=2.0,
            speed=1.0,
        )

    print(f"  [OK] Generated Mel-Spectrogram Shape : {list(mel_out.shape)}")
    print(f"  [OK] Generated 24kHz Audio Wave Shape : {list(audio_out.shape)}")
    print(f"  [OK] Total Audio Samples Generated   : {audio_out.shape[-1]:,} samples")
    print(f"  [OK] Audio Duration                  : {audio_out.shape[-1] / 24000:.2f} seconds")

    # 4. Test Checkpoint Strict Loading
    ckpt_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "checkpoints", "viuai_tts_200m_init.pt")
    if os.path.exists(ckpt_path):
        print("\n[+] Testing Checkpoint Compatibility (strict=True)...")
        try:
            ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=True)
        except Exception:
            ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False)
        state_dict = ckpt["model_state_dict"] if "model_state_dict" in ckpt else ckpt
        model.load_state_dict(state_dict, strict=True)
        print("  [OK] Checkpoint passed strict=True loading verification!")

    print("\n" + "=" * 65)
    print("[SUCCESS] All ViuAI_TTS_200M Human-Realism checks passed successfully!")
    print("=" * 65)


if __name__ == "__main__":
    run_verification()