Dự đoán next-token: embeddings và ý nghĩa của perplexity
Huấn luyện mô hình ký tự trên 32.033 tên, xem gradient descent tái tạo bảng đếm, rồi hiểu vì sao perplexity hiếm khi khớp.
Trên trang này
Đây là mười cái tên do một chương trình chưa từng thấy một từ nào tạo ra:
cexze momakurailezitynn konimittain llayn ka
da moliellavo emia sade ftlspKhông cái nào là tên thật. Nhưng gần như tất cả đều đang cố gắng. Chúng có thể phát âm được, kết thúc ở nơi tên thường kết thúc, và một cái — emia — chỉ cách một tên thật đúng một chữ cái. Chương trình tạo ra chúng nắm 729 con số, không có khái niệm về từ, âm tiết hay con người, và được fit chỉ bằng một lượt đếm các cặp chữ cái kề nhau.
Đến cuối chương này, một mạng neural sẽ cắt một phần ba điểm số của chương trình đó trên cùng phép đo. Phần đáng ở lại là điều mạng làm trước tiên: nó tự tái tạo bảng đếm đến ba chữ số thập phân trên mọi hàng có đủ dữ liệu, không cần prompt, vì hai đối tượng này là câu trả lời cho cùng một câu hỏi. Mọi thứ sau đó là những gì việc đếm không bao giờ làm được.
Mục tiêu là một đẳng thức, không phải lựa chọn thiết kế
Liên kết đến mục: Mục tiêu là một đẳng thức, không phải lựa chọn thiết kếChương 7 để lại cho bạn một chuỗi số nguyên và không có lý do nào để số này đi sau số kia. Đây là lý do, và nó nằm trong một dòng của Chương 2.
Một mô hình ngôn ngữ là một hàm nhận các token cho đến hiện tại và trả về một phân phối trên token sẽ xuất hiện tiếp theo: một con số cho mỗi mục trong từ vựng, không âm, tổng bằng một. Không gì khác. Để đi từ đó đến xác suất cho toàn bộ tài liệu, áp dụng quy tắc dây chuyền của xác suất:
Đó là một đẳng thức, đúng với mọi chuỗi của bất cứ thứ gì, không kèm giả định nào. Vì vậy một mô hình làm được việc nhỏ — next token khi biết những token trước đó — đã làm xong việc lớn là gán xác suất cho mọi tài liệu có thể có, chính xác và miễn phí. Cách diễn giải phổ biến rằng đây là một mẹo rẻ tiền (“nó chỉ dự đoán từ tiếp theo”) đã hiểu ngược logic: dự đoán next token chính là mô hình hóa phân phối chung. Chưa bao giờ có việc thứ hai cần làm.
Loss cũng đi theo một cách cơ học như vậy. Ở mỗi vị trí, mô hình tạo ra một phân phối và sự thật là một token đã biết duy nhất, nên entropy chéo của Chương 4 được áp dụng nguyên vẹn:
Đó là negative log-likelihood trung bình — công thức của Chương 2 với một phân phối categorical ở vị trí trước đó là Gaussian. Và vì phân phối thật là one-hot, entropy của nó bằng không, nên theo đẳng thức của Chương 4, entropy chéo bằng KL divergence: kéo con số này xuống và kéo niềm tin của mô hình về phía dữ liệu là cùng một hành động.
Một hệ quả xứng đáng có câu riêng, vì nó là sự thật kinh tế nằm dưới toàn bộ lĩnh vực. Nhãn chính là dữ liệu, dịch đi một vị trí. Không ai annotate gì cả. Một nghìn tỷ token văn bản là một nghìn tỷ ví dụ đã được gắn nhãn sẵn, đó là lý do corpus huấn luyện của một mô hình hiện đại là “internet” chứ không phải “một dataset do ai đó xây dựng”.
Baseline trung thực: đếm
Liên kết đến mục: Baseline trung thực: đếmTrước mọi mạng neural, hãy có baseline: 32.033 tên, mỗi dòng một tên, và nhiệm vụ tạo thêm tên mới, từng chữ cái một.1
Từ vựng gồm 26 chữ cái cộng với một ký hiệu biên . đánh dấu cả đầu và cuối của một tên, nên mô hình phải học tên bắt đầu ở đâu và dừng ở đâu. Có 27 ký hiệu, và mô hình nhỏ nhất có thể là một bảng đếm xem mỗi ký hiệu đã đi sau mỗi ký hiệu khác bao nhiêu lần.
N = torch.zeros((27, 27), dtype=torch.int32)
for w in words:
cs = ["."] + list(w) + ["."]
for a, b in zip(cs, cs[1:]):
N[stoi[a], stoi[b]] += 1
P = N.float()
P = P / P.sum(1, keepdim=True) # one distribution per row Hai dòng số học là mô hình đã được fit — và đây không phải heuristic: chia số đếm cho tổng từng hàng là ước lượng maximum-likelihood cho một phân phối categorical, tức công thức của Chương 2 với phần giải tích đã làm xong.
names: 32033 train/val/test: 25626 / 3203 / 3204
training bigrams: 182583
the six most likely letters after 'a':
a -> '.' 0.1944 a -> 'n' 0.1600 a -> 'r' 0.0967
a -> 'l' 0.0749 a -> 'h' 0.0690 a -> 'y' 0.0606Lấy mẫu từ nó — chọn một chữ cái từ hàng của chữ cái hiện tại, chuyển sang hàng đó, lặp lại đến khi ký hiệu biên xuất hiện — và bạn nhận được các tên ở đầu chương này. Chúng thất bại theo một cách cụ thể và nhiều thông tin: hợp lý cục bộ, vô nghĩa toàn cục. Mọi cặp chữ cái kề nhau trong momakurailezitynn đều là một cặp xuất hiện trong tên thật; chỉ là có đến mười bảy cặp như vậy nối tiếp nhau. Mô hình chỉ có bộ nhớ một chữ cái, nên nó không thể biết mình đã kéo dài quá lâu.
Perplexity, và cách đọc nó
Liên kết đến mục: Perplexity, và cách đọc nóLoss trên tập tên held-out là 2,4546 nats. Bản thân con số đó không nói lên gì nhiều, đó là lý do perplexity tồn tại:
Viết tường minh, không để thư viện làm thay:
@torch.no_grad()
def perplexity(logits, Y):
logp = F.log_softmax(logits, dim=1) # log q for every symbol
chosen = logp[torch.arange(len(Y)), Y] # log q of the one that came next
return torch.exp(-chosen.mean()) Lấy hàm mũ đảo ngược logarit và đưa con số trở về đơn vị của việc đếm các lựa chọn. Cách rõ nhất để thấy nó đếm gì là đo một mô hình hoàn toàn không biết gì — một mô hình gán xác suất cho mọi ký hiệu bất kể context:
uniform over 27 symbols loss 3.2958 nats ppl 27.000
bigram counts, add-one smoothed loss 2.4546 nats ppl 11.642Chính xác 27,000, vì . Perplexity là số lượng hiệu dụng các lựa chọn có xác suất ngang nhau mà mô hình đang phải chọn giữa. Perplexity bằng 27 nghĩa là “không biết gì, có thể là bất cứ thứ gì”. Con số 11,642 của mô hình đếm nghĩa là một chữ cái context khiến nó còn bất định tương đương một người nhắm mắt chọn từ khoảng mười hai lựa chọn thay vì hai mươi bảy — đó là lý do người ta trích perplexity chứ không trích raw loss.
Có hai điều hay hỏng với nó, và điều thứ hai hỏng cả trong các bài báo đã xuất bản.
Xác suất bằng không là chí mạng. Trong 729 ô của bảng, 113 ô không bao giờ xuất hiện khi huấn luyện — 15,5 % bảng trống. Điều đó ổn cho đến khi tập held-out rơi vào một ô như vậy, và bảy bigram trong validation đã làm thế, trong đó có d→q, z→j và q→o hai lần. Xác suất bằng không nghĩa là log , tức loss vô hạn và perplexity vô hạn: một tên trong ba nghìn tên phá hỏng metric. Miếng vá thường dùng là cộng 1 vào mọi số đếm trước khi chuẩn hóa, và ở đây chi phí gần như bằng không (2,4546 thay vì 2,4524). Nhưng miếng vá là một lời thú nhận. Một mô hình đếm hoàn toàn không thể generalise. Nó không có cách nào nghi ngờ rằng q→o là hợp lý vì q→u rất phổ biến và o hành xử giống u ở nơi khác, vì nó không có khái niệm rằng hai ký hiệu có thể giống nhau. Mỗi ô được học riêng lẻ, và sửa điều đó là mục tiêu của phần còn lại trong chương này.
Perplexity là giá trên mỗi token, và token là một tham số tự do. Đây là lỗi xuất hiện liên tục khi so sánh các mô hình, và rất dễ thấy khi bạn nhìn vào. Lấy cùng corpus văn xuôi tiếng Anh từ Chương 7, cùng mô hình bigram nội suy, và chỉ thay đổi cách cắt văn bản:
| đơn vị | từ vựng | tokens trong test | entropy chéo | perplexity | bits trên mỗi ký tự |
|---|---|---|---|---|---|
| ký tự | 76 | 14.469 | 2,5217 | 12,45 | 3,6378 |
| BPE, 512 merges | 329 | 6.871 | 3,8547 | 47,21 | 2,6407 |
| BPE, 2.048 merges | 1.820 | 4.233 | 5,7468 | 313,20 | 2,4254 |
| từ | 2.991 | 6.284 | 3,5627 | 35,26 | 2,2322 |
Perplexity thay đổi 25 lần giữa các hàng đó. Không có gì về mô hình thay đổi; chỉ kích thước của thứ đang được dự đoán thay đổi. Dự đoán cả một từ khó hơn dự đoán một chữ cái, nên chi phí trên mỗi lần dự đoán cao hơn — và có ít lần dự đoán hơn.
Giờ đọc cột cuối, cột chia tổng chi phí cho số ký tự thay vào đó và đổi sang bits. Nó đảo lại bảng. Theo perplexity, thứ hạng là ký tự, từ, BPE-512, BPE-2048; theo bits trên mỗi ký tự, thứ hạng là từ, BPE-2048, BPE-512, ký tự. Mô hình ký tự đi từ hạng nhất xuống hạng chót. Mô hình 2.048-merge, theo perplexity trông tệ hơn mô hình 512-merge 6,6 lần, thực ra là mô hình tốt hơn trong hai cái: 2,4254 bits so với 2,6407.
Vì vậy một perplexity chỉ so sánh được giữa hai mô hình dùng chung tokenizer, và các mô hình có tokenizer khác nhau chỉ có thể so sánh bằng bits trên mỗi ký tự — đại lượng Shannon đo năm 1951 bằng cách cho người tham gia đoán chữ cái tiếp theo của văn bản tiếng Anh, và chặn trên xấp xỉ một bit trên mỗi ký tự.2 Bigram tốt nhất của chúng ta ở mức 2,23 bits, một tóm tắt khá công bằng về quãng đường chương này còn phải đi.
Cùng một thứ, được học
Liên kết đến mục: Cùng một thứ, được họcGiờ hãy xây cùng mô hình đó như một mạng. Nó sẽ cần nhiều phép tính hơn vài bậc độ lớn để đi đến cùng một nơi, và việc đi đến cùng một nơi chính là điểm cần thấy.
Thay bảng bằng một ma trận trọng số có shape . Biến chữ cái hiện tại thành vector one-hot, nhân, và gọi kết quả là logits — các điểm số chưa chuẩn hóa từ Chương 4. Rồi softmax, rồi entropy chéo, rồi gradient descent.
W = torch.randn((27, 27), requires_grad=True)
for step in range(3000):
logits = W[xs]
loss = F.cross_entropy(logits, ys)
W.grad = None
loss.backward()
W.data -= 50.0 * W.gradDòng được nhấn mạnh chứa một định nghĩa đáng giữ lại. Nhân một vector one-hot với một ma trận sẽ chọn một hàng của ma trận đó, nên phép nhân là một lookup — và mọi implementation đều bỏ qua phép tính số học để lookup trực tiếp, đó là W[xs].
Đó là một embedding table. Một ma trận có một hàng cho mỗi mục từ vựng, được index bằng token id. Không hình học, không ngữ nghĩa, không thuật toán riêng: một lookup table mà nội dung tình cờ được học bằng gradient descent cùng với mọi thứ khác. Mọi tuyên bố huyền bí về “embedding space” đều chạm đáy ở đây.
Huấn luyện nó và xem nó đi về đâu:
step 1 train 3.7550 val 3.3882 max gap to the count table 0.757269
step 100 train 2.4732 val 2.4726 max gap to the count table 0.388354
step 1000 train 2.4557 val 2.4549 max gap to the count table 0.041862
step 3000 train 2.4547 val 2.4544 max gap to the count table 0.004048Cột cuối là sai khác tuyệt đối lớn nhất giữa bất kỳ ô nào của softmax(W) và ô tương ứng trong bảng đếm, và nó tiến về không. Sau 3.000 bước, bất đồng lớn nhất ở bất kỳ đâu trong 729 ô là 0,004048 và trung bình là 0,000224. Ô tệ nhất là q→i, chỉ thấy mười hai lần trong toàn bộ tập huấn luyện; trong 22 hàng có hơn một nghìn lần xuất hiện, bất đồng tệ nhất là 0,000562.
count table network
a -> '.' 0.1945 0.1945
a -> 'n' 0.1601 0.1601
a -> 'r' 0.0967 0.0967Gradient descent, bắt đầu từ các số ngẫu nhiên và không được nói gì ngoài “hãy làm log-probability của chữ cái tiếp theo lớn lên”, đã tái phát hiện bảng đếm. Và nó buộc phải vậy: các số đếm là ước lượng maximum-likelihood, entropy chéo là negative log-likelihood, nên cả hai quy trình tối ưu cùng một mục tiêu và mục tiêu đó có một optimum. Mạng không học một thứ giống đếm. Nó hội tụ về đếm, một cách chậm chạp.
Điều này đặt ra câu hỏi công bằng: vậy tại sao ai phải bận tâm? Vì bảng đếm không còn nơi nào để đi tiếp, còn mạng thì có.
Context là nút thắt, không phải capacity
Liên kết đến mục: Context là nút thắt, không phải capacityMở rộng mô hình để nhìn hơn một ký tự trước đó. Đây là kiến trúc năm 2003 của Bengio, tổ tiên trực tiếp của mọi mô hình trong phần còn lại của khóa học này:4 lấy ba ký tự cuối, map từng ký tự qua một embedding table thành một hàng 10 chiều, nối các hàng thành 30 số, đẩy chúng qua hidden layer của Chương 5, rồi kết thúc bằng một output layer tạo một logit cho mỗi mục từ vựng.
C = torch.randn((27, 10)) # the embedding table
W1 = torch.randn((3 * 10, 200)) # the hidden layer from Chapter 5
W2 = torch.randn((200, 27)) # one output per vocabulary entry
emb = C[X].view(-1, 30) # three lookups, concatenated
h = torch.tanh(emb @ W1 + b1)
logits = h @ W2 + b2
loss = F.cross_entropy(logits, Y)Hãy chú ý cái gì mới và cái gì không. Hidden layer là của Chương 5, không đổi; loss là của Chương 4, không đổi. Điểm mới là embedding table ở đầu và một output layer rộng bằng từ vựng của Chương 7 — và cái thứ hai là phần đắt đỏ của mọi mô hình ngôn ngữ từng được xây dựng, vì một từ vựng thật có 100.000 mục và phép nhân ma trận này chạy ở mọi vị trí.
Cùng đoạn code, huấn luyện giống hệt, chỉ thay đổi kích thước context window:
| context | tham số | validation loss | validation perplexity |
|---|---|---|---|
| đếm, 1 ký tự | 729 | 2,4546 | 11,642 |
| neural, 1 ký tự | 7.897 | 2,4577 | 11,678 |
| neural, 3 ký tự | 11.897 | 2,1145 | 8,285 |
| neural, 8 ký tự | 21.897 | 2,0506 | 7,773 |
Hàng thứ hai mới là hàng thú vị. Một mạng với hidden layer 200 unit và số tham số gấp mười một lần bảng đếm cho kết quả đúng bằng bảng đếm và không tốt hơn. Capacity chưa bao giờ là giới hạn. Một ký tự context cho phép một mức loss nhất định và không có thứ gì bạn gắn thêm có thể xuống thấp hơn, vì thông tin không có ở đó.
Cho nó ba ký tự và perplexity giảm từ 11,68 xuống 8,29 — giảm 29 %, mua bằng 4.000 tham số thêm. Nó thắng đếm ở đây đúng vì lý do đã chẩn đoán trước đó: một mô hình đếm trên context ba ký tự cần hàng, phần lớn trống hoặc chỉ có một quan sát, và học từng hàng một. Mạng thì chia sẻ. Nếu a, e và i kết thúc với các hàng embedding tương tự, thứ nó học sau bra sẽ transfer sang bre dù nó chưa từng thấy bre. Sự transfer đó là toàn bộ giá trị của embedding table, và nó chính là khoảng cách giữa hàng hai và hàng ba.
Các mẫu cũng cải thiện tương ứng:
deliah nellara joce kael quintis
salayson reety khyrmin mahnen madiaryxiaVẫn chưa phải một danh sách tên thật. Nhưng deliah, nellara và kael sẽ không quá lạc lõng trong một danh sách như vậy, và các quái vật kéo dài đã biến mất: tên dài nhất trong hai mươi mẫu từ mô hình đếm là mười chín chữ cái, còn dài nhất trong hai mươi mẫu từ mô hình này là mười ba.
Thực sự có gì bên trong embedding table
Liên kết đến mục: Thực sự có gì bên trong embedding tableBảng là : mỗi ký tự một hàng mười số, tất cả khởi tạo ngẫu nhiên và chỉ được dịch chuyển bởi gradient của loss dự đoán ký tự tiếp theo. Không ai đặt thứ gì vào đó. Vậy cuối cùng nó chứa gì?
Công cụ để hỏi là cosine similarity, tức tích vô hướng của Chương 1 sau khi chia bỏ độ dài:
Nó đo góc giữa hai vector và bỏ qua độ dài của chúng, đúng thứ bạn muốn khi độ dài của một hàng phản ánh token của nó xuất hiện thường xuyên đến đâu hơn là nó có nghĩa gì. Chuẩn hóa mọi vector về độ dài 1 trước — như các hệ thống thật làm, một lần, khi indexing — và cosine similarity chỉ đơn giản là tích vô hướng.
Đây là các hàng xóm gần nhất của vài ký tự trong bảng đã huấn luyện:
'c' -> 'k':+0.598 'j' -> 'z':+0.650 'i' -> 'y':+0.541
'u' -> 'e':+0.482 'a' -> 'h':+0.367 '.' -> 'q':+0.077Một phần trong đó đúng như folklore hứa hẹn. c và k có thể thay thế nhau trong tên, i và y cũng vậy; j và z đều hiếm, chủ yếu là phụ âm đầu, và hành xử giống nhau. Ký hiệu biên . gần như không gần gì cả — 0,077 đến chữ cái gần nhất — vì nó là ký hiệu duy nhất đánh dấu một vị trí thay vì một âm.
Và một phần thì không. Hàng xóm gần nhất của a là h, không phải một nguyên âm khác. Trung bình trên mọi cặp:
mean cosine, vowel to vowel : +0.1889
mean cosine, consonant to consonant : +0.0765
mean cosine, vowel to consonant : -0.0042Các nguyên âm giống nhau hơn so với giống phụ âm, và hiệu ứng này có thật nhưng nhỏ. Kiểm tra với 2.000 nhóm năm chữ cái được chọn ngẫu nhiên, 58 nhóm trong số đó tách biệt sạch ít nhất như vậy — một khoảng cách có ý nghĩa ở khoảng . Vậy là có thật, nhưng không hề giống hòn đảo hình học sắc nét mà các mô tả phổ biến về embeddings thường gợi ra.
Đó là mô tả trung thực về một embedding table, và đáng giữ trong đầu cho phần còn lại của khóa học. Nó không phải bản đồ ý nghĩa. Nó là một phép đổi tọa độ, được học thay vì được thiết kế, có nhiệm vụ duy nhất là làm cho công việc của layer tiếp theo dễ hơn — cùng câu mà Chương 5 dùng cho hidden layer đã gấp mặt phẳng để giải XOR. Bất kỳ cấu trúc nào bạn tìm thấy trong đó đều ở đó vì nó đã hạ loss, và cấu trúc nào không hạ loss thì đơn giản là không có ở đó.
word2vec, GloVe, và phép số học ai cũng trích
Liên kết đến mục: word2vec, GloVe, và phép số học ai cũng tríchNếu phần hữu ích là bảng, bạn có thể nhắm thẳng vào nó. Đó là word2vec: giữ embedding lookup, bỏ mô hình ngôn ngữ.5
Mục tiêu skip-gram with negative sampling chỉ một dòng. Với một cặp (trung tâm, context) thật lấy từ corpus, đẩy tích vô hướng của chúng lên; với cặp giả lấy từ một phân phối nhiễu, đẩy nó xuống:6
Đó là một bài toán phân loại nhị phân — “hai từ này có thật sự xuất hiện cùng nhau không?” — và nó rẻ chính vì không bao giờ chạm vào toàn bộ từ vựng, điều đã khiến việc huấn luyện trên hàng tỷ từ trở nên thực tế vào năm 2013. GloVe đi đến các vector tương tự từ hướng ngược lại, bằng cách factorize ma trận số đếm co-occurrence toàn cục thay vì stream qua từng ví dụ.7 Cả hai đều được fit đúng trên statistic mà bảng đếm đã được xây từ đó. Chúng là đếm, được nén lại.
Huấn luyện trên text8 — 17.005.207 từ của Wikipedia tiếng Anh, 71.290 từ trong số đó xuất hiện ít nhất năm lần, 100 chiều, ba lượt — các vector xuất hiện với tính chất đã làm chúng nổi tiếng:
king -> charles 0.700, son 0.693, queen 0.686, henry 0.669, throne 0.667
physics -> chemistry 0.672, electromagnetism 0.661, quantum 0.654, theoretical 0.624
guitar -> bass 0.733, vocals 0.732, acoustic 0.728, guitars 0.703, drums 0.685
three -> seven 0.892, two 0.877, one 0.875, five 0.871, four 0.870Không ai cung cấp category cho nhạc cụ hay chữ số. Giờ đến phần nổi tiếng: lấy king, trừ man, cộng woman, rồi tìm vector gần nhất với kết quả.
king - man + woman
nothing excluded : king 0.693, elizabeth 0.657, wife 0.629, woman 0.607
a, b, c excluded : elizabeth 0.657, wife 0.629, mary 0.607 (queen is 4th, 0.604)Vector gần nhất với king - man + woman là king. Đây không phải một quirk của một ví dụ. Bộ đánh giá của Mikolov đặt các câu hỏi dạng a : b :: c : ? — 8.869 câu semantic (paris : france :: rome : italy) và 10.675 câu syntactic (walking : walked :: swimming : swam) — và trên 4.103 câu semantic mà từ vựng này có thể trả lời, đáp án thắng là một trong ba từ đầu vào 99,8 % thời gian. Các demo đã xuất bản không nhắc đến điều này, vì quy tắc chấm điểm chuẩn xóa a, b và c trước khi nhìn. Đó là một quy tắc hợp lệ, và nó đang làm nhiều việc hơn phép số học:
| cách chọn câu trả lời | semantic | syntactic |
|---|---|---|
| offset, loại trừ các input (chuẩn) | 17,0 % | 11,9 % |
| offset, không loại trừ gì | 0,1 % | 0,4 % |
hàng xóm gần nhất của riêng c, loại trừ input | 13,1 % | 9,3 % |
hàng xóm gần nhất của riêng b, loại trừ input | 2,3 % | 0,4 % |
Hàng thứ ba là hàng cần ngồi lại với nó. Bỏ a và b đi, không làm phép số học nào cả, trả về bất cứ thứ gì gần nhất với c — và bạn giữ được 77 % điểm semantic. Phần lớn thứ trông như suy luận tương tự là proximity cộng với một quy tắc cấm các đáp án hiển nhiên, đúng như Linzen đã đo trên các vector được huấn luyện đúng cách và như các baseline ở trên tái lập.8 Các vector cụ thể này nhỏ — 17 triệu từ so với hàng tỷ từ phía sau các mô hình đã xuất bản — nên hãy đọc các phần trăm như một hình dạng, không phải state of the art. Hình dạng đó tồn tại ở mọi scale: phép số học là thật, và yếu hơn rất nhiều so với một demo mà ai cũng trích.
Static và contextual: một vector cho mỗi từ, hay một vector cho mỗi lần xuất hiện
Liên kết đến mục: Static và contextual: một vector cho mỗi từ, hay một vector cho mỗi lần xuất hiệnMọi thứ đến đây đều có một giới hạn cứng nằm ngay trong cấu trúc dữ liệu. Một bảng có một hàng cho mỗi token. Từ bank nhận một vector, cùng một vector trong câu nói về bờ sông và trong câu nói về khoản vay mua nhà — tất yếu, vì lookup theo id không thể phụ thuộc vào bất cứ thứ gì khác.
Cách sửa là ngừng đọc vector ra khỏi bảng và bắt đầu tính nó từ câu. Đó là contextual embedding, được ELMo giới thiệu năm 2018 và được BERT biến thành chuẩn cùng năm.910 Đo trên mô hình thật, các con số sắc hơn lời giải thích:
sentence A: "He sat on the bank of the river and watched the water go by."
sentence B: "She deposited the cheque at the bank on the corner of the street."
static vector for 'bank' (a row of the input embedding table)
cosine A vs B ........................ 1.000000
contextual vector for 'bank', layer by layer
layer | A vs B | A vs another river sentence | B vs another money sentence
0 | 0.9512 | 0.9512 | 0.9359
4 | 0.5647 | 0.8987 | 0.7716
9 | 0.4284 | 0.8699 | 0.7568
12 | 0.5278 | 0.8702 | 0.7335Hàng đầu tiên là chính xác, không xấp xỉ: vector static cho bank là cùng 768 con số trong cả hai câu, nên cosine bằng 1 theo cấu trúc. Chín layer sau, hai lần xuất hiện nằm ở 0,43, trong khi bank trong hai câu khác nhau về sông vẫn ở 0,87. Không ai gắn nhãn nghĩa ở bất cứ đâu trong quá trình này; các nghĩa tách ra vì tách chúng khiến mục tiêu huấn luyện — đoán một token bị ẩn từ các hàng xóm của nó — dễ thỏa mãn hơn.
Có hai chi tiết đáng chú ý. Layer 0 đã là 0,9512 thay vì 1,0, vì position embeddings đã được cộng vào và từ nằm ở vị trí khác nhau trong mỗi câu. Và similarity tăng trở lại ở layers 11 và 12: các layer cuối của một mô hình pretrained được chuyên biệt hóa cho mục tiêu huấn luyện của nó, và thường không phải nơi tốt nhất để lấy representation.
Hiện chi tiết
Tùy chọn: weight tying.
Trong bert-base-uncased, embedding table là — 23.440.896 con số, 21,4 % trong 109.482.240 tham số của mô hình. Trong một mô hình ngôn ngữ nhỏ, tỷ lệ còn lớn hơn, đó là lý do một trick gần như phổ quát: bảng input và output layer tạo logits là cùng một ma trận, dùng một lần bằng lookup theo hàng và một lần ở dạng chuyển vị.11 Output layer vốn đã gán cho mỗi mục từ vựng một vector — nó lấy tích vô hướng với từng vector — và tying nói rằng vector dùng để đọc một token và vector dùng để viết token đó nên là cùng một đối tượng. Nó vừa cắt tham số vừa cải thiện perplexity, một điều đủ hiếm để đáng chú ý.
Một embedding model không phải mô hình ngôn ngữ
Liên kết đến mục: Một embedding model không phải mô hình ngôn ngữĐể tìm kiếm một corpus theo nghĩa, bạn cần một vector cho mỗi câu. Khi đã có chúng, việc tìm kiếm là tầm thường — đây là toàn bộ semantic retrieval, và Chương 19 nói về mọi thứ xung quanh nó:
E = normalise(embed(sentences)) # (200, d), every row of length 1
q = normalise(embed([query])) # (1, d)
scores = q @ E.T # one matrix multiply
top5 = scores[0].argsort()[::-1][:5]Vậy câu hỏi thật sự duy nhất là embed đến từ đâu. Bước hiển nhiên là lấy một mô hình ngôn ngữ pretrained, chạy từng câu qua nó và lấy trung bình các vector token. Đây là phương pháp đó so với bốn lựa chọn khác, chấm theo hai cách: rank correlation giữa cosine và đánh giá similarity của con người trên 1.379 cặp của benchmark STS, và top-1 retrieval trên một index xây từ 200 cặp được paraphrase mạnh nhất trong số đó — một vế của mỗi cặp được index, vế kia dùng làm query.
| cách embed câu | rank correlation | top-1 trên index 200 câu |
|---|---|---|
| trùng lặp từ nhị phân (không có mô hình nào) | 0,5500 | 89,0 % |
| trung bình các vector static đã huấn luyện ở trên | 0,5263 | 85,5 % |
BERT, token [CLS] | 0,2030 | 67,0 % |
| BERT, trung bình vector token | 0,4729 | 84,0 % |
| MiniLM, huấn luyện contrastively | 0,8203 | 92,0 % |
Đọc ba hàng giữa so với hai hàng đầu. Một pretrained transformer 109 triệu tham số, dùng theo cách hiển nhiên, tệ hơn trong việc đánh giá similarity giữa câu so với đếm xem hai câu chia sẻ bao nhiêu từ — và tệ hơn cả việc lấy trung bình các vector text8 100 chiều vừa huấn luyện. Token [CLS], thứ các tutorial vẫn khuyến nghị vì BERT được pretrained với một mục tiêu cấp câu gắn vào nó, còn tệ hơn một nửa của con số đó.
Đây không phải lỗi của BERT. Đó là mục tiêu. Một mô hình ngôn ngữ được huấn luyện để hidden states dự đoán một token; không có gì ở đó yêu cầu hai paraphrase kết thúc gần nhau, và không có gì thưởng cho một hình học trong đó cosine nghĩa là “cùng nghĩa”. Hàng cuối là một mô hình nhỏ bằng một phần năm (22.713.216 tham số) được huấn luyện trên một loss hoàn toàn khác: contrastive learning, nơi ví dụ là các cặp — một câu hỏi và câu trả lời của nó, một câu và paraphrase của nó — và mục tiêu kéo các cặp đúng lại gần nhau trong khi đẩy các negative được lấy mẫu ra xa. Đó là đóng góp của Sentence-BERT và là nguồn gốc của toàn bộ ngành embedding-model.12 Dense Passage Retrieval áp dụng cùng công thức trực tiếp cho tìm kiếm, với một encoder cho query và một encoder cho passage.13
Vậy quy tắc thực tế là:
Một embedding model không phải là mô hình ngôn ngữ bị tháo layer cuối. Nó là một mô hình khác trên một mục tiêu khác, thường nhỏ hơn nhiều, mà cosine của nó có nghĩa bạn muốn vì nó được huấn luyện trên các cặp nơi đó chính là target. Bảng trên là cái giá của việc thay cái này bằng cái kia.
Và họ mô hình này thất bại với thứ tự từ. “The dog bit the man” và “the man bit the dog” có bag of words giống hệt nhau, nên word overlap và trung bình vector static cho cosine đúng 1,000000, còn mean-pooled BERT, dù có thấy position, vẫn gần như vậy — và MiniLM được huấn luyện contrastively vẫn đặt chúng ở 0,979. Nếu tác vụ retrieval của bạn phụ thuộc vào ai làm gì với ai, không cosine threshold nào cứu được bạn.
Chương 19 xây một hệ thống retrieval production trên nền tảng này và đi đến một ngưỡng cosine cụ thể. Phép đo cuối cùng trong chương này là thứ khiến một con số như vậy có thể bảo vệ được thay vì chỉ là phép màu.
Lời nguyền chiều cao, trong một bảng
Liên kết đến mục: Lời nguyền chiều cao, trong một bảngEmbeddings thật có hàng trăm hoặc hàng nghìn thành phần, và khoảng cách hành xử kỳ lạ ở đó. Lấy 1.000 điểm ngẫu nhiên trong hypercube đơn vị của chiều và nhìn vào tỷ lệ giữa khoảng cách lớn nhất và nhỏ nhất giữa bất kỳ hai điểm nào:
| số chiều | cặp gần nhất | cặp xa nhất | tỷ lệ |
|---|---|---|---|
| 2 | 0,0007 | 1,3612 | 1921,66 |
| 10 | 0,2361 | 2,3397 | 9,91 |
| 100 | 3,0047 | 5,1752 | 1,72 |
| 1.000 | 11,7809 | 14,0306 | 1,19 |
| 10.000 | 39,6152 | 42,0125 | 1,06 |
Trong mười nghìn chiều, cặp điểm xa nhất chỉ xa hơn cặp gần nhất 6 %. Mọi thứ gần như cách đều mọi thứ khác, “nearest neighbour” bắt đầu mang rất ít thông tin, và đó là lời nguyền chiều cao — đồng thời cũng là một lý do các vector database lớn không làm exact nearest-neighbour search. Mặt kia của cùng đồng xu là điều khiến cosine threshold dùng được: đo trên một nghìn cặp vector đơn vị ngẫu nhiên, cosine trung bình nằm ở trong 100 chiều và trong 768 chiều, với độ lệch chuẩn 0,0968 và 0,0357 — và trong 768 chiều chỉ 0,2 % cặp ngẫu nhiên vượt quá 0,1 theo trị tuyệt đối. Vì vậy một similarity đo được là 0,4 không phải “giống nhau 40 %”; nó nằm rất xa bất cứ thứ gì ngẫu nhiên tạo ra, đó là lý do threshold giữa 0,3 và 0,7 tách tín hiệu khỏi nhiễu thay vì nằm ở giữa chúng.
Tiếp theo đi đâu
Liên kết đến mục: Tiếp theo đi đâuMô hình trong chương này đọc một số lượng cố định các ký tự trước đó, lookup từng ký tự và dán kết quả lại với nhau theo thứ tự. Thiết kế đó có hai vấn đề, và chúng là cùng một vấn đề.
Nhìn lại bảng context: đi từ ba ký tự lên tám gần như nhân đôi số tham số và mua được 0,06 nats. Chi phí tăng tuyến tính với context — mỗi vị trí thêm cần một slab riêng của ma trận trọng số đầu tiên — còn lợi ích thì không. Đẩy nó lên một nghìn token và layer đầu tiên một mình đã nặng hơn phần còn lại của mô hình, phần lớn dành cho những vị trí không quan trọng với bất kỳ dự đoán cụ thể nào.
Đó cũng là vấn đề thứ hai: mô hình không có cách nào quyết định token trước đó nào quan trọng. Vị trí hai có trọng số riêng và vị trí bảy có trọng số riêng, vĩnh viễn, bất kể có gì trong chúng. Khi mô hình đang đánh vần nell, ký tự quyết định là ký tự ngay trước đó. Khi một câu chứa đại từ, từ xác định tham chiếu của nó có thể nằm cách bốn mươi token trước — và không slot cố định nào có thể được gán cho “cách bốn mươi”, vì lần sau nó sẽ là sáu.
Điều ta muốn là một mô hình tính, cho mỗi dự đoán, mỗi token trước đó nên được tính bao nhiêu — các trọng số trên context được tạo bởi nội dung thay vì cố định bởi layout. Viết điều đó cẩn thận, nó bắt đầu như một thứ hoàn toàn đời thường: trung bình trên các token trước đó. Rồi để trọng số của trung bình đó được học, và để chúng phụ thuộc vào token nào đang đặt câu hỏi.
Đó là attention, và nó là Chương 9.
Nguồn và phương pháp
Liên kết đến mục: Nguồn và phương phápCũng đáng đọc song song: chương 3 của Speech and Language Processing của Jurafsky và Martin, bàn về n-gram models, smoothing và perplexity kỹ hơn nhiều so với phạm vi ở đây, bao gồm vì sao interpolation và back-off tốt hơn cộng một; ghi chú Stanford CS229 §17.1–17.2 về mô hình hóa ngôn ngữ từ phía xác suất; và bài của Linzen ở trên, ngắn và đáng đọc trọn vẹn.
Tài liệu tham khảo
Liên kết đến mục: Tài liệu tham khảo-
Ví dụ tạo tên, dataset và tiến trình từ bảng đếm đến mạng kiểu Bengio đi theo series building makemore của Andrej Karpathy, trong đó hai phần đầu là tài liệu đồng hành tốt nhất cho chương này. ↩
-
Shannon, C. E. Prediction and Entropy of Printed English. Bell System Technical Journal 30(1), pp. 50–64 (1951). Người tham gia đoán chữ cái tiếp theo của tiếng Anh in, và phép đo bits-per-character nguyên thủy. ↩
-
Shannon, C. E. A Mathematical Theory of Communication. Bell System Technical Journal 27 (1948). Định lý mã hóa nguồn, và việc đồng nhất dự đoán với nén. ↩
-
Bengio, Y., Ducharme, R., Vincent, P. and Jauvin, C. A Neural Probabilistic Language Model. Journal of Machine Learning Research 3, pp. 1137–1155 (2003). Kiến trúc dùng ở trên: một embedding cho mỗi từ, nối qua một cửa sổ cố định, đi qua hidden layer, đến một softmax trên từ vựng. ↩
-
Mikolov, T., Chen, K., Corrado, G. and Dean, J. Efficient Estimation of Word Representations in Vector Space. arXiv:1301.3781 (2013). CBOW và skip-gram, cùng bộ analogy dùng ở trên. ↩
-
Mikolov, T., Sutskever, I., Chen, K., Corrado, G. and Dean, J. Distributed Representations of Words and Phrases and their Compositionality. arXiv:1310.4546 (2013). Negative sampling, subsampling các từ thường gặp, và phân phối nhiễu lũy thừa 3/4 dùng ở trên. ↩
-
Pennington, J., Socher, R. and Manning, C. GloVe: Global Vectors for Word Representation. EMNLP 2014. Vector từ từ việc factorize ma trận co-occurrence toàn cục thay vì các cửa sổ cục bộ được stream. ↩
-
Linzen, T. Issues in evaluating semantic spaces using word analogies. RepEval 2016, arXiv:1606.07736. Nguồn của các baseline không dùng offset được tái lập ở trên. ↩
-
Peters, M. et al. Deep contextualized word representations. arXiv:1802.05365 (2018). ELMo: một vector cho mỗi lần xuất hiện, được tính bởi một mô hình ngôn ngữ hai chiều. ↩
-
Devlin, J., Chang, M.-W., Lee, K. and Toutanova, K. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. arXiv:1810.04805 (2018). Mô hình được đo trong thí nghiệm bank. ↩
-
Press, O. and Wolf, L. Using the Output Embedding to Improve Language Models. arXiv:1608.05859 (2016), and Inan, H., Khosravi, K. and Socher, R. Tying Word Vectors and Word Classifiers. arXiv:1611.01462 (2016). Hai lập luận độc lập cho cùng một trick. ↩
-
Reimers, N. and Gurevych, I. Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. arXiv:1908.10084 (2019). Phép đo mở đầu của nó — mean-pooled BERT kém hơn vector static trung bình trên similarity giữa câu — là điều bảng trên tái tạo. ↩
-
Karpukhin, V. et al. Dense Passage Retrieval for Open-Domain Question Answering. arXiv:2004.04906 (2020). Huấn luyện contrastive cho retriever hai encoder; tổ tiên trực tiếp của retrieval stack trong Chương 19. ↩