Business Information Learning

  1. Trang chủ
  2. Lưu
  3. Thẻ
  4. Hỏi - Đáp

 
 
Trang chủ
BIL'log, ⌚ 2021-10-04
***
☕ Nhàn đàm ICT: Text-to-speech 🗎→🔈
Tác giả: Lê Văn Lợi
Bài đã đăng trên diễn đàn ICT_VN (ict_vn@googlegroups.com).
Ngày đăng: 4-10-2021.

Để giúp anh/chị quyết định có đọc tiếp hay không, tôi xin phép cung cấp các thông tin liên quan đến bài post này như sau:

  • Chủ đề: Khoa học thường thức (80%), Machine Learning (20%)
  • Tính thời sự: Tháng 5 năm 2019.
  • Thời gian đọc: 7 phút, không tính thời gian uống cà phê.

-

Xin phép anh/chị, hôm nay chúng ta đàm đạo về “máy nói”, nhưng chỉ giới hạn trong khuôn khổ là “máy nói theo văn bản”: “text-to-speech” (TTS). Nghĩa là chúng ta không đi quá xa về “máy nói”: người đối thoại với máy, người hỏi – máy trả lời, “máy diễn thuyết”, … Chỉ đơn giản là cho một đoạn văn bản và xin mời “máy đọc đoạn văn bản đấy”. Tất nhiên, trước hết máy phải đọc đúng, đọc rõ, sau nữa đọc càng hay thì càng tốt.

🗎→🔈

Một cách giản lược, chúng ta có thể hình dung quy trình biến đổi “văn bản-thành-giọng nói” như sau:

  • Giả thiết chúng ta có một đoạn văn bản. Đoạn văn bản này có thể chứa các con số hoặc từ viết tắt. Nếu có con số hoặc từ viết tắt thì trước hết chúng ta phải biến chúng thành “lời”. Ví dụ, “12” thành “mười hai”; “TW” thành “trung ương”.
    (Công đoạn này được đặt tên là “chuẩn hóa văn bản”: text normalization.)
    -
  • Tiếp theo, người ta tách văn bản thành từng từ, phiên âm từng từ và phối các phiên âm thành các đoạn có ngữ điệu, ví dụ: cụm từ, mệnh đề, câu văn. Đến đây, đoạn văn bản được biến thành một dãy các đoạn mã phiên âm (phonetic transcription).
    (Công đoạn này được đặt tên là “chuyển đổi văn bản thành phiên âm”: text-to-phoneme.)
    -
  • Căn cứ vào đoạn mã phiên âm, người ta cho phát ra thành âm thanh, ra loa.
    (Công đoạn này có tên là “bộ tổng hợp”: synthesizer.)
    -

🗎→🔈

Tiếp theo, chúng ta bàn chi tiết hơn các giải pháp cho “text-to-speech”. Khi nói đến các giải pháp TTS, người ta thường quan tâm đến 2 yêu cầu rất cơ bản về chất lượng. Đó là:

  • Dễ hiểu (intelligibility): chúng ta phải hiểu được “máy nói” một cách dễ dàng. “Dễ hiểu” ở đây không có ý về ngữ nghĩa câu văn mà là phát âm nghe dễ hiểu.
  • Tính tự nhiên (naturalness): “máy nói” giống như người nói.

Có rất nhiều cách để biến “văn bản-thành-giọng nói”. Dưới góc độ các giải pháp “kinh điển”, xin phép anh/chị bàn về 2 cách tiếp cận: ghép âm và máy tự tạo giọng nói.

  • ➡ Ghép âm (concatenation synthesis). Phương thức tổng hợp này là ghép (xâu chuỗi) các đoạn “người nói” đã được ghi âm lại với nhau. Cách này rõ ràng là đạt được mức độ tự nhiên cao. Tuy nhiên sự biến thiên trong giọng nói của đoạn trước không dễ gì khớp với sự biến thiên trong đoạn tiếp theo ngay sau đó nên thường xảy ra hiện tượng “lệch sóng” giữa 2 đoạn liền nhau. Cùng chung cách ghép âm, có 3 cách tiếp cận.
     
  1. Tuyển chọn đơn nguyên âm thanh (Unit selection synthesis). Theo cách này, đầu tiên người ta thiết lập một cơ sở dữ liệu (CSDL) về “lời nói” được ghi âm. Trong quá trình thiết lập CSDL, mỗi một câu nói được tách ra thành các “đơn nguyên” (đơn vị phát âm). Các “đơn nguyên” có thể là đơn âm (phone), cặp âm (diphone), bán âm (half-phone), âm tiết (syllable), hình vị (morpheme), từ (word), cụm từ (phrase), câu (sentence). Mỗi một bản ghi của CSDL còn có một số thuộc tính khác đi kèm như âm độ (pitch), thời lượng, vị trí của âm tiết, các âm vị trước, sau âm tiết. Ngoài phần ghi âm, người ta còn lưu sóng và phổ của phần ghi âm để có thể dễ dàng khảo sát đoạn ghi âm bằng đồ thị.
    -
    Làm thế nào để chuyển đổi văn bản thành giọng nói? Cách làm: bộ tổng hợp (synthesizer) chia đoạn văn bản thành các “đơn nguyên”. Mỗi một “đơn nguyên” phải tương ứng với một bản ghi trong CSDL nói trên. Sau khi thay các “đơn nguyên” bằng các đoạn ghi âm, kết quả là đoạn văn bản được chuyển thành một chuỗi các các đoạn ghi âm nối tiếp nhau được lấy ra từ CSDL. Việc của máy là cho “phát thanh” chuỗi các các đoạn ghi âm này.
    -
    Ở trên, tôi chưa đề cập đến thuật toán chuyển văn bản thành chuỗi “đơn nguyên”. Một văn bản có thể chuyển thành rất nhiều chuỗi “đơn nguyên” khác nhau. Nghĩa là có rất nhiều chuỗi “đơn nguyên” khác nhau cùng “nói” một đoạn văn bản. Vậy chuỗi nào là tối ưu? Để biết được chuỗi nào là tối ưu người ta căn cứ vào hàm đánh giá (cost function). Chuỗi nào có tổng “giá” thấp nhất, chuỗi đó là tối ưu.
    -
    Về mặt nguyên tắc, cách tiếp cận này đạt độ tự nhiên cao nhất, vì các đoạn ghi âm trong CSDL là ghi lời nói của người thật. Tuy nhiên, chúng ta vẫn phải tính đến vấn đề khớp nối giữa 2 đoạn ghi âm. Chú ý rằng, đây là khớp nối giữa 2 đoạn sóng phát âm. Trong thực tế, biên độ cuối của đoạn sóng đứng đằng trước (của “đơn nguyên” trước) thường sẽ không khớp với biên độ đầu của đoạn sóng tiếp theo (của “đơn nguyên” sau). Đây là hiện tượng xô lệch âm thanh. Vì vậy, vẫn phải cần có sự can thiệp của xử lý tín hiệu số (digital signal processing - DSP) nhằm làm mịn đoạn sóng ở chỗ khớp nối – tức là giảm thiểu mức xô lệch âm thanh.  Chúng ta cũng lưu ý rằng càng có nhiều DSP thì mức độ tự nhiên càng giảm. Muốn DSP ít can thiệp thì CSDL cần có các đơn nguyên dài hơn, ghi âm bằng lời nói tự nhiên, để tránh hiện tượng xô lệch âm thanh. Khi thêm các đơn nguyên dài như vậy, CSDL phải rất lớn và hàm đánh giá (cost function) chạy chậm hơn. [Tham khảo ở đây.]
    -
  2. Cặp âm (Diphone synthesis). Trước khi bàn đến cách tiếp cận này, chúng ta tìm hiểu qua khái niệm về cặp âm (diphone)? Trong ngữ âm, diphone là cặp đơn âm đi liên kề nhau khi phát âm. Ví dụ, từ diphone, trong tiếng Anh, khi phiên âm chúng ta được: [daɪfəʊn]. Dưới góc độ cặp âm, đoạn phiên âm [daɪfəʊn] gồm các cặp âm sau: [da], [aɪ], [ɪf], [fə], [əʊ], [ʊn].
    -
    Trở lại với phương pháp tiếp cận. Đối với một ngôn ngữ, người ta thiết lập một CSDL gồm tất cả các cặp âm (diphone) có thể có. Về mặt nguyên tắc, nếu ngôn ngữ đó có P đơn âm thì sẽ có P2 cặp âm. Tuy nhiên, trên thực tế không phải cặp đơn âm nào cũng đi liền với nhau được. Ví dụ, tiếng Tây Ban Nha có 800 cặp âm, còn tiếng Đức có 2.500 cặp âm.
    -
    Lại nói về việc phân tích văn bản thành phát âm. Chúng ta thấy, một từ bất kỳ trong ngôn ngữ, khi phiên âm, là một chuỗi ghép của các cặp âm (diphone). Người ta chia đoạn văn bản thành từng câu. Và câu là tổ hợp của các từ. Kết quả là, khi phiên âm, đoạn văn bản biến thành một chuỗi các cặp âm.
    -
    Chú ý rằng các cặp âm “chồng lên nhau” (overlap). Trong ví dụ về phiên âm từ diphone thì cặp [da] chồng lên cặp [aɪ], cặp [aɪ] lại chồng lên cặp [ɪf], … Vì vậy, để ghép các cặp âm, người ta cần đến các thuật toán xử lý tín hiệu số (DSP) như PSOLA (Pitch Synchronous Overlap and Add), MBROLA (Multi-Band Resynthesis OverLap Add). Trong thực tế, giải pháp diphone synthesis về mặt thương mại không hấp dẫn, chủ yếu chỉ để dùng trong nghiên cứu.
    -
  3. Theo lĩnh vực cụ thể (Domain-specific synthesis). Cách làm của phương pháp này là ghép các từ (hoặc cụm từ) được thu âm từ trước. Có vẻ như cách tiếp cận này giống với tuyển chọn đơn nguyên âm thanh (unit selection synthesis)? Đúng, về mặt nguyên tắc là giống nhau. Tuy nhiên, do số từ (cụm từ) rất ít (cỡ vài chục đơn nguyên) nên thuật toán ghép không cần hàm đánh giá mục tiêu và không cần thuật toán tìm chuỗi tối ưu.

    Khác với 2 phương pháp 1. và 2., cách ghép này không bị hiện tượng xô lệch âm thanh hay hiện tượng chồng âm: có một khoảng lặng ngắn giữa 2 từ (cụm từ).
    -
    Dùng ở đâu? Ở các phòng đợi xếp hàng chờ đến lượt (ngân hàng, phòng khám), thông báo tàu, xe hay thông báo ở trong các thang máy, …
    -

 

  • ➡ Máy tự tạo giọng nói (formant synthesis / parametric TTS). Cách tiếp cận này không sử dụng tiếng người mà giọng nói được tạo ra từ máy (artificial speech). Căn cứ vào các tham số của phát âm (như tần số cơ bản, dao động tuần hoàn của ngữ âm, thời lượng, …) máy tự tạo ra sóng âm thanh với “âm tiếng nói bằng máy” tương ứng. Phương pháp này còn được gọi là bộ tổng hợp dựa trên quy tắc (rules-based synthesis).
    -
    Cách tiếp cận này tất nhiên cho kết quả “thiếu tự nhiên”. Bằng máy mà (tiếng nói được tạo ra từ các công thức toán học), chả tự nhiên tý nào! 😊 Bù lại, người ta đánh giá giải pháp này “nghe được”, ngay cả khi “máy nói” nhanh. Người ta có thể điều chỉnh tốc độ nói, âm thanh cao thấp bằng cách thay đổi tham số. Ngoài ra, phần mềm tương đối nhẹ, cần rất ít bộ nhớ và có thể dễ dàng “nhúng” vào các hệ thống tự động hóa. Chúng ta có thể lập trình được “máy nói” theo ý muốn: nhịp điệu, thanh sắc, … [Tham khảo ở đây.]
    -

 

🗎→🔈

Bây giờ chúng ta bàn đến cách đo chất lượng mô hình. Khi nghiên cứu một vấn đề nào đó, cộng đồng nghiên cứu thường đề xuất các thước đo chất lượng. Thước đo này giúp chúng ta đánh giá một giải pháp nào đó tốt đến mức độ nào. Lấy ví dụ. Trong dịch máy (Machine Translation), chúng ta có thước đo BLEU. Giải pháp nào đạt BLEU cao là giải pháp đó tốt. Trong nghiên cứu “speech-to-text”, chúng ta có thước đo WER. Giải pháp nào có WER nhỏ thì giải pháp đó tốt. Các thước đo BLEU và WER có một tính chất rất quan trọng: đây là các thước đo khách quan (objective). Nghĩa là không có một tổ chức hay cá nhân nào đứng ra đo, mà thước đo này có công thức, có cách tính tự động: máy đo.

-

Thế còn đối với vấn đề “text-to-speech” thì thế nào? Rất đáng tiếc là cho đến thời điểm hiện nay, chưa ai đề xuất ra được thước đo khách quan nào cả. Nghĩa là chưa có một công thức hay cách tính tự động bằng máy, máy “nghe thử” và cho kết quả đánh giá. Như vậy, chỉ còn cách duy nhất là cần đến con người để đánh giá chất lượng. Đây là thước đo chủ quan (subjective).

-

Vấn đề còn lại là tổ chức như thế nào để “thuê” được nhóm người đánh giá chất lượng kết quả nghiên cứu một cách “không thiên kiến”, “không bị tác động lẫn nhau”? “Không thiên kiến” nghĩa là người đánh giá không biết sản phẩm nghiên cứu đấy là của ai, của công ty nào. “Không bị tác động lẫn nhau” nghĩa là nhóm người đánh giá không biết nhau. Trả lời cho câu hỏi này, tôi thấy phần lớn các công ty công nghệ tổ chức thuê ngoài theo mô hình có tên gọi là Amazon Mechanical Turk (MTurk). Đây là một hình thức thuộc dòng crowdsource (nguồn cộng đồng), crowdworker (lao động cộng đồng). Mô hình này do Jeff Bezos, ông chủ của Amazon đề xướng. Đại ý là người ta thuê ngoài “lao động cộng đồng” thông qua một giao diện (Application Programming Interface - API) trên mạng Internet. Người “lao động cộng đồng” (crowdworker) chỉ biết đến giao diện và không biết nhau.   (Không biết trên diễn đàn này liệu đã có anh/chị nào tham gia Mturk chưa nhỉ? 😊)

Gốc của cụm từ Mechanical Turk: là máy cơ chơi cờ vua tự động – máy có thể chơi cờ vua với người (từ năm 1770 đến năm 1854). Thực tế đây chỉ là trò bịp, vì nấp đằng sau máy vẫn là một người thật. Có lẽ vì vậy mà Jeff Bezos đã lấy cụm từ này, vì đằng sau giao diện (tưởng như là tự động) vẫn là con người.

-

Trong trường hợp đo chất lượng synthesizer, người ta yêu cầu đánh giá chất lượng theo 5 mức:

5

Excellent

4

Good

3

Fair

2

Poor

1

Bad

 

Giả thiết người ta thuê N người đánh giá, và có kết quả lần lượt là R1, R2, …, RN. Từ đó, người ta tính ra điểm số trải nghiệm bình quân có tên viết tắt là MOS:

MOS (Mean Opinion Score) = (R1 + R2 + … + RN)/N.

Như vậy, MOS đạt tối đa là 5.0 và tối thiểu là 1.0. Thước đo MOS vẫn còn nhiều tranh luận, nhưng có lẽ chúng ta khỏi tốn thời gian vào các tranh luận này.

Khi đọc các bài báo về “text-to-speech”, chúng ta thường thấy người ta đánh giá mô hình thông qua điểm MOS. Nếu điểm MOS đạt trên 4.3 là rất tốt rồi đấy!

🗎→🔈

Khái niệm vocoder. Vocoder là ghép của phần đầu từ voice với phần đuôi từ encoder – tạm dịch nghĩa là bộ mã hóa giọng nói. Đặt trong tổng thể của synthesizer thì vocoder chính là “phát thanh” của synthesizer. Quan trọng hơn, chất lượng của vocoder gần như quyết định của chất lượng của synthesizer.

Gốc của vocoder là mã hóa nguồn phát, truyền phần mã hóa đó qua đường truyền viễn thông và đầu nhận thông tin đường truyền có trách nhiệm giải mã tín hiệu nhận được và phát ra loa. (Vocoder được Homer Dudley tại Bell Labs phát minh vào năm 1938.) Anh/chị nếu có ai tò mò về nguyên lý của vocoder thì tham khảo đường link tôi đã dẫn ở trên.

-

Bàn thêm về ngôn từ. Trong bài nhàn đàm này, chúng ta thống nhất coi vocoder là phát thanh của synthesizer. Và chúng ta dùng luôn từ vocoder, khỏi phải dịch sang tiếng Việt.

<Mở ngoặc>
Theo quan điểm của riêng cá nhân tôi, nhiều từ chúng ta nên chấp nhận để nguyên gốc tiếng Anh, chấp nhận “nhập khẩu” một số từ. Lý do: nếu chúng ta cứ cố ép phải dịch thì kết quả là, trong nhiều trường hợp, bản dịch thường khó hiểu và tệ hại hơn, thậm chí còn bị hiểu nhầm. Mà ngay như từ “vocoder” cũng không có trong từ điển Anh-Anh đâu.
<Đóng ngoặc>

-

🗎→🔈

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 nói băng sang chuyện khác, rồi trở lại trả lời câu hỏi trên. Nếu anh/chị không có hứng thú đọc thì xin bỏ qua phần tôi đánh dấu “<Bên lề>”.

   <Bên lề>

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 về quá khứ. Khi anh/chị đọc bài post này, anh/chị hiểu từng từ dựa trên sự hiểu biết của anh/chị về những từ trước đó. Rõ ràng là như vậy. Anh/chị không vứt bỏ mọi thứ và bắt đầu suy nghĩ lại từ đầu. Dòng suy nghĩ của anh/chị 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 anh/chị tham khảo bài này, anh/chị 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. Anh/chị 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ó.

  1. 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.
     
  2. 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! 😊

   </Bên lề>

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 anh/chị 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 “<Bên lề>”.
  • 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).
    -

Anh/chị 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 (frequency) và cường độ (intensity). WaveNet lấy 16,000 mẫu/giây (tương đương với tần số 16kHz). Cường độ (intensity), 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).
    • 💡 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.
      -
    • 💡 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 anh/chị 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 vocoderWORLDWaveGlow.
    -

➡ 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”! 😊

 

(_/)
( •_•)
/ >☕