Views
No views yet
| 단계 | Mel Loss | Stop Loss | 보상 | 에포크 |
|---|---|---|---|---|
| PreTraining | 0.4196 | 0.0008 | - | 50 |
| FineTuning | 0.2854 | 0.0007 | - | 30 |
| RL (최종) | 0.1845 | 0.0006 | 0.85+ | 20 |
PreTraining: 3.196 → 0.4196 (87% 개선)
↓
FineTuning: 0.4196 → 0.2854 (32% 개선)
↓
RL: 0.2854 → 0.1845 (35% 개선)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
총합: 97% 개선!Python 3.8+
├── PyTorch 2.7.1 (cu118)
├── numpy 1.24.3
├── scipy 1.11.1
├── librosa 0.10.0
├── soundfile 0.12.1
├── tqdm 4.66.1
└── huggingface-hub 1.0.0입력: 한글 텍스트(예: "안녕하세요")
↓
[토큰화] (Syllable Encoding)
- 한글 음절 범위: 0xAC00 ~ 0xD7A3
- 어휘 크기: 2,000
↓
[Embedding Layer] (256차원)
↓
[Encoder] (BiLSTM + Conv1D)
- Conv1D: 256 채널, 3개 레이어
- BiLSTM: 256 숨겨진 유닛, 1 레이어
- 양방향 처리 (전체 문맥 인식)
↓
[Attention Mechanism] (Additive Attention)
- Query: Decoder 상태
- Key/Value: Encoder 출력
- 음성-텍스트 정렬 학습
↓
[Decoder] (Autoregressive LSTM)
- LSTM: 256 숨겨진 유닛, 2 레이어
- Pre-net: Linear(256) → Linear(256)
- 자동회귀 생성 (한 프레임씩)
↓
[Output Layer]
├── Mel-spectrogram (80 채널)
└── Stop Token (이진 분류)
↓
출력: 멜 스펙트로그램 (batch, time, 80)
↓
[Vocoder] (별도, Griffin-Lim 또는 Neural Vocoder)
↓
최종: 음성 파일 (WAV)1# Conv1D Encoder
2Conv1D(1, 256, kernel=5) → ReLU → Dropout(0.2)
3Conv1D(256, 256, kernel=5) → ReLU → Dropout(0.2)
4Conv1D(256, 256, kernel=5) → ReLU → Dropout(0.2)
5
6# BiLSTM
7BiLSTM(256, 256, 1, bidirectional=True)1# Additive Attention (Bahdanau Attention)
2score = tanh(W_q * query + W_k * key + b)
3attention_weights = softmax(v^T * score)
4context = sum(attention_weights * value)1# Pre-net (음성-텍스트 분리)
2Linear(80, 256) → ReLU → Dropout
3Linear(256, 256) → ReLU → Dropout
4
5# LSTM Cell (자동회귀)
6LSTMCell(256 + 256, 256) # Input + Context
7
8# Output Projection
9Linear(256, 80) → Mel-spectrogram
10Linear(256, 1) → Stop Token설정:
├── Epochs: 50
├── Batch Size: 32
├── Learning Rate: 1e-3 (Adam)
├── Dropout: 0.2
├── Teacher Forcing: 100% (항상 정답 사용)
├── Data Augmentation: SpecAugment + Mixup
└── Time: ~2.5 hours (GTX 1080 Ti)
손실 변화:
Epoch 1: 3.196
Epoch 10: 1.456
Epoch 25: 0.6842
Epoch 50: 0.4196 ✅1# Teacher Forcing: 정답 음성을 입력으로 사용
2mel_targets = actual_mel_spectrograms
3decoder_input = mel_targets[:, :-1, :] # 이전 프레임
4output = model(encoder_output, decoder_input)
5loss = MSE(output, mel_targets[:, 1:, :])설정:
├── Epochs: 30
├── Batch Size: 16
├── Learning Rate: 5e-4
├── Dropout: 0.15
├── Teacher Forcing: 90% → 0% (Curriculum Learning)
├── Scheduled Sampling: Yes
└── Time: ~2 hours (GTX 1080 Ti)
손실 변화:
Epoch 1: 0.4196 (PreTraining에서 로드)
Epoch 10: 0.3521
Epoch 20: 0.3012
Epoch 30: 0.2854 ✅1# Teacher Forcing Ratio 감소
2def get_teacher_forcing_ratio(epoch):
3 return max(0.0, 0.9 - 0.03 * epoch)
4
5# Epoch 0: 90% (대부분 정답 사용)
6# Epoch 5: 75% (섞어쓰기 시작)
7# Epoch 10: 60%
8# Epoch 20: 30%
9# Epoch 29: 0% (100% 자동회귀)1if random() < teacher_forcing_ratio:
2 # 정답 사용 (학습)
3 decoder_input = mel_targets[:, t-1, :]
4else:
5 # 모델 출력 사용 (추론 시뮬레이션)
6 decoder_input = model_output[:, t-1, :]설정:
├── Epochs: 20
├── Batch Size: 8
├── Learning Rate: 1e-4
├── Teacher Forcing: 0% (100% Autoregressive)
├── Reward Type: MOS (Mean Opinion Score)
├── Entropy Weight: 0.01
└── Time: ~1 hour (GTX 1080 Ti)
손실 변화:
Epoch 1: 0.2854 (FineTuning에서 로드)
Epoch 5: 0.2231
Epoch 10: 0.1962
Epoch 20: 0.1845 ✅
보상 변화:
Epoch 1: 0.62
Epoch 5: 0.74
Epoch 10: 0.81
Epoch 20: 0.85+ ✅1# 액션: 다음 프레임 생성
2action = model.decoder(context)
3
4# 보상: 생성된 음성 품질
5reward = calculate_reward(action)
6
7# 손실: -기댓값(보상) + 정규화
8policy_loss = -log_prob * (reward - baseline)
9entropy_bonus = -entropy_weight * entropy(distribution)
10total_loss = policy_loss + entropy_bonus1def calculate_mos_like_reward(mel_output, reference_mel):
2 """
3 MOS (Mean Opinion Score) 유사 보상
4
5 - 음성 품질 평가
6 - 연속성 평가
7 - 명확성 평가
8 """
9 quality_score = 1.0 - MSE(mel_output, reference_mel)
10 continuity_score = smoothness(mel_output)
11 clarity_score = energy_variance(mel_output)
12
13 return 0.5 * quality_score + 0.3 * continuity_score + 0.2 * clarity_score1# 모델이 다양한 옵션을 탐색하도록 격려
2entropy = -sum(prob * log(prob))
3entropy_bonus = entropy_weight * entropy
4total_loss = policy_loss - entropy_bonus # 감소시키면 탐색 증가손실 함수 (Mel Loss)
3.5 │ PreTraining
│ ●
3.0 │ ●●
│ ●●●
2.5 │ ●●●
│ ●●
2.0 │ ●●
│ ●●●
1.5 │ ●●●
│ ●●●
1.0 │ ●●●
│ ●●
0.5 │ ●●● FineTuning
│ ●●●●●
0.2 │ ●●●●●●●●●●●●●●●●●●●●●●●●●●
│ ●●●● RL
└─────────────────────────────────────────────────────────────────
0 10 20 30 40 50 | 60 70 80 90 |100 110 120
PreTraining Epochs | FineTuning E. | RL Epochs1Python >= 3.8
2PyTorch >= 2.7.1 (CUDA 11.8)1# 방법 1: 자동 다운로드
2pip install huggingface-hub
3
4python -c "
5from huggingface_hub import hf_hub_download
6
7# 모델 다운로드
8model_path = hf_hub_download(
9 repo_id='skytinstone/full-tuned-tacotron-minseok',
10 filename='rl_best.pt'
11)
12print(f'모델 다운로드 완료: {model_path}')
13"1pip install torch==2.7.1 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
2pip install numpy==1.24.3
3pip install scipy==1.11.1
4pip install librosa==0.10.0
5pip install soundfile==0.12.1
6pip install matplotlib==3.8.01# Hugging Face에서 파일 다운로드
2git clone https://huggingface.co/skytinstone/full-tuned-tacotron-minseok
3
4cd full-tuned-tacotron-minseok1import torch
2from tacotron_model import Tacotron
3from hparams_optimized import OptimizedHParams
4
5# 1. 모델 준비
6device = 'cuda' if torch.cuda.is_available() else 'cpu'
7hparams = OptimizedHParams(phase='rl')
8model = Tacotron(hparams).to(device)
9
10# 2. 체크포인트 로드
11checkpoint = torch.load('rl_best.pt', map_location=device)
12model.load_state_dict(checkpoint['model_state_dict'])
13model.eval()
14
15# 3. 텍스트 인코딩
16text = "안녕하세요"
17tokens = []
18for char in text:
19 if 0xAC00 <= ord(char) <= 0xD7A3:
20 idx = ord(char) - 0xAC00
21 tokens.append(idx % 2000)
22
23tokens = torch.tensor([tokens], dtype=torch.long).to(device)
24text_lengths = torch.tensor([tokens.shape[1]]).to(device)
25
26# 4. 추론
27with torch.no_grad():
28 mel_outputs, stop_tokens = model(
29 tokens,
30 text_lengths,
31 mel_targets=None,
32 teacher_forcing=False
33 )
34
35# 5. 결과
36print(f"입력: {text}")
37print(f"Mel 스펙트로그램 크기: {mel_outputs.shape}")
38print(f"음성 길이: {mel_outputs.shape[1] * 0.01:.1f}초")1import torch
2from tacotron_model import Tacotron
3from hparams_optimized import OptimizedHParams
4
5device = 'cuda' if torch.cuda.is_available() else 'cpu'
6model = Tacotron(OptimizedHParams(phase='rl')).to(device)
7checkpoint = torch.load('rl_best.pt', map_location=device)
8model.load_state_dict(checkpoint['model_state_dict'])
9model.eval()
10
11# 여러 문장 처리
12sentences = ["안녕하세요", "반갑습니다", "좋은 아침입니다"]
13
14for text in sentences:
15 tokens = []
16 for char in text:
17 if 0xAC00 <= ord(char) <= 0xD7A3:
18 idx = ord(char) - 0xAC00
19 tokens.append(idx % 2000)
20
21 tokens = torch.tensor([tokens], dtype=torch.long).to(device)
22 text_lengths = torch.tensor([tokens.shape[1]]).to(device)
23
24 with torch.no_grad():
25 mel_outputs, stop_tokens = model(
26 tokens,
27 text_lengths,
28 mel_targets=None,
29 teacher_forcing=False
30 )
31
32 print(f"✅ {text} → {mel_outputs.shape[1] * 0.01:.1f}초")1import torch
2import soundfile as sf
3import numpy as np
4from scipy import signal
5from tacotron_model import Tacotron
6from hparams_optimized import OptimizedHParams
7
8# Tacotron 추론
9device = 'cuda' if torch.cuda.is_available() else 'cpu'
10model = Tacotron(OptimizedHParams(phase='rl')).to(device)
11checkpoint = torch.load('rl_best.pt', map_location=device)
12model.load_state_dict(checkpoint['model_state_dict'])
13model.eval()
14
15# 텍스트 → Mel-spectrogram
16text = "안녕하세요"
17tokens = torch.tensor([[ord(c) - 0xAC00 for c in text if 0xAC00 <= ord(c) <= 0xD7A3]],
18 dtype=torch.long).to(device)
19text_lengths = torch.tensor([tokens.shape[1]]).to(device)
20
21with torch.no_grad():
22 mel_outputs, _ = model(tokens, text_lengths, mel_targets=None, teacher_forcing=False)
23
24mel = mel_outputs[0].cpu().numpy() # (time, 80)
25
26# Vocoder: Griffin-Lim Algorithm (간단함)
27# 참고: 더 나은 음성 품질을 원하면 WaveGlow, HiFi-GAN 등 사용
28def griffin_lim(mel_spec, n_iter=100, n_fft=2048):
29 """
30 Mel-spectrogram → 음성 변환
31 """
32 # Mel → Linear spectrogram
33 mel_to_linear = np.dot(mel_spec, np.linalg.pinv(librosa.filters.mel(48000, 2048)))
34
35 # Griffin-Lim
36 phase = np.angle(np.exp(2j * np.pi * np.random.random_sample(mel_to_linear.shape)))
37
38 for _ in range(n_iter):
39 spectrogram = np.abs(mel_to_linear) * np.exp(1j * phase)
40 waveform = librosa.istft(spectrogram)
41 phase = np.angle(librosa.stft(waveform))
42
43 return waveform
44
45waveform = griffin_lim(mel)
46
47# 파일 저장
48sf.write('output.wav', waveform, sr=48000)
49print("✅ 음성 파일 생성: output.wav")1@model{korean_tacotron_tts_2024,
2 title={Korean Tacotron Text-to-Speech with Reinforcement Learning},
3 author={MinSeok Shin},
4 year={2024},
5 publisher={Hugging Face Hub},
6 howpublished={\url{https://huggingface.co/skytinstone/full-tuned-tacotron-minseok}}
7}Shin, MinSeok. (2024). Korean Tacotron Text-to-Speech with Reinforcement Learning.
Hugging Face Hub. Retrieved from https://huggingface.co/skytinstone/full-tuned-tacotron-minseokMIT License
Copyright (c) 2024 MinSeok Shin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.