Học biểu diễn ngôn ngữ cho máy tính

word-embeddings

#1

Bài này mình giới thiệu lại một số phương pháp học biểu diễn ngôn ngữ (learning language representation) là Word2Vec. Các phương pháp mới hơn sau này đều có sự cải tiến từ word2vec như FastText, và GloVe. Nội dung bài bao gồm 3 phần: (1) giới thiệu vấn đề, (2) các phương pháp biểu diễn ngôn ngữ, và (3) demo biểu diễn ngôn ngữ tiếng Việt.

I. Vấn đề biểu diễn ngôn ngữ

Có thể nói ngôn ngữ là cái quan trọng nhất khiến con người có thể phát triển vượt bậc hơn so với các động vật khác. Do đó ngôn ngữ là cực kỳ phực tạp. Một đứa trẻ mất ít nhất 2 năm mới bắt đầu có nhận thức và suy nghĩ về ngôn ngữ. Vậy thì làm thế nào mình dạy cho máy tính hiểu ngôn ngữ? - một bài toán không hề đơn giản. Khi nói đến quả táo bạn hình dùng ngay đến đồ ăn, nói đến yêu bạn có thể hình dung ngay đến một nửa của mình. Nghe đã thấy trừu tượng đúng không nào? Rõ ràng để cho máy tính phân biệt được một nửa ở trên là gì, có gì khác so với một nửa trong một nửa quả táo thì đây là vấn đề hóc búa.
Vấn đề đã rõ và một trong những cách biểu diễn hiệu quả cho máy tính hiểu chính là dùng các phương pháp Word2Vec, GloVe, hay mới hơn là FastText để biểu diễn ngôn ngữ. Nhưng chung quy những phương pháp này đều phục vụ cho mục đích learning text representations. Hiện tại phương pháp biểu diễn word embeddings đang chiếm ưu thế và phổ biến hơn cả.

II. Các phương pháp biểu diễn ngôn ngữ

Định nghĩa word embeddings (tạm dịch là tập nhúng từ):

Tập nhúng từ là tên chung cho một tập hợp các mô hình ngôn ngữ và các phương pháp học đặc trưng trong xử lý ngôn ngữ tự nhiên (NLP), nơi các từ hoặc cụm từ từ vựng được ánh xạ tới vectơ số thực. Về mặt khái niệm, nó liên quan đến việc nhúng toán học từ một không gian với một chiều cho mỗi từ vào một không gian vectơ liên tục với kích thước thấp hơn nhiều.

Định nghĩa thì rườm rà nhưng ngắn gọn lại word embeddings (tập nhúng từ) là phương pháp ánh xạ mỗi từ vào một không gian số thực nhiều chiều nhưng có kích thước nhỏ hơn nhiều so với kích thước từ điển. Sau đây chúng ta cùng duyệt qua các phương pháp biểu diễn phổ biến trước thời word embeddings:

1. One-hot encoding (tạm gọi mã hoá số 1):

Đây là cách đơn giản để biểu diễn ngôn ngữ sang dạng vector với số chiều là kích thước từ điển. Giống như tên của nó, chỉ ở chiều mà vị trí một từ xuất hiện trong từ điển có giá trị là 1. Các chiều khác đều có giá trị là 0.
Ví dụ đơn giản khi tập dữ liệu của ta có 3 câu: Câu 1: tôi đang đi tìm một_nửa của mình Câu 2: tôi đã ăn một_nửa quả táo Câu 3: tôi đã đi tìm một_nửa quả táo

Như vậy từ điển V = {tôi_1, đang_2, đi_3, tìm_4, một-nửa_5, của_6, mình_7, đã_8, ăn_9, quả_{10}, táo_{11}} có kích thước S = 11. Biểu diễn theo one-hot thì:
tôi = [1 0 0 0 0 0 0 0 0 0 0]
đang = [0 1 0 0 0 0 0 0 0 0 0]

mình = [0 0 0 0 0 0 1 0 0 0 0]
táo = [0 0 0 0 0 0 0 0 0 0 1]
Cách biểu diễn này rõ ràng là rất đơn giản nhưng giới hạn của nó cũng đã rõ. Chẳng hạn bạn muốn tính độ tương đồng giữa tôimình thì sẽ ra kết quả là 0 (bằng cách dùng cosine similarity). Nhưng trên thực tế chúng ta hiểu tôimình ở ngữ cảnh này đều là một. Thêm nữa, chẳng hạn với bộ dữ liệu 1Terabyte của Google chứa 13 triệu từ (13M) thì chiều của từng vector cũng sẽ là 13M. Cách biểu diễn này rõ ràng là tốn tài nguyên nhưng thông tin mà nó lưu trữ lại không được nhiều như số chiều của nó.

2. Co-occurrence matrix (ma trận đồng xuất hiện):

Từ năm 1957, nhà ngôn ngữ học J.R. Firth [1] đã định nghĩa You shall know a word by the company it keeps (tạm dịch: bạn sẽ hiểu một từ qua các từ đi cùng với nó). Chẳng hạn nói đến Hà_Nội, nếu lúc buồn buồn thì bạn nghĩ đến Hà Lội, rồi khói bụi, hay lúc vui bạn nghĩ tới mùa thu Hà Nội. Hoặc nói đến yêu bạn nghĩ đến người yêu, yêu thích. Ví dụ như hình dưới biểu diễn mối tương quan của từ yêu và các đồng xuất hiện gần nhất của nó:

Hình 1: biểu diễn từ yêu bằng các từ lân cận nó. Nguồn hình ảnh: Xuan-Son Vu

Như vậy rõ ràng là một từ được biểu diễn ngữ nghĩa bởi các từ xung quanh nó. Khi nhắc đến Hà Nội có nhiều bài báo ca ngợi vẻ đẹp của mùa thu Hà Nội nhưng cũng có nhiều bài báo về ngập lụt của Hà Lội. Do đó những từ này phần nào miêu tả thế nào là `Hà Nội.

Ma trận đồng xuất hiện: được đề xuất ở hai mức là mức document (văn bản) và mức windows (cửa sổ từ). Mức văn bản cho thông tin chung về các chủ đề hướng tới các phương pháp LSA (latent semantic analysis). Mức cửa sổ từ cho thông tin về cả chức năng cú pháp của từ và ngữ nghĩa.

57

Hình 2: Ma trận đồng xuất hiện của tập dữ liệu 3 câu ví dụ ở trên với window_size=1. Tức là ma trận đồng xuất hiện chỉ đếm 2 từ liền kề nhau. Nếu tăng window_size=2 thì ma trận này sẽ ghi nhận các từ là đồng xuất hiện với các từ đứng kề bên và cách một từ. Như ví dụ trên, khi tăng window_size=2 thì giá trị giữa từ tôiđi ở ma trận đồng xuất hiện sẽ có giá trị là 2 do tôiđi xuất hiện ở câu 1 và câu 3 và nằm trong khoảng cách window_size=2. Nguồn hình ảnh: Xuan-Son Vu

Cách biểu diễn này hợp lý hơn ở chỗ nó ghi nhận được chính xác thông tin đồng xuất hiện của các từ trong dữ liệu học. Nhưng quay lại vấn đề từ tôi và từ mình thì 2 vectors của chúng như sau: tôi = [0 1 0 0 0 0 2 0 0 0] mình = [0 0 0 0 1 0 0 0 0] Khi tính cosine similarity thì 2 vectors này vẫn cho giá trị là 0. Vấn đề ở đây là do từ tôi và từ mình xuất hiện quá xa nhau nên window_size=1 không thể lưu được thông tin giữa 2 từ này. Muốn lưu được thông tin của 2 từ này hoặc là ta phải có thêm dữ liệu (ví dụ thêm câu tôi mình vốn chẳng giống nhau) hoặc là phải tăng kích thước window_size=6 để lưu thông tin giữa tôimình. Thông thường window_size được đặt là từ 3-10.

Vấn đề của phương pháp: phương pháp này tuy lưu trữ được thông tin nhiều hơn one-hot encoding nhưng vẫn tồn tại ít nhất 2 vấn đề lớn:

  • Chiều của vector tăng theo kích thước từ điển.
  • Cần không gian nhớ lớn để lưu thông tin.
  • Các mô hình phân loại sau đó dựa trên cách biểu diễn này sẽ gặp phải vấn đề biểu diễn thưa (sparsity issues).

Để cải thiện vấn đề trên thì một phương pháp là dùng Singular Value Decomposition (SVD) [2] để giảm số chiều và có biểu diễn cô đọng (dense) hơn. Tuy nhiên SVD có một nhược điểm là chi phí tính toán tăng nhanh theo số chiều matrận O(mn^2) khi (n<m). Thêm nữa phương pháp này cũng gây khó khăn khi thêm dữ liệu mới.

3. Word embeddings (tạm gọi tập nhúng từ)

Do một đống vấn đề của ma trận đồng xuất hiện mà đã có nhiều nghiên cứu hướng theo giải pháp học biểu diễn ở số chiều thấp hơn. Trước thời word2vec đã có các nghiên cứu như bài của nhóm bác Bengio năm 2003 [3]. Nhưng những giải pháp này vẫn gặp vđề về chi phí tính toán. Cho đến năm 2013, nhóm Mikolov giúp giới NLP thở phào với giải pháp mới mang tên word2Vec. Từ thời điểm này hàng loạt bài toán NLP được giải quyết với độ chính xác cao hơn nhiều so với trước.

1. Tổng quát phương pháp

Ý tưởng chính của word2vec là:

  • Thay vì lưu thông tin xuất hiện của các từ bằng cách đếm trực tiếp như ma trận đồng xuất hiện, word2vec học để đoán từ lân cận của tất cả các từ.
  • Các giải pháp sau đó như Glove cũng tương tự word2vec được đề xuất bởi nhóm Pennington năm 2014.
  • Tính toán nhanh hơn và dễ dàng thêm dữ liệu mới vào trong mô hình

Phương pháp:

  1. Đoán các từ lân cận trong cửa số m của mỗi từ 1.1. Với mỗi từ t = 1 \dots T 1.2. Đoán các từ trong cửa sổ bán kính m của tất cả các từ
  2. Hàm mục tiêu (objective function): tối ưu hợp lý hoá cực đại của bất kỳ từ ngữ cảnh (context word) đối với một từ đang xét hiện tại (center word). J(\theta) = -\frac{1}{T}\prod_{t=1}^{T}\prod_{-m \leq j \leq m, j \neq 0} p(w_{t+j}|w_t;\theta)

Các kiến trúc khác nhau: (1) cho ngữ cảnh đoán từ hiện tại (CBoW), và (2) cho từ hiện tại đoán ngữ cảnh (Skip-gram).

Hình 3: hai mô hình cơ bản của word2vec là CBoW và Skip-gram

CBoW:

  • Cho các từ ngữ cảnh
  • Đoán xác suất của một từ đích

Skip-gram:

  • Cho từ đích
  • Đoán xác suất của các từ ngữ cảnh

Nguồn hình ảnh: Mikolov at #mostly.ai/summit

Trong bài báo giới thiệu word2vec [4], Mikolov và cộng sự có so sánh và cho thấy 2 mô hình này cho kết quả tương đối giống nhau.

2. Ưu điểm của word2vec:

2.1. Tốc độ học mô hình:

10

Bảng 1: Bảng so sánh hiệu năng của các mô hình khác nhau. Mô hình CBOW cho kết quả ấn tượng với thời gian học bằng phút thay vì bằng giờ hay tháng như các mô hình trước đây. Tất nhiên đây không phải là những so sánh tuyệt đối công bằng do các mô hình được đánh giá trên các tập dữ liệu khác nhau trên những máy tính có tốc độ xử lý khác nhau. Nhưng phần nào cũng thể hiện được ưu điểm mà word2vec mang lại. Nguồn hình ảnh: Mikolov at #mostly.ai/summit

2.2. Khám phá bất ngờ: directional similarity (hướng của sự tương đồng)

Một kết quả bất ngờ mà Mikolov chỉ ra là các thông tin về hướng của sự tương đồng giữa các từ cũng được lưu lại trong mô hình. Giờ đây bạn có thể tính toán trên biểu diễn của các từ. Ví dụ: vector(vua) + vector(hoàng hậu) = vector(chồng) + vector(vợ).

Hình 4: suy luận ngữ nghĩa với các vector trong mô hình word2vec. Chẳng hạn quan hệ giữa italyrome cũng tương tự với quan hệ giữa franceparis vì 2 quan hệ này đều là quan hệ đất nướcthủ đô. Nguồn hình ảnh: #deeplearn2017

Tương tự các quan hệ ngữ nghĩa khác cũng được thể hiện:

Hình 5: các tháng trong năm xuất hiện gần nhau trong mô hình. Nguồn hình ảnh: #deeplearn2017

Hình 6: các nước và các bang của Mỹ cũng xuất hiện gần nhau trong mô hình. Nguồn hình ảnh: #deeplearn2017

III. Demo bộ word2vecVN

Bộ này do mình train dựa trên tập dữ liệu cung cấp bởi nhóm của anh Lê Hồng Phương và đã mở cho các bạn cùng sử dụng [5]. Rất nhiều bạn đã nói chất lượng bộ này khá tốt, dùng cái accuracy tăng ngay nên nếu bạn chưa thử thì dùng ngay đi nhé :smile:.

Hình 7: các từ lân cận với từ giận trong bộ word2vecVN Nguồn hình ảnh: Xuan-Son Vu

Hình 8: các từ lân cận với từ ghét trong bộ word2vecVN Nguồn hình ảnh: Xuan-Son Vu

Tóm tắt: bài này mình giới thiệu tổng quan các phương pháp học biểu diễn khác nhau cho máy tính hiểu ngôn ngữ tự nhiên. Không như xử lý ảnh, xử lý văn bản có nhiều vấn đề do tính đa hình đa nghĩa của ngôn ngữ. Cho nên sử dụng câu nói một bức ảnh có thể có giá trị hơn cả vạn lời nói xem ra cũng hợp lý để mô tả tính phức tạp của ngôn ngữ so với hình ảnh.

[1] https://en.wikipedia.org/wiki/John_Rupert_Firth [2] https://en.wikipedia.org/wiki/Singular-value_decomposition [3] http://www.jmlr.org/papers/volume3/bengio03a/bengio03a.pdf [4] https://arxiv.org/pdf/1301.3781.pdf [5] https://github.com/sonvx/word2vecVN


[VNLP Core] [2] Thực hành training và sử dụng biểu diễn từ trong không gian - word embedding
[Hỏi] Xây dựng tập dữ liệu training cho n-gram language model phục vụ bài toán tách từ
#2

Quá công phu anh ơi.

Bây giờ thì ai cũng có thể chia sẻ rõ ràng như thế này rồi (y).


#3

hay quá anh Sơn, mình đang học cái word embedding mà giảng tiếng anh, chưa hiểu lắm, đọc lại bài tiếng việt dễ hiểu hơn hẳn. cảm ơn anh nhé


#4

Anh Sơn tiếp tục đi, hóng nè


#5

Hi anh, cảm ơn anh về bài viết, các tập pretrained khác (vd như Word2vec, Fasttext) với tiếng việt người ta có dùng bộ tokenizer để tách tiếng việt không ạ ? và a có nghĩ là cần bô tokenizer ko ? tại em thấy nhiêu trường hợp nó tách vẫn chưa đúng, có thể ảnh hưởng đến kq sau cùng.


#6

Word2vec thì mình chưa thấy cho tiếng Việt (nếu có thì có thể do cộng đồng người Việt mình làm). Còn Fasttext thì theo như trang chủ của họ thì họ dùng công cụ UETsegmenter của người Việt mình nghiên cứu xây dựng để tách từ trước khi tạo word embedding.


#7

Hi em, Các bộ pretrained models như của fastText [1], nếu người ta không dùng tokenizer thì do nguyên nhân chủ yếu là họ muốn dùng kiểu end2end model (cho inputs vào và ra outputs) chứ không phải dùng thêm bất cứ resources hay một bước custom nào khác. Chính vì vậy nên họ mới có thể apply cho hầu hết các ngôn ngữ và cũng vì thế nên chất lượng sẽ không bằng các bộ do cộng đồng của ngôn ngữ đó làm ra (e.g., word2vecVN). Đơn giản như việc fastText được train trên bộ wiki tiếng Việt với vỏn vẹn > 500M text trong khi bộ dữ liệu word2vecVN đc train là từ 7G text :wink:.

Về vấn đề có nên dùng tokenizer không và kết quả tốt hay xấu hơn thì còn phụ thuộc vào mục đích cho bài toán sau đó. Nhìn chung các bài toán NLP cho tiếng Việt thì dùng tokenizer sẽ tốt hơn đối với dữ liệu chuẩn.

[1] https://github.com/facebookresearch/fastText/blob/master/pretrained-vectors.md


#8

Cool, a ko để ý vụ này [1]. Cũng là dùng hàng UET làm ra nên hay quá :smile:.

[1] https://fasttext.cc/docs/en/crawl-vectors.html


#9

Cho hỏi bộ dữ liệu train của anh Lê Hồng Phương làm sao download ? Hình như link đã hỏng.


#10

Cái này bạn liên hệ a Phương để xin nhé.


#12

Có bài viết này sớm thì mình đỡ tốn bao nhiêu công mày mò. Cám ơn tác giả nhiều nhé! Có điều mình xin hỏi thêm là khi mình training mô hình word2vec (cả CBOW và skip-gram) thì có cách nào để cải thiện được 2 từ trái nghĩa với nhau không? (Chẳng hạn, “yêu” và “ghét” hay “tốt” và “xấu”… có thể có vector khá giống nhau sau khi huấn luyện mô hình do chúng chỉ phân biệt các từ ở gần nhau thôi). Mình đang học về sentiment analysis nên cái này khá ảnh hưởng đến việc phân lớp quan điểm của các câu.


#13

Cảm ơn anh về bài giới thiệu rất tổng quát. Em hi vọng sắp tới được đọc những bài của anh về các thuật toán như skip-gram và CBoW hay cách tính giá trị directional similarity cho các từ để tìm sự tương đồng.


#14

Để cải thiện vấn đề này bạn có thể nghĩ cách để embed thêm các thông tin sentiment trong dữ liệu bạn có. Bạn có thể tìm hiểu Paragraph Vector của anh Quoc Le & Mikolov [1]. Tư tưởng chính của phương pháp này là thêm thông tin về paragraph trong lúc học model, và lúc này mục đích sẽ cụ thể hơn đó là predicting words in a paragraph thay vì chỉ predict words. Bài này cũng có đánh giá cho sentiment task và kqua cải thiện khá đáng kể.

[1] https://arxiv.org/pdf/1405.4053.pdf


#15

Skip-gram hay CBoW thì đúng là cần 1 bài khác để viết kỹ hơn vì bài này cũng đã khá dài. Còn về tính giá trị directional similarity thì khá đơn giản. Em chỉ dùng cosine similarity là code ra ngay thôi. E tìm x trong w_1:w_2 = w_3:x => V_x = V_3 - V_1 + V_2. Giả sử e cần tìm x gần nhất cho vua - chồng + hoàng\_hậu.

arg max(cos(x, vua - chồng + hoàng\_hậu)) = arg max_x(cos(x,vua) - cos(x, chồng) + cos(x, hoàng\_hậu)). Tất nhiên cái gần nhất có phải là vợ hay không thì còn phụ thuộc vào dữ liệu học có đủ lớn và lúc train có đủ hội tụ hay không. Như hình 4 trong bài e cũng thấy không phải lúc nào câu trả lời đúng cũng là top 1.


#16

Cảm ơn bài viết của anh, em có câu hỏi là với OOV thì thầy Phương có ghi là “we create random vectors for these words by uniformly sampling from the range [-sqrt(3/dim), sqrt(3/dim)]” là tạo 1 vector cho tất cả các tứ không có hay là mỗi từ một vector ạ? và normalize vector trong pos/tag có hiệu quả không hay là giữ nguyên ạ?


#17

Anh Sơn ơi, Cho em hỏi là anh có thể cho em bộ pre-train word2vecVN để em sử dụng đánh giá cho bài toán của em được không anh. Em có xây dựng xây dựng 1 bộ dữ liệu để huấn luyện domain word2vec. Em muốn xem là với common word2vec có tăng hiệu quả so với domain embedding không anh.


#18

Như này là mỗi 1 từ OOV sẽ có 1 random vector đc sampling trong khoảng [-sqrt(3/dim), sqrt(3/dim)] em nhé. Với các từ OOV thì mỗi người có 1 cách xử lý khác nhau, cách sampling này cũng tốt, hoặc lấy mean của tất cả các vectors. Vđề thứ 2 a ko rõ bài toán nên ko có comment gì.


#19

Đc chứ, em cứ thử thôi. Thường có domain knowledge sẽ tốt hơn với điều kiện có đủ dữ liệu. Nếu dữ liệu nhỏ quá thì ko ăn thua so với pre-trained embeddings e nhé. E cứ so sánh và cũng nên kết hợp 2 embeddings (1 cái từ domain của em và 1 cái pre-trained như word2vecVN).


#20

Dạ thế anh gửi cho em được không anh. Bộ dữ liệu train domain embedding của gồm 3,2 triệu câu, 53tr tokens, 25k vocabulary đã tách từ. Em đã cài được thuật toán CCA, KCCA để combine 2 bộ embedding lại nhưng lại chưa có bộ common word2vecVN chất lượng. Anh có thể cho em xin bộ pre-train của anh để thử nghiệm được không anh.


Lỗi ảnh trên forum
#21

Em xem github (link [5]) ở trên nhé, a có open bộ pretrain này từ lâu rồi.