Series “Học phương pháp cùng Ngẫm” chính thức khởi động chuyên đề mới, tập trung nghiên cứu và hệ thống hóa kiến thức từ tài liệu nền tảng của ngành Xử lý Ngôn ngữ Tự nhiên: “Speech and Language Processing” (Bản thảo lần thứ 3) của hai tác giả Daniel Jurafsky và James H. Martin.
Daniel Jurafsky and James H. Martin. 2025. Speech and Language Processing: An Introduction to Natural Language Processing, Computational Linguistics, and Speech Recognition with Language Models, 3rd edition. Online manuscript released August 24, 2025. https://web.stanford.edu/~jurafsky/slp3.
Trong phần đầu tiên, chúng ta sẽ đi sâu vào một trong những bước cơ bản và quan trọng nhất trong xử lý ngôn ngữ tự nhiên (NLP): tokenization (tách token). Giải thích tại sao việc sử dụng “từ” (word) làm đơn vị xử lý cơ bản lại gặp nhiều vấn đề và giới thiệu các khái niệm để giải quyết những thách thức đó.
Chương bắt đầu bằng một đoạn hội thoại với ELIZA, một trong những chatbot đầu tiên được tạo ra vào những năm 1960. ELIZA hoạt động rất đơn giản: nó sử dụng phương pháp đối sánh mẫu (pattern matching). Ví dụ, khi người dùng nói “Tôi cần X” (I need X), ELIZA sẽ nhận dạng mẫu này và chuyển thành câu trả lời “Điều đó có ý nghĩa gì với bạn nếu bạn nhận được X?” (What would it mean to you if you got X?). Mặc dù rất thô sơ so với các mô hình hiện đại, ELIZA cho thấy ý tưởng cơ bản về việc xử lý văn bản bằng cách nhận dạng các mẫu dựa trên từ. Cách tiếp cận này chính là “tổ tiên” của tokenization – nhiệm vụ tách một đoạn văn bản thành các đơn vị nhỏ hơn gọi là “token”. Tokenization là bước đầu tiên trong mọi hệ thống NLP hiện đại.
Vấn đề cốt lõi: “Từ” (Word) là gì?
Định nghĩa một “từ” phức tạp hơn chúng ta tưởng. Trong câu “Họ đi dã ngoại bên hồ bơi, sau đó nằm dài trên cỏ và ngắm các vì sao.” (They picnicked by the pool, then lay back on the grass and looked at the stars.), có 16 từ nếu không tính dấu câu, và 18 từ nếu tính cả dấu phẩy và dấu chấm. Các mô hình ngôn ngữ lớn thường coi dấu câu là các token riêng biệt vì chúng mang thông tin quan trọng về cấu trúc và ngữ nghĩa (ví dụ: dấu chấm hỏi thay đổi ý nghĩa của cả câu).
Trong giao tiếp thực tế, mọi chuyện còn phức tạp hơn. Phát ngôn (Utterance) là thuật ngữ kỹ thuật chỉ một câu nói trong hội thoại. Sự ngập ngừng/lỗi trôi chảy (Disfluencies) gồm Từ bị ngắt quãng (Fragment): Ví dụ như main- trong câu “I do uh main- mainly business data processing”; Từ đệm (Filled Pauses): Các từ như uh, um. Liệu chúng có phải là “từ” không? Câu trả lời là tùy thuộc vào ứng dụng. Trong nhận dạng giọng nói, các từ đệm như uh, um lại hữu ích vì chúng có thể báo hiệu rằng người nói đang sắp xếp lại suy nghĩ, và do đó chúng thường được giữ lại và coi như những từ bình thường. Loại từ (Word Types) vs. Lần xuất hiện của từ (Word Instances): Đây là một sự phân biệt quan trọng. Loại từ (Types): Là số lượng các từ khác nhau trong một kho ngữ liệu. Nó giống như kích thước của một cuốn từ điển. Lần xuất hiện của từ (Instances): Là tổng số từ đang chạy trong văn bản. Ví dụ, trong câu trên, có 14 loại từ nhưng có 16 lần xuất hiện. Từ “the” xuất hiện 2 lần, “and” xuất hiện 1 lần, v.v. “They” và “they” có nên được coi là cùng một loại từ không? Một lần nữa, câu trả lời là tùy thuộc vào tác vụ. Đôi khi việc viết hoa mang ý nghĩa quan trọng (ví dụ như phân biệt tên riêng), đôi khi thì không.
Khái niệm “từ” được phân tách bằng khoảng trắng chủ yếu đúng với tiếng Anh và các ngôn ngữ châu Âu. Nhiều ngôn ngữ khác không như vậy. Các ngôn ngữ như Trung, Nhật, Thái không dùng khoảng trắng để ngăn cách các từ. Tiếng Trung sử dụng các ký tự (hán tự), mỗi ký tự thường đại diện cho một hình vị (đơn vị ngữ nghĩa nhỏ nhất) và được phát âm thành một âm tiết. Một câu tiếng Trung như 姚明进入总决赛 (Diêu Minh tiến vào vòng chung kết) có thể được phân tách theo nhiều cách:
3 từ: 姚明 (Diêu Minh) | 进入 (tiến vào) | 总决赛 (vòng chung kết). Đây là cách tách phổ biến, coi tên riêng là một đơn vị.
5 từ: 姚 (Diêu) | 明 (Minh) | 进入 (tiến vào) | 总 (tổng) | 决赛 (chung kết). Cách này tách tên riêng và một số thành phần khác.
7 ký tự: 姚 | 明 | 进 | 入 | 总 | 决 | 赛. Coi mỗi ký tự là một đơn vị.
Sự mơ hồ này cho thấy việc sử dụng “từ” làm đơn vị cơ bản là không hiệu quả khi xây dựng các hệ thống NLP đa ngôn ngữ.
Vấn đề thứ hai: Có quá nhiều từ!
Kho ngữ liệu (corpus) càng lớn, số lượng loại từ (từ khác nhau) càng nhiều. Vốn từ vựng dường như phát triển không có giới hạn. Định luật Heaps (Heaps’ Law) là công thức toán học mô tả mối quan hệ này: V = kN^β. Kích thước vốn từ vựng (V) tăng theo tổng số từ trong văn bản (N). Vì số mũ β nhỏ hơn 1, nó không tăng nhanh bằng N, nhưng nó không bao giờ ngừng tăng. Có hai loại từ. Từ chức năng (như a, the, của, là) là một tập hợp hữu hạn. Nhưng từ nội dung (danh từ, động từ, tính từ), đặc biệt là tên riêng và thuật ngữ kỹ thuật, liên tục được tạo ra. Vấn đề về từ chưa biết (unknown words) hoặc từ ngoài vốn từ vựng (out-of-vocabulary – OOV). Bất kể mô hình của bạn được huấn luyện trên bao nhiêu dữ liệu, nó sẽ luôn gặp phải những từ mới mà nó chưa từng thấy. Đây là một vấn đề cực kỳ lớn đối với các mô hình học máy.
Do hai vấn đề lớn: (1) khó định nghĩa “từ” một cách nhất quán giữa các ngôn ngữ và (2) số lượng từ là vô hạn, các mô hình NLP hiện đại không sử dụng “từ” làm đơn vị xử lý. Thay vào đó, chúng sử dụng các đơn vị nhỏ hơn gọi là subwords (từ con). Các “từ con” này có thể được kết hợp lại để tạo thành các từ đã biết và quan trọng hơn là để biểu diễn các từ mới mà mô hình chưa từng gặp.
Hình vị (Morphemes): Các thành phần của từ
Để hiểu về “từ con”, chúng ta đi sâu vào Hình vị (Morphemes) – Các phần nhỏ nhất của từ có mang ý nghĩa (ví dụ, trong từ longer có hình vị long và -er).
Từ không chỉ được cấu tạo từ các ký tự, mà còn từ các đơn vị nhỏ hơn có mang ý nghĩa. Hình vị (Morpheme): Là đơn vị mang ý nghĩa nhỏ nhất trong một ngôn ngữ. Ví dụ: Từ fox (con cáo) chỉ có một hình vị là fox. Nhưng từ cats (những con mèo) có hai hình vị: cat (con mèo) và -s (chỉ số nhiều). Hình thái học (Morphology): Là ngành ngôn ngữ học nghiên cứu về các hình vị và cách chúng kết hợp với nhau để tạo thành từ.
Các loại hình vị:
Thân từ/Gốc từ (Root): Là hình vị trung tâm của từ, mang ý nghĩa chính. Ví dụ: work trong worked, glass trong glasses.
Phụ tố (Affix): Là hình vị được thêm vào gốc từ để bổ sung ý nghĩa. Có hai loại chính: Hình vị biến tố (Inflectional Morphemes): Thường mang ý nghĩa ngữ pháp, có tính hệ thống và dễ dự đoán. Chúng không tạo ra từ mới mà chỉ biến đổi dạng của từ. Ví dụ trong tiếng Anh: phụ tố -s thêm vào danh từ để chỉ số nhiều (cat -> cats), phụ tố -ed thêm vào động từ để chỉ thì quá khứ (work -> worked). Hình vị phái sinh (Derivational Morphemes): Dùng để tạo ra các từ mới, thường là thay đổi cả loại từ (danh từ, động từ, tính từ). Ý nghĩa của chúng thường khó đoán hơn. Ví dụ: Gốc từ care (sự quan tâm – danh từ) + phụ tố -ful → careful (cẩn thận – tính từ) + phụ tố -ly → carefully (một cách cẩn thận – trạng từ).
Từ phụ/Từ tựa (Clitic): Là một hình vị hoạt động như một từ về mặt cú pháp nhưng lại bị rút gọn về hình thức và phải dính vào một từ khác. Ví dụ: ‘ve trong I’ve (viết tắt của I have). Nó mang nghĩa của từ have nhưng không thể đứng một mình. Hoặc sở hữu cách ‘s trong the teacher’s book.
Ngôn ngữ trên thế giới có cấu trúc từ rất khác nhau.
Số lượng hình vị trên mỗi từ:
Ngôn ngữ đơn lập (Isolating Languages): Các từ thường chỉ có một hình vị. Tiếng Việt là một ví dụ điển hình. Câu ví dụ trong sách dùng tiếng Quảng Đông cũng tương tự: mỗi từ là một hình vị, một âm tiết.
Ngôn ngữ tổng hợp (Synthetic Languages) và Đa tổng hợp (Polysynthetic Languages): Một từ có thể được cấu tạo từ rất nhiều hình vị, đôi khi tương đương với cả một câu trong tiếng Anh. Ví dụ về tiếng Koryak cho thấy một từ duy nhất có thể mang nghĩa: “Tôi đã may rất nhiều tấm phủ lều yurt vào giữa đêm.”
Mức độ dễ dàng tách bạch các hình vị:
Ngôn ngữ chắp dính (Agglutinative Languages): Các hình vị được “dán” vào nhau một cách rõ ràng, ranh giới giữa chúng rất dễ nhận biết (giống như các hạt được xâu chuỗi lại). Tiếng Thổ Nhĩ Kỳ là một ví dụ.
Ngôn ngữ hòa kết (Fusion Languages): Ranh giới giữa các hình vị bị mờ đi. Một phụ tố duy nhất có thể “hòa trộn” hoặc “kết hợp” nhiều ý nghĩa ngữ pháp khác nhau. Ví dụ, trong tiếng Anh, đuôi -s của động từ reads (trong câu She reads) vừa mang nghĩa “ngôi thứ ba số ít” vừa mang nghĩa “thì hiện tại”. Không thể tách bạch hai ý nghĩa này ra thành các phần riêng biệt của chữ -s.
Do sự đa dạng và phức tạp trong cách các ngôn ngữ cấu tạo từ, việc định nghĩa và tách các hình vị một cách nhất quán trên toàn cầu là vô cùng khó khăn. Điều này làm cho “hình vị” cũng không phải là một đơn vị lý tưởng để làm chuẩn cho tokenization.
Unicode
Sau khi chỉ ra các vấn đề của “từ” và “hình vị”, phần này chuyển sang đơn vị nhỏ hơn và cơ bản hơn: ký tự (character). Nó giải thích cách máy tính biểu diễn tất cả các ký tự trên thế giới thông qua tiêu chuẩn Unicode.
ASCII
ASCII (American Standard Code for Information Interchange): Là một bộ mã cũ, chỉ dành cho tiếng Anh. Nó dùng 1 byte (thực tế chỉ 7 bit) để biểu diễn 127 ký tự (chữ cái, số, dấu câu trong tiếng Anh). SCII hoàn toàn không đủ để biểu diễn các ký tự có dấu (như ñ trong tiếng Tây Ban Nha) hoặc các hệ thống chữ viết hoàn toàn khác (như chữ Devanagari của Ấn Độ, chữ Hán của Trung Quốc).
Unicode
Unicode ra đời để giải quyết vấn đề của ASCII. Nó là một tiêu chuẩn gán một mã định danh duy nhất cho mọi ký tự trong mọi hệ thống chữ viết trên thế giới (hơn 150.000 ký tự, bao gồm cả các ngôn ngữ cổ, biểu tượng cảm xúc, ký hiệu toán học, v.v.). Điểm mã (Code Point) là một con số định danh duy nhất, mang tính trừu tượng, được gán cho mỗi ký tự. Nó thường được viết dưới dạng thập lục phân (hex) với tiền tố U+. Ví dụ: U+0061 là điểm mã cho ký tự a. U+1F600 là điểm mã cho biểu tượng cảm xúc mặt cười toe toét (). Hình tự (Glyph) là hình ảnh trực quan của một ký tự. Một điểm mã có thể có nhiều hình tự khác nhau. Ví dụ, điểm mã U+0061 có thể được hiển thị là a (in đậm), a (in nghiêng), hoặc a (font Courier). Font chữ là thứ quyết định hình tự trông như thế nào.
Mã hóa (Encoding)
Điểm mã là một con số trừu tượng. Để lưu trữ văn bản trong một tệp tin, chúng ta cần một phương pháp để biểu diễn các điểm mã này dưới dạng một chuỗi các byte. Quá trình này gọi là mã hóa (encoding). Có hơn 1 triệu điểm mã có thể có, nên cần nhiều hơn 1 byte để biểu diễn. Một cách đơn giản là dùng 4 byte cho mỗi ký tự (gọi là UTF-32), nhưng cách này rất lãng phí dung lượng và không tương thích ngược với các hệ thống cũ. UTF-8 (Unicode Transformation Format 8) là phương pháp mã hóa phổ biến nhất hiện nay (hầu như toàn bộ web sử dụng UTF-8). Mã hóa có độ dài thay đổi (variable-length encoding). Các ký tự ASCII (127 ký tự đầu tiên) chỉ dùng 1 byte. Điều này giúp nó tương thích hoàn toàn với ASCII. Các ký tự phổ biến khác (như chữ cái có dấu ở châu Âu) dùng 2 byte. Hầu hết các ký tự Trung, Nhật, Hàn (CJK) dùng 3 byte. Các ký tự hiếm hơn và biểu tượng cảm xúc dùng 4 byte. Ưu điểm của UTF-8 gồm việc rất hiệu quả về dung lượng, tương thích ngược với ASCII, và có cấu trúc thông minh giúp dễ dàng xác định điểm bắt đầu của một ký tự ngay cả khi dữ liệu bị lỗi. Kể từ Python 3, các chuỗi (string) trong bộ nhớ được lưu trữ dưới dạng một chuỗi các điểm mã Unicode. Khi bạn đọc/ghi tệp, bạn cần chỉ định một phương pháp mã hóa, và UTF-8 là lựa chọn mặc định và tốt nhất trong hầu hết các trường hợp.
Tokenization bằng từ con (Subword Tokenization): Byte-Pair Encoding (BPE)
Thay vì cố gắng định nghĩa một đơn vị hoàn hảo về mặt ngôn ngữ học, chúng ta sẽ sử dụng một cách tiếp cận dựa trên dữ liệu (data-driven) để tự động “học” ra một bộ token tối ưu. Các token này thường là các từ con (subwords).
Tại sao cần Tokenization?
Tiêu chuẩn hóa: Nó biến đổi một văn bản đầu vào thành một tập hợp các đơn vị cố định và xác định. Điều này rất quan trọng để đảm bảo các thí nghiệm NLP có thể được tái tạo và các thuật toán khác nhau có thể thống nhất về các câu hỏi cơ bản như: “Văn bản này dài bao nhiêu token?”.
Giải quyết vấn đề “Từ chưa biết” (Unknown Word): Các mô hình học máy học từ một kho dữ liệu huấn luyện. Nếu một từ xuất hiện trong dữ liệu kiểm tra nhưng chưa từng có trong dữ liệu huấn luyện (ví dụ: từ lower), mô hình sẽ không biết phải làm gì với nó. Giải pháp của Subword: Bằng cách sử dụng các token nhỏ hơn từ (từ con), chúng ta có thể biểu diễn bất kỳ từ mới nào dưới dạng một chuỗi các “từ con” đã biết. Ví dụ, nếu mô hình chưa từng thấy từ lower nhưng đã thấy low và er trong quá trình huấn luyện, nó có thể tách lower thành low + er. Trong trường hợp tệ nhất, một từ rất lạ có thể được tách thành từng ký tự riêng lẻ.
Thuật toán Byte-Pair Encoding (BPE)
BPE là một trong những thuật toán phổ biến nhất để tạo ra bộ từ vựng subword. Nó có hai phần: huấn luyện (trainer) và mã hóa (encoder).
Huấn luyện BPE (BPE Training)
Quá trình huấn luyện BPE hoạt động bằng cách liên tục hợp nhất các cặp token kề nhau xuất hiện thường xuyên nhất.
Các bước hoạt động:
Khởi tạo: Bắt đầu với một bộ từ vựng chỉ bao gồm tất cả các ký tự riêng lẻ có trong kho dữ liệu.
Lặp lại: a. Tìm cặp token kề nhau xuất hiện nhiều nhất trong toàn bộ kho dữ liệu. b. Hợp nhất cặp này thành một token mới. c. Thêm token mới này vào bộ từ vựng. d. Thay thế tất cả các lần xuất hiện của cặp token đó trong kho dữ liệu bằng token mới vừa được hợp nhất.
Dừng lại: Quá trình này lặp lại một số lần định trước (k lần), với k là một tham số của thuật toán (ví dụ: 30,000 lần hợp nhất để tạo ra bộ từ vựng khoảng 30,000 token).
Ví dụ thực tế:
Hãy xem ví dụ trong sách với một kho dữ liệu nhỏ: set new new renew reset renew.
Bước 1: Chuẩn bị: Tách corpus thành các “từ” (dựa trên khoảng trắng) và đếm tần suất. Việc hợp nhất sẽ chỉ diễn ra bên trong các từ này, không vượt qua ranh giới khoảng trắng.
Cặp kề nhau phổ biến nhất là n và e (xuất hiện 2 lần trong new và 2 lần trong renew, tổng cộng 4 lần).
Hợp nhất n + e -> ne.
Từ vựng mới: {e, n, r, s, t, w, ne}
Bước 3: Hợp nhất lần 2:
Bây giờ, cặp phổ biến nhất là ne và w (xuất hiện 4 lần).
Hợp nhất ne + w -> new.
Từ vựng mới: {…, ne, new}
Các bước tiếp theo: Quá trình tiếp tục, ví dụ như hợp nhất r + e -> re, sau đó re + new -> renew, s + e -> se, se + t -> set.
Kết quả: Sau nhiều lần hợp nhất, bộ từ vựng sẽ chứa các ký tự gốc, các hình vị phổ biến (re-), và các từ nguyên vẹn (new, set, renew).
Mã hóa BPE (BPE Encoder)
Sau khi đã “học” xong bộ từ vựng và một danh sách các quy tắc hợp nhất theo thứ tự, bộ mã hóa sẽ sử dụng chúng để token hóa một câu mới (câu kiểm tra).
Cơ chế: Nó hoạt động một cách tham lam (greedily). Tức là nó sẽ áp dụng các quy tắc hợp nhất đã học, theo đúng thứ tự mà chúng được học, lên câu mới. Nó không quan tâm đến tần suất xuất hiện trong câu mới, chỉ tuân theo các quy tắc từ corpus huấn luyện.
Ví dụ: Với một từ mới như revisit, nó sẽ áp dụng quy tắc hợp nhất r+e->re nếu quy tắc đó đã được học.
BPE trong thực tế
Xử lý Unicode: Thay vì chạy trên các ký tự Unicode, BPE thường được chạy trên từng byte của văn bản đã được mã hóa theo chuẩn UTF-8. Điều này đảm bảo không bao giờ có “ký tự” chưa biết (vì chỉ có 256 byte khả dĩ).
Ví dụ từ GPT-4o:
Sách minh họa bằng một công cụ trực quan cho thấy tokenizer của GPT-4o hoạt động như thế nào.
Hầu hết các từ thông dụng là một token duy nhất (thường bao gồm cả khoảng trắng ở đầu). Các từ hiếm hoặc từ ghép bị tách ra. Các từ phụ như ‘s có thể bị tách ra (Jane’s -> Jane + ‘s) hoặc không (shes là một token). Cách viết hoa cũng ảnh hưởng đến kết quả tokenization (Anyhow bị tách, trong khi anyhow thì không).
Tiền-token hóa (Pretokenization): Trước khi áp dụng BPE, văn bản thường được xử lý sơ bộ bằng các biểu thức chính quy (regular expressions) để tách tại các khoảng trắng, dấu câu, và xử lý các trường hợp đặc biệt như số.
SuperBPE: Một biến thể nâng cao cho phép hợp nhất token vượt qua cả ranh giới khoảng trắng ở giai đoạn thứ hai, tạo ra các token đa từ (superword tokens) hiệu quả hơn.
Vấn đề với đa ngôn ngữ:
Gốc rễ vấn đề: Dữ liệu huấn luyện của các mô hình lớn chủ yếu là tiếng Anh. Do đó, trong quá trình huấn luyện BPE, hầu hết các “suất” token (ví dụ 50,000 token) được dành để biểu diễn các từ và hình vị tiếng Anh một cách hiệu quả.
Hệ quả: Các ngôn ngữ khác có ít “suất” token hơn, dẫn đến việc từ của các ngôn ngữ đó bị phân mảnh quá mức (oversegmenting).
Ví dụ minh họa: Sách so sánh một câu tiếng Anh và bản dịch tiếng Tây Ban Nha. Câu tiếng Anh (14 từ) được mã hóa thành 18 token (hầu hết các từ là 1 token). Trong khi đó, câu tiếng Tây Ban Nha (16 từ) bị chia nhỏ thành 33 token. Nhiều từ cơ bản như hondo (sâu) bị tách thành h + ondo.
Tác động tiêu cực: Việc phân mảnh này làm cho việc biểu diễn ngữ nghĩa trở nên kém hiệu quả, đòi hỏi mô hình phải xử lý các chuỗi dài hơn, và làm tăng chi phí tính toán khi huấn luyện và suy luận.
Tóm lại, phần này đã chỉ ra rằng việc sử dụng “từ” làm đơn vị xử lý cơ bản là không hiệu quả do sự mơ hồ trong định nghĩa và vấn đề từ vựng vô hạn. Giải pháp hiện đại là tokenization bằng “từ con” (subword) dựa trên dữ liệu, mà tiêu biểu là thuật toán Byte-Pair Encoding (BPE). BPE tự động học một bộ từ vựng gồm các mảnh từ phổ biến, cho phép biểu diễn linh hoạt mọi chuỗi văn bản, giải quyết triệt để vấn đề từ chưa biết (unknown words) và trở thành nền tảng cho các mô hình ngôn ngữ lớn ngày nay.
Trong các phần tiếp theo, chúng ta sẽ khám phá các công cụ và khái niệm bổ trợ quan trọng cho quá trình tokenization và xử lý văn bản. Cụ thể, chúng ta sẽ bắt đầu với Tokenization dựa trên quy tắc (Rule-based tokenization), sau đó tìm hiểu về Kho ngữ liệu (Corpora) – nguồn dữ liệu thô cho mọi tác vụ, tiếp đến là công cụ cực kỳ mạnh mẽ Biểu thức chính quy (Regular Expressions), và cuối cùng là các Công cụ Unix đơn giản để Tokenization từ (Simple Unix Tools for Word Tokenization).