Xây dựng hệ thống nhái giọng nói tiếng Trung theo thời gian thực với MockingBird

MockingBird là công cụ mã nguồn mở cho phép tái tạo giọng nói người thật với độ trễ thấp, hỗ trợ đặc biệt tốt cho tiếng Trung Quốc phổ thông. Dự án tận dụng kiến trúc encoder-synthesizer-vocoder để tạo ra âm thanh tự nhiên từ đoạn văn bản đầu vào.

Triển khai môi trường

Trước tiên cần tải mã ngun và cài đặt các phụ thuộc:

git clone https://github.com/babysor/MockingBird.git
cd MockingBird
pip install -r requirements.txt

Cấu trúc bộ mã hóa (Encoder)

Bộ encoder đóng vai trò trích xuất đặc trưng âm thanh, chuyển đổi file âm thanh thành vector nhúng đại diện cho giọng nói. File triển khai chính nằm tại models/encoder/:

import torch.nn as nn

class VoiceEmbedder(nn.Module):
    def __init__(self, mel_channels=40, hidden_dim=256):
        super().__init__()
        self.lstm_stack = nn.LSTM(
            input_size=mel_channels,
            hidden_size=hidden_dim,
            num_layers=3,
            batch_first=True
        )
        self.projection = nn.Linear(hidden_dim, hidden_dim)
    
    def forward(self, mel_spectrogram):
        outputs, _ = self.lstm_stack(mel_spectrogram)
        # Lấy frame cuối cùng làm đại diện
        embedding = self.projection(outputs[:, -1, :])
        return embedding / torch.norm(embedding, dim=1, keepdim=True)

Xây dựng bộ tổng hợp (Synthesizer)

Bộ synthesizer nhận vector nhúng từ encoder và chuỗi ký tự văn bản, sau đó sinh ra mel-spectrogram tương ứng. ây là phần cốt lõi quyết định chất lượng đầu ra:

class TacotronSynthesizer(nn.Module):
    def __init__(self, embed_dim=256, vocab_size=70, mel_frames=80):
        super().__init__()
        self.char_embed = nn.Embedding(vocab_size, embed_dim)
        self.encoder_rnn = nn.LSTM(embed_dim, 256, 2, batch_first=True)
        self.attention = LocationSensitiveAttention(256)
        self.decoder_rnn = nn.LSTM(256 + mel_frames, 256, 2, batch_first=True)
        self.mel_proj = nn.Linear(256, mel_frames)
    
    def synthesize(self, text_indices, speaker_embed, max_steps=1000):
        encoded = self.char_embed(text_indices)
        encoder_out, _ = self.encoder_rnn(encoded)
        
        mel_outputs = []
        decoder_state = None
        prev_mel = torch.zeros(speaker_embed.size(0), 1, 80)
        
        for t in range(max_steps):
            context = self.attention(decoder_state, encoder_out)
            decoder_input = torch.cat([context, prev_mel], dim=-1)
            decoder_out, decoder_state = self.decoder_rnn(decoder_input)
            mel_frame = self.mel_proj(decoder_out)
            
            mel_outputs.append(mel_frame)
            prev_mel = mel_frame
            
            # iều kiện dừng khi gặp frame im lặng
            if self._is_silent(mel_frame):
                break
                
        return torch.stack(mel_outputs, dim=1)

Tích hợp Vocoder HiFi-GAN

Sau khi có mel-spectrogram, cần chuyển đổi thành sóng âm thanh tần số lấy mẫu cao. HiFi-GAN được tích hợp sẵn trong models/vocoder/hifigan/:

class HiFiGenerator(nn.Module):
    def __init__(self, upsample_rates=[8,8,2,2]):
        super().__init__()
        self.conv_pre = nn.Conv1d(80, 128, 7, padding=3)
        
        self.upsample_blocks = nn.ModuleList([
            ResBlockUpsample(128, 256, rate) 
            for rate in upsample_rates
        ])
        
        self.conv_post = nn.Conv1d(128, 1, 7, padding=3)
    
    def waveform_generate(self, mel_spec):
        x = self.conv_pre(mel_spec)
        for upsample in self.upsample_blocks:
            x = upsample(x)
        return torch.tanh(self.conv_post(x))

Pipeline nhái giọng hoàn chỉnh

Kết hợp các thành phần để tạo luồng xử lý end-to-end:

class RealTimeVoiceCloner:
    def __init__(self, encoder_ckpt, synth_ckpt, vocoder_ckpt):
        self.embedder = VoiceEmbedder()
        self.synthesizer = TacotronSynthesizer()
        self.vocoder = HiFiGenerator()
        
        self.embedder.load_state_dict(torch.load(encoder_ckpt))
        self.synthesizer.load_state_dict(torch.load(synth_ckpt))
        self.vocoder.load_state_dict(torch.load(vocoder_ckpt))
    
    def clone(self, reference_audio, target_text, text_processor):
        # Bước 1: Trích xuất giọng từ mẫu tham chiếu
        mel_ref = audio_to_mel(reference_audio)
        speaker_vec = self.embedder(mel_ref.unsqueeze(0))
        
        # Bước 2: Mã hóa văn bản đích
        text_indices = text_processor.chinese_to_sequence(target_text)
        
        # Bước 3: Tổng hợp mel-spectrogram
        mel_synth = self.synthesizer.synthesize(
            text_indices, speaker_vec
        )
        
        # Bước 4: Tạo sóng âm thanh
        waveform = self.vocoder.waveform_generate(mel_synth.squeeze(0))
        
        return waveform

Tối ưu cho tiếng Trung

Để đạt chất lượng tốt nhất với tiếng Trung, cần lưu ý:

  • Sử dụng bộ tokenizer phù hợp như pypinyin hoặc g2pM để chuyển Hán tự thành phiên âm
  • Điều chnh vocab_size theo số lượng âm vị tiếng Trung (khoảng 400 âm vị cơ bản)
  • Trong file configs/hifigan_16k.json, tăng fmax lên 8000Hz để bắt các sắc âm cao

Xử lý sự cố thường gặp

Hiện tượngNguyên nhânCách khắc phục
Âm thanh bị rè, méo tiếngHiFi-GAN chưa hội tụTăng số bước warmup, giảm learning rate
Giọng nói không giống mẫuEncoder chưa tách bạch speakerTăng số lượng speaker trong batch
Ngắt quãng giữa các từAttention alignment kémKiểm tra guided attention loss

Chạy inference nhanh

Demo command-line để kiểm tra kết quả:

python demo_toolbox.py \
    --encoder_path saved_models/encoder.pt \
    --synthesizer_path saved_models/synthesizer.pt \
    --vocoder_path saved_models/vocoder.pt \
    --input_wav samples/reference.wav \
    --text "这是一个语音合成的测试"

Thẻ: MockingBird Tacotron HiFi-GAN PyTorch

Đăng vào ngày 30 tháng 7 lúc 16:27