Làm chủ tham số TTS để ra đúng giọng mong muốn

Mục lục bài viết15 mục

Trong bài này, mình giúp bạn tách rõ đầu ra huấn luyện khỏi tham số suy luận, lập bản đồ tệp sang các nút vặn, tối ưu length_scale, pitch, energy có đo WPM và F0, chốt preset sẵn sản xuất, kèm quy tắc an toàn. Ví dụ minh họa dùng FastPitch, Glow-TTS, VITS và SSML của Google, Azure, Polly.

Vì sao phải tách rõ đầu ra huấn luyện và tham số suy luận

Sau khi huấn luyện hoặc fine-tune TTS, bạn có một đống tệp và checkpoint. Nếu chỉ giữ checkpoint mà không tách bạch phần nào là đầu ra cố định của mô hình, phần nào là tham số bạn sẽ vặn lúc tổng hợp, bạn rất dễ rơi vào 3 rủi ro thực tế: 1) không tái lập được giọng vì mỗi lần synth lại khác, 2) không điều chỉnh được tốc độ, cao độ, ngắt nghỉ theo yêu cầu của PM hoặc khách hàng, 3) lãng phí giờ nghe-chỉnh vì sửa nhầm thứ thuộc về training thay vì inference. Tệ hơn, khi giọng phát sinh lỗi như nuốt phụ âm, méo nhịp hoặc metallic, bạn sẽ không biết phải kiểm ở khâu nào để gỡ.

Mình muốn bạn xem toàn bộ quy trình như hai lớp rõ ràng. Lớp đầu ra huấn luyện là những thứ bất biến khi synth: trọng số mô hình âm học, trọng số vocoder, embedding người nói và bản đồ speaker ID, file cấu hình kèm thống kê chuẩn hóa, từ điển hoặc bộ tách phoneme, cùng log và chỉ số validation. Lớp tham số suy luận là các nút vặn bạn điều khiển mỗi lần synth: tốc độ trường độ, cao độ, năng lượng, ngắt nghỉ, nhấn nhá, cùng các tham số ngẫu nhiên như temperature hoặc noise scale. Mục tiêu của bài là đặt một bản đồ thực dụng nối từ mỗi tệp sau train sang đúng nhóm nút vặn khi synth để bạn kiểm soát giọng theo ý, thay vì mò mẫm.

Đây là mẫu điền sẵn để bạn hình dung bản đồ cần có đi kèm với mỗi lần bàn giao mô hình, dùng ngôn ngữ phù hợp cho cả kỹ sư audio và PM:

  • Mô hình: FastPitch + HiFi-GAN, đơn người nói, sr 22050 Hz, hop 256
  • Tệp sau train
  • fastpitch_20260710.pt
  • hifiganuniversalv1.pt
  • configfastpitch.yaml, melstats.npy
  • lexicon_vi.txt
  • Nút vặn khi synth và dải khuyến nghị
  • length_scale: 0.9 đến 1.2 để chỉnh nhanh chậm mức vừa, mặc định 1.0
  • pitch shift theo bán âm: −2 đến +2 nếu pipeline cho phép can thiệp F0 trước khi vocoder
  • energy scale: 0.9 đến 1.1 để tăng giảm năng lượng nhẹ, tránh clip
  • break nội câu: chèn dấu phẩy hoặc SSML break 100 đến 300 ms khi cần ngắt rõ
  • random seed cố định khi cần tái lập
  • Preset kiểm duyệt nội bộ
  • Đọc chậm, trầm nhẹ: length_scale 1.15, pitch −1 st, energy 1.0
  • Đọc nhanh, sáng giọng: length_scale 0.92, pitch +1 st, energy 1.05

Nếu bạn dùng VITS đa người nói, khối tệp giữ nguyên ý nghĩa, và bộ nút vặn thường là lengthscale 0.9 đến 1.1, noisescale 0.6 đến 0.85, noisescalew 0.8 đến 1.0. Cùng một phiếu bàn giao cũng cần ghi rõ speaker ID hoặc tên trong speakers.json để PM và kỹ sư audio gọi đúng giọng, và một preset mặc định đã kiểm tra tốc độ đọc và cao độ đáp ứng yêu cầu. Khi mọi thứ được tách bạch và gắn vào một bản đồ như vậy, bạn có thể điều khiển giọng theo mục tiêu nghe thấy ngay, thay vì bị trói vào một checkpoint khó hiểu.

Bạn nhận được gì sau huấn luyện TTS

Sau một vòng huấn luyện hoặc fine-tune TTS, bạn sẽ có một gói hiện vật gồm nhiều tệp khác nhau. Mỗi tệp có một vai trò cụ thể trong suy luận và gắn trực tiếp với khả năng điều khiển giọng. Dưới đây là những hạng mục cốt lõi, cách chúng tham gia vào pipeline synth, cùng tiêu chí nhận biết bản đã sẵn sàng cho sản xuất.

  • Trọng số mô hình âm học
  • Bạn thường thấy tệp .pt, .ckpt, .onnx hoặc thư mục checkpoint của mô hình sinh đặc trưng trung gian như mel hoặc unit từ văn bản hay phoneme. Ví dụ điển hình: tacotron2xxx.pt, fastpitchxxx.pt, glowttsxxx.ckpt, vitsxxx.ckpt.
  • Vai trò ở suy luận: nhận text đã chuẩn hóa và chuỗi phoneme, dự đoán duration, F0 và mel tùy kiến trúc. Toàn bộ tham số điều khiển như length_scale, pitch shift, energy scale bám vào đầu ra của khối này.
  • Dấu hiệu sẵn sàng: checkpoint inference-only hoặc best-val, không chứa optimizer state nặng; không NaN; log huấn luyện cho thấy loss validation ổn định; có file config khớp để tái tạo front-end và kiến trúc.
  • Trọng số vocoder
  • Tệp trọng số cho HiFi-GAN, WaveGlow, UnivNet, v.v. thường là .pt hoặc .ckpt. Có thể là universal hoặc fine-tune theo giọng.
  • Vai trò ở suy luận: biến mel thành waveform. Không tham gia vào điều chỉnh tốc độ hay cao độ ở mức ngôn ngữ, nhưng rất nhạy với thống kê mel như số bin, fmin, fmax, hop_length, sample rate.
  • Dấu hiệu sẵn sàng: thông số front-end ghi rõ ràng trong manifest hoặc config trùng với khối âm học. Có mẫu WAV kiểm thử không artefact khi feed mel chuẩn hóa đúng cách.
  • Embedding người nói và bản đồ speaker ID
  • Có thể là một ma trận embedding .npy hoặc tích hợp trong checkpoint. Kèm tệp speakers.json hay tương đương để map tên người nói sang chỉ số ID hoặc khóa.
  • Vai trò ở suy luận: chọn giọng. Với mô hình đa người nói, bạn truyền speakerid hoặc speakername kèm theo. Với voice cloning, có thể là một embedding vector riêng biệt cho từng bản sao giọng.
  • Dấu hiệu sẵn sàng: speakers.json ổn định tên và ID giữa các phiên bản; embedding có kích thước đúng như cấu hình mô hình. Nếu single speaker, speakers.json vẫn nên có một mục mặc định để quy trình suy luận thống nhất.
  • File cấu hình và thống kê chuẩn hóa
  • File config YAML hoặc JSON mô tả kiến trúc, front-end, tiền xử lý và tham số mel. Thống kê chuẩn hóa thường ở mel_stats.npy, scaler.json hoặc mean-std theo từng đặc trưng.
  • Vai trò ở suy luận: đảm bảo text normalization, phonemization, trích xuất mel và chuẩn hóa đúng với lúc train. Đây là chìa khóa tương thích giữa acoustic và vocoder.
  • Dấu hiệu sẵn sàng: cấu hình ghi rõ samplerate, hoplength, n_mels, fmin, fmax, preemphasis nếu có, kèm phiên bản tokenizer hoặc phonemizer. Có checksum hoặc commit hash để đối chiếu.
  • Từ điển và bản đồ phoneme
  • Từ điển phát âm lexicon_xx.txt để chuyển từ sang chuỗi phoneme; bộ tách phoneme hoặc model G2P khi không có từ điển đầy đủ. Bản đồ phoneme id2phoneme.json và phoneme2id.json để đảm bảo đồng bộ hóa với mô hình.
  • Vai trò ở suy luận: đầu vào của acoustic model thường là chuỗi phoneme hay tương đương. Nếu dùng trực tiếp chữ cái, bộ quy tắc chuẩn hóa văn bản phải đi kèm để giữ nhịp và dấu câu đúng.
  • Dấu hiệu sẵn sàng: tỉ lệ phủ lexicon cao với domain của bạn; bản đồ phoneme trùng khớp kích thước embedding trong checkpoint; ghi rõ fallback khi từ không có trong từ điển.
  • Log và chỉ số validation
  • Log huấn luyện như TensorBoard scalars, hình alignment hoặc đánh dấu lỗi phát âm, cùng chỉ số như mel loss, duration loss, F0 RMSE nếu kiến trúc có. Có thể kèm script hoặc bảng tổng hợp best checkpoint.
  • Vai trò ở suy luận: không dùng trực tiếp, nhưng là bằng chứng chất lượng. Bạn sẽ dựa vào đây để quyết định chọn checkpoint, biết dải tham số an toàn và phát hiện drift bất thường giữa bản thử và bản cuối.
  • Dấu hiệu sẵn sàng: checkpoint được chọn có lý do định lượng kèm trích xuất 5 đến 10 mẫu WAV kiểm thử. Loss validation không còn giảm đáng kể hoặc đã có early stopping hợp lệ.

Một gói bàn giao mẫu hoàn chỉnh để bạn, PM và kỹ sư audio làm việc chung mượt mà:

{
  "model_name": "vi_fastpitch_hifigan_20260710",
  "acoustic": {
    "weights": "fastpitch_20260710.pt",
    "config": "config_fastpitch.yaml",
    "sha256": "9f1d7a7b8c0f4e1e9c6a2e3b1a5e7d2234a7b6c2b1e0d9c8f7a6b5c4d3e2f1a0"
  },
  "vocoder": {
    "weights": "hifigan_universal_v1.pt",
    "config": "config_hifigan.yaml",
    "sha256": "2d1c9e5b4a7f0c3e8a9b1d2f3c4e5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f"
  },
  "frontend": {
    "sr": 22050,
    "hop_length": 256,
    "n_mels": 80,
    "fmin": 0,
    "fmax": 8000,
    "text_normalizer": "vi_basic_v1",
    "phonemizer": "vi_g2p_v2",
    "lexicon": "lexicon_vi.txt",
    "phoneme_map": "phoneme_id_map.json",
    "mel_stats": "mel_stats.npy"
  },
  "speakers": {
    "map": "speakers.json",
    "embedding": "speaker_embed.npy",
    "default": "vi_narrator_female"
  },
  "validation": {
    "best_checkpoint_step": 241000,
    "notes": "Stable val loss plateau. No NaN. Alignments clean on 20 held-out lines.",
    "samples": [
      "samples/val_001.wav",
      "samples/val_002.wav",
      "samples/val_003.wav"
    ]
  },
  "inference_presets": {
    "default": {"length_scale": 1.0, "pitch_semitone": 0, "energy_scale": 1.0},
    "slow_warm": {"length_scale": 1.12, "pitch_semitone": -1, "energy_scale": 1.0},
    "fast_bright": {"length_scale": 0.93, "pitch_semitone": 1, "energy_scale": 1.05}
  },
  "ready_for_production": true,
  "version": "2026.07.10",
  "commit": "a3c5e2f9"
}

Biến thể điền theo dự án khác, bạn chỉ cần thay các trường tương ứng:

  • model_name
  • acoustic.weights | acoustic.config | acoustic.sha256
  • vocoder.weights | vocoder.config | vocoder.sha256
  • frontend.sr | hoplength | nmels | fmin | fmax | textnormalizer | phonemizer | lexicon | phonememap | mel_stats
  • speakers.map | speakers.embedding | speakers.default
  • validation.bestcheckpointstep | validation.notes | validation.samples[]
  • inferencepresets.default | slowwarm | fast_bright
  • readyforproduction | version | commit

Checklist nhận biết phiên bản đã dùng được cho sản xuất mà không phải mò mẫm:

  • Tương thích front-end giữa acoustic và vocoder: cùng sr, hoplength, nmels, fmin, fmax. Sai một tham số mel là vỡ tiếng.
  • Có đủ file cấu hình và thống kê chuẩn hóa: config YAML hoặc JSON và mel_stats. Nếu pipeline cần chuẩn hóa per-speaker, đảm bảo stats tương ứng đi kèm.
  • Speaker map ổn định và rõ ràng: speakers.json có khóa người nói dễ hiểu cho PM và kỹ sư audio. Với multi-speaker, embedding .npy trùng kích thước với mô hình.
  • Checkpoint inference-only hoặc best-val kèm log chọn bản: có lý do chọn, không phải latest-step tùy tiện.
  • Smoke test gắn với preset: 5 đến 10 câu chuẩn synth qua preset mặc định và 1 preset chậm êm. Không có nuốt phụ âm, không metallic rõ, tốc độ và cao độ trong vùng mong đợi.
  • Manifest có checksum và version: giúp tái lập, truy vết lỗi nhanh. Lưu kèm 3 mẫu WAV và thông số preset đã dùng để tạo chúng.

Lưu ý nhỏ để bạn không bị kẹt vào checkpoint khó hiểu:

  • Đặt tên tệp có ngày-tháng và kiến trúc, ví dụ fastpitch20260710.pt thay vì modelfinal.pt.
  • Luôn gói kèm speakers.json kể cả single speaker để thống nhất giao diện suy luận.
  • Với mô hình clone giọng, ghi rõ nguồn embedding và ngày tạo để tránh nhầm lẫn giữa các bản gần giống nhau.

Với bộ tệp trên, vai trò từng phần trong suy luận đã rõ ràng: text đi qua chuẩn hóa và phonemizer dùng lexicon và bản đồ phoneme, acoustic model sinh mel có điều kiện theo speaker embedding, vocoder biến mel thành WAV, còn preset giúp bạn điều khiển tốc độ, cao độ, năng lượng ổn định. Khi mọi tham số front-end khớp và log xác nhận chất lượng, bản build đó có thể được coi là sẵn sàng cho sản xuất.

Bản đồ tham số: huấn luyện vs suy luận vs điều khiển giọng

Ba nhóm tham số này sống ở ba thời điểm khác nhau và giải quyết các vấn đề khác nhau. Nếu bạn trộn chúng, bạn sẽ mất thời gian chỉnh những nút không thể tạo ra thay đổi mong muốn. Mình tách rành mạch theo bối cảnh sử dụng, nêu ví dụ điển hình learning rate vs noisescale vs lengthscale và khi nào mỗi nhóm ảnh hưởng trực tiếp đến kết quả.

  • Nhóm 1: Hyperparameter huấn luyện
  • Là những tham số quyết định quá trình học, chỉ tác động khi bạn train hoặc fine-tune. Ví dụ: learning rate, scheduler, batch size, số bước huấn luyện, dropout, gradient clip, loss weights cho duration và F0 trong FastPitch, guided-attention cho Tacotron, data augmentation, seed, cùng các tham số front-end cố định như sr, hoplength, nmels, fmin, fmax.
  • Ảnh hưởng đến kết quả khi nào: khi mô hình đang học cách căn chỉnh, phát âm, mô hình hóa cao độ và năng lượng. Nếu learning rate quá cao mô hình không hội tụ, attention đứt, phát âm sai hoặc nuốt phụ âm; quá thấp thì underfit, giọng phẳng. Những lỗi kiểu này không thể giải quyết bằng nút vặn suy luận hay SSML, bạn buộc phải retrain hoặc fine-tune với cấu hình phù hợp.
  • Dấu hiệu cần quay lại nhóm này: attention không sạch, duration và F0 dự đoán sai hệ thống, lỗi phát âm lặp lại bất kể bạn đổi tham số suy luận, vocoder feed mel chuẩn vẫn kêu metallic trên toàn bộ câu vì mel nền kém. Lúc đó, chỉnh learning rate, số bước warmup, loss balance, hoặc bổ sung dữ liệu/regularization mới là đúng hướng.
  • Nhóm 2: Tham số suy luận của engine
  • Là những nút vặn của chính mô hình khi synth, không đổi trọng số. Tùy kiến trúc mà bạn có:
  • length_scale: nhân trực tiếp lên độ dài phoneme hoặc phân bổ frame. Nhỏ hơn làm nói nhanh, lớn hơn làm chậm. Xuất hiện ở FastSpeech/FastPitch, Glow-TTS, VITS.
  • noisescale, noisescale_w, temperature: điều khiển mức ngẫu nhiên khi lấy mẫu ở Glow-TTS/VITS. Tăng lên tạo biểu cảm và biến thiên cục bộ, nhưng dễ jitter, trôi ID, tăng nguy cơ lỗi nhịp.
  • seed: cố định để tái lập kết quả khi có sampling.
  • Một số vocoder hoặc pipeline có thêm tham số suy luận riêng. Ví dụ WaveGlow có denoiser strength để khử residual noise sau tổng hợp. HiFi-GAN thường không cần tham số như vậy.
  • Ảnh hưởng đến kết quả khi nào: khi bạn muốn đổi tính ngẫu nhiên, nhịp nội bộ, độ ổn định và tính nhận dạng giọng mà không đụng đến trọng số. Ví dụ:
  • noise_scale thấp giúp giọng ổn định, bám ID hơn, nhưng có thể nghe hơi máy.
  • noise_scale cao tạo đa dạng cảm xúc, đổi sắc thái, nhưng nguy cơ rung nhịp và trôi ID tăng.
  • length_scale giảm giúp tăng WPM, nhưng nếu hạ quá mức có thể nuốt phụ âm ngắn; tăng quá tay làm câu loãng và mất tự nhiên.
  • Quy tắc thực dụng để bắt đầu: đặt seed cố định; đặt lengthscale khoảng 0.9 đến 1.1 để tinh chỉnh nhịp nhỏ; với Glow-TTS/VITS giữ noisescale ở mức vừa phải trước khi đụng đến tham số điều khiển giọng của người dùng. Sau đó đo WPM và F0 trên vài câu 5 đến 10 giây để chốt vùng an toàn của chính mô hình bạn.
  • Nhóm 3: Tham số điều khiển giọng do người dùng chỉnh
  • Là những tham số được bộc lộ cho tác vụ sáng tạo hoặc yêu cầu kỹ thuật của sản phẩm. Chúng map thẳng sang cảm nhận người nghe và chỉ số đo được:
  • Tốc độ nói: length_scale trong các mô hình có duration predictor hoặc thuộc tính rate trong SSML. Đo bằng WPM.
  • Cao độ: pitch shift tính theo bán âm hoặc phần trăm, hoặc thuộc tính pitch trong SSML. Đo bằng F0 trung bình trên khung hữu thanh.
  • Năng lượng/âm lượng: energy_scale trong mô hình có dự đoán energy, gain ở post-process, hoặc volume trong SSML. Đo bằng RMS hoặc LUFS.
  • Ngắt nghỉ, nhấn nhá và style: break, emphasis, style trong SSML; ở open-source thì thường là preset nhịp kèm lengthscale, energy và đôi khi noisescale nhẹ.
  • Ảnh hưởng đến kết quả khi nào: khi bạn cần đáp ứng brief như nhanh hơn 10 phần trăm, cao hơn 1 bán âm, hơi to và dứt khoát hơn, nhưng không muốn thay đổi nền tảng học của mô hình. Những tham số này phải được lưu thành preset để PM và kỹ sư audio tái lập trong duyệt chất lượng.

Ví dụ điền sẵn để bạn hình dung rõ ranh giới ba lớp tham số, áp trên cùng một checkpoint:

  • Case A cần sửa lỗi hệ thống: mô hình thường xuyên nuốt phụ âm tắc, alignment xấu. Dùng đúng nút ở Nhóm 1. Hành động: giảm learning rate đỉnh, thêm warmup, tăng trọng số duration loss, train thêm 50k bước. Các tham số Nhóm 2 và 3 chỉ che khuyết điểm tạm thời.
  • Case B cần giữ giọng ổn định hơn khi synth nhiều câu dài: dùng Nhóm 2. Hành động: cố định seed, đặt noisescale 0.7 đến 0.8, giữ lengthscale quanh 1.0. Kết quả là ít jitter, ID bám hơn, không thay đổi tốc độ hoặc cao độ mục tiêu mặc định.
  • Case C cần đáp ứng yêu cầu phát sóng: nhanh hơn 10 phần trăm, cao hơn 1 bán âm, dày tiếng hơn. Dùng Nhóm 3 trước, Nhóm 2 sau để giữ ổn định.
  • Preset hoàn chỉnh gợi ý cho FastPitch + HiFi-GAN: lengthscale 0.92, pitchsemitone +1, energy_scale 1.05, seed 1234.
  • Preset hoàn chỉnh gợi ý cho VITS: lengthscale 0.92, pitchsemitone +1, energyscale 1.05, noisescale 0.75, seed 1234.
  • Cách áp dụng: synth 1 vòng với preset, đo WPM và F0. Nếu WPM chưa đạt, lùi lengthscale từng bước 0.02; nếu F0 lệch, chỉnh pitchsemitone theo bậc bán âm. Giữ noise_scale cố định để không làm trôi ID khi bạn đang nhắm vào các chỉ tiêu định lượng.

Cách nhớ nhanh để khỏi lẫn lộn mỗi khi bạn chuẩn bị sản xuất:

  • Sai do mô hình chưa học: quay lại hyperparameter huấn luyện, đừng kỳ vọng length_scale hay rate SSML cứu được.
  • Sai do bất ổn, rung nhịp, mất đồng nhất giữa các lần synth: chỉnh tham số suy luận của engine như noisescale, seed, và chỉ chạm nhẹ lengthscale để tránh biến dạng âm vị.
  • Nhu cầu sáng tạo và tiêu chuẩn kiểm thử như WPM, F0, RMS: ưu tiên tham số điều khiển giọng, vì chúng map thẳng sang cảm nhận và có thể đóng gói thành preset bàn giao cho PM và kỹ sư audio.

Ba tầng tham số không thay thế nhau. Bạn sẽ đi nhanh và chắc khi quyết định đúng tầng cho đúng loại vấn đề, rồi cố định preset đạt yêu cầu cùng số đo WPM, F0, RMS để toàn đội dùng thống nhất.

Điều khiển trên Tacotron và họ FastSpeech FastPitch

Tacotron là mô hình tự hồi quy dùng attention nên trường độ được quyết định ngầm bởi attention và dấu câu. Không có duration predictor hay length regulator, vì vậy không có nút length_scale để nén giãn tốc độ một cách ổn định. Nếu bạn cần điều khiển nhịp, tốc độ, cao độ một cách định lượng, họ FastSpeech và đặc biệt FastPitch là lựa chọn đúng vì có duration predictor, length regulator và các nhánh dự đoán F0, energy để vặn trực tiếp lúc suy luận.

Cơ chế duration predictor và length regulator trong FastSpeech FastPitch

  • Duration predictor: dự đoán độ dài mỗi phoneme tính theo số frame mel. Nhiều triển khai dự đoán log-duration rồi lấy exp về số thực dương.
  • Length regulator: nhân các vector ẩn của từng phoneme theo số frame đã dự đoán để dàn trải thành chuỗi frame mel, sau đó mạng sinh mel lấy chuỗi này làm điều kiện.
  • lengthscale: hệ số nhân trực tiếp lên duration trước khi làm tròn về số nguyên. lengthscale nhỏ làm nói nhanh, lớn làm chậm. Nguy cơ
  • Skip kỹ thuật: một phoneme bị rơi về 0 frame sau khi nhân scale và làm tròn.
  • Near-skip và merge cảm nhận: phoneme bị rút còn 1 frame hoặc hai phoneme ngắn dính lại về mặt nghe.
  • Điểm khởi đầu an toàn để thử trên câu 3 đến 10 giây, hop_length 256, sr 22.05 đến 24 kHz
  • length_scale khoảng 0.6 đến 1.4 thường an toàn.
  • Dưới khoảng 0.5 đến 0.6 rủi ro skip hoặc near-skip tăng nhanh vì nhiều phụ âm tắc chỉ dài 1 đến 2 frame.
  • Trên khoảng 2.0 đến 2.5 thường không tạo skip kỹ thuật nhưng nhịp nghe loãng, dễ dính cảm nhận ở phụ âm cuối.
  • Các yếu tố làm ngưỡng xê dịch
  • hoplength lớn hơn làm mỗi frame dài hơn, nên nguy cơ rơi 0 hoặc 1 frame xuất hiện sớm khi bạn hạ scale. Với hop 512, giữ lengthscale cao hơn đáng kể so với hop 256.
  • Quy tắc làm tròn và clamp: nếu code clamp tối thiểu 1 frame sau khi scale, skip kỹ thuật biến mất, nhưng near-skip 1 frame vẫn tăng mạnh khi bạn hạ dưới 0.6.

Điều khiển F0 và energy trong FastPitch

  • F0: FastPitch dự đoán và dùng F0 làm điều kiện để sinh mel. Bạn có thể
  • Dịch cao độ theo bán âm: đặt k bán âm, áp dụng F0′ = F0 × 2^(k/12). Điều này đổi cảm nhận trầm bổng có kiểm soát.
  • Thay thế F0 bằng đường F0 bên ngoài nếu bạn có bộ trích F0 tin cậy, giữ lại nhịp duration gốc.
  • Energy: FastPitch có nhánh energy, bạn có thể scale năng lượng khung theo hệ số tuyến tính hoặc cộng theo dB tùy triển khai.
  • Quy tắc thực dụng
  • Pitch shift trong khoảng ±2.5 bán âm thường an toàn. Từ 3 đến 4 bán âm nên nghe kiểm tra vì nguy cơ lệch sắc giọng và artefact tăng theo vocoder.
  • Energy scale nhẹ 0.9 đến 1.1 giúp cân bằng cảm nhận khi bạn đổi pitch. Tăng F0 thì nhích energy lên 1 đến 2 dB, giảm F0 thì hạ nhẹ cho đỡ bí tiếng.
  • Kết hợp nhỏ nhắn để giữ tự nhiên: tăng pitch +2 st, giảm length_scale 0.05 đến 0.1 và tăng energy 1.05 thường cho cảm nhận sáng, nhanh hơn nhưng chưa gắt.

Ví dụ preset điền sẵn cho FastPitch khi synth một câu đọc nhanh hơn, cao hơn và dày tiếng hơn

  • length_scale: 0.92
  • pitch_semitone: +2
  • energy_scale: 1.05
  • seed: 1234

Biến thể có tham số

  • length_scale: L
  • pitch_semitone: K
  • energy_scale: E
  • seed: S

Cách kiểm chứng ngưỡng length_scale riêng của mô hình bằng forced alignment

  1. Chuẩn bị tập kiểm định
  • Chọn 100 câu tiếng Việt, mỗi câu 3 đến 10 giây sau khi đọc. Đa dạng dấu câu vừa phải để phản ánh nhịp tự nhiên.
  1. Quét length_scale theo lưới
  • Các giá trị đề xuất: 0.4, 0.5, 0.6, 0.7, 1.0, 1.5, 2.0, 2.5.
  • Synth audio cho mọi cặp câu và length_scale, dùng cùng vocoder và seed cố định để loại trừ ngẫu nhiên.
  1. Forced alignment trên audio đã synth
  • Căn chỉnh text thành chuỗi phoneme với audio synth để lấy thời lượng mỗi phoneme theo giây. Bạn có thể dùng một aligner CTC hoặc công cụ align phổ biến và ánh xạ thời lượng sang số frame mel bằng công thức frames = round(durationsec × sr / hoplength).
  • Lưu ý đồng bộ sr và hop_length đúng với pipeline mel của bạn.
  1. Tính chỉ số skip và near-skip
  • Skip kỹ thuật: tỷ lệ phoneme có frames = 0.
  • Near-skip: tỷ lệ phoneme có frames ∈ {0, 1}. Với pipeline có clamp tối thiểu 1 frame, chỉ số skip kỹ thuật bằng 0, bạn dùng near-skip để thay thế.
  • Tính riêng theo từng length_scale, tổng hợp trên toàn bộ 100 câu.
  1. Suy ra ngưỡng an toàn
  • Chọn length_scale nhỏ nhất sao cho skip kỹ thuật dưới 1 phần trăm. Nếu pipeline clamp min 1 frame, dùng near-skip dưới 1 phần trăm làm tiêu chí.
  • Ghi chú thêm độ tự nhiên cảm nhận khi scale lớn hơn 2.0 đến 2.5 vì không phải lỗi skip nhưng có thể là vùng loãng nhịp. Nghe mù A B tại hai mốc biên để quyết định có dùng trong sản xuất hay không.
  1. Khóa preset và văn bản hóa
  • Ghi lại sr, hoplength, quy tắc làm tròn hoặc clamp của length regulator, bộ lưới đã quét, ngưỡng lengthscale tối thiểu đạt tiêu chí, cùng ví dụ preset. Kỹ sư audio có thể dựa vào đây để duyệt và tái lập.

Gợi ý thực hành khi kết hợp các nút vặn

  • Luôn ưu tiên ổn định duration trước khi đẩy pitch. Nếu length_scale bạn chọn ở sát ngưỡng nhỏ, hãy giữ pitch shift trong ±2 bán âm để tránh cộng dồn rủi ro.
  • Khi cần nói nhanh mà vẫn rõ phụ âm tắc, thử tăng nhẹ energy thay vì tiếp tục hạ length_scale. Điều này thường giúp giữ bật phụ âm mà không cần vượt rào ngưỡng near-skip.
  • Nếu bạn đổi hoplength so với lúc train mel, phải đo lại ngưỡng lengthscale vì toàn bộ phân bố độ dài theo frame đã khác.

Điều khiển trên Glow-TTS và VITS

Glow-TTS và VITS đều sinh mel bằng normalizing flow có điều kiện và dùng Monotonic Alignment Search để gán số frame cho từng phoneme. Vì vậy, bạn kiểm soát nhịp bằng lengthscale trên tuyến căn chỉnh và kiểm soát mức ngẫu nhiên bằng noisescale, noisescalew, đôi khi gọi chung là temperature của mẫu Gaussian trong flow. Điều quan trọng là giữ tốc độ tự nhiên mà không nuốt phụ âm hay làm trôi ID giọng khi tăng ngẫu nhiên.

MAS và length_scale vận hành ra sao

  • MAS tìm đường căn chỉnh đơn điệu từ chuỗi phoneme sang chuỗi frame mel. Ở suy luận, độ dài mỗi phoneme theo frame được nhân length_scale rồi làm tròn để dàn trải thành chuỗi frame.
  • Nếu length_scale quá nhỏ, một phần phoneme ngắn sẽ bị rơi về 0 hoặc 1 frame. 0 frame là skip kỹ thuật. 1 frame thường biến mất về mặt cảm nhận – người nghe chấm là dính âm.
  • Lưu ý thực hành:
  • Hãy clamp tối thiểu 1 frame sau khi nhân scale và làm tròn. Điều này loại bỏ skip kỹ thuật, dù near-skip 1 frame vẫn có thể tăng nếu bạn hạ scale quá tay.
  • hoplength càng lớn, mỗi frame càng dài, nên cùng một scale sẽ dễ rơi 0-1 frame sớm hơn. Nếu bạn đổi từ 256 sang 512, cần nâng lengthscale an toàn lên tương ứng.
  • Ngưỡng tham khảo với câu tiếng Việt 3–10 giây, sr 22.05–24 kHz, hop_length 256:
  • Glow-TTS: length_scale nhỏ hơn khoảng 0.55–0.65 dễ phát sinh tỷ lệ skip hoặc near-skip tăng rõ, nhất là các phụ âm tắc sát khoảng lặng. Vùng 0.7–1.6 thường an toàn. Trên 2.0–2.5 nhịp nghe loãng, không tự nhiên, dù không gây skip kỹ thuật.
  • VITS: nhạy hơn ở phía nhỏ do có thêm nhiễu trong posterior. Dưới khoảng 0.6–0.7 thường bắt đầu nuốt phụ âm hoặc dính âm cảm nhận. Vùng 0.7–1.6 thường an toàn nếu bạn giữ nhiễu ở mức vừa.

Cơ chế noisescale, noisescale_w, temperature trong flow

  • noise_scale: hệ số nhân phương sai khi lấy mẫu z từ Gaussian gốc của flow. Tăng giá trị này làm phổ và F0 cục bộ rung mạnh hơn, tự nhiên có thể tăng nhẹ nhưng ID giọng kém bám hơn do formant và jitter biến thiên.
  • temperature: trong nhiều codebase bằng với noise_scale – cùng tác động lên z. Nếu cả hai cùng tồn tại, chúng thường nhân lại thành một hệ số hiệu dụng áp lên Gaussian.
  • noisescalew: điều khiển ngẫu nhiên của độ dài – độ rộng căn chỉnh theo phoneme. Tăng giá trị này làm nhịp vi mô rung và dễ biến dạng trường độ.
  • Vùng an toàn điển hình khi mục tiêu là giữ tự nhiên và ID ổn định:
  • noisescale 0.6–0.85, noisescalew 0.7–1.0. Đẩy noisescale lên 0.9–1.0 thường làm cảm nhận giọng bớt ổn định – khi đo sẽ thấy cosine x-vector so với tham chiếu giảm đáng kể. Nếu muốn thêm sinh động, ưu tiên tăng nhẹ noisescalew thay vì đẩy noise_scale.

Ảnh hưởng đến tự nhiên và độ bám ID giọng

  • Tự nhiên: lengthscale lớn sẽ chậm và đôi khi rời rạc; lengthscale nhỏ tăng nguy cơ thiếu phụ âm. noise_scale vừa phải có thể tạo cảm giác sống động; quá cao sinh jitter F0 và năng lượng bất thường, nghe hụt hơi hoặc kim loại tùy vocoder.
  • Độ bám ID giọng: tăng noisescale làm embedding x-vector lệch khỏi tham chiếu vì phổ và formant dao động – lengthscale không bù được drift gốc này. Giữ lengthscale gần 1.0, noisescale trong 0.6–0.85 thường giúp cosine similarity giảm không đáng kể so với baseline.

Quy trình đo cosine x-vector để phát hiện drift

  • Mục tiêu: khi đổi tham số, độ giảm cosine trung bình so với cấu hình baseline không vượt 0.05.
  • Bước thực hiện:
  1. Chọn 3–5 câu tiếng Việt, mỗi câu 5–10 giây đã cho kết quả tốt ở baseline. Ghi lại cấu hình baseline, ví dụ lengthscale 1.0, noisescale 0.667, noisescalew 0.8, seed cố định.
  2. Sinh audio ở baseline và ở cấu hình bạn muốn thử. Với VITS nên synth 2–3 lần mỗi cấu hình với seed khác nhau để lấy trung bình.
  3. Trích x-vector bằng một encoder sẵn có và nhất quán cho mọi audio, ví dụ ECAPA-TDNN đã huấn luyện trên VoxCeleb trong SpeechBrain. Tính cosine giữa mẫu synth và 2–3 clip tham chiếu cùng người nói.
  4. Tính trung bình cosine theo câu và theo seed. Nếu giảm quá 0.05 so với baseline, hãy lùi noisescale hoặc noisescale_w.
  • Mẫu mã Python đo x-vector và cosine với SpeechBrain:
# Mục đích: trích x-vector và tính cosine giữa WAV synth và WAV tham chiếu
from speechbrain.pretrained import EncoderClassifier
import torchaudio, torch, numpy as np

enc = EncoderClassifier.from_hparams(source="speechbrain/spkrec-ecapa-voxceleb")
def xvec(path):
    wav, sr = torchaudio.load(path)
    if sr != 16000:  # ECAPA của SpeechBrain mặc định 16 kHz
        wav = torchaudio.functional.resample(wav, sr, 16000)
    emb = enc.encode_batch(wav).squeeze(0).mean(dim=0)  # gộp theo thời gian
    v = emb.detach().cpu().numpy()
    return v / np.linalg.norm(v)

def cos(a, b): return float(np.dot(a, b))

ref = xvec("ref_speaker.wav")
test = xvec("synth_candidate.wav")
print("cosine:", cos(ref, test))
  • Lưu ý cho kỹ sư audio và PM: báo cáo điểm cosine trung bình, độ lệch chuẩn theo seed, kèm 2–3 mẫu nghe A/B. Cosine không thay thế thẩm định tai, nhưng giúp chốt vùng tham số ổn định.

Ví dụ lệnh suy luận điền sẵn trên một repo VITS mở phổ biến

  • Ý nghĩa: synth một câu, giữ nhịp gần tự nhiên, tăng nhẹ độ sống động nhưng không trôi ID.
python inference.py \
  --model vits_multispeaker.ckpt \
  --config vits_config.json \
  --text "Xin chào, đây là thử nghiệm điều chỉnh tham số để kiểm soát nhịp và độ tự nhiên." \
  --speaker_id 7 \
  --length_scale 0.95 \
  --noise_scale 0.75 \
  --noise_scale_w 0.9 \
  --seed 1234 \
  --out wav/vits_demo.wav
  • Biến thể có tham số:
  • length_scale: L
  • noise_scale: N
  • noisescalew: W
  • seed: S

Mẹo an toàn khi áp dụng trên tiếng Việt

  • Với hoplength 256: đừng hạ lengthscale dưới 0.65 cho Glow-TTS và 0.7 cho VITS nếu bạn chưa kiểm chứng skip bằng aligner. Nếu bắt buộc nói nhanh hơn, giảm đến sát ngưỡng rồi bù bằng tăng nhẹ năng lượng hoặc giảm khoảng lặng trong văn bản thay vì tiếp tục hạ scale.
  • Nếu bạn đổi hoplength hoặc thay vocoder, đo lại ngưỡng lengthscale vì phân bố frame đã đổi.
  • Kiểm tra pipeline đã clamp min 1 frame sau khi scale. Nếu chưa có, bổ sung ngay để tránh skip kỹ thuật – sau đó dùng chỉ số near-skip 1 frame làm tiêu chí theo dõi khi hạ scale.

Điều khiển qua SSML trên Google Cloud Amazon Polly Azure Speech

SSML cho phép bạn điều khiển tốc độ, cao độ, âm lượng, ngắt nghỉ, nhấn nhá và cả phong cách biểu cảm của giọng. Điểm mấu chốt là bám vào phần chung của chuẩn SSML, đồng thời biết rõ chỗ mỗi vendor làm khác nhau để không ngạc nhiên khi kết quả lệch mục tiêu tốc độ hay cao độ.

Những thuộc tính cốt lõi và đơn vị nên dùng

  • rate – tốc độ nói:
  • Giá trị: phần trăm như +10%, -20% hoặc từ khóa x-slow, slow, medium, fast, x-fast.
  • Google Cloud – Azure – Polly đều nhận phần trăm và từ khóa.
  • Lưu ý: rate không co giãn toàn bộ pause. Pauses do punctuation và các break tuyệt đối thường không bị nhân theo rate, nên WPM thực tế hiếm khi tăng đúng 20% khi bạn đặt +20%, nhất là với câu ngắn hoặc nhiều dấu phẩy.
  • pitch – cao độ:
  • Giá trị: bán âm st như +2st, -3st nơi được hỗ trợ, hoặc phần trăm +8%, -10%, hoặc từ khóa x-low..x-high.
  • Google Cloud – Azure: hỗ trợ bán âm st. Amazon Polly: không chuẩn hóa st, nên dùng phần trăm hoặc từ khóa.
  • Lưu ý: engine thường clamp ở vùng cực trị để giữ tự nhiên – đẩy quá cao hoặc quá thấp sẽ bị giới hạn, nhất là trên đỉnh – đáy ngữ điệu.
  • volume – âm lượng:
  • Giá trị: từ khóa silent, x-soft, soft, medium, loud, x-loud.
  • Lưu ý: một số giọng có loudness normalization sẵn nên thay đổi volume không luôn cho ra mức LUFS như bạn kỳ vọng. Ưu tiên dùng từ khóa thay vì trông chờ phần trăm hay dB không được chuẩn hóa.
  • break – ngắt nghỉ:
  • Giá trị: time tuyệt đối time="400ms" hoặc time="1.2s", hoặc strength none, x-weak, weak, medium, strong, x-strong.
  • Lưu ý: break là tuyệt đối – hầu như không bị rate co giãn. Một số vị trí đầu – cuối câu có thể bị ràng ngưỡng tối thiểu.
  • emphasis – nhấn nhá:
  • Giá trị: level="reduced|moderate|strong".
  • Azure và Polly áp dụng tương đối nhất quán. Google có thể giảm nhẹ hoặc bỏ qua tùy giọng – hãy thử và nghe.
  • expressive style – phong cách:
  • Không có chuẩn chung. Azure dùng thẻ mở rộng mstts:express-as với style và styledegree – chỉ một số voice hỗ trợ. Polly có thẻ mở rộng amazon:domain cho các miền giọng như conversational hoặc newscaster, và amazon:effect như whispered cho thì thầm – cũng tùy giọng. Google Cloud không có thẻ style chung, chủ yếu điều khiển qua prosody và chọn voice phù hợp.

Khác biệt triển khai quan trọng cần nhớ

  • rate không nhân lên mọi khoảng dừng. Vì vậy WPM tăng thường nhỏ hơn tỷ lệ bạn đặt, đặc biệt với văn bản ngắn hoặc nhiều dấu câu.
  • pitch có thể bị clamp ở vùng rất cao hoặc rất thấp để tránh giọng biến dạng. Trên ngôn ngữ có thanh điệu như tiếng Việt, bạn nên giữ trong ±2 st cho nội dung bình thường để không phá bố cục thanh điệu.
  • break strength là ánh xạ nội bộ theo từng engine – mức medium của vendor A không bằng medium của vendor B. Nếu cần độ chính xác, dùng time theo ms.
  • emphasis và style mang tính best-effort. Nếu voice không hỗ trợ, thẻ có thể bị bỏ qua mà không báo lỗi.

Cú pháp điển hình an toàn – không phụ thuộc vendor

  • Mục tiêu: tăng tốc độ +15%, nâng cao độ +2 bán âm, chèn ngắt nghỉ 400 ms, nhấn một cụm từ.
  • Dạng generic dùng tốt ở cả 3 dịch vụ. Nếu engine không hiểu một thuộc tính, nó sẽ bỏ qua mà không hỏng toàn bộ.
<speak>
  <p>
    <prosody rate="+15%" pitch="+2st" volume="medium">
      Xin chào, mình đang thử điều chỉnh tốc độ và cao độ để phù hợp kịch bản.
    </prosody>
    <break time="400ms"/>
    <emphasis level="strong">Đây là phần cần nhấn mạnh.</emphasis>
  </p>
</speak>
  • Biến thể thân thiện với Amazon Polly khi cần tránh st – chuyển pitch sang phần trăm:
<speak>
  <p>
    <prosody rate="+15%" pitch="+10%" volume="medium">
      Xin chào, mình đang thử điều chỉnh tốc độ và cao độ để phù hợp kịch bản.
    </prosody>
    <break time="400ms"/>
    <emphasis level="strong">Đây là phần cần nhấn mạnh.</emphasis>
  </p>
</speak>

Gợi ý dùng style nơi có hỗ trợ

  • Azure – dùng mstts:express-as. Lưu ý style và styledegree chỉ hợp lệ với một số voice nhất định – kiểm tra danh sách style hỗ trợ của từng voice trước khi áp.
<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis"
       xmlns:mstts="http://www.w3.org/2001/mstts" xml:lang="en-US">
  <voice name="en-US-AriaNeural">
    <mstts:express-as style="chat" styledegree="1.2">
      <prosody rate="+10%" pitch="+2st">This is a friendly chatty style sample.</prosody>
    </mstts:express-as>
  </voice>
</speak>
  • Amazon Polly – dùng amazon:domain và amazon:effect cho một số hiệu ứng:
<speak xmlns="http://www.w3.org/2001/10/synthesis"
       xmlns:amazon="http://www.amazon.com/ssml">
  <amazon:domain name="conversational">
    <prosody rate="+10%" pitch="+8%">Hi there, this sounds more conversational.</prosody>
  </amazon:domain>
  <amazon:effect name="whispered">this part is whispered</amazon:effect>
</speak>

Cách kiểm nhanh để chắc bạn đang điều khiển đúng hướng

  • Dùng văn bản 2 câu, tổng 12 – 15 giây thoại có tiếng.
  • Tạo 2 phiên bản: baseline và SSML đã chỉnh. Đo:
  • WPM – mong đợi tăng nhỏ hơn tỷ lệ rate đặt, đặc biệt nếu có nhiều break.
  • F0 trung bình – với Google và Azure, pitch bằng +2st thường gần mục tiêu; với Polly, dùng phần trăm thay cho st.
  • Nếu WPM tăng quá ít, giảm bớt break time hoặc hạ strength, không tiếp tục đẩy rate. Nếu F0 nghe gắt hoặc đục, lùi về ±1 đến 2 st và tránh kết hợp pitch cao cùng volume lớn.

Bản đồ tham số sang cảm nhận

Mình tóm các “nút vặn” thành cảm nhận của tai người để bạn biết phải xoay tham số nào cho đúng ý và nhận ra khi đã đi quá tay. Hãy xem đây như một bản đồ ngắn gọn từ kỹ thuật sang trải nghiệm nghe, có kèm ngưỡng thực dụng và cách lùi về vùng an toàn.

  • Tốc độ nói
  • lengthscale của mô hình có duration predictor: giảm lengthscale làm nói nhanh, tăng lên làm chậm. Cảm nhận đi kèm nhanh – gấp – căng nếu giảm quá nhiều; chậm – thong thả – đôi khi lê thê nếu tăng quá mức.
  • rate trong SSML: cùng tác dụng ở tầng engine.
  • Dấu hiệu quá tay: nuốt phụ âm ngắn, dính âm, nhịp gấp gáp bất thường khi scale quá thấp; nhịp loãng, câu như hụt hơi hoặc ngắt không đúng chỗ khi scale quá cao.
  • Vùng an toàn và lùi về: với FastSpeech – FastPitch giữ lengthscale khoảng 0.7 – 1.8; với Glow-TTS – VITS giữ 0.8 – 1.8 để tránh nuốt âm trên câu tiếng Việt 3 – 10 giây. Nếu đã nghe thiếu phụ âm, tăng lengthscale từng nấc 0.1 đến khi hết dính; với SSML rate, giới hạn ±15% cho nội dung bình thường, thay vì cố bù bằng +30%.
  • Cao độ
  • pitch trong SSML hoặc scale F0 trong mô hình: tăng cho cảm giác trẻ – sáng – khẩn trương; giảm cho trầm – chín chắn – bình tĩnh.
  • Dấu hiệu quá tay: tăng nhiều nghe the thé, chipmunk; giảm nhiều nghe đục, nặng nề. Dễ lộ méo khi kết hợp pitch cao với volume lớn.
  • Vùng an toàn và lùi về: giữ trong khoảng ±2 bán âm cho nội dung phổ thông; 2 – 4 bán âm là vùng cần nghe soát. Nếu nghe gắt, hạ 1 bán âm và bù bằng tăng nhẹ energy.
  • Năng lượng – âm lượng
  • energy trong mô hình hoặc volume trong SSML: tăng cho cảm nhận to – dày – quyết liệt; giảm cho nhỏ – mỏng – nhẹ nhàng.
  • Dấu hiệu quá tay: quá to gây xì – lạo xạo ở âm bật mạnh; quá nhỏ thành thều thào, thiếu hài cao.
  • Vùng an toàn và lùi về: tăng giảm ở mức vừa phải theo nấc preset của engine hoặc từng bước nhỏ 1 – 2 dB nếu có nút gain riêng. Khi đã nghe méo hoặc thều thào, quay về mức trung bình rồi cân lại bằng break và pitch thay vì tiếp tục đẩy volume.
  • Ngắt nghỉ
  • break time hoặc strength trong SSML, hoặc chèn token tĩnh lặng trong pipeline: tăng break làm câu rành mạch – điềm đạm; giảm break cho mạch nói liền lạc – khẩn trương.
  • Dấu hiệu quá tay: ngắt vụn như đọc đánh vần nếu break dày – dài; hụt hơi, đuổi chữ nếu thiếu break.
  • Vùng an toàn và lùi về: mid-phrase 200 – 400 ms, cuối câu 500 – 800 ms là dải dễ nghe. Nếu WPM không lên dù tăng rate, rút bớt break thay vì tiếp tục tăng rate.
  • Nhấn nhá
  • emphasis trong SSML hoặc điều khiển stress – prominence trong mô hình: thêm lực – độ nổi cho cụm từ quan trọng.
  • Dấu hiệu quá tay: kịch hóa, lấn át mạch câu, làm người nghe mệt.
  • Vùng an toàn và lùi về: mỗi câu tối đa 1 – 2 điểm nhấn. Nếu đã nặng tai, hạ level về moderate hoặc bỏ nhấn ở cụm phụ.
  • Style – expressiveness
  • Thẻ style của engine hoặc conditioning style trong mô hình: điều khiển thái độ tổng thể như conversational, chatty, newsy.
  • Dấu hiệu quá tay: lố, “diễn” quá đà không hợp nội dung; lệch ID giọng khi style kéo F0 và energy ra khỏi thói quen giọng.
  • Vùng an toàn và lùi về: chọn style khớp miền nội dung; nếu có tham số cường độ styledegree, giữ quanh 0.8 – 1.2. Nếu nghe lố, giảm độ style trước, rồi mới canh lại pitch – energy.
  • Temperature – noise_scale
  • temperature trong diffusion hoặc noise_scale trong flow như VITS: tăng tạo đa dạng vi mô – sống động; giảm cho ổn định – nhất quán. Người nghe cảm nhận tăng temperature là bớt nhàm chán nhưng dễ rung nhịp – phập phù cao độ.
  • Dấu hiệu quá tay: jitter F0, run rẩy, s, x, f xì gió, trôi nhận diện giọng giữa các lần synth.
  • Vùng an toàn và lùi về: 0.6 – 0.85 thường là dải cân bằng tự nhiên – ổn định. Nếu đã rung – trôi ID, hạ 0.05 – 0.1 và cố định seed. Với VITS, ưu tiên hạ noisescale trước khi động vào lengthscale.
  • length_scale so với cảm nhận tự nhiên – robotic
  • length_scale quá đồng nhất hoặc quá cực đoan khiến trường độ các âm không còn tương quan thật, tai người nghe thành “đều đều” – robotic hoặc “cụt hơi”.
  • Dấu hiệu quá tay: câu bị nấc nhịp, phụ âm cuối mờ dần khi giảm quá thấp, hoặc kéo dài thiếu mục đích khi tăng quá cao.
  • Vùng an toàn và lùi về: neo về 1.0 làm mốc, điều chỉnh từng bước 0.05 – 0.1 và nghe A/B trên cùng câu 6 – 10 giây. Nếu phải tăng pitch nhiều, bù bằng rút nhẹ length_scale 5 – 10% và tăng energy chút để giữ độ sáng mà không the thé.

Ba công thức phối tham số để đạt cảm nhận mong muốn

  • Thư giãn – ấm áp: rate +5% hoặc length_scale 0.95 – 1.05, pitch -1 st, volume soft – medium, break mid-phrase 300 – 400 ms, emphasis tối đa 1 điểm nhẹ. Nếu chớm buồn ngủ, tăng pitch về 0 st.
  • Khẩn trương – căng thẳng tích cực: rate +10 – 15% hoặc lengthscale 0.85 – 0.9, pitch +1 – 2 st, energy medium – loud, break 150 – 250 ms, emphasis 1 điểm ở động từ hành động. Nếu dính âm, tăng lengthscale thêm 0.05.
  • Trung tính – tự nhiên để thuyết minh: rate 0 đến +5% hoặc length_scale 0.95 – 1.05, pitch 0 st, energy medium, break 250 – 350 ms, emphasis moderate tại thuật ngữ chính. Nếu hơi robot, tăng nhẹ temperature 0.05 hoặc nới break 50 ms.

Quy tắc lùi về vùng an toàn khi đã đi quá tay

  • Đặt lại mốc: lengthscale 1.0, pitch 0 st, rate 0%, volume medium, break mid-phrase 300 ms, temperature – noisescale 0.7 – 0.8.
  • Khử lỗi theo triệu chứng:
  • Nuốt phụ âm – dính âm: tăng length_scale +0.1, giữ temperature thấp.
  • Gắt – the – mệt: hạ pitch 1 st, giảm volume một nấc, tăng break +50 – 100 ms.
  • Chậm lê thê: giảm break -50 – 100 ms trước, chỉ giảm length_scale nếu vẫn dài.
  • Rung – thiếu ổn định: hạ temperature – noisescale -0.05, cố định seed, có thể tăng nhẹ lengthscale 0.05 để làm dịu nhịp.
  • Nghe “máy” – đều đều: tăng temperature +0.05 hoặc thêm 1 điểm emphasis nhỏ, không chạm mạnh vào pitch.
  • Xác nhận bằng nghe mù A/B trên cùng 2 câu 6 – 10 giây và dừng khi phiên bản mới không còn cải thiện rõ.

Bạn không cần vặn tất cả nút cùng lúc. Bắt đầu từ bộ khung length_scale – pitch – break, sau đó nêm nếm energy và temperature vừa đủ. Khi mỗi tham số đều có “bản đồ” trong tai bạn, việc tái lập một chất giọng nhất quán và đúng ý sẽ trở nên nhanh gọn.

Quy trình tối ưu tham số có kiểm chứng

Mục tiêu của quy trình là đi từ một preset mặc định đến cấu hình có thể tái lập, đạt đúng tốc độ nói và cao độ mong muốn, nghe tự nhiên trên cả tai chuyên môn và người dùng cuối. Mình chia thành các bước nhỏ, mỗi bước khóa bớt biến để mọi thay đổi đều có lý do và bằng chứng.

  1. Cố định mục tiêu và chuẩn bị dữ liệu thử
  • Chốt tiêu chí định lượng trước khi chạy: mục tiêu WPM, mục tiêu F0 trung bình tính theo bán âm so với baseline, ngưỡng chấp nhận ví dụ WPM trong ±5% và F0 trong ±1 bán âm. Thêm điều kiện tối thiểu về lỗi phát âm – không nuốt phụ âm, không méo thanh điệu.
  • Chuẩn hóa văn bản test: 3 câu dài tổng 12 – 18 giây thoại sau synth, không viết tắt, số đọc ra chữ, dấu câu vừa phải. Giữ nguyên chính tả giữa mọi lần synth.
  • Nếu bạn làm tiếng Việt hoặc ngôn ngữ có thanh điệu, chuẩn bị 2 bộ: một bộ trung tính thanh điệu, một bộ cố ý giàu thanh sắc – hỏi – ngã để kiểm xem preset có bền khi phân bố F0 thay đổi.
  1. Thiết lập baseline vững
  • Chọn một tham số gốc an toàn: lengthscale 1.0, pitch 0 st, rate 0%, energy ở mức medium, noisescale 0.7 – 0.8, noisescalew 0.8 – 0.9, temperature theo khuyến nghị engine.
  • Cố định seed để loại ngẫu nhiên. Với mô hình có randomness, render 3 lần cùng seed để chắc không có jitter nội bộ.
  • Đo baseline: WPM = số từ chia thời lượng thoại đã VAD-trim, F0 trung bình tính trên khung hữu thanh bằng CREPE hoặc Harvest. Báo thêm Δst = 12*log2(F0mod/F0base) khi bạn bắt đầu chỉnh pitch.
  1. Lập lưới thay đổi nhỏ và một lần một nút
  • Lưới hẹp và có kiểm soát, mỗi vòng chỉ đổi 1 nhóm nút:
  • Vòng tốc độ: length_scale {0.9, 1.0, 1.1} hoặc SSML rate {−10%, 0%, +10%}.
  • Vòng cao độ: pitch {−2 st, 0 st, +2 st}.
  • Vòng năng lượng: energy hoặc volume tăng giảm từng nấc nhỏ.
  • Với VITS hoặc flow model, nếu cần đổi độ sống động, thử noisescale {0.7, 0.8, 0.85}. Không đổi noisescale và length_scale cùng lúc ở vòng đầu.
  • Dùng đúng 3 câu baseline cho mọi cấu hình. Cố định seed để kết quả khác biệt đến từ tham số, không từ may rủi.
  1. Đo lường khách quan và lọc theo tiêu chí
  • Với mỗi cấu hình, synth 1 lần nếu đã khóa seed. Nếu engine nhiều nhiễu, synth 3 lần khác seed và lấy trung bình.
  • Đo và so sánh với mục tiêu:
  • WPM trong ±5% mục tiêu – nếu vượt, ưu tiên chỉnh length_scale hoặc rate trước khi động vào break.
  • F0 trung bình trong ±1 bán âm mục tiêu – nếu lệch, ưu tiên pitch hoặc F0 control nội bộ trước khi bù bằng energy.
  • Kiểm âm lỗi thô: nuốt phụ âm, méo nguyên âm dài, rung F0. Loại cấu hình dù đạt WPM – F0 nếu mắc lỗi này.
  1. Nghe mù A/B hoặc ABX để xác nhận cảm nhận
  • Chọn 2 – 3 cấu hình dẫn đầu theo đo lường. Chuẩn bị cặp A – B cho từng câu, tráo thứ tự ngẫu nhiên giữa người nghe.
  • Tối thiểu 3 người nghe, gồm 1 kỹ sư audio hoặc người quen nghe TTS. Nhiệm vụ: chọn bản tự nhiên hơn và dễ hiểu hơn. Với ABX, họ nghe A và B trước, sau đó phải đoán X là A hay B.
  • Quy tắc dừng đơn giản: nếu một cấu hình được chọn nhiều hơn hẳn ở cả hai tiêu chí trên đa số câu, giữ nó cho vòng kế tiếp – không cần đếm phần trăm thống kê phức tạp.
  1. Khóa seed và giảm randomness ở giai đoạn chốt
  • Khi đã có 1 cấu hình tốt, test lại ở 3 seed để ước lượng dao động. Nếu WPM hoặc F0 dao động quá 5% giữa seed, hạ noisescale – temperature hoặc tăng lengthscale nhẹ 0.05 để làm mượt nhịp, sau đó chọn 1 seed chuẩn cho sản xuất.
  • Với dịch vụ đám mây không có seed, tăng kích thước tập test và dùng kết quả trung bình của 3 lần synth lại để đảm bảo tính ổn định.
  1. Chốt cấu hình và ghi nhận điều kiện tái lập
  • Lưu preset gồm: tên model và phiên bản checkpoint, hash file trọng số, tham số mel – hop_length – sample rate, tham số suy luận cuối cùng, seed, văn bản test, WPM – F0 đo được, file WAV minh chứng.
  • Với PM – khách hàng và kỹ sư audio, nộp thêm bảng so sánh ngắn A/B và ghi chú cảm nhận đi kèm số đo. Điều này giúp họ duyệt mà không cần tái chạy.

Ví dụ minh họa – phiếu preset điền sẵn

  • Engine: VITS multi-speaker r1.5 – checkpoint 7c2f4b1
  • Inference: lengthscale 0.90, noisescale 0.75, noisescalew 0.85, pitch +2 st, seed 20240715
  • Front-end: sr 22050 Hz, hop 256, mel 80 bin
  • Text set: 3 câu – 17.2 s thoại sau VAD
  • Đo lường: WPM mục tiêu 170, WPM đạt 169.2, lệch −0.5%; F0 mục tiêu +2 st, Δst đạt +1.8 st; không nuốt phụ âm, không rung F0
  • Nghe mù: 3 người, 2 câu chọn B, 1 câu hòa – chốt cấu hình B

Lưu ý đặc thù văn bản và ngôn ngữ có thanh điệu

  • WPM chịu ảnh hưởng lớn từ dấu câu – khi so sánh, giữ nguyên câu và dấu câu. Nếu văn bản thay đổi, dời ngưỡng chấp nhận WPM lên ±7 – 8%.
  • F0 trung bình phụ thuộc phân bố thanh – so sánh theo bán âm và trên cùng văn bản. Nếu phải đổi văn bản, chấp nhận biên ±1.5 bán âm hoặc đo theo Δst từng âm tiết trung tâm thay vì toàn câu.
  • Trên câu ngắn dưới 8 giây, thay vì ép đúng WPM bằng tăng rate mạnh, ưu tiên tinh chỉnh break nội câu – giữ nhịp tự nhiên sẽ giúp điểm nghe mù tốt hơn.

Công thức vận hành nhanh

  • Vòng 1: khóa seed, grid length_scale hoặc rate để chạm WPM mục tiêu.
  • Vòng 2: giữ WPM đã đạt, grid pitch theo bán âm để chạm Δst.
  • Vòng 3: tinh chỉnh energy – break nhỏ để tối ưu nghe mù.
  • Vòng 4: nếu cần sinh động, tăng noise_scale 0.05 – 0.1 rồi kiểm WPM – F0 lại. Không để noise phá vỡ tiêu chí ổn định đã chốt.

Khi bạn tuân theo chuỗi khóa – đo – nghe – khóa, preset cuối sẽ không chỉ đúng con số mà còn nghe đúng, và quan trọng là có thể tái lập bất cứ lúc nào với đúng điều kiện đã ghi nhận.

Thực đơn thao tác để sinh 1 WAV đạt tốc độ và cao độ mục tiêu

Bạn cần một quy trình gọn, đo được ngay sau mỗi lần synth để kịp chỉnh và chốt. Dưới đây là thực đơn thao tác tối thiểu, áp dụng được cả cho engine nội bộ có length_scale và dịch vụ đám mây có SSML rate, pitch, volume. Mục tiêu là chạm WPM và F0 trung bình theo yêu cầu, nghe tự nhiên và có thể tái lập.

  1. Lấy baseline rất ngắn
  • Synth 1 bản với preset an toàn của engine. Giữ noise hoặc temperature ở mức thấp để đo ổn định.
  • Đo thời lượng thoại có tiếng: cắt silence đầu cuối bằng VAD hoặc mắt thường trong DAW, lấy thời gian từ khi bắt đầu có tiếng đến khi hết tiếng.
  • Đếm số từ phát âm thực tế trên văn bản. WPM_base = số từ chia thời lượng thoại tính theo phút.
  • Đo F0 trung bình trên đoạn có tiếng bằng một tracker tin cậy như Praat, CREPE hoặc Harvest, bỏ frame vô thanh. Ghi F0_base.
  • Nếu bạn đã có một mẫu tham chiếu voice, bạn có thể lấy F0_base từ chính preset hiện tại, không cần audio tham chiếu khác.
  1. Ước lượng tham số lần 1
  • Với engine nội bộ có lengthscale: lengthscale1 ≈ lengthscale0 × (WPMbase / WPMtarget). Vì lengthscale tăng thì nói chậm, giảm thì nói nhanh.
  • Với SSML rate: rate1% ≈ 100 × (WPMtarget / WPM_base − 1). Bắt đầu trong khoảng ±10 đến ±15% để tránh biến dạng nhịp do pause không co giãn hết.
  • Pitch theo bán âm: kst = 12 × log2(F0target / F0base). Đặt pitch = +kst st hoặc −kst st theo mục tiêu. Nếu engine chỉ nhận phần trăm, quy đổi gần đúng pitch% ≈ 100 × (2^(kst/12) − 1).
  • Energy hoặc volume hoặc gain: để tự nhiên, tăng nhẹ +1 đến +3 dB nếu bạn vừa tăng pitch, giảm nhẹ −1 đến −3 dB nếu bạn vừa hạ pitch. Tham số này không thay đổi WPM hay F0 nhưng giúp giữ cảm nhận nhất quán.
  1. Synth lần 1 và lưu lại
  • Với engine nội bộ, áp lengthscale và pitch control của model nếu có, xuất WAV1 và ghi kèm tham số.
  • Với SSML, áp rate, pitch, volume trong thẻ prosody, xuất WAV_1.
  1. Đo nhanh và tính sai số
  • Đo WPM1 giống bước 1, tính sai số ewpm = WPM1 − WPMtarget.
  • Đo F01, tính sai số est = 12 × log2(F01 / F0target) theo bán âm. Dấu dương là cao hơn mục tiêu, âm là thấp hơn.
  1. Hiệu chỉnh vòng 2 có kiểm soát
  • Nếu |e_wpm| lớn hơn ngưỡng chấp nhận, chỉnh nhỏ theo quy tắc nhân:
  • lengthscale2 ≈ lengthscale1 × (WPM1 / WPMtarget).
  • hoặc rate2% bổ sung ≈ 100 × (WPMtarget / WPM_1 − 1). Giới hạn mỗi vòng ±10% để giữ tự nhiên, thay vì nhảy vọt.
  • Nếu |e_st| lớn, chỉnh trực tiếp theo phần dư:
  • pitch2st = pitch1st + (ksttarget − kstmeasured).
  • hoặc pitch_2% nhân theo tỉ lệ 2^(Δst/12).
  • Nếu nghe hơi mảnh khi pitch tăng, tăng volume thêm +1 dB. Nếu nghe ồm khi pitch hạ, giảm −1 dB. Không đụng thêm tham số khác trong cùng vòng.
  1. Synth lần 2, kiểm tra tiêu chí và lặp tối đa một vòng
  • Làm lại bước 4. Khi WPM nằm trong ±5% và F0 nằm trong ±1 bán âm quanh mục tiêu, dừng. Nếu chưa đạt, lặp thêm một vòng hiệu chỉnh nhỏ. Tránh đẩy length_scale hoặc rate quá mạnh trong một lần vì pause nội câu thường không tỷ lệ hoàn toàn với rate.
  1. Xuất WAV cuối và ghi preset để tái lập
  • Đặt tên file có timestamp và tham số chính. Ghi preset gồm model, phiên bản trọng số, seed nếu có, length_scale hoặc rate, pitch, volume, WPM và F0 đo được, văn bản đã phát.

Ví dụ điền sẵn, dùng SSML trên Google Cloud TTS để đạt WPM khoảng 170 và tăng cao độ +2 bán âm

  • Baseline: WPMbase = 150, F0base = 180 Hz.
  • Mục tiêu: WPMtarget = 170, F0target = 180 × 2^(2/12) ≈ 202.5 Hz.
  • Ước lượng: rate_1% ≈ 100 × (170/150 − 1) ≈ +13.3%, pitch = +2st, volume = +1dB.
  • SSML dùng để synth lần 1:
<speak>
  <prosody rate="+13%" pitch="+2st" volume="+1dB">
    Xin chào, đây là đoạn kiểm thử tốc độ và cao độ cho tổng hợp giọng nói.
  </prosody>
</speak>
  • Đo lần 1: WPM1 = 168, Δst1 = +1.7 st. Hiệu chỉnh nhỏ lần 2: rate tăng thêm +1% để chạm 170, pitch tăng thêm +0.3 st.
  • SSML lần 2:
<speak>
  <prosody rate="+14%" pitch="+2.3st" volume="+1dB">
    Xin chào, đây là đoạn kiểm thử tốc độ và cao độ cho tổng hợp giọng nói.
  </prosody>
</speak>
  • Kết quả: WPM = 170.4, Δst = +2.0 st. Xuất WAV và ghi preset.

Mẫu tổng quát có biến số

<speak>
  <prosody rate="+{RATE_PERCENT}%" pitch="+{PITCH_ST}st" volume="{VOLUME_DB}dB">
    {TEXT_CONTENT}
  </prosody>
</speak>

Gợi ý tương tự cho engine nội bộ có length_scale

  • Baseline: WPMbase = 160, mục tiêu 184. Ước lượng lengthscale1 ≈ 1.00 × (160/184) ≈ 0.87, pitch1 = +2 st, gain_out = +1 dB.
  • Đo lần 1 ra WPM1 = 181.5. Hiệu chỉnh lengthscale_2 ≈ 0.87 × (181.5/184) ≈ 0.86. Giữ pitch và gain. Synth lần 2 thường chạm mục tiêu trong ±5%.

Mẹo an toàn khi thao tác

  • Thay đổi theo nấc nhỏ và một nhóm tham số mỗi vòng. Đa số trường hợp chỉ cần 2 vòng là chạm mục tiêu.
  • Nếu dùng rate SSML, nhớ rằng pause do dấu câu có thể không co giãn hết. Khi WPM vẫn thiếu một chút dù rate đã tăng, thêm hoặc bớt break nội câu thay vì tăng rate quá tay.
  • Với length_scale của mô hình duration, nên bắt đầu gần 1.0 rồi hạ hoặc tăng từng nấc 0.02 đến 0.05 để tránh nuốt phụ âm hoặc kéo giãn thiếu tự nhiên.

Checklist ghi preset cuối cùng để bàn giao

  • Model và phiên bản checkpoint
  • Seed hoặc trạng thái xác định ngẫu nhiên
  • Front end audio: sample rate, hop length, số mel bin
  • Tham số: length_scale hoặc rate, pitch, volume hoặc gain
  • Văn bản đã synth, WPM và F0 đo được, file WAV minh họa
  • Ghi chú nghe mù nếu có, giúp PM và kỹ sư audio duyệt nhanh

Tiêu chí ưng ý và cách đo lường

Để duyệt nội bộ nhanh và nhất quán, mình đề xuất bộ tiêu chí tối thiểu có thể đo được. Mỗi tiêu chí đi kèm cách đo cụ thể và ngưỡng chấp nhận thực dụng để bạn quyết định pass hay cần chỉnh tham số.

Bộ tiêu chí tối thiểu

  • Độ dài phần thoại và tốc độ WPM
  • Cách đo: chuẩn hóa biên độ nhẹ cho ổn định, dùng VAD theo RMS 20 ms, ngưỡng khoảng −35 dBFS, hangover 100 ms để cắt bỏ silence đầu cuối. Trên đoạn còn lại, đặt cửa sổ đo theo năng lượng tích lũy 5 đến 95 phần trăm để loại biên. Đếm số từ phát âm thực sự, tính WPM = số từ chia cho thời lượng cửa sổ tính theo phút.
  • Ngưỡng chấp nhận: WPM nằm trong ±5 phần trăm so với mục tiêu. Nếu văn bản dày dấu câu hoặc nhiều liệt kê, cho phép ±8 phần trăm để không phạt vì các pause cứng.
  • Cao độ trung bình F0
  • Cách đo: trích F0 bằng CREPE, Harvest hoặc RAPT với hop 5 đến 10 ms, lọc khung vô thanh, làm mượt log-F0 bằng median 3 frame và moving average khoảng 100 ms. Lấy trung bình trên cùng cửa sổ năng lượng đã dùng cho WPM. So sánh với mục tiêu theo bán âm: Δst = 12 × log2(F0đo/F0mục tiêu).
  • Ngưỡng chấp nhận: |Δst| ≤ 1 bán âm. Nếu mục tiêu cực đoan cho giọng đó, nghe lại A B để xác nhận dù nằm trong ngưỡng.
  • Kiểm tra lỗi phát âm
  • Cách đo tự động: forced alignment trên audio tổng hợp với chuỗi phoneme chuẩn của văn bản để lấy độ dài từng phoneme theo frame. Đếm số phoneme bị gán 0 frame là skip kỹ thuật và 1 frame là near skip. Có thể bổ sung một vòng nghe chéo 2 người để rà từ khó, tên riêng và chữ số.
  • Ngưỡng chấp nhận: skip kỹ thuật bằng 0, near skip ≤ 1 phần trăm tổng số phoneme. Không có xóa âm tiết, không thay thanh điệu ở từ khóa.
  • Điểm tự nhiên cảm nhận
  • Cách đo: panel nội bộ 3 đến 5 người nghe mù, thang 1 đến 5. Nếu có baseline, chạy A B và ghi ưu tiên theo cặp.
  • Ngưỡng chấp nhận: MOS trung vị ≥ 4.0. Nếu thấp hơn nhưng WPM và F0 đạt, kiểm tra lại length_scale hoặc rate quá tay, break không hợp ngữ điệu, hoặc dấu hiệu metallic whisper.

Phiếu duyệt mẫu đã điền

  • Văn bản: Xin chào, đây là đoạn kiểm thử tốc độ và cao độ cho tổng hợp giọng nói.
  • Mục tiêu: WPM 170, F0 202.5 Hz
  • Đo bằng VAD và cửa sổ năng lượng 5 đến 95 phần trăm
  • WPM đo: 168.4, sai số −0.9 phần trăm → đạt
  • F0 đo: 201.8 Hz, Δst −0.06 → đạt
  • Forced alignment: skip 0, near skip 0.4 phần trăm → đạt
  • Nghe mù 4 người: MOS trung vị 4.3, không ai báo metallic whisper → đạt
  • Kết luận: pass, lưu preset

Gợi ý ghi nhận khi bàn giao cho PM và kỹ sư audio

  • Báo cả WPM, F0, log đo VAD và tracker dùng, cùng phiếu duyệt ngắn như trên. Với nội dung giàu dấu câu, thuyết minh rõ WPM dùng ngưỡng ±8 phần trăm để tránh hiểu nhầm do pause không tỷ lệ.

Lỗi thường gặp và cách tránh

Phần lớn lỗi sau huấn luyện TTS không nằm ở “mô hình hỏng” mà ở cấu hình dữ liệu, chuẩn hóa văn bản và cách bạn vặn tham số suy luận. Mình tổng hợp các lỗi hay gặp nhất, dấu hiệu nhận biết, nguyên nhân kỹ thuật, cùng cách phòng tránh và khắc phục ngay trên pipeline thực hành.

  • Overfit giọng
  • Dấu hiệu: giọng rất khớp vài câu quen thuộc nhưng hụt hơi khi gặp văn bản mới, ngữ điệu nghèo nàn, dễ rung metallic khi đẩy pitch hoặc tốc độ.
  • Nguyên nhân: tập huấn luyện hẹp nội dung hoặc một giọng đơn, fine-tune quá lâu, thiếu regularization.
  • Phòng tránh: đa dạng hóa câu chữ và thể loại câu, thêm chuẩn hóa văn bản nhất quán để giảm học vẹt, theo dõi validation loss và nghe mù A B để dừng sớm, giữ dropout và weight decay hợp lý. Nếu chỉ voice cloning ngắn, giữ số bước fine-tune vừa đủ và khóa một phần tầng dưới của vocoder.
  • Khắc phục: mở rộng tập train với nội dung mới và nhịp điệu đa dạng, thêm augmentation nhẹ ở F0 và năng lượng trong huấn luyện acoustic model để giảm dính timbre vào cao độ.
  • Dữ liệu ồn hoặc sai sample rate
  • Dấu hiệu: sibilant rít, breathy đều toàn câu, pitch tracker nhảy loạn, audio synth bị cao độ hoặc tốc độ lệch so với thu gốc.
  • Nguyên nhân: bản ghi chứa noise nền, réverb nặng, cắt đầu đuôi không sạch, hoặc training ở 22050 Hz nhưng inference resample ra 24000 Hz, hop_length và STFT khác cấu hình huấn luyện.
  • Phòng tránh: chuẩn hóa sample rate và hop_length thống nhất từ thu đến suy luận, dùng VAD và trim im lặng đầu cuối, lọc nhiễu nhẹ nếu cần nhưng không làm mỏng phổ.
  • Khắc phục: resample toàn bộ dữ liệu và inference về đúng sr, hoplength, nfft, fmin, fmax mà vocoder đã học; nếu đã lỡ synth sai sr, không cố “chữa” bằng thay đổi pitch hậu kỳ.
  • Chuẩn hóa văn bản và dấu câu
  • Dấu hiệu: đọc sai số và đơn vị, pause quá dày ở dấu phẩy, nhịp câu lắt nhắt.
  • Nguyên nhân: text normalization không quyết liệt, nhiều dấu câu thừa, từ điển phiên âm thiếu nhất quán.
  • Phòng tránh: cố định pipeline chuẩn hóa số, viết tắt, đơn vị; chuẩn hóa dấu câu về mức tối thiểu cần thiết cho ngữ điệu; duy trì từ điển phiên âm có kiểm soát biến thể.
  • Khắc phục nhanh bằng SSML: giảm mật độ pause nội câu, ràng buộc rate, pitch nhẹ để cứu nhịp.
<speak>
  <prosody rate="+10%" pitch="+1st">
    Kết thúc quý một<break time="200ms"/> doanh thu đạt một trăm hai mươi tỷ đồng.
  </prosody>
</speak>
  • Biến thể có tham số: rate=RATEDELTA, pitch=PITCHDELTA, break time=BREAK_MS
  • length_scale quá thấp gây nuốt âm, quá cao làm loãng nhịp
  • Dấu hiệu: phụ âm tắc biến mất, âm cuối mờ khi lengthscale nhỏ; câu rề rà, merge cảm nhận khi lengthscale lớn.
  • Nguyên nhân: duration predictor hoặc căn chỉnh MAS bị ép, nhiều phoneme rơi về 0 hoặc 1 frame, hoặc bị kéo giãn vượt vùng tự nhiên.
  • Phòng tránh: đặt baseline lengthscale quanh 0.9 đến 1.1; kiểm tra repo có clamp tối thiểu 1 frame sau scale; tránh đẩy cả noisescale lên cùng lúc.
  • Khắc phục có kiểm chứng: chạy lưới lengthscale và đếm skip bằng forced alignment trên chính mel tổng hợp. Nếu tỷ lệ 0 frame hoặc 1 frame vượt 1 phần trăm, lùi về mức cao hơn. Với tiếng Việt, đa số mô hình bắt đầu rủi ro khi hạ dưới khoảng 0.6 đến 0.7, nhưng bạn nên tự đo vì ngưỡng phụ thuộc hoplength và luật làm tròn.
  • Trộn tham số làm ID trôi khi noise_scale lớn
  • Dấu hiệu: timbre bớt giống người gốc, x-vector cosine với mẫu tham chiếu giảm đáng kể, F0 và nhịp dao động bất định dù văn bản không đổi.
  • Nguyên nhân: tăng noisescale hoặc temperature đẩy mẫu ra ngoài phân phối đã học, làm phổ dao động mạnh, embedding người nói mất ổn định; tăng noisescale_w làm jitter thời lượng.
  • Phòng tránh: ưu tiên giữ noisescale khoảng 0.6 đến 0.85, tinh chỉnh nhịp bằng noisescalew ở 0.8 đến 1.0 thay vì tăng noisescale; khóa seed khi cần tái lập; giữ length_scale gần 1.0.
  • Khắc phục: đo cosine x-vector giữa clip synth và tham chiếu cùng speaker trên lưới tham số, chọn vùng làm rơi cosine dưới 0.05 so với baseline ít nhất. Nếu vẫn trôi, giảm noisescale và trả lengthscale về 0.9 đến 1.1.
  • Vocoder metallic hoặc whisper khi F0 hay mức dB lệch miền huấn luyện
  • Dấu hiệu: lấp lánh kim loại khi pitch cao, thì thào khi năng lượng thấp, nhất là trên nguyên âm kéo dài hoặc cụm âm xát.
  • Nguyên nhân: mel đầu vào có log-F0 hoặc dynamic range nằm ngoài phân phối của vocoder universal; discriminator theo chu kỳ hoặc stack residual bị đẩy vào vùng ít dữ liệu.
  • Phòng tránh: giữ pitch shift trong vùng an toàn đo theo Δst và năng lượng trong vùng ΔdB gần domain; bám cấu hình trích mel gốc; nếu cần pitch cực đoan, cân nhắc fine-tune vocoder ngắn hạn trên mel mục tiêu.
  • Khắc phục: đo Δst = 12 × log2(F0meantarget/F0meandomain) và ΔdB theo RMS sau tiền xử lý giống huấn luyện. Nếu vượt dải 6 đến 8 bán âm hoặc 6 đến 8 dB, hoặc nhiều câu vượt 2 độ lệch chuẩn domain của bạn, lùi mức pitch hoặc normalize năng lượng trước khi qua vocoder.
  • Mismatch cấu hình mel giữa acoustic model và vocoder
  • Dấu hiệu: méo phổ có hệ thống, metallic ngay cả khi F0 và dB trong vùng an toàn.
  • Nguyên nhân: khác nfft, hoplength, fmin, fmax, số mel bin, chuẩn hóa log-mel.
  • Phòng tránh và khắc phục: duy nhất đúng là đồng bộ hoàn toàn cấu hình mel và thống kê chuẩn hóa giữa hai khối. Không bù bằng EQ hay compressor ở hậu kỳ.

Phiếu kiểm nhanh lỗi phổ biến – bản điền sẵn

  • sr 22050 | hop 256 | mel 80 | fmin 50 | fmax 11025
  • lengthscale 1.00 | noisescale 0.70 | noisescalew 0.85 | seed 1234
  • Forced alignment: skip 0.0 phần trăm | near skip 0.3 phần trăm
  • Δst so với domain 180 Hz: +1.2 st | ΔdB so với domain: −1.8 dB
  • SSML kiểm soát pause: break 200 ms ở dấu phẩy dài
  • Kết luận: an toàn, không metallic, không whisper, ID ổn định

Phiếu kiểm nhanh lỗi phổ biến – mẫu có biến số

  • sr SRHZ | hop HOP | mel MELBINS | fmin FMIN | fmax FMAX
  • lengthscale LSCALE | noisescale NSCALE | noisescalew NSCALEW | seed SEED
  • Forced alignment: skip SKIPPCT phần trăm | near skip NEARSKIP_PCT phần trăm
  • Δst so với domain F0DOMAINHZ: DELTAST st | ΔdB so với domain: DELTADB dB
  • SSML kiểm soát pause: break BREAK_MS ms ở vị trí cần
  • Kết luận: GHI_CHÚ

Quy trình gỡ lỗi nhanh bạn có thể áp ngay

  • So khớp cấu hình: xác nhận sr, hop_length, mel bins, fmin, fmax, chuẩn hóa mel giữa train và inference. Nếu lệch, sửa trước khi nghe tiếp.
  • Đo kỹ thuật: tạo 3 câu 5 đến 10 giây, chạy lưới length_scale và đếm skip 0 frame và near skip 1 frame bằng forced alignment trên mel synth. Chốt khoảng an toàn của chính mô hình bạn.
  • Kiểm tra ID: trên cùng câu, quét noisescale và noisescale_w, đo cosine x-vector so với tham chiếu speaker. Giữ vùng rơi cosine nhỏ hơn 0.05 so với baseline.
  • Kiểm tra vocoder: đo Δst và ΔdB so với domain. Nếu vượt, lùi mức pitch, normalize năng lượng hoặc fine-tune vocoder ngắn ngày trên mel mục tiêu.
  • Dọn văn bản: chuẩn hóa số và dấu câu, dùng SSML break vừa phải để tránh nhịp lắt nhắt. Tiếp đó mới nghe quyết định.

Kiểm chứng ngưỡng kỹ thuật quan trọng và quy tắc an toàn

Bạn cần hai lớp kiểm chứng: 1 kiểm độ an toàn của length_scale đối với skip và near skip ở cấp phoneme, 2 kiểm rủi ro vocoder khi pitch hoặc mức dB lệch miền huấn luyện. Mình đưa quy trình đo có thể áp ngay, cộng với quy tắc suy ngưỡng từ chính phân bố độ dài phoneme của mô hình bạn để tránh dựa vào mốc kinh nghiệm mơ hồ.

Quy trình test lưới length_scale và đếm skip bằng forced alignment

  1. Chuẩn bị bộ câu kiểm tra
  • Chọn 100 câu tiếng Việt dài 3 đến 10 giây, không quá dày dấu câu. Dùng đúng phonemizer và từ điển đã dùng khi huấn luyện để sinh chuỗi phoneme chuẩn.
  • Cố định cấu hình âm thanh và mel đúng với lúc train: sample rate, hoplength, nfft, số mel bin, fmin, fmax, chuẩn hóa mel.
  1. Sinh mel và WAV trên lưới length_scale
  • Lưới ví dụ: {0.4, 0.5, 0.6, 0.7, 1.0, 1.5, 2.0, 2.5}. Giữ nguyên noise_scale và mọi tham số khác, seed cố định.
  • Vocode ra WAV để đưa vào aligner. Nếu chưa có vocoder, dùng Griffin–Lim để có audio tạm nghe và đủ cho aligner hoạt động.
  1. Forced alignment để lấy thời lượng phoneme
  • Nếu bạn có acoustic model phù hợp ngôn ngữ và từ điển phát âm, dùng Montreal Forced Aligner để căn chỉnh WAV với chuỗi phoneme.
  • Nếu không có model cho tiếng Việt, dùng một aligner CTC như ctc-segmentation kết hợp posterior từ một ASR CTC, nhưng khi đó bạn chỉ nên coi kết quả như xấp xỉ và xác thực lại trên mẫu nghe.
  • Chuyển thời lượng phoneme từ mili giây sang số frame mel: frames = round(durationsec × sr / hoplength).
  1. Đếm skip và near skip
  • skip rate = tỉ lệ phoneme có frames == 0.
  • near skip rate = tỉ lệ phoneme có frames ≤ 1.
  • Ngưỡng cảnh báo thực dụng: nếu skip > 0 phần trăm hoặc near skip ≥ 1 phần trăm ở bất kỳ length_scale nào, coi đó là vùng vàng bắt buộc nghe lại. Với tiếng Việt, đặc biệt chú ý phụ âm tắc, âm vô thanh trước pau, và bán nguyên âm ngắn.

Suy ngưỡng length_scale từ phân bố độ dài và luật làm tròn

  • Gọi d là số frame gốc mỗi phoneme ở baseline s = 1, đo bằng forced alignment như trên. Lấy d_p1 là bách phân vị 1 phần trăm của d.
  • Nếu luật là floor, không clamp tối thiểu, công thức duration’ = floor(s × d). Skip khi s × d < 1 nghĩa là s < 1 / d. Ngưỡng để skip đạt 1 phần trăm rơi tại s ≤ 1 / d_p1.
  • Nếu luật là round, không clamp tối thiểu, skip khi round(s × d) = 0, gần tương đương s × d < 0.5. Ngưỡng 1 phần trăm nằm tại s ≤ 0.5 / d_p1.
  • Nếu có clamp min 1 frame sau làm tròn, skip kỹ thuật biến mất. Khi đó dùng near skip:
  • round + clamp: near skip khi s × d < 1.5, ngưỡng 1 phần trăm tại s ≤ 1.5 / d_p1.
  • floor + clamp: near skip khi s × d < 2.0, ngưỡng 1 phần trăm tại s ≤ 2.0 / d_p1.
  • hoplength ảnh hưởng trực tiếp d và dp1. Đổi hoplength lớn hơn sẽ làm d nhỏ đi, do đó ngưỡng s an toàn phía nhỏ phải tăng theo tỉ lệ. Cách đúng là đo lại dp1 ở cấu hình hop hiện tại thay vì dùng hệ số ước đoán.

Mẫu tính ngưỡng bằng Python, bạn sửa đúng luật làm tròn và clamp theo repo của mình

import numpy as np

# d_frames: mảng số frame/phoneme đo ở baseline s=1 bằng forced alignment
# rule: "floor" hoặc "round", clamp_min1: True/False
def s_threshold_for_one_percent(d_frames, rule="floor", clamp_min1=False, percentile=1.0):
    d = np.array(d_frames, dtype=float)
    d_p1 = np.percentile(d, percentile)
    if rule == "floor" and not clamp_min1:
        c = 1.0
    elif rule == "round" and not clamp_min1:
        c = 0.5
    elif rule == "floor" and clamp_min1:
        c = 2.0   # near skip
    elif rule == "round" and clamp_min1:
        c = 1.5   # near skip
    else:
        raise ValueError("Unsupported setting")
    return c / max(d_p1, 1e-6)

Đo rủi ro vocoder theo chênh logF0 và RMS dB so với domain

  • F0: tính logF0 trên các frame hữu thanh theo cùng front end như khi train, bỏ unvoiced. Lấy meanlogF0domain trên tập train. Với audio synth, tính Δst = 12 × log2(exp(meanlogF0synth) / exp(meanlogF0domain)).
  • Năng lượng: đo RMS sau cùng sơ đồ tiền xử lý giống huấn luyện vocoder. Lấy meanRMSdomain và sdRMSdomain quy đổi dB. Với audio synth, tính ΔdB = 20 × log10(RMSsynth / meanRMS_domain).
  • Quy tắc an toàn thực dụng:
  • Nếu hơn 20 phần trăm câu có |Δst| vượt khoảng 2 độ lệch chuẩn logF0 của domain, hoặc |ΔdB| vượt khoảng 2 độ lệch chuẩn RMS-domain, coi là vùng vàng. Nếu thiếu số liệu độ lệch chuẩn, dùng mốc định hướng: |Δst| khoảng 6 đến 8 bán âm hoặc |ΔdB| khoảng 6 đến 8 dB là đã nên nghe lại.
  • Vượt |Δst| 10 đến 12 bán âm hoặc |ΔdB| 10 dB, rất dễ gặp metallic hoặc whisper ngay cả khi length_scale an toàn.

Khi nào phải nghe lại và chốt vùng vàng

  • Bất kỳ length_scale nào khiến near skip ≥ 1 phần trăm, hoặc làm tăng đột biến tỷ lệ 1-frame ở cụm phụ âm ngắn.
  • Bất kỳ thiết lập pitch hoặc gain nào đưa |Δst| và |ΔdB| vào dải 2 độ lệch chuẩn domain trở lên.
  • Khi đổi hoplength hoặc thay luật làm tròn, luôn đo lại dp1 và lưới length_scale rồi nghe A B giữa 2 điểm sát ngưỡng.

Ví dụ biên bản đo, điền sẵn để bạn hình dung đầu ra mong muốn

  • sr 22050 | hop 256 | mel 80 | round floor | clampmin1 yes | dp1_frame 2.0
  • lengthscale 0.55 | skippct 0.0 | nearskippct 1.3
  • lengthscale 0.60 | skippct 0.0 | nearskippct 0.9
  • lengthscale 0.70 | skippct 0.0 | nearskippct 0.4
  • Δst +6.4 st | ΔdB −1.5 dB | kết luận vocoder: vùng vàng, bắt buộc nghe lại
  • Ghi chú: giảm pitch 1 st hoặc tăng gain 2 dB trước vocoder để về vùng an toàn

Mẫu biên bản có biến số

  • sr SRHZ | hop HOP | mel MELBINS | round FLOORORROUND | clampmin1 YESNO | dp1frame D_P1
  • lengthscale LSCALE | skippct SKIPPCT | nearskippct NEARSKIPPCT
  • Δst DELTASTST st | ΔdB DELTA_DB dB | kết luận vocoder: NOTE
  • Ghi chú: NOTE2

Mẹo thực hành nhanh

  • Không có aligner tiếng Việt? Lấy d từ durations của chính mô hình ở baseline s = 1 để ước lượng d_p1, rồi vẫn chạy forced alignment ở 2 mức s sát ngưỡng dự báo để xác nhận bằng tai.
  • Nếu repo không rõ luật làm tròn, in ra chuỗi durations trước và sau scale ở một câu dài để suy ra rule và clamp. Sai luật làm tròn là nguyên nhân số một khiến bạn đặt nhầm ngưỡng.
  • Khi hoplength tăng, đừng chỉ dời lengthscale. Hãy nghe lại vì MAS hoặc duration predictor có thể thay đổi hành vi gán frame theo nội dung, đặc biệt ở phụ âm tắc.

Preset tham số khởi điểm theo họ mô hình và SSML

Bạn cần một cấu hình mặc định an toàn để synth giọng ổn ngay từ lần đầu, rồi mới tinh chỉnh nhỏ theo mục tiêu WPM và F0. Dưới đây là các preset khởi điểm thực dụng theo từng họ mô hình và ba dịch vụ SSML lớn. Mình giữ biên độ chỉnh hẹp để tránh skip, méo nhịp và trôi ID giọng, đồng thời ghi chú rõ khi nào nên bước ra khỏi preset.

Preset nhanh gọn theo họ mô hình mở

  • FastSpeech
  • length_scale: 1.0 làm mốc. Băng an toàn để chạy ngay: 0.9 đến 1.1.
  • Khi cần: nhanh hơn thì 0.85 đến 0.9, chậm hơn thì 1.1 đến 1.2. Tránh < 0.7 và > 1.5 cho tiếng Việt nếu chưa đo skip bằng aligner.
  • Bước ra khỏi preset khi: WPM lệch mục tiêu > 10 phần trăm sau 1 vòng đo. Điều chỉnh theo bước 0.05 và nghe lại cụm có phụ âm tắc.
  • FastPitch
  • length_scale: như FastSpeech.
  • pitch ở suy luận: nếu pipeline của bạn có nút scale hoặc shift F0, chỉ đổi hẹp ±1 đến ±2 bán âm. Tránh kéo rộng hơn khi chưa kiểm A B vì dễ sáng giọng hoặc lệch formant.
  • energy nếu có: đổi trong ±10 phần trăm để bù cảm nhận khi đã chỉnh pitch.
  • Bước ra khỏi preset khi: cần đạt cao độ mục tiêu mà ±2 bán âm chưa đủ. Khi đó tăng theo bước 0.5 bán âm và nghe lại rung metallic.
  • Glow-TTS
  • length_scale: 1.0, băng an toàn 0.9 đến 1.2.
  • noise_scale: 0.6 đến 0.75, mặc định thường 0.667. Giữ thấp để mel sạch, tránh rung nhịp vô cớ.
  • Bước ra khỏi preset khi: giọng quá đều, thiếu sinh động. Nâng noisescale từng bước 0.05 nhưng giữ ≤ 0.85, đồng thời không giảm lengthscale xuống dưới 0.8 khi chưa đo near skip.
  • VITS
  • length_scale: 1.0, băng an toàn 0.9 đến 1.1.
  • noise_scale: 0.7 làm mốc, băng an toàn 0.6 đến 0.85.
  • noisescalew: 0.85 đến 0.95 để nhịp tự nhiên hơn mà không rung.
  • Quy tắc: ưu tiên tăng noisescalew trước nếu muốn sinh động hơn. Tránh đẩy noise_scale lên gần 1.0 khi cần bám ID giọng.
  • Bước ra khỏi preset khi: cần chất giọng đa cảm hơn. Chỉ tăng noisescalew thêm 0.05 mỗi lần và giữ noisescale ≤ 0.85. Nếu nghe thấy trôi ID, lùi noisescale về 0.7.

Gợi ý SSML khởi điểm theo dịch vụ

  • Google Cloud Text-to-Speech
  • rate: +10 phần trăm hoặc −10 phần trăm cho nhu cầu nhanh chậm nhẹ.
  • pitch: +1 st hoặc −1 st. Tránh vượt ±2 st nếu không có kiểm chứng A B.
  • break: time 250 đến 350 ms giữa câu. Với liệt kê, 180 đến 250 ms giữa mục.
  • emphasis: không bắt buộc. Nếu dùng, chỉ áp nhẹ trên từ khóa ngắn, tối đa 1 đến 2 lần mỗi câu.

Ví dụ điền sẵn cho Google

<speak>
  <voice languageCode="vi-VN">
    <prosody rate="+10%" pitch="+1st">Xin chào, đây là bản đọc thử.</prosody>
    <break time="300ms"/>
    <prosody rate="+10%" pitch="+1st">Mời bạn kiểm tra thông số.</prosody>
  </voice>
</speak>

Bản có biến số

<speak>
  <voice languageCode="LANG">
    <prosody rate="RATE_pct%" pitch="PITCH_stst">TEXT_A</prosody>
    <break time="BREAK_msms"/>
    <prosody rate="RATE_pct%" pitch="PITCH_stst">TEXT_B</prosody>
  </voice>
</speak>
  • Microsoft Azure Speech
  • rate: +10 phần trăm hoặc −10 phần trăm.
  • pitch: +1 st hoặc −1 st, tối đa ±2 st khi chưa nghe mù.
  • break: 250 đến 350 ms giữa câu, 180 đến 250 ms giữa mệnh đề.
  • emphasis: level="moderate" cho 1 đến 2 từ khóa, tránh strong để không kịch tính.

Ví dụ điền sẵn cho Azure

<speak version="1.0" xml:lang="vi-VN">
  <voice name="vi-VN-HoaiMyNeural">
    <prosody rate="+10%" pitch="+1st">Xin chào, đây là bản đọc thử.</prosody>
    <break time="300ms"/>
    <emphasis level="moderate">thông số</emphasis>
    <prosody rate="+10%" pitch="+1st">đang ở mức an toàn.</prosody>
  </voice>
</speak>

Bản có biến số

<speak version="1.0" xml:lang="LANG">
  <voice name="VOICE_NAME">
    <prosody rate="RATE_pct%" pitch="PITCH_stst">TEXT_A</prosody>
    <break time="BREAK_msms"/>
    <emphasis level="EMPH_LEVEL">KEYWORD</emphasis>
    <prosody rate="RATE_pct%" pitch="PITCH_stst">TEXT_B</prosody>
  </voice>
</speak>
  • Amazon Polly
  • rate: +10 phần trăm hoặc −10 phần trăm.
  • pitch: dùng phần trăm, giữ trong ±8 đến ±12 phần trăm. Tránh dùng đơn vị bán âm vì không phổ quát ở Polly.
  • break: 250 đến 350 ms giữa câu.
  • emphasis: level="moderate" cho một vài từ khóa ngắn.

Ví dụ điền sẵn cho Polly

<speak>
  <prosody rate="+10%" pitch="+10%">Xin chào, đây là bản đọc thử.</prosody>
  <break time="300ms"/>
  <emphasis level="moderate">thông số</emphasis>
  <prosody rate="+10%" pitch="+10%">đang ở mức an toàn.</prosody>
</speak>

Bản có biến số

<speak>
  <prosody rate="RATE_pct%" pitch="PITCH_pct%">TEXT_A</prosody>
  <break time="BREAK_msms"/>
  <emphasis level="EMPH_LEVEL">KEYWORD</emphasis>
  <prosody rate="RATE_pct%" pitch="PITCH_pct%">TEXT_B</prosody>
</speak>

Ngưỡng bước ra khỏi preset – khi nào và theo hướng nào

  • Khi WPM đo được lệch mục tiêu quá 10 phần trăm
  • Mô hình mở: chỉnh length_scale theo bước 0.05 đến 0.1 rồi nghe lại cụm có phụ âm tắc để tránh near skip.
  • SSML: đổi rate theo bước 5 phần trăm. Tránh vượt ±20 phần trăm vì pause nội câu thường không co giãn tuyến tính.
  • Khi F0 trung bình lệch mục tiêu hoặc cảm nhận sáng quá hay tối quá
  • FastPitch: nếu có nút F0, đổi theo bước 0.5 bán âm nhưng không qua ±2 bán âm khi chưa A B.
  • SSML: Google và Azure dùng ±0.5 đến ±1 st mỗi bước. Polly dùng ±3 đến ±4 phần trăm mỗi bước, giữ tổng trong ±12 phần trăm.
  • Khi nghe thấy nuốt âm hoặc dính cụm
  • Lùi length_scale về 0.9 đến 1.1. Nếu cần nhanh hơn, dừng ở 0.85 đến 0.9 và xác nhận near skip < 1 phần trăm bằng aligner.
  • Khi cần thêm sinh động nhưng phải giữ ID giọng
  • Glow-TTS: tăng noise_scale đến tối đa 0.8 rồi dừng.
  • VITS: ưu tiên tăng noisescalew lên 0.9 đến 0.95. Giữ noisescale trong 0.6 đến 0.85. Nếu ID trôi, lùi noisescale về 0.7 và cố định seed.

Mẹo gắn preset với mục tiêu nghe duyệt của PM và kỹ sư audio

  • Ghi rõ preset theo cặp mục tiêu, ví dụ: WPM 170 đến 185, F0_mean +1 st so với baseline, break câu 300 ms, emphasis moderate x 2 mỗi câu.
  • Với mỗi preset, lưu một bộ 2 đến 3 câu WAV mẫu và SSML đi kèm để người duyệt nghe nhanh sự khác nhau giữa các mức rate và pitch, tránh tranh luận cảm tính.

Tài liệu hóa đóng gói và bàn giao cấu hình

Mục tiêu bàn giao là để mỗi lần synth lại đều cho cùng kết quả trong cùng điều kiện, và để PM hoặc kỹ sư audio kiểm nhanh chất lượng so với chuẩn đã duyệt. Mình gợi ý một gói bàn giao có chuẩn đặt tên rõ ràng, manifest máy đọc, preset tham số và bộ mẫu đo kiểm đi kèm.

Chuẩn đặt tên phiên bản và speaker ID

  • Tên phiên bản theo SemVer và có build-date để tiện đối chiếu: tts-<họmôhình>-<ngôn_ngữ>-<sr>-<vocoder>-<semver>+<yyyymmdd>. Ví dụ: tts-fastpitch-viVN-24000-hifigan-v1.2.3+20260720.
  • Tên tệp gắn cùng version, ví dụ weights-acoustic-v1.2.3.pt, config-acoustic-v1.2.3.yaml.
  • Speaker ID dùng số cố định, ba chữ số, đi kèm alias mô tả: spk000, spk001. File mapping đi kèm để không nhầm khi đổi thứ tự embedding.
  • Chuẩn speaker_map.csv: cột id,alias,gender,locale,note. Alias chỉ để đọc, id mới là khóa dùng trong inference.

Cấu trúc gói bàn giao đề nghị

  • MANIFEST.yaml: mô tả đầy đủ phiên bản, tham số mặc định, checksum và tương thích SSML.
  • acoustic/: weights và config của mô hình âm học.
  • vocoder/: weights và config của vocoder.
  • resources/: lexicon, phonemap, speaker_map.csv, normalization stats.
  • presets/: các file preset tham số đã duyệt.
  • qa/: câu đo kiểm, kết quả đo WPM và F0 mục tiêu và mẫu WAV tham chiếu.
  • README.md: hướng dẫn ngắn cho PM và kỹ sư audio, nêu cách chọn preset và tiêu chí pass.

Ví dụ MANIFEST.yaml điền sẵn đầy đủ

project: tts-fastpitch-viVN-24000-hifigan-v1.2.3+20260720
date: 2026-07-20
git_commit: 9f3c1a2
acoustic:
  family: FastPitch
  version: 1.2.3
  sample_rate: 24000
  hop_length: 256
  mel_bins: 80
  f0_conditioning: true
  weights: acoustic/weights-acoustic-v1.2.3.pt
  config: acoustic/config-acoustic-v1.2.3.yaml
  sha256: 3b1f0c3e...e91
vocoder:
  family: HiFi-GAN
  version: 1.1.0
  weights: vocoder/weights-hifigan-v1.1.0.pt
  config: vocoder/config-hifigan-v1.1.0.yaml
  sha256: a27c9fbd...2aa
resources:
  lexicon: resources/lexicon-vi.txt
  phonemap: resources/phonemap-vi.txt
  speaker_map: resources/speaker_map.csv
  normalization_stats:
    mel_mean_std: resources/mel_stats.json
    f0_log_mean_std: resources/f0_stats.json
    energy_mean_std: resources/energy_stats.json
inference_defaults:
  length_scale: 1.0
  noise_scale: null
  noise_scale_w: null
  pitch_shift_st: 0
  rate_pct: 0
  volume_db: 0
  default_seed: 20260720
qa:
  sentences: qa/qa_sentences_vi.txt
  metrics_target:
    wpm_range: [170, 185]
    f0_mean_shift_st: 0
  baseline_samples:
    - qa/samples/spk000_baseline_01.wav
    - qa/samples/spk000_baseline_02.wav
compatibility:
  ssml:
    google:
      tested: ["vi-VN-Standard-A","vi-VN-Neural2-A"]
      notes: rate and pitch in %, st supported for pitch
    azure:
      tested: ["vi-VN-HoaiMyNeural"]
      notes: rate and pitch in %, st supported for pitch
    polly:
      tested: ["Vicki"]
      notes: pitch in % recommended

Bản MANIFEST.yaml có biến số để tái dùng

project: tts-<MODEL_FAMILY>-<LANG>-<SR>-<VOCODER>-<SEMVER>+<DATE_YYYYMMDD>
date: <DATE_YYYY-MM-DD>
git_commit: <GIT_HASH>
acoustic:
  family: <MODEL_FAMILY>
  version: <SEMVER>
  sample_rate: <SR>
  hop_length: <HOP>
  mel_bins: <MEL_BINS>
  f0_conditioning: <true_or_false>
  weights: acoustic/<FILENAME_WEIGHTS>
  config: acoustic/<FILENAME_CONFIG>
  sha256: <SHA256>
vocoder:
  family: <VOCODER_FAMILY>
  version: <SEMVER_VOCODER>
  weights: vocoder/<FILENAME_WEIGHTS>
  config: vocoder/<FILENAME_CONFIG>
  sha256: <SHA256>
resources:
  lexicon: resources/<FILENAME_LEXICON>
  phonemap: resources/<FILENAME_PHONEMAP>
  speaker_map: resources/<FILENAME_SPEAKER_MAP>
  normalization_stats:
    mel_mean_std: resources/<FILENAME_MEL_STATS>
    f0_log_mean_std: resources/<FILENAME_F0_STATS>
    energy_mean_std: resources/<FILENAME_ENERGY_STATS>
inference_defaults:
  length_scale: <FLOAT>
  noise_scale: <FLOAT_OR_NULL>
  noise_scale_w: <FLOAT_OR_NULL>
  pitch_shift_st: <INT>
  rate_pct: <INT>
  volume_db: <INT>
  default_seed: <INT>
qa:
  sentences: qa/<FILENAME_QA_SENTENCES>
  metrics_target:
    wpm_range: [<WPM_MIN>, <WPM_MAX>]
    f0_mean_shift_st: <INT>
  baseline_samples:
    - qa/samples/<FILENAME_WAV_1>
    - qa/samples/<FILENAME_WAV_2>
compatibility:
  ssml:
    google:
      tested: [<LIST_VOICES>]
      notes: <TEXT>
    azure:
      tested: [<LIST_VOICES>]
      notes: <TEXT>
    polly:
      tested: [<LIST_VOICES>]
      notes: <TEXT>

Presets tham số và cách lưu

  • Mỗi preset nên ghi rõ áp dụng cho họ mô hình hay cho SSML, và có file WAV mẫu đã synth từ đúng preset để PM nghe duyệt.
  • Định dạng JSON đơn giản, máy đọc tốt, có trường scope để engine bỏ qua khóa không liên quan.

Ví dụ preset JSON hoàn chỉnh

{
  "name": "prod_vi_female_neutral",
  "scope": "fastpitch",
  "speaker_id": "spk000",
  "length_scale": 1.0,
  "pitch_shift_st": 0,
  "energy_pct": 0,
  "noise_scale": null,
  "noise_scale_w": null,
  "rate_pct": 0,
  "volume_db": 0,
  "break_ms_default": 300,
  "seed": 20260720,
  "notes": "Preset mặc định dùng cho đọc tin, WPM 170-185, F0 giữ baseline."
}

Bản preset có biến số

{
  "name": "<PRESET_NAME>",
  "scope": "<fastspeech|fastpitch|glow-tts|vits|ssml>",
  "speaker_id": "<SPK_ID>",
  "length_scale": <FLOAT_OR_NULL>,
  "pitch_shift_st": <INT_OR_NULL>,
  "energy_pct": <INT_OR_NULL>,
  "noise_scale": <FLOAT_OR_NULL>,
  "noise_scale_w": <FLOAT_OR_NULL>,
  "rate_pct": <INT_OR_NULL>,
  "volume_db": <INT_OR_NULL>,
  "break_ms_default": <INT>,
  "seed": <INT>,
  "notes": "<TEXT>"
}

Thống kê chuẩn hóa và file đi kèm

  • Gắn kèm stats chuẩn hóa dùng khi huấn luyện để tái lập đầu vào và suy luận giống nhau:
  • mel_stats.json: mean và std cho từng bin hoặc toàn cục tùy pipeline.
  • f0_stats.json: mean và std trên logF0 voiced.
  • energy_stats.json: mean và std RMS theo dB.
  • Trong README, ghi rõ cách áp dụng stats đó ở suy luận nếu cần chuẩn hóa trước khi vào vocoder.

Bộ đo kiểm chuẩn hóa cho duyệt chất lượng

  • qa/qasentencesvi.txt: 8 đến 12 câu, 12 đến 20 giây thoại có tiếng sau synth, bao phủ dấu câu và thanh điệu thường gặp.
  • qa/expectedmetrics.json: WPM mục tiêu, F0meanshiftst mục tiêu, khoảng chấp nhận. Có thể thêm nearskiprate_max nếu bạn đã đo bằng aligner.
  • qa/samples/: WAV sinh từ preset chính, một bản cho mỗi speaker bàn giao.

Ví dụ expected_metrics.json điền sẵn

{
  "wpm_range": [170, 185],
  "f0_mean_shift_st": 0,
  "near_skip_rate_max_pct": 1.0
}

Checklist bàn giao để bạn soát lần cuối

  • Tên phiên bản và thư mục đúng chuẩn SemVer + date.
  • MANIFEST.yaml có đủ gitcommit, checksum sha256, stats chuẩn hóa, sample rate, hoplength, mel_bins.
  • speaker_map.csv liệt kê đúng ID và alias, không trùng khoá.
  • Ít nhất 1 preset JSON mỗi speaker, có WAV minh hoạ.
  • Bộ qa gồm câu, expected_metrics và 2 mẫu WAV baseline đã đo đạt mục tiêu.
  • README.md nêu cách gọi đúng speakerid, preset và tiêu chí pass cho PM: WPM, F0mean và lỗi phát âm 0 trong bộ qa.

Với bộ tài liệu hóa như trên, người nhận chỉ cần mở MANIFEST.yaml, chọn preset, bật các WAV mẫu và so WPM, F0mean trong qa với expectedmetrics là yên tâm duyệt hoặc tái hiện chất lượng đã thống nhất.

Kết luận

Với khung thực hành này, mình giúp bạn điều khiển giọng theo ý bằng cách tách bạch train vs infer, map tệp sang nút vặn, đo WPM và F0 để tối ưu lengthscale, pitch, energy và chốt preset sẵn sàng cho sản xuất. Lưu ý quan trọng: luôn kiểm chứng ngưỡng an toàn trên chính mô hình và vocoder bạn dùng, vì khác biệt hoplength, ngôn ngữ và triển khai SSML có thể bị clamp ở cực trị hoặc làm trôi ID.