Máy nói theo văn bản - Text to speech (Phần2)

14:46, 13/10/2021

Được sự đồng ý của Tác giả, Tòa soạn Công nghệ và Đời sống đăng lại bài viết Chuyên gia về Text-To-Speed.

ⓔ Biến hóa vocoder

  • Như đã đề cập ở trên, “tiếng máy nói” được tạo ra bằng cách ghép các đoạn ghi âm (concatenation synthesis) hoặc được tạo ra dựa trên các công thức toán học (parametric TTS).

  • Bây giờ chúng ta đặt vấn đề. Giả sử chúng ta muốn thay giọng nam bằng giọng nữ, hoặc chúng ta muốn thay giọng theo vùng miền (Bắc, Trung, Nam) thì làm thế nào? Nếu theo phương pháp của concatenation synthesis thì đành phải thay hết các đoạn ghi âm. Ví dụ, để có 10 giọng nói khác nhau thì chúng ta phải lập 10 CSDL khác nhau về giọng nói tương ứng. Cách làm này cũng được, mặc dù hơi mất công. Nhưng liệu có cách nào khác không?

Tiếp theo, tôi muốn lướt sang chuyện khác, rồi trở lại trả lời câu hỏi trên. Nếu bạn không có hứng thú đọc thì xin bỏ qua phần in chữ nhỏ này.

Tháng 8/2013, tác giả Alex Graves đăng bài Generating Sequences With Recurrent Neural Networks (tạo chuỗi bằng mạng RNN). Tác giả liên tưởng cấu trúc mạng RNN (Recurrent Neural Network) với sự phát sinh của chuỗi. Lấy ví dụ con người suy luận dựa trên hiểu biết quá khứ. Khi bạn đọc bài post này, bạn hiểu từng từ dựa trên sự hiểu biết của bạn về những từ trước đó. Rõ ràng là như vậy. Bạn không vứt bỏ mọi thứ và bắt đầu suy nghĩ lại từ đầu. Dòng suy nghĩ của bạn có tính phát sinh liên tục: cái sau dựa vào chuỗi của những cái trước đó. Để hiểu từ đang đọc, bằng một cách nào đó, chúng ta “liên kết” với các từ đứng đằng trước, thậm chí là các từ đứng ở đầu bài post.

Dựa vào tính chất này, tác giả thiết kế mô hình tạo chuỗi: phần tử tiếp theo của chuỗi là một “suy diễn dự đoán” từ các phần tử trước đó. Nghĩa là phần tử tiếp theo là “tiếp diễn” một cách có quy luật của các phần tử trước. Thực hiện việc này bằng cách nào? Tác giả sử dụng mô hình mạng LSTM (LSTM là một dạng đặc biệt của RNN) để tạo chuỗi. Tất nhiên, trước khi tạo chuỗi, mô hình cần được huấn luyện với một tập dữ liệu. Bài báo thử nghiệm với 2 loại dữ liệu: dữ liệu văn bản và nét chữ viết tay.

  • Trường hợp đầu tiên, nếu dữ liệu là tập hợp các văn bản thì khi tạo chuỗi, chúng ta thu được điều gì có ý nghĩa? Mời bạn tham khảo bài này, bạn sẽ thấy rằng mô hình tạo chuỗi văn bản bắt chước được “văn phong” của tập văn bản dùng để huấn luyện nó! Tác giả bài báo (Andrej Karpathy) thuyết minh rằng mô hình có thể bắt chước được phong cách viết bài luận của Paul Graham, văn phong viết kịch của Shakespeare, bắt chước cấu trúc cú pháp của Wikipedia, cách viết công thức rất phức hợp của Latex, phong cách viết mã nguồn của Linux. Chú ý rằng, chuỗi do mạng tạo ra có nội dung vô nghĩa, nhưng cái chính là nó bắt chước được văn phong, nó nhại lại “style” của văn bản đó. Rất bí hiểm. 😊

  • Trường hợp thứ hai là nét chữ viết tay. Phần tử của chuỗi, trong trường hợp này, là điểm chấm bút khi chúng ta viết tay. Nghĩa là một tọa độ (x, y) trong không gian hai chiều. Chuỗi chính là dãy các tọa độ như vậy. Bạn hãy chú ý đến chi tiết rất thú vị: mô hình “handwriting synthesis” (trong bài báo) có thể “bắt chước nét chữ viết tay”! Trong thế giới thực, đối với những người quen thân, khi họ cho chúng ta xem bản viết tay, chúng ta có thể nhận biết người đó là ai. Tôi đoán rằng rất ít trong số chúng ta (trên diễn đàn này) có thể bắt chước được nét chữ viết tay của người khác. Thế mà máy có thể làm được điều đó. Thì đó chính là trí tuệ nhân tạo (Artificial Intelligence) chứ còn gì nữa!

💡 Cái chung về dữ liệu của hai trường hợp trên là gì? Trong tiếng Anh, người ta gọi loại dữ liệu này là autoregressive. Tôi dịch từ này ra tiếng Việt là “tự động tiếp diễn”. Vì sao vậy?

  • Đối với trường hợp văn bản thì muốn văn bản có nghĩa, “từ” tiếp theo phải là một “tiếp diễn” có quy luật nào đó của dãy các từ trước đó.

  • Đối với trường hợp viết tay, lấy ví dụ viết chữ “a”. Kể từ khi chúng ta đặt bút xuống giấy thì nét sau phải “tiếp diễn” các nét trước, theo một quy tắc nhất định, để “vẽ” được chữa “a”, chứ không phải nét bút di chuyển một cách bất kỳ. Tức là “nét” tiếp theo tuân theo một quy luật nào đó của dãy các “nét” trước đó.

  • Trong một lần diễn thuyết năm 2015, Alex Graves có đề cập đến việc ứng dụng mô hình “handwriting synthesis” vào TTS. Chú ý sự tương đồng giữa chữ viết tay và âm thanh giọng nói: chúng đều là dữ liệu autoregressive - dữ liệu “tự động tiếp diễn”.

💡 “Nghiền ngẫm” sâu hơn một chút, chúng ta nhận thấy dữ liệu “autoregressive” (tự động tiếp diễn) có những đặc tính rất thú vị và thực tế nó có ảnh hưởng sâu sắc đến Machine Learning. Ở đây, tôi chỉ xin đàm luận đến 2 đặc tính của nó.

  • Dữ liệu không cần dán nhãn – Unsupervised Learning. Chúng ta chú ý tính chất phát sinh của loại dữ liệu autoregressive. Phần tử tiếp theo được tạo ra dựa trên dãy các phần tử trước đó. “Nhãn” trong trường hợp này được lấy từ chính chuỗi dữ liệu đầu vào. Tính chất này giúp máy “tự học” mà không cần giám sát, đó chính là Unsupervised Learning. Do việc dán nhãn mất rất nhiều công sức, đắt đỏ và thâm chí la bất khả thi nên giới nghiên cứu tập trung vào tìm các giải pháp cho Unsupervised Learning. Dữ liệu autoregressive là một ứng viên tuyệt vời.

  • Tri thức suy diễn từ dữ liệu. Vì mỗi một phần tử trong dữ liệu autoregressive được tạo ra từ dãy các phần tử trước đó nên bản thân các dãy dữ liệu chứa một quy tắc suy diễn nào đó. Từ đó suy ra, càng có nhiều đoạn dữ liệu, tức là dữ liệu càng lớn thì càng có nhiều quy tắc suy diễn – nghĩa là số lượng “tri thức suy diễn” càng nhiều. Trong đời sống thực tế, mỗi một kiến thức mới học được, rõ ràng là phải dựa vào khối kiến thức chúng ta đã học trước đó. Nếu, bằng một cách nào đó, có một mô hình có thể “thâu tóm” được hầu hết các “tri thức suy diễn” từ xưa đến nay, thì mô hình đó rõ ràng là một cỗ máy trí tuệ nhân tạo khổng lồ, tương tự như trí tuệ của một siêu nhân! 😊

➡ Neural Vocoder (vocoder trên nền mạng nơ-ron)
Bàn về neural vocoder, theo quan sát của riêng cá nhân, tôi thấy DeepMind đi tiên phong với đề xuất WaveNet vào năm 2016. Sau WaveNet có một số đề xuất khác như SampleRNN, WaveGlow hoặc WaveGAN. Tuy nhiên, do WaveNet đi đầu và có nhiều ý tưởng đột phá, nên tôi xin phép bạn chỉ đàm luận về mô hình này.

Trước khi đi vào chi tiết bài báo, theo tôi, chúng ta nên nắm các ý tưởng chính của họ:

  • Sóng âm thanh là loại dữ liệu autoregressive (tự động tiếp diễn) – như đã được đề cập ở phần “”.

  • Sóng âm thanh được tạo ra theo hình thức “tự động phát sinh”, phần tử sau được “suy diễn” ra từ chuỗi các phần tử trước. Hình thức “suy diễn” là áp dụng thuật toán softmax. Nghĩa là trong P ứng viên (candidate) của kết quả “suy diễn”, ứng viên nào có xác suất lớn nhất sẽ được chọn.

  • Người ta huấn luyện mô hình WaveNet cho toàn bộ các phát âm của một ngôn ngữ với N “người nói” (speaker), với rất nhiều đoạn văn bản thuộc ngôn ngữ đấy. Tập hợp “người nói” được chọn sao họ có tính đại diện cao nhất: vùng, miền, phương ngữ. Sau khi huấn luyện, mạng WaveNet coi như biết “tiếng nói” của ngôn ngữ đó với đầy đủ đặc tính vùng, miền, phương ngữ.

💡 Như vậy, WaveNet có thể “nói” được bất cứ ngôn ngữ nào miễn là nó được huấn luyện một cách đầy đủ (số người nói và số giờ nói).

Bạn nào muốn hiểu kỹ về mô hình này thì cách tốt nhất là nên đọc bài báo tôi đã dẫn đường link (WaveNet). Trong phần tiếp theo, chúng ta cùng khảo sát vài điểm đặc biệt của mô hình:

  • Mạng được chọn không phải là RNN mà là CNN (Convolutional Neural Network). Vì sao không chọn RNN là mạng thích hợp với dữ liệu tuần tự mà lại chọn CNN? Lý do: khi huấn luyện CNN, có thể tính song song đầu ra, vì vào thời điểm huấn luyện, tất cả dữ liệu mẫu đã được gán nhãn (tức là biết trước đầu ra). Lưu ý: điều này chỉ đúng khi huấn luyện. Còn khi suy diễn (inference) thì mô hình suy diễn tuần tự từng “điểm” sóng âm thanh một: đầu tiên là “tính” x1, xong “tính” x2 dựa trên x1, …, “tính” xn dựa trên x1, x2, …, xn-1, … Nếu trong 1 giây cần lấy 16,000 mẫu thì mô hình phải hoàn tất công việc tính toán 16,000 mẫu dưới 1 giây để hệ thống đảm bảo có thể chạy theo thời gian thực (real-time). Đây là nhược điểm trong phiên bản đầu tiên của WaveNet.

  • Đầu ra của WaveNet: sóng âm thanh. Đương nhiên, sóng âm thanh có giá trị liên tục. Vì máy tính không lưu được các giá trị liên tục nên cần phải lấy mẫu. Khi lấy mẫu chúng ta chú ý đến 2 chi tiết: tần số lấy mẫu và cường độ. WaveNet lấy 16,000 mẫu/giây (tương đương với tần số 16kHz). Cường độ, sau khi chuẩn hóa (normalization), thực chất là một số nguyên 16 bit. Như vậy, dưới góc độ lập trình, đầu ra của WaveNet là mảng các số nguyên 16 bit. Mỗi một giây, WaveNet sản sinh ra 16,000 số nguyên như vậy. (Chú ý thêm: cách họ biến đổi số 16 bit thành số 8 bit khi áp dụng thuật toán softmax – xem mục 2.2 trang 3)

  • WaveNet dựng mô hình như thế nào? Đầu tiên, để xây dựng mô hình tổng thể ban đầu, người ta cho mạng huấn luyện bằng cách “nghe” 109 người nói trong thời gian 44 giờ. Sau khi “học” xong, mạng có khả năng nói giọng tổng hợp, “lơ lớ” gần giống với tất cả 109 người này.

  • Sau đó, mô hình có thể “đọc” một đoạn văn bản nào đó bằng giọng “tổng hợp” của 109 người nói trên. Bên cạnh đó, rất đáng chú ý, mạng cũng có thể đọc văn bản bằng cách “lọc riêng” một giọng của một trong số 109 người nói đã tham gia huấn luyện!

  • Bằng cách nào mà họ có thể thực hiện được như vậy (lọc giọng từng người nói)? Đây là một câu hỏi rất thú vị. Trong bài báo, họ có giải thích. Cách họ vận hành mạng có tên gọi là “WaveNet có điều kiện” (Conditional WaveNet). Họ chia thành 2 loại điều kiện: điều kiện tổng thể (global condition) và điều kiện cục bộ (local condition).

o 💡 Thế nào gọi là điều kiện tổng thể?

Là điều kiện làm thay đổi toàn bộ quy trình phát sinh dữ liệu từ đầu đến cuối. Ví dụ về trường hợp này là chọn giọng đọc của một người. Nhưng làm thế nào mà người ta “lọc” ra được giọng của riêng một người? Chúng ta chú ý đến cách họ mã hóa “người nói” trong mô hình, họ dùng kỹ thuật one-hot vector. Nghĩa là mỗi một “người nói” ứng với một vector mà trong vector đó chỉ có một ô có giá trị bằng 1, còn lại tất cả các ô khác có giá trị bằng 0. Chúng ta chú ý đến phương trình số 2 – ký hiệu là Eq. (2) ở cuối trang 4 – trong tham số hàm kích hoạt (activation function), người ta nhân h (h trong trường hợp này là one-hot vector) với ma trận của các hệ số (weight). Chúng ta hình dung kết quả phép nhân: hủy hết tất cả “người nói” khác với h (các ô có giá trị bằng 0 trong one-hot vector thì nhân với bất cứ cái gì cũng bằng 0).

Một cách trực quan: ứng với mỗi một “người nói” (speaker) là một công-tắc tắt/bật. Việc lọc ra một giọng đọc cũng giống như việc chúng ta chỉ bật một công-tắc và tắt 108 công-tắc còn lại.

o 💡 Thế nào gọi là điều kiện cục bộ?

Là điều kiện chỉ làm thay đổi mô hình trong một khoảng thời gian nào đó. Ví dụ về trường hợp này là “đọc” một đoạn văn bản. Cách họ làm: căn cứ vào đoạn văn bản để “phát sinh” một chuỗi “sóng âm thanh”. Chuỗi sóng âm thanh của văn bản có tần số có thể không khớp với tần số của WaveNet (thường là nhỏ hơn tần số của WaveNet). Do đó, họ phải khớp 2 tần số, bằng cách upsampling (tăng) tần số của “văn bản” cho bằng tần số của WaveNet. Chuỗi dữ liệu được làm khớp này sau đó được trộn với dòng dữ liệu chính của WaveNet. Cách trộn: sử dụng phép toán tích chập (convolution). Để dễ hình dung, chúng ta tưởng tượng lúc này có 2 “sợi sóng”: một sợi là của hệ thống chính và một sợi được “chiết” ra từ đoạn văn bản. Phép tích chập tức là chúng ta chập 2 “sợi sóng” đấy lại với nhau. Kết quả là sợi “chập” nằm khoảng giữa 2 sợi: thấp hơn sợi cao và cao hơn sợi thấp.

  • Để khắc phục nhược điểm suy diễn (inference) chậm, phiên bản sau của WaveNet được nâng cấp thành Parallel WaveNet – mời bạn tham khảo bài báo. Phiên bản nâng cấp của WaveNet sử dụng tần số 24kHz. Tần số cao hơn cho kết quả là sóng “mịn” hơn nhưng đòi hỏi nhiều phép tính hơn.

Đến đây tôi xin trả lời cho câu hỏi được đặt ra ở phần đầu của đàm luận về vocoder: với WaveNet, chúng ta có thể dễ dàng thay giọng đọc “tổng hợp” bằng giọng đọc của một người bất kỳ trong số những người tham gia huấn luyện mô hình.

ⓕ Cách tiếp cận theo tư duy Machine Learning

Các mô hình theo tư duy mạng nơ-ron chỉ xuất hiện sau khi WaveNet ra đời (năm 2016). Xin lược kể một vài mô hình:

  • Đầu tiên phải kể đến giải pháp Char2Wav của Viện Trí tuệ nhân tạo Mila (Mila - Quebec AI Institute) vào đầu năm 2017. Vocoder của Char2Wav là SampleRNN (neural vocoder).

  • Tiếp theo có giải pháp Tacotron của Google, sau đó họ nâng cấp lên thành bản Tacontron2. Dĩ nhiên, họ sử dụng neural vocoder là WaveNet vì DeepMind đã sát nhập vào Google từ năm 2014.

  • Cũng trong năm 2017, Facebook cho ra đời giải pháp VoiceLoop. Họ sử dụng vocoder có tên là WORLD.

  • Năm 2019, nhóm nghiên cứu của Microsoft và Baidu đã đề xuất giải pháp FastSpeech. Trong kiến trúc mô hình họ không đề cập đến vocoder. Tuy nhiên, trong thử nghiệm họ sử dụng vocoder là WORLD và WaveGlow.

➡ Các mô hình này có điểm gì chung không?

Trả lời: Có – ngoại trừ FastSpeech, gần như tất cả các mô hình đều theo cách tiếp cận “end-to-end” (E2E). Cách tiếp cận E2E luôn luôn là lực hút đối với giới nghiên cứu trong thời gian gần đây, đặc biệt kể từ sau năm 2014.

Giải pháp E2E “cậy” vào 2 điểm tựa: dữ liệu nhiều (Big Data) và mạng nơ-ron (Neural Network). Nghĩa là cứ có thật nhiều bản ghi [Văn bản → Sóng âm thanh], rồi lấy tập hợp dữ liệu này huấn luyện cho một mô hình mạng nơ-ron nào đó. Sau đó, khi có văn bản mới đưa vào, mô hình sẽ “suy diễn” ra “sóng âm thanh” (của tiếng nói) tương ứng với văn bản đó. Cách tiếp cận này bỏ qua các bước “lằng nhằng trung gian” ở giữa. Mà, như chúng ta biết đấy, thông thường các bước “lằng nhằng trung gian” gây nhức đầu. 😊

🎗 Reminder: Trong mấy lần nhàn đàm trước, chúng ta đã khá quen với giải pháp E2E. Nhân tiện đây tôi xin nhắc lại để làm tươi bộ nhớ:

Viết một cách vắn tắt:
E2E = encoder-attention-decoder (mã hóa-chú ý-giải mã).

E2E đối với trường hợp “text-to-speech”:
[văn bản/âm vị]→mã hóa→ [context]→giải mã→ [sóng âm thanh]→vocoder

ⓕ Một vài thách thức đối với text-to-speech

  • Thách thức đầu tiên là tìm ra thước đo khách quan về chất lượng mô hình. Thước đo MOS vẫn chỉ là thước đo chủ quan, phụ thuộc vào việc chọn tập hợp người đánh giá. Hai mô hình với hai tập hợp người đánh giá khác nhau, hai tập dữ liệu mẫu khác nhau thì khó so sánh khách quan được. Chỉ có thước đo khách quan thì cộng đồng nghiên cứu mới “tự tin” để so sánh giữa các mô hình. Như đàm luận ở phần trước, cho đến hiện nay, chưa ai tìm được thước đo này.

    Để khắc phục một phần, một số nhà khoa học thống nhất đo chất lượng mô hình thông qua một tập dữ liệu chung và tổ chức việc đo chất lượng mô hình hàng năm (kể từ năm 2005): "Blizzard Challenge".

  • Một thách thức khác là việc chuẩn hóa văn bản (text normalization): chuyển đổi số và chữ viết tắt thành lời.

    Ví dụ về chuyển chữ viết tắt thành lời: NASA. Chuyển thành “na-xa” hay chuyển thành “nờ-a-ét-xì-a”?

    Ví dụ về chuyển đổi số: 135. Chuyển thành “một-ba-năm” hay chuyển thành “một trăm ba lăm”? Nếu viết “Chương VI” thì sẽ thành “chương vi” hay “chương sáu”?

  • Một thách thức nữa là việc “chuyển đổi văn bản thành phiên âm”: (text-to-phoneme). Đối với tiếng Việt chúng ta ít có vấn đề nhưng đối với các ngôn ngữ khác như tiếng Anh có một chút khác biệt. Thông thường mỗi một từ chỉ có một cách phát âm. Điều này đúng với tiếng Việt. Nhưng đối với một số ngôn ngữ khác như tiếng Anh thì có vấn đề về heteronym (cùng từ khác âm). Cùng một từ nhưng lại có nhiều cách phát âm – tùy vào nghĩa của từ hoặc tùy vào “thì”. Ví dụ từ “tear” trong tiếng Anh có 2 cách phát âm (/teə/ hoặc /tɪə/). Ví dụ khác là từ “read” trong tiếng Anh. Thì hiện tại thì phiên âm là /riːd/ còn thì quá khứ thì phiên âm là /red/.

Đấy là chúng ta bàn cho “hết nhẽ” thế thôi, chứ nếu chúng ta xem “máy nói” như người nước ngoài nói tiếng mẹ đẻ của mình thì chúng ta vẫn dễ dàng hiểu, dù có một vài chỗ phát âm chưa thật “chuẩn”!

ThS. Lê Văn Lợi