Chuyển tới nội dung chính

Một từ, nhiều nghĩa, và hàng xóm của nó

Sửa cả từ trung tâm lẫn ngữ liệuBản đồ nhiệt cosinek-means tự cài, không ngẫu nhiên

Một từ, nhiều nghĩa, và hàng xóm của nó

Chữ đường trong con đường và chữ đường trong ly cà phê là cùng một chuỗi ký tự. Máy không có cách nào tách chúng ra nếu chỉ nhìn vào bản thân chữ đó. Nhưng nhìn sang mấy từ đứng cạnh thì mọi thứ sáng ra ngay.

Bài trước biểu diễn cả câu bằng một vector đếm. Bây giờ ta thu nhỏ ống kính lại: thay vì đếm mọi từ trong câu, chỉ đếm những từ nằm trong một cửa sổ quanh một từ được chọn. Kết quả là một vector ngữ cảnh, và nó không mô tả câu nữa, nó mô tả cái chỗ mà từ đó đang đứng.

Ý tưởng phía sau chỉ có một dòng: hai lần xuất hiện của cùng một chữ mà có hàng xóm giống nhau thì nhiều khả năng đang mang cùng một nghĩa. Ngữ liệu mặc định dưới đây có mười câu, mỗi câu chứa chữ đường một lần, năm câu theo nghĩa lối đi và năm câu theo nghĩa chất ngọt. Bạn gán nghĩa thật cho từng câu bằng phần đứng trước dấu gạch đứng, sim không hề dùng nhãn đó để tính toán, nó chỉ dùng để chấm điểm ở cuối.

Một từ, nhiều nghĩa · ngữ cảnh nào tách được chúng
tương phản khối 0.431cụm khớp nghĩa 10/10
Hai nghĩa, mỗi nghĩa năm câu. Hàng xóm của nghĩa lối đi là con, xe, chạy; hàng xóm của nghĩa chất ngọt là cho, thêm, vào. Bản đồ nhiệt phải hiện hai khối sáng nằm trên đường chéo.
cosine trung bình, cùng nghĩa
0.435
20 cặp câu
cosine trung bình, khác nghĩa
0.004
25 cặp câu
tương phản khối
0.431
0.4350.004
cụm khớp nghĩa thật
10/10
46 từ hàng xóm khác nhau
Từng câu: từ trung tâm tô đậm, hàng xóm trong cửa sổ tô nền
#Nghĩa thậtCụm máy chiaCâuSố hàng xóm
1lối điCụm 2con đường này xe chạy suốt ngày rất ồn 5
2lối điCụm 2chiều nay con đường ra biển xe chạy rất đông 7
3lối điCụm 2người ta vừa trải nhựa con đường này nên xe chạy êm 8
4lối điCụm 2mưa lớn làm con đường này ngập nước xe chạy không nổi 8
5lối điCụm 2từ chợ về nhà chỉ một con đường nhỏ xe chạy khó 8
6chất ngọtCụm 1mẹ cho thêm đường vào nồi chè cho ngọt 7
7chất ngọtCụm 1pha phê nhớ cho thêm đường vào cho ngọt 7
8chất ngọtCụm 1bác khuyên cho ít đường vào nước cam cho đỡ ngọt 8
9chất ngọtCụm 1chị ấy thích cho nhiều đường vào ly trà cho thật ngọt 8
10chất ngọtCụm 1bánh này người ta rắc thêm đường lên mặt cho ngọt hơn 8
Bản đồ nhiệt cosine giữa mọi cặp câu · đang xếp thứ tự nhập · hai hàng trên cùng bây giờ là câu 1 với câu 2, cosine 0.507
câu12345678910
1lối đi1.000.510.630.470.470.000.000.000.000.00
2lối đi0.511.000.400.270.400.000.000.000.000.00
3lối đi0.630.401.000.370.370.000.000.000.000.00
4lối đi0.470.270.371.000.250.000.000.110.000.00
5lối đi0.470.400.370.251.000.000.000.000.000.00
6chất ngọt0.000.000.000.000.001.000.670.530.530.35
7chất ngọt0.000.000.000.000.000.671.000.530.530.47
8chất ngọt0.000.000.000.110.000.530.531.000.500.22
9chất ngọt0.000.000.000.000.000.530.530.501.000.22
10chất ngọt0.000.000.000.000.000.350.470.220.221.00
nhạt = 0đậm = 1Mỗi ô làm tròn hai chữ số; rê chuột vào ô để xem ba chữ số. Độ đậm bị chặn ở mức vừa phải để chữ trong ô luôn đọc được ở cả nền sáng lẫn nền tối.
k-means với k bằng 2 đã làm gì
Hạt giống là hai câu xa nhau nhất, tức cặp có cosine nhỏ nhất trong cả bảng: câu 8 câu 2, cosine 0.000. Từ đó thuật toán lặp 2 vòng rồi nhãn đứng yên, chia được 5 câu vào Cụm 1 và 5 câu vào Cụm 2. Không có một lời gọi ngẫu nhiên nào, và đổi thứ tự các dòng trong ô ngữ liệu cũng không đổi cách chia.
CụmSố câuNghĩa chiếm đa số trong cụmCâu khớp với nghĩa đó
Cụm 15chất ngọt5/5
Cụm 25lối đi5/5

Hãy làm bốn việc trong sim, theo thứ tự.

Một: nhìn bản đồ nhiệt ở trạng thái vừa mở. Cửa sổ đang là ±4 từ, tức bốn từ mỗi bên. Bảng cosine hiện lên hai khối sáng nằm gọn trên đường chéo, năm câu đầu một khối và năm câu sau một khối, còn hai góc chéo còn lại thì trắng gần như hoàn toàn. Con số đi kèm: cosine trung bình của các cặp cùng nghĩa là 0.435 trên 20 cặp, của các cặp khác nghĩa là 0.004 trên 25 cặp, chênh nhau 0.431. Cái 0.004 đó không phải làm tròn từ một đám số nhỏ, nó đến từ đúng một cặp duy nhất trong 25 cặp có cosine khác 0: câu 4 và câu 8, cả hai đều có chữ nước rơi vào cửa sổ, cho ra 0.11. Hai mươi bốn cặp còn lại bằng 0 chằn chặn.

Điều đáng chú ý là không câu nào trong nhóm lối đi chung với câu nào một cụm từ dài, chúng chỉ chung mấy từ lẻ như con, xe, chạy. Vậy mà chừng đó đã đủ. Cặp câu 1 và câu 3 chung bốn từ hàng xóm và cho cosine 0.63; cặp câu 6 và câu 7 chung cho hai lần cộng thêmvào, cho 0.67.

Phải nói ngay ở đây, chứ không để tới cuối bài: hai khối đẹp như vậy là vì tôi cố ý viết ngữ liệu như vậy. Mười câu này được dựng sao cho các câu cùng nghĩa dùng lại chung vài từ ngay sát chữ đường, nên tín hiệu mạnh hơn nhiều so với văn bản thật. Trên văn bản thật một chữ đa nghĩa cần hàng nghìn lần xuất hiện mới mong có được bảng sạch cỡ này, và ngay cả khi đó hai khối cũng lem vào nhau nhiều hơn. Hãy đọc bảng dưới như một minh hoạ cho cơ chế, không phải như bằng chứng rằng phương pháp này chạy ngon.

Hai: đổi ô Xếp hàng theo sang theo nghĩa thật rồi sang theo cụm máy chia. Ô này không tính lại gì cả, nó chỉ đổi chỗ ngồi của các hàng và cột. Với ngữ liệu mặc định thì hai cách xếp cho ra cùng một hình, và đó chính là tin tốt: cụm mà máy chia trùng khít với nghĩa mà bạn gán, chỉ số khớp là 10/10. Máy chưa từng nhìn thấy nhãn của bạn.

Cách chia đó do một cài đặt k-means rất gọn làm ra, k bằng 2, viết tay trong engine.ts, không dùng thư viện và không gọi hàm ngẫu nhiên lần nào. Hai hạt giống là cặp câu xa nhau nhất trong bảng, ở đây là câu 8 và câu 2 với cosine 0, rồi lặp hai vòng là nhãn đứng yên. Vì không có ngẫu nhiên nên chạy lại bao nhiêu lần cũng ra một kết quả, và vì thuật toán sắp xếp lại danh sách theo một thứ tự chuẩn trước khi chạy nên đổi thứ tự các dòng trong ô ngữ liệu cũng không đổi cách chia. Bạn thử đảo hai dòng bất kỳ rồi so lại là thấy.

Nhớ giùm một chi tiết ở đây, lát nữa sẽ cần tới. Ngay ở cửa sổ mặc định này thì "cặp xa nhau nhất" đã không phải một cặp duy nhất rồi: có tới 24 cặp cùng bằng 0, và thuật toán chỉ lấy cặp nó gặp đầu tiên. Lần này cặp đó tình cờ là hai câu khác nghĩa nên mọi thứ trơn tru. Đó là may, không phải là bảo đảm.

Ba: kéo cửa sổ về ±1 từ. Bây giờ mỗi câu chỉ còn hai từ hàng xóm. Tương phản khối tăng lên 0.550 và ô cosine trung bình, khác nghĩa về đúng 0.000, nhìn bảng thì hai khối còn sạch hơn cả lúc nãy. Nhưng chỉ số khớp cụm tụt xuống 6/10 và hai cụm chia thành 9 với 1. Đây là chỗ đáng dừng lại lâu nhất trong cả bài.

Chuyện xảy ra như sau, và tôi kể chi tiết vì chỗ này rất dễ giải thích ẩu. Cửa sổ hẹp làm mỗi vector chỉ còn hai chiều, nên bảng cosine đầy số 0: cả 25 cặp khác nghĩa đều bằng 0, cộng thêm 2 cặp cùng nghĩa cũng bằng 0 là câu 8 với câu 10 và câu 9 với câu 10. Tổng cộng 27 trên 45 cặp cùng nằm ở đáy. Lưu ý là chỉ có 2 cặp cùng nghĩa rơi về 0 thôi, không phải phần lớn.

Vấn đề nằm ở chỗ tiếp theo. Khi 27 cặp cùng bằng 0 thì "cặp xa nhau nhất" không còn là một cặp xác định nữa, nó là một thế hoà 27 bên, và người quyết định là luật gỡ hoà mà tôi tự đặt trong engine.ts: lấy cặp nhỏ nhất gặp đầu tiên khi duyệt danh sách đã sắp theo thứ tự chữ cái. Hai câu đứng đầu bảng chữ cái là câu 8 (bác sĩ...) và câu 10 (bánh này...), cặp đầu tiên được duyệt cũng chính là chúng, và cosine của chúng đã bằng 0 rồi nên chúng thắng ngay. Cả hai đều là nghĩa chất ngọt.

Hỏng từ hạt giống thì phần còn lại đổ theo, và đổ một cách khá thảm: đo lại thì 7 trên 10 câu cách đều đúng bằng nhau tới cả hai hạt giống, trong đó cả năm câu lối đi đều có cosine 0 với cả hai. Chúng không được xếp cụm theo dữ liệu, chúng bị luật hoà đẩy hết vào Cụm 1. Chỉ có câu 10 tự ngồi một mình, ra 9 chọi 1.

Đây là chỗ phải nói cho rõ, kẻo bài học bị nhớ sai: 9 chọi 1 là hậu quả của hai quy ước tôi tự chọn, không phải một quy luật của k-means. Bằng chứng: giữ nguyên toàn bộ dữ liệu, chỉ thêm một chữ vào đầu câu 5 ở xa chữ đường nên không vector nào, không ô cosine nào và cả tương phản 0.550 cũng không đổi một chút nào, nhưng câu đó nhảy lên đầu bảng chữ cái nên hạt giống trở thành một cặp khác nghĩa. Kết quả quay lại 5 chọi 510/10 ngay. Ép bất kỳ cặp khác nghĩa nào làm hạt giống cũng cho đúng như vậy. Cấu trúc chưa từng rời khỏi dữ liệu, chỉ là cách khởi tạo của tôi không với tới nó.

Bài học rút ra vẫn còn nguyên giá trị, chỉ cần phát biểu cho đúng cỡ: một chỉ số tổng hợp đẹp lên không bảo đảm việc phía sau nó chạy tốt hơn, phải nhìn cả hai. Và khi bước phía sau hỏng, hãy hỏi xem nó hỏng vì dữ liệu hay vì một quy ước cài đặt của chính mình.

Bốn: bấm đá: ba nghĩa nhưng k vẫn bằng 2. Ngữ liệu này có ba nghĩa thật là hòn đá, nước đá và đá bóng, nhưng thuật toán chỉ được phép chia hai. Nó buộc phải gộp, và nó gộp nhóm hòn đá với nhóm đá bóng thành một cụm bốn câu, để riêng hai câu nước đá. Chỉ số khớp chốt ở 4/6, mức trần cho tình huống này. Không có gì sai trong cài đặt, chỉ là bạn đã hỏi sai câu hỏi: số cụm là thứ bạn đưa vào, không phải thứ thuật toán tìm ra.

Vài chuyện phải nói thẳng, kẻo bài học này bị nhớ to hơn cỡ thật của nó:

  • Túi từ của cửa sổ vứt bỏ thứ tự. Ở cửa sổ mặc định ±4 từ, câu xe chạy trên đường và câu đường chạy trên xe cho ra hai vector ngữ cảnh giống hệt nhau, cùng là xe, chạy, trên mỗi từ một lần, nên cosine bằng đúng 1 dù câu thứ hai chẳng có nghĩa gì. Điều đó đúng từ cửa sổ ±2 trở lên; riêng ở ±1 thì hai câu chỉ còn trênchạy nên chúng lại rơi về 0, một kiểu đúng vì lý do sai. Dù sao thì mọi thông tin về việc từ nào đứng trước từ nào cũng đã bị ném đi ngay bước đầu tiên.
  • Mười câu là quá ít và cụm rất dễ vỡ. Bấm ngữ liệu quá bé nên cụm vỡ để thấy: bốn câu, mỗi câu nói một kiểu, không cặp nào chung hàng xóm, cả bản đồ nhiệt trắng trơn ngoài đường chéo, tương phản khối đúng 0.000, và cách chia 3 với 1 hoàn toàn tuỳ tiện. Nhắc lại điều đã nói ở trên: ngữ liệu mặc định cho khối đẹp là vì tôi cố ý viết những câu có hàng xóm chồng nhau.
  • Vector rỗng là một trường hợp phải định nghĩa, không được để lọt NaN. Câu không chứa từ trung tâm, hoặc chỉ có mỗi từ trung tâm mà không có hàng xóm nào, sẽ có vector rỗng. Vector rỗng không có hướng, nên ở đây quy ước mọi cosine liên quan tới nó bằng 0, kể cả ô nằm trên đường chéo, và câu đó không được xếp vào cụm nào thay vì bị nhét bừa. Xoá bớt chữ trong ô ngữ liệu là thấy sim báo ngay.
  • Vài lựa chọn ở đây là quy ước chứ không phải chân lý. Chọn hạt giống bằng cặp xa nhau nhất, gỡ hoà bằng cách lấy cặp gặp đầu tiên theo thứ tự chữ cái, đẩy câu cách đều hai trọng tâm về Cụm 1, giữ nguyên trọng tâm khi một cụm rỗng: cả bốn đều có thể làm khác đi và cho kết quả khác. Chúng được chọn vì tất định và dễ giải thích, không phải vì tối ưu. Cái 9 chọi 1 ở cửa sổ ±1 là do đúng hai quy ước đầu tiên trong danh sách này gây ra, nên đừng đọc nó thành một tính chất của k-means.

Từ đây tới vector nhúng chỉ còn đúng một bước tư duy. Ở bài này mỗi từ hàng xóm là một chiều riêng, nên xe hơiô tô vẫn là hai chiều không liên quan gì nhau, và hai câu nói cùng một điều bằng hai bộ từ khác nhau vẫn cho cosine 0. Điều người ta làm tiếp theo là ép hàng chục nghìn chiều thưa thớt đó xuống vài trăm chiều đặc, sao cho những từ hay xuất hiện trong cùng loại hàng xóm thì nằm gần nhau. Bản chất tín hiệu vẫn y nguyên là cái bảng bạn đang nhìn, chỉ khác cách nén.

Điều rút ra

Nghĩa của một từ không nằm trong bản thân từ đó mà nằm trong đám từ đứng quanh nó. Đổi cửa sổ là đổi luôn cái mà máy coi là nghĩa, và một cửa sổ cho tương phản đẹp hơn vẫn có thể làm bước gom cụm phía sau hỏng nặng hơn. Cấu trúc có nằm trong dữ liệu là một chuyện, thuật toán có tìm ra nó hay không là chuyện khác.

Câu hỏi tự kiểm0/3 đúngchưa trả lời
  1. 1Ở trạng thái mặc định, cosine trung bình của các cặp cùng nghĩa là 0.435 còn của các cặp khác nghĩa là 0.004. Con số 0.004 nói lên điều gì?
  2. 2Chuyển cửa sổ về ±1 từ. Tương phản khối tăng lên 0.550 nhưng chỉ số khớp cụm tụt xuống 6/10. Cách giải thích nào đúng?
  3. 3Với từ trung tâm là đường và cửa sổ đủ rộng, hai câu xe chạy trên đường và đường chạy trên xe cho ra vector ngữ cảnh như thế nào?