Chuẩn hoá văn bản tiếng Việt trong bộ dữ liệu là đưa mọi biến thể ký tự của cùng một chữ về một dạng duy nhất trước khi đếm, lọc trùng, tách từ hay gán nhãn, gồm năm việc theo thứ tự: chuyển mã cũ (TCVN3, VNI, VIQR) sang Unicode, chuẩn hoá về Unicode dựng sẵn (NFC), thống nhất kiểu đặt dấu thanh, thay ký tự trông giống hệt nhưng khác mã, và xử lý khoảng trắng, ký tự ẩn. Riêng viết tắt, không dấu và tiếng lóng thì không nên "sửa" thẳng vào dữ liệu gốc mà lưu song song một bản chuẩn hoá.
Lý do phải làm: máy so chuỗi theo mã ký tự, không theo hình dáng. Hai chữ trông giống hệt trên màn hình nhưng khác mã sẽ bị coi là hai từ khác nhau, làm sai thống kê tần suất, làm lọc trùng bỏ sót, làm bộ tách từ không nhận ra từ trong từ điển, và làm mô hình phải học hai lần cùng một thứ. Phần lý giải vì sao tiếng Việt có nhiều dạng mã như vậy có ở chuyên mục về đặc điểm tiếng Việt với máy; bài này tập trung vào việc làm trong đường ống dữ liệu.
Bước 1: chuyển mã cũ sang Unicode
Trước khi Unicode phổ biến, tiếng Việt trên máy tính dùng nhiều bảng mã riêng: TCVN3 (còn gọi là ABC, đi với các phông chữ tên bắt đầu bằng ".Vn"), VNI (phông chữ "VNI-"), và VIQR, một quy ước gõ dấu bằng ký tự thường như "Vie^.t Nam". Từ đầu những năm 2000, văn bản của cơ quan nhà nước chuyển dần sang bộ mã Unicode theo tiêu chuẩn TCVN 6909:2001, nhưng kho tài liệu cũ, tệp Word cũ, văn bản trích từ PDF cũ vẫn còn mang mã cũ.
Dấu hiệu nhận ra: văn bản hiển thị đầy ký tự Latin có dấu lạ, ký hiệu tiền tệ hay chữ Hy Lạp xen giữa các chữ cái không dấu, đặc biệt ở những vị trí đáng lẽ phải là nguyên âm có dấu. Một cách phát hiện tự động là đếm tần suất các ký tự hiếm trong tiếng Việt chuẩn; tài liệu nào có tỷ lệ bất thường thì đưa vào hàng chờ chuyển mã.
Chuyển mã cần đoán đúng bảng mã gốc. Các công cụ chuyển mã tiếng Việt hỗ trợ TCVN3, VNI, VIQR và vài bảng mã ít gặp hơn. Sau khi chuyển, kiểm bằng tỷ lệ âm tiết hợp lệ: âm tiết tiếng Việt có cấu trúc rõ (phụ âm đầu, vần, thanh), nên một văn bản chuyển đúng sẽ có tỷ lệ âm tiết hợp lệ cao. Tài liệu chuyển xong mà tỷ lệ vẫn thấp thì có thể đã đoán sai bảng mã, hoặc văn bản pha trộn nhiều mã, nên tách ra xử lý tay hoặc loại.
Bước 2: đưa về Unicode dựng sẵn (NFC)
Trong Unicode, một chữ như "ệ" có thể được biểu diễn bằng một mã duy nhất (dạng dựng sẵn) hoặc bằng chữ "e" cộng các dấu kết hợp theo sau (dạng tổ hợp). Bộ gõ, hệ điều hành, phần mềm soạn thảo khác nhau có thể sinh ra dạng khác nhau; tên tệp và văn bản sao chép từ một số môi trường còn ở dạng tách. Mắt người không phân biệt được, nhưng độ dài chuỗi, kết quả tìm kiếm và mã băm khác hẳn.
Unicode định nghĩa các dạng chuẩn hoá, trong đó NFC gộp các tổ hợp về dạng dựng sẵn khi có thể, NFD tách ra. Với tiếng Việt, NFC là lựa chọn mặc định hợp lý vì mọi chữ Việt đều có mã dựng sẵn, văn bản gọn hơn và tương thích với hầu hết công cụ. Hầu hết ngôn ngữ lập trình đều có sẵn hàm chuẩn hoá Unicode; việc cần làm chỉ là gọi nó ở đầu đường ống cho mọi văn bản, kể cả nhãn, tên tệp và từ điển dùng kèm.
Một lỗi hay gặp là chuẩn hoá dữ liệu huấn luyện nhưng quên chuẩn hoá đầu vào lúc chạy thật. Người dùng gõ từ một bộ gõ sinh dạng tổ hợp, mô hình nhận chuỗi khác với những gì đã học, kết quả kém mà không ai hiểu vì sao. Quy tắc: hàm chuẩn hoá dùng cho dữ liệu phải là cùng một hàm dùng cho đầu vào của sản phẩm.
Bước 3: thống nhất kiểu đặt dấu thanh
Hai kiểu cùng tồn tại. Với các vần như "oa", "oe", "uy", có hai thói quen đặt dấu: kiểu "hòa, thủy, khỏe" (dấu ở nguyên âm đầu) và kiểu "hoà, thuỷ, khoẻ" (dấu ở nguyên âm sau). Cả hai đều phổ biến trong văn bản thực tế, và chúng là những chuỗi khác nhau ngay cả sau NFC, vì dấu nằm trên hai chữ cái khác nhau.
Chọn một kiểu cho dữ liệu nội bộ. Chuẩn hoá NFC không gộp được hai kiểu này; phải viết quy tắc riêng theo vần. Chọn kiểu nào không quan trọng bằng việc chọn một và áp nhất quán. Nhiều nhóm chọn kiểu phổ biến hơn trong dữ liệu của mình để giảm số chữ phải đổi.
Sửa lỗi đặt dấu sai hẳn. Ngoài hai kiểu hợp lệ còn có lỗi thật như "qúy" thay vì "quý", "gìa" thay vì "già", dấu nằm trên phụ âm do bộ gõ trục trặc. Những lỗi này sửa được bằng quy tắc dựa trên cấu trúc âm tiết: xác định nguyên âm chính rồi đặt dấu lên đúng chỗ.
Đừng gộp i và y. Các cặp như "kỹ/kĩ", "lý/lí" là biến thể chính tả cùng tồn tại, nhưng "Lý" còn là họ người, "Mỹ" là tên nước, "y tế" không viết "i tế". Gộp máy móc sẽ làm sai tên riêng. Nếu cần gộp để thống kê, làm ở bản chuẩn hoá phụ, giữ nguyên văn gốc.
Bước 4: ký tự trông giống nhưng khác mã
Đây là lớp lỗi khó thấy nhất vì không có gì trông sai. Bảng dưới liệt kê các cặp hay gặp trong văn bản tiếng Việt.
| Trông giống | Thực ra là | Hay đến từ đâu | Cách xử lý |
|---|---|---|---|
| Đ, đ của tiếng Việt | Ð, ð của tiếng Iceland (eth) hoặc ký tự khác | Bộ gõ, phông chữ cũ, chuyển mã lỗi | Thay về Đ (U+0110), đ (U+0111) |
| Khoảng trắng thường | Khoảng trắng không ngắt, khoảng trắng hẹp | Sao chép từ trang web, tệp văn phòng | Thay về khoảng trắng thường, gộp nhiều khoảng trắng |
| Không có gì | Ký tự rộng bằng không, ký tự định hướng, gạch nối mềm | Trang web, tệp PDF, tin nhắn | Xoá, trừ khi bài toán cần giữ |
| Dấu nháy, dấu gạch | Nháy cong, nháy thẳng, gạch ngang dài, gạch nối | Phần mềm soạn thảo tự đổi | Thống nhất theo quy ước của dự án |
| Chữ Latin | Chữ Kirin hay Hy Lạp trông giống (a, o, e) | Văn bản lừa lọc từ khoá, lỗi phông | Phát hiện bằng kiểm khối ký tự trong một từ |
Ký tự Kirin hay Hy Lạp lẫn trong chữ Latin không chỉ là lỗi vô tình: trang rác hay dùng để né bộ lọc từ khoá, ví dụ viết từ cấm với chữ "o" Kirin. Kiểm một từ có trộn nhiều khối chữ không là phép lọc rẻ và bắt được nhiều.
Bước 5: viết tắt, không dấu, tiếng lóng — lưu song song, đừng ghi đè
Tiếng Việt trên mạng có cả một hệ viết tắt: "k", "ko", "hok" cho "không"; "đc", "dc" cho "được"; "j" cho "gì"; "ng" cho "người"; "bt" có thể là "bình thường" hoặc "biết" tuỳ câu. Thêm vào đó là văn bản không dấu và cách viết lái, viết kéo dài chữ "điiiii" để nhấn mạnh. Đây là tiếng Việt thật của người dùng, không phải rác.
Có hai lý do không nên ghi đè bản chuẩn hoá lên dữ liệu gốc. Thứ nhất, khôi phục dấu và giải viết tắt đều có lỗi; "bt" đoán sai nghĩa sẽ thành một câu khác hẳn, và lỗi đó trở thành dữ liệu huấn luyện. Thứ hai, mô hình chạy thật sẽ gặp văn bản không dấu, viết tắt; nếu dữ liệu đã bị "làm sạch" hết những thứ đó, mô hình không học được cách đọc chúng.
Cách làm tốt là giữ hai cột: văn bản gốc (chỉ chuẩn hoá Unicode và ký tự lạ) và văn bản chuẩn hoá (thêm dấu, giải viết tắt, gộp chữ kéo dài). Bài toán nào cần bản nào thì dùng bản đó, và có thể huấn luyện mô hình trên cả hai để nó bền với cách viết đời thường. Với danh sách viết tắt, xây theo dữ liệu của chính dự án và ghi rõ trong thẻ dữ liệu, vì viết tắt thay đổi theo nhóm tuổi, nền tảng và thời gian.
Kiểm tra sau chuẩn hoá và những chỗ không được đụng
Sau khi chuẩn hoá, chạy vài phép kiểm: đếm số ký tự khác nhau trong toàn bộ kho (sau chuẩn hoá, con số này phải giảm và ổn định); liệt kê các ký tự ngoài bảng chữ Việt và dấu câu thông thường kèm tần suất để đọc qua; so tần suất các chữ hay bị lỗi như "hoà/hòa", "thuỷ/thủy" để chắc chỉ còn một kiểu. Đọc tay một mẫu ngẫu nhiên là bước không bỏ được.
Có những chỗ không nên chuẩn hoá. Tên riêng, tên thương hiệu, tên người có cách viết riêng phải giữ nguyên, kể cả khi trái quy tắc đặt dấu thông thường. Trích dẫn nguyên văn từ văn bản pháp luật, văn bản cổ, thơ cần giữ đúng như bản gốc. Dữ liệu dành cho bài toán sửa lỗi chính tả thì càng phải giữ lỗi, vì lỗi chính là đầu vào. Ghi các ngoại lệ này vào cấu hình của đường ống, đừng để mỗi người tự xử.
Cuối cùng, lưu phiên bản hàm chuẩn hoá cùng với dữ liệu. Khi quy tắc đặt dấu đổi, phải biết bộ dữ liệu nào đã chạy theo quy tắc cũ, và đầu vào của mô hình nào cần chạy hàm nào.
Chuẩn hoá đứng ở đâu so với tách từ và bộ token
Tiếng Việt viết cách theo âm tiết chứ không theo từ: "học sinh", "máy tính", "trí tuệ nhân tạo" là từ nhiều âm tiết nhưng giữa chúng vẫn có khoảng trắng. Vì thế nhiều công cụ xử lý tiếng Việt có bước tách từ, nối các âm tiết của một từ bằng dấu gạch dưới, như bộ tách từ trong VnCoreNLP mà mô hình PhoBERT dùng để chuẩn bị đầu vào. Bộ tách từ dựa vào từ điển và dữ liệu đã học; chữ "hoà" kiểu dấu khác hay "đ" mã lạ sẽ không khớp từ điển, và từ bị tách sai kéo theo mọi bước sau.
Do đó thứ tự đúng là: chuẩn hoá ký tự trước, tách từ sau. Với mô hình ngôn ngữ dùng bộ token học từ dữ liệu (chia văn bản thành các mảnh dựa trên tần suất), chuẩn hoá càng quan trọng hơn: nếu kho huấn luyện bộ token có hai kiểu đặt dấu, bộ token sẽ tốn chỗ trong từ vựng cho cả hai, và mỗi kiểu lại ít dữ liệu hơn để học. Một bộ token huấn luyện trên dữ liệu đã chuẩn hoá thường biểu diễn tiếng Việt gọn hơn.
Nếu dự án dùng mô hình có sẵn chứ không tự huấn luyện, hãy tìm hiểu mô hình đó được huấn luyện với dạng chuẩn hoá nào và có tách từ không, rồi chuẩn bị dữ liệu tinh chỉnh khớp với dạng đó. Đưa văn bản đã tách từ vào một mô hình vốn học trên văn bản thường, hoặc ngược lại, là lỗi lặng lẽ làm giảm chất lượng mà không báo lỗi nào.
Câu hỏi thường gặp
Nên chuẩn hoá về NFC hay NFD cho tiếng Việt?
NFC là lựa chọn mặc định hợp lý vì mọi chữ Việt đều có mã dựng sẵn, chuỗi gọn và tương thích nhiều công cụ. NFD đôi khi hữu ích khi muốn tách dấu ra để xử lý, ví dụ bỏ dấu, nhưng nên quay về NFC trước khi lưu.
Chuẩn hoá NFC có gộp được "hòa" và "hoà" không?
Không. Hai chữ này đặt dấu trên hai nguyên âm khác nhau nên vẫn là hai chuỗi khác sau NFC. Muốn gộp phải viết quy tắc riêng theo từng vần như oa, oe, uy và áp nhất quán cho cả dữ liệu lẫn đầu vào.
Có nên tự động thêm dấu cho toàn bộ văn bản không dấu?
Nên lưu bản thêm dấu song song, không ghi đè. Công cụ khôi phục dấu có lỗi, nhất là với câu ngắn và từ đa nghĩa, và lỗi đó sẽ thành dữ liệu sai. Giữ bản gốc giúp mô hình học được cả cách viết không dấu của người dùng thật.
Làm sao biết một tệp cũ đang dùng mã TCVN3 hay VNI?
Nhìn tên phông chữ gốc nếu còn (".Vn" cho TCVN3, "VNI-" cho VNI) hoặc thử chuyển theo từng bảng mã rồi đo tỷ lệ âm tiết tiếng Việt hợp lệ. Bảng mã cho tỷ lệ cao nhất thường là bảng đúng.
Có nên đổi "kĩ" thành "kỹ" cho thống nhất không?
Chỉ nên làm ở bản chuẩn hoá phụ dùng cho thống kê hay tìm kiếm. Trong văn bản gốc, gộp i và y máy móc dễ làm sai tên riêng như họ Lý hay tên nước Mỹ. Đây là biến thể chính tả cùng tồn tại, không phải lỗi.
Chuẩn hoá có cần áp cho đầu vào của sản phẩm không?
Có, và phải dùng đúng cùng một hàm với dữ liệu huấn luyện. Nếu không, người dùng gõ bằng bộ gõ sinh dạng tổ hợp hay kiểu dấu khác sẽ đưa vào chuỗi mô hình chưa từng thấy, chất lượng tụt mà khó tìm nguyên nhân.