Mô Hình Hóa Chuỗi Với CTC

Hướng dẫn trực quan về Connectionist Temporal Classification, thuật toán huấn luyện mạng nơ-ron sâu cho nhận dạng giọng nói, chữ viết tay và các bài toán chuỗi khác.

Cách CTC thu gọn chuỗi
Với đầu vào,
như tiếng nói
Dự đoán một
chuỗi
token
Dùng return để
nhập blank (\epsilon)
Gộp ký tự lặp,
bỏ \epsilon
Đầu ra cuối

Giới Thiệu

Hãy bắt đầu với nhận dạng giọng nói. Ta có các đoạn âm thanh và bản chép lời tương ứng, nhưng không biết từng ký tự trong bản chép lời khớp với đoạn âm thanh nào. Chính khoảng trống căn chỉnh này làm việc huấn luyện khó hơn nhiều so với vẻ ngoài ban đầu.

Không có căn chỉnh, các cách học có giám sát đơn giản không còn dùng được. Ta có thể đặt luật như “một ký tự ứng với mười khung đầu vào”, nhưng tốc độ nói thay đổi liên tục nên luật đó dễ sai. Cũng có thể căn chỉnh thủ công từng ký tự, nhưng với dữ liệu đủ lớn thì việc này quá tốn thời gian.

Vấn đề này không chỉ xuất hiện trong giọng nói. Nhận dạng chữ viết tay từ ảnh hoặc nét bút là một ví dụ; gán nhãn hành động trong video là một ví dụ khác.

Nhận dạng chữ viết tay: The input can be (x,y) coordinates of a pen stroke or pixels in an image.
Nhận dạng giọng nói: The input can be a spectrogram or some other frequency based feature extractor.

Connectionist Temporal Classification, hay CTC, là cách vượt qua việc không biết căn chỉnh giữa đầu vào và đầu ra. Nó đặc biệt phù hợp với những ứng dụng như nhận dạng giọng nói và chữ viết tay.


Nói hình thức hơn, ta muốn ánh xạ một chuỗi đầu vào X, chẳng hạn âm thanh, sang một chuỗi đầu ra Y, chẳng hạn bản chép lời. Mục tiêu là học ánh xạ chính xác từ X sang Y.

Có ba trở ngại chính đối với học có giám sát thông thường:

CTC giải quyết các trở ngại này bằng cách gán cho mỗi X một phân phối xác suất trên mọi chuỗi Y khả dĩ. Phân phối đó có thể dùng để suy ra đầu ra có khả năng cao, hoặc để đánh giá xác suất của một đầu ra đã cho.

Không phải mọi cách tính loss và suy luận đều khả thi. Với CTC, cả hai việc này phải được thực hiện hiệu quả.

Hàm mất mát: với một đầu vào, ta muốn mô hình đặt xác suất cao nhất cho đáp án đúng. Vì vậy cần tính hiệu quả xác suất có điều kiện p(Y|X), và hàm này phải khả vi để có thể huấn luyện bằng gradient descent.

Suy luận: sau khi huấn luyện, ta muốn tìm một Y có khả năng cao với X đã cho. Lý tưởng là tìm nghiệm tối ưu hiệu quả; với CTC ta chấp nhận một nghiệm xấp xỉ đủ rẻ để tính.

Thuật Toán

CTC có thể gán xác suất cho mọi Y ứng với một X. Chìa khóa nằm ở cách CTC hiểu các căn chỉnh giữa chuỗi đầu vào và chuỗi đầu ra.

Căn Chỉnh

CTC không cần căn chỉnh cho trước. Tuy nhiên, để tính xác suất của một đầu ra, nó cộng xác suất trên tất cả các căn chỉnh có thể tạo ra đầu ra đó.

Để thấy dạng căn chỉnh của CTC, xét ví dụ đầu vào dài sáu bước và đầu ra [c, a, t]. Một cách ngây thơ là gán mỗi bước đầu vào cho một ký tự rồi gộp các ký tự lặp.

Cách ngây thơ này có hai lỗi.

CTC thêm một token đặc biệt gọi là blank, ký hiệu epsilon. Token này không tương ứng với ký tự đầu ra nào và sẽ bị xóa khi thu gọn chuỗi.

Mỗi căn chỉnh CTC có cùng độ dài với đầu vào. Một căn chỉnh hợp lệ là căn chỉnh sau khi gộp lặp và xóa blank sẽ cho đúng Y.

Nếu Y có hai ký tự giống nhau liên tiếp, một căn chỉnh hợp lệ phải có blank ở giữa chúng. Nhờ vậy “hello” và “helo” được phân biệt.

Quay lại đầu ra [c, a, t] với đầu vào dài sáu bước. Hình dưới cho vài căn chỉnh hợp lệ và không hợp lệ.

Căn chỉnh CTC có vài tính chất quan trọng: đơn điệu, nhiều-về-một, và đầu ra không thể dài hơn đầu vào.

Hàm Mất Mát

Các căn chỉnh CTC cho ta một cách tự nhiên để đi từ xác suất tại từng bước thời gian đến xác suất của cả chuỗi đầu ra.

Với một cặp (X, Y), mục tiêu CTC là tổng xác suất của mọi căn chỉnh hợp lệ tạo ra Y.

p(Y \mid X) \;\; =
\sum_{A \in \mathcal{A}_{X,Y}}
\prod_{t=1}^T \; p_t(a_t \mid X)
The CTC conditional probability
marginalizes over the set of valid alignments
computing the probability for a single alignment step-by-step.

Mô hình CTC thường dùng RNN để ước lượng phân phối xác suất tại từng bước thời gian. RNN hữu ích vì nó đưa ngữ cảnh của đầu vào vào dự đoán, nhưng CTC không bắt buộc phải dùng RNN.

Nếu tính trực tiếp, loss CTC rất đắt vì số căn chỉnh có thể khổng lồ.

May mắn là ta có thể tính nhanh bằng quy hoạch động. Ý tưởng chính: nếu hai căn chỉnh đi đến cùng một trạng thái tại cùng một thời điểm, ta có thể gộp chúng.

Cộng trên mọi căn chỉnh có thể rất tốn kém.
Quy hoạch động gộp các căn chỉnh trùng trạng thái, nên nhanh hơn nhiều.

Vì có thể có blank trước, sau, và giữa các token của Y, thuật toán thường làm việc với chuỗi Z, là Y đã được chèn blank ở các vị trí đó.

Gọi alpha là điểm số của các căn chỉnh đã được gộp tại một nút. Từ các alpha ở bước trước, ta tính được alpha ở bước hiện tại.

Trường hợp 1:

Khi không được nhảy qua token trước đó trong Z, chỉ có hai vị trí ở bước trước có thể chuyển tới nút hiện tại.

Điều này bảo đảm ta không bỏ qua ký tự cần thiết và không làm mất blank giữa các ký tự lặp.

\alpha_{s, t} \; =
(\alpha_{s-1, t-1} + \alpha_{s, t-1}) \quad\quad \cdot
Xác suất CTC của hai dãy con hợp lệ sau t-1 bước đầu vào.
p_t(z_{s} \mid X)
Xác suất của ký tự hiện tại tại bước đầu vào t.

Trường hợp 2:

Khi token trước là blank nằm giữa hai ký tự khác nhau, ta được phép nhảy qua nó. Khi đó có ba vị trí ở bước trước có thể chuyển tới.

\alpha_{s, t} \; =
(\alpha_{s-2, t-1} + \alpha_{s-1, t-1} + \alpha_{s, t-1}) \quad\quad \cdot
Xác suất CTC của ba dãy con hợp lệ sau t-1 bước đầu vào.
p_t(z_{s} \mid X)
Xác suất của ký tự hiện tại tại bước đầu vào t.

Hình dưới minh họa phép tính của quy hoạch động. Mỗi căn chỉnh hợp lệ tương ứng với một đường đi trong đồ thị.

đầu ra
Y = [a, b]
đầu vào, X
Nút (s, t) trong hình biểu diễn \alpha_{s, t} – the CTC score of the subsequence Z_{1:s} after t bước đầu vào.

Có hai nút bắt đầu và hai nút kết thúc hợp lệ vì blank ở đầu và cuối chuỗi là tùy chọn. Xác suất đầy đủ là tổng của hai nút cuối.

Sau khi tính loss hiệu quả, ta có thể lấy gradient và huấn luyện mô hình. Loss CTC khả vi theo xác suất đầu ra tại từng bước, nên có thể lan truyền ngược như thường lệ.

Với tập huấn luyện, ta tối ưu tham số bằng cách tối thiểu hóa negative log-likelihood thay vì tối đa hóa likelihood trực tiếp.

Suy Luận

Sau khi huấn luyện, bài toán suy luận là tìm đầu ra có xác suất cao cho một đầu vào đã cho.

Y^* \enspace = \enspace {\mathop{\text{argmax}}\limits_{Y}} \enspace p(Y \mid X)

Một heuristic đơn giản là chọn token có xác suất cao nhất tại mỗi bước thời gian.

A^* \enspace = \enspace {\mathop{\text{argmax}}\limits_{A}} \enspace \prod_{t=1}^{T} \; p_t(a_t \mid X)

Sau đó gộp các ký tự lặp và xóa blank để thu được Y.

Heuristic này thường ổn khi phần lớn xác suất nằm trên một căn chỉnh duy nhất, nhưng có thể sai vì một đầu ra có thể có rất nhiều căn chỉnh.

Ví dụ, hai căn chỉnh của [a] riêng lẻ có thể kém [b], nhưng tổng xác suất của chúng lại lớn hơn [b]. Khi đó chọn căn chỉnh tốt nhất sẽ bỏ lỡ đầu ra đúng hơn.

Beam search sửa vấn đề này bằng cách giữ nhiều giả thuyết cùng lúc. Beam lớn hơn tốn tính toán hơn nhưng tiến gần nghiệm tốt hơn.

Beam search chuẩn mở rộng từng giả thuyết bằng mọi ký tự có thể, rồi chỉ giữ lại các ứng viên tốt nhất.

Beam search chuẩn với bảng chữ cái \{\epsilon, a, b\} và beam size bằng ba.

Với CTC, beam không nên lưu căn chỉnh thô mà nên lưu prefix sau khi gộp lặp và xóa blank. Điểm của một prefix là tổng điểm của mọi căn chỉnh dẫn tới nó.

Beam search cho CTC với bảng chữ cái đầu ra \{\epsilon, a, b\} và beam size bằng ba.

Khi mở rộng một prefix bằng ký tự lặp, cùng một ký tự có thể tạo ra hai prefix đầu ra khác nhau; vì vậy cần xử lý riêng trường hợp kết thúc bằng blank.

Khi thêm [a] để tạo [a, a], chỉ phần điểm của các căn chỉnh kết thúc bằng blank được dùng. Nếu không mở rộng prefix, ta dùng phần không kết thúc bằng blank.

Vì vậy mỗi prefix trong beam cần hai xác suất: xác suất các căn chỉnh kết thúc bằng blank và xác suất các căn chỉnh không kết thúc bằng blank.

Hiện thực thuật toán không dài, nhưng đặc và dễ sai; nên kiểm thử cẩn thận.

Trong nhận dạng giọng nói, thêm mô hình ngôn ngữ vào suy luận thường cải thiện độ chính xác. Ta có thể đưa nó vào như một nhân tử của bài toán suy luận.

Y^* \enspace = \enspace {\mathop{\text{argmax}}\limits_{Y}}
p(Y \mid X) \quad \cdot
Xác suất có điều kiện của CTC.
p(Y)^\alpha \quad \cdot
Xác suất của mô hình ngôn ngữ.
L(Y)^\beta
Hệ số thưởng chèn “từ”.

Hàm L(Y) đo độ dài của Y theo token của mô hình ngôn ngữ và đóng vai trò thưởng chèn từ. Với mô hình ngôn ngữ theo từ, nó đếm số từ; với mô hình theo ký tự, nó đếm số ký tự.

Điểm mô hình ngôn ngữ chỉ được thêm khi prefix được mở rộng, nên tìm kiếm có xu hướng ưu tiên prefix ngắn. Hệ số thưởng chèn từ bù lại xu hướng này.

Các Tính Chất Của CTC

Bây giờ ta xem kỹ hơn các tính chất và đánh đổi của CTC.

Độc Lập Có Điều Kiện

Một hạn chế thường được nhắc đến của CTC là giả định độc lập có điều kiện giữa các đầu ra.

Ghi Chú Tài Liệu

Thuật toán CTC được Graves và cộng sự công bố lần đầu năm 2006. Các thí nghiệm đầu tiên dùng TIMIT, một benchmark nhận dạng âm vị phổ biến; Chương 7 trong luận án của Graves cũng trình bày CTC rất chi tiết.

Một trong những ứng dụng CTC đầu tiên cho nhận dạng giọng nói từ vựng lớn là công trình của Graves và cộng sự năm 2014. Sau đó Hannun và cộng sự chứng minh các hệ nhận dạng giọng nói dựa trên CTC đạt kết quả hàng đầu trên benchmark lớn hơn.

CTC cũng thành công trong nhiều bài toán khác như nhận dạng chữ viết tay trực tuyến, đọc khẩu hình từ video, nhận dạng hành động và phát hiện từ khóa trong âm thanh.

Nhiều mở rộng của CTC đã được đề xuất, bao gồm Sequence Transducer bỏ giả định độc lập có điều kiện, Gram-CTC biên hóa trên lớp n-gram, và các biến thể có cấu trúc đoạn.

HMM được phát triển từ thập niên 1960 và ứng dụng vào nhận dạng giọng nói từ thập niên 1970. Bài khảo sát của Rabiner là tài liệu kinh điển để bắt đầu.

Các mô hình encoder-decoder xuất hiện năm 2014. Distill có một hướng dẫn sâu về attention trong encoder-decoder.

Lời Cảm Ơn

Tôi đặc biệt biết ơn đội ngũ Distill vì đã cải thiện đáng kể chất lượng bài viết. Các góp ý của Chris Olah giúp cả phần chữ và phần hình tốt hơn nhiều; Shan Carter cải thiện đáng kể các hình; Ludwig Schubert hỗ trợ template Distill.

Cảm ơn Sanjeev Satheesh, Chris Lengerich, Dan Jurafsky và các phản biện ẩn danh vì phản hồi của họ. Tôi cũng rất biết ơn Andrew Ng vì góp ý và sự hỗ trợ cho bài viết.

Thảo Luận Và Phản Biện

Phản biện 1 Ẩn danh
Phản biện 2 Ẩn danh