Transformer và Mô hình Ngôn ngữ¶
Transformer thay thế tính tuần tự (recurrence) bằng cơ chế tự chú ý (self-attention) và trở thành kiến trúc thống trị cho việc hiểu và sinh ngôn ngữ. File này bao gồm BERT, GPT, T5, mã hoá vị trí (sinusoidal, RoPE), các mục tiêu tiền huấn luyện (MLM, CLM), tinh chỉnh (fine-tuning), thiết kế prompt (prompt engineering), và các định luật tỷ lệ (scaling laws) — bản thiết kế đằng sau các LLM hiện đại.
-
Trong chương 06, chúng ta đã giới thiệu kiến trúc Transformer: tự chú ý, chú ý đa đầu (multi-head attention), mã hoá vị trí, và cấu trúc mã hoá-giải mã (encoder-decoder). Ở đây chúng ta tập trung vào cách Transformer được điều chỉnh cho các mô hình NLP cụ thể, các mô hình định hình NLP hiện đại (BERT, GPT, T5), và các kỹ thuật giúp chúng khả thi ở quy mô lớn.
-
Nhắc lại thao tác cốt lõi: chú ý tích vô hướng có tỷ lệ (scaled dot-product attention) tính \(\text{softmax}(QK^T / \sqrt{d_k}) V\), trong đó query, key và value là các phép chiếu tuyến tính của đầu vào. Chú ý đa đầu (Multi-head attention) chạy \(h\) đầu chú ý song song, mỗi đầu có các phép chiếu học được khác nhau, và nối các kết quả lại. Khối Transformer bọc phần này bằng các kết nối dư (residual connections), chuẩn hoá lớp (layer normalisation), và một mạng truyền thẳng theo vị trí (position-wise feed-forward network) (chương 06).
-
Một lựa chọn kiến trúc tinh tế nhưng quan trọng là vị trí của chuẩn hoá lớp (layer normalisation). Transformer nguyên gốc dùng post-norm: phần dư và chuẩn hoá nằm sau lớp con (sublayer), dưới dạng \(\text{LayerNorm}(x + \text{Sublayer}(x))\).
-
Hầu hết các mô hình hiện đại dùng pre-norm: chuẩn hoá trước lớp con, dưới dạng \(x + \text{Sublayer}(\text{LayerNorm}(x))\). Pre-norm ổn định hơn khi huấn luyện vì kết nối dư truyền gradient trực tiếp qua đường đồng nhất (identity path) mà không bị ảnh hưởng bởi chuẩn hoá. Điều này giúp huấn luyện các mô hình rất sâu dễ dàng hơn mà không cần tinh chỉnh cẩn thận tốc độ học.
-
Lớp truyền thẳng (feed-forward sublayer) trong mỗi khối Transformer là một MLP hai lớp áp dụng độc lập cho mỗi vị trí token:
-
Chiều trong thường gấp 4 lần chiều mô hình (ví dụ: \(d_{\text{model}} = 768\), \(d_{\text{ff}} = 3072\)). FFN này chiếm khoảng hai phần ba tham số trong mỗi khối và được cho là hoạt động như một bộ nhớ key-value lưu trữ tri thức sự kiện học được trong huấn luyện.
-
Mã hoá vị trí (Positional encoding) cung cấp cho mô hình thông tin về thứ tự token, vì bản thân cơ chế chú ý là bất biến với hoán vị (permutation-equivariant). Mã hoá sin/cosin (sinusoidal encoding) nguyên gốc (chương 06) dùng các hàm sin và cosin cố định ở các tần số khác nhau. Embedding vị trí học được (Learned positional embeddings) đơn giản là cộng một vector có thể huấn luyện cho mỗi vị trí (được BERT và GPT-2 dùng). Cả hai đều là mã hoá tuyệt đối: vị trí 5 nhận cùng một vector bất kể ngữ cảnh.
-
Rotary Position Embedding (RoPE) mã hoá vị trí bằng cách xoay các vector query và key trong các không gian con 2D. Với một cặp chiều \((q_{2i}, q_{2i+1})\), phép xoay góc \(m\theta_i\) (với \(m\) là vị trí và \(\theta_i = 10000^{-2i/d}\)) áp dụng:
-
-
Vẻ đẹp của RoPE là tích vô hướng \(q'^T k'\) giữa các query và key đã xoay chỉ phụ thuộc vào vị trí tương đối \(m - n\), không phải các vị trí tuyệt đối.
-
Để thấy tại sao, viết phép xoay thành \(q' = R_m q\) và \(k' = R_n k\), với \(R_m\) là ma trận xoay khối chéo (block-diagonal). Điểm số chú ý trở thành:
-
Bước cuối cùng suy ra từ tính chất nhóm phép xoay: \(R_m^T R_n = R_{n-m}\) (xoay lùi \(m\) rồi xoay tới \(n\) bằng xoay \(n - m\)).
-
Điều này có nghĩa điểm số chú ý chỉ phụ thuộc vào khoảng cách tương đối \(n - m\), không phải các vị trí tuyệt đối \(m\) và \(n\) riêng lẻ.
-
Mô hình thu được một khái niệm khoảng cách tự nhiên mà không cần bất kỳ tham số vị trí học được nào và có thể khái quát hoá cho các độ dài chuỗi chưa thấy trong huấn luyện.
-
ALiBi (Attention with Linear Biases) dùng cách tiếp cận còn đơn giản hơn: nó cộng một hình phạt tuyến tính cố định vào điểm số chú ý dựa trên khoảng cách, dưới dạng \(\text{score}_{ij} = q_i^T k_j - m \cdot |i - j|\), với \(m\) là độ dốc riêng cho mỗi đầu. Các đầu khác nhau dùng các độ dốc khác nhau, cho phép một số đầu tập trung cục bộ và các đầu khác tập trung toàn cục. ALiBi không cần tham số vị trí học được và khái quát hoá tốt cho các chuỗi dài hơn những chuỗi thấy trong huấn luyện.
-
Ba mô hình thống trị cho mô hình ngôn ngữ dựa trên Transformer là chỉ mã hoá (encoder-only), chỉ giải mã (decoder-only), và mã hoá-giải mã (encoder-decoder). Chúng khác nhau ở những gì mô hình có thể thấy (mặt nạ chú ý - attention mask) và cách chúng được huấn luyện.
-
-
BERT (Bidirectional Encoder Representations from Transformers, Devlin và cộng sự, 2019) là mô hình chỉ mã hoá kinh điển. Nó xử lý văn bản với chú ý hai chiều đầy đủ: mọi token có thể chú ý đến mọi token khác, cả trái lẫn phải. Điều này cho BERT các biểu diễn ngữ cảnh phong phú nhưng đồng nghĩa nó không thể sinh văn bản tự hồi quy.
-
BERT được tiền huấn luyện với hai mục tiêu. Mô hình ngôn ngữ có mặt nạ (Masked language modelling - MLM) ngẫu nhiên che 15% các token đầu vào và huấn luyện mô hình dự đoán chúng. Trong các token được chọn, 80% được thay bằng token [MASK], 10% bằng một từ ngẫu nhiên, và 10% giữ nguyên (để ngăn mô hình học chỉ dự đoán khi thấy [MASK]). Mục tiêu huấn luyện là:
-
trong đó \(\mathcal{M}\) là tập các vị trí bị che và \(w_{\backslash \mathcal{M}}\) là câu với các vị trí đó bị che. Đây là một mục tiêu khử nhiễu (denoising): mô hình học cách tái tạo đầu vào bị hỏng.
-
-
Dự đoán câu tiếp theo (Next Sentence Prediction - NSP) huấn luyện BERT dự đoán xem hai câu có liên tiếp nhau trong văn bản gốc hay không. Một token đặc biệt [CLS] ở đầu đầu vào được dùng cho phân loại nhị phân này. NSP được đưa vào để hỗ trợ các tác vụ như trả lời câu hỏi đòi hỏi hiểu quan hệ câu, dù các nghiên cứu sau (RoBERTa) chỉ ra nó đóng góp rất ít và có thể bỏ qua.
-
Các biểu diễn đã tiền huấn luyện của BERT được thích ứng cho các tác vụ hạ nguồn bằng cách thêm một "đầu" theo tác vụ (một lớp tuyến tính đơn giản) lên trên và tinh chỉnh toàn bộ mô hình. Với các tác vụ phân loại, biểu diễn token [CLS] được dùng. Với các tác vụ cấp token (NER, POS tagging), biểu diễn của mỗi token được dùng. Cách tiếp cận tinh chỉnh (fine-tuning) này chuyển giao tri thức ngôn ngữ học được học trong tiền huấn luyện sang các tác vụ mới với lượng dữ liệu có nhãn tương đối ít.
-
GPT (Generative Pre-trained Transformer, Radford và cộng sự, 2018) là mô hình chỉ giải mã kinh điển. Nó dùng chú ý nhân quả (tự hồi quy - causal/autoregressive): mỗi token chỉ có thể chú ý đến các token ở các vị trí trước đó (và chính nó). Điều này được thực thi bằng cách che các vị trí tương lai trong ma trận chú ý (đặt điểm số của chúng thành \(-\infty\) trước softmax). Mục tiêu huấn luyện là mô hình ngôn ngữ nhân quả (causal language modelling) đơn giản: dự đoán token tiếp theo dựa trên mọi token trước đó.
-
Đây là cùng mục tiêu mô hình ngôn ngữ n-gram từ file 02, nhưng với cách tham số hoá Transformer có thể điều kiện trên toàn bộ ngữ cảnh trước đó thay vì chỉ \(k-1\) token cuối.
-
GPT-2 mở rộng quy mô này lên 1,5 tỷ tham số và chứng minh hiệu suất zero-shot mạnh: không cần tinh chỉnh, nó có thể thực hiện các tác vụ bằng cách điều kiện trên một prompt ngôn ngữ tự nhiên ("Translate English to French: ...").
-
GPT-3 (175 tỷ tham số) cho thấy quy mô đơn thuần có thể kích hoạt học trong ngữ cảnh (in-context learning): bằng cách cung cấp một vài ví dụ đầu vào-đầu ra trong prompt, mô hình có thể thực hiện các tác vụ mới mà không cần bất kỳ cập nhật gradient nào.
-
Mô hình mã hoá-giải mã như T5 (Text-to-Text Transfer Transformer, Raffel và cộng sự, 2020) đóng khung mọi tác vụ NLP như văn bản-sang-văn bản: đầu vào là một chuỗi văn bản (có thể có tiền tố tác vụ như "translate English to German:") và đầu ra là một chuỗi văn bản. Encoder xử lý đầu vào với chú ý hai chiều, và decoder sinh đầu ra tự hồi quy với cơ chế chú ý chéo (cross-attention) tới encoder.
-
T5 được tiền huấn luyện với làm hỏng đoạn (span corruption): các đoạn token liền kề ngẫu nhiên được thay bằng các token sentinel, và mô hình phải sinh ra các token gốc. Ví dụ, "The cat sat on the mat" có thể trở thành "The [X] on [Y]" làm đầu vào, và mục tiêu là "[X] cat sat [Y] the mat". Đây là sự tổng quát hoá của MLM của BERT từ token đơn lẻ sang đoạn.
-
BART (Lewis và cộng sự, 2020) là một mô hình mã hoá-giải mã khác được tiền huấn luyện với mục tiêu khử nhiễu, nhưng nó áp dụng một tập các chiến thuật làm hỏng đa dạng hơn: che token, xoá token, che đoạn, hoán vị câu, và xoay vòng tài liệu. Sự đa dạng của việc làm hỏng buộc mô hình học các biểu diễn mạnh mẽ hơn.
-
Khi mô hình ngôn ngữ lớn hơn, tinh chỉnh toàn bộ (full fine-tuning) (cập nhật mọi tham số) trở nên không khả thi: một mô hình 175B tham số đòi hỏi hàng trăm gigabyte chỉ để lưu trạng thái bộ tối ưu hoá. Các phương pháp tinh chỉnh hiệu quả tham số (Parameter-efficient fine-tuning - PEFT) chỉ thích ứng một phần nhỏ tham số.
-
Adapters chèn các lớp thắt cổ chai (bottleneck) nhỏ (thường là hai lớp tuyến tính với một hàm phi tuyến: chiếu xuống chiều nhỏ, rồi chiếu lên lại) giữa các lớp Transformer hiện có. Chỉ các trọng số adapter được huấn luyện; trọng số mô hình gốc bị đóng băng. Điều này thêm dưới 5% tham số mới trong khi đạt hiệu suất tinh chỉnh toàn bộ trên hầu hết tác vụ.
-
LoRA (Low-Rank Adaptation) sửa đổi chính các ma trận trọng số mà không thêm lớp mới. Thay vì cập nhật ma trận trọng số đầy đủ \(W\), LoRA học một phân rã hạng thấp (low-rank) của phần cập nhật: \(W' = W + BA\), với \(B\) là \(d \times r\) và \(A\) là \(r \times d\) với \(r \ll d\) (thường \(r = 4\) đến \(r = 64\)). Trọng số gốc \(W\) bị đóng băng; chỉ \(A\) và \(B\) được huấn luyện. Tại thời điểm suy luận, phần cập nhật có thể được gộp vào trọng số gốc mà không thêm độ trễ:
-
-
Prefix tuning thêm một chuỗi các "token ảo" có thể học vào các ma trận key và value của mỗi lớp chú ý. Mô hình chú ý đến các vector tiền tố này như thể chúng là token thật, và chỉ các tham số tiền tố được huấn luyện. Nó tương tự prompt tuning nhưng hoạt động trong không gian kích hoạt (activation) thay vì không gian embedding.
-
Thiết kế prompt (Prompt engineering) là nghệ thuật thiết kế văn bản đầu vào để gợi ra hành vi mong muốn từ mô hình đã tiền huấn luyện mà không cập nhật tham số nào.
- Prompt zero-shot mô tả tác vụ bằng ngôn ngữ tự nhiên ("Classify the sentiment of the following review:").
- Prompt few-shot cung cấp các ví dụ đầu vào-đầu ra trước truy vấn thực tế.
- Prompt chuỗi suy nghĩ (Chain-of-thought - CoT) thêm "Let's think step by step" hoặc đưa các dấu vết lập luận vào các ví dụ, cải thiện đáng kể hiệu suất trên các tác vụ số học và lập luận logic bằng cách hướng dẫn mô hình phân rã vấn đề.
-
Học trong ngữ cảnh (In-context learning - ICL) là hiện tượng các mô hình ngôn ngữ lớn có thể học thực hiện các tác vụ từ các ví dụ được cung cấp trong prompt, mà không cần cập nhật gradient. Trọng số mô hình không thay đổi; nó dùng các ví dụ như một dạng đặc tả ngầm.
-
Cơ chế ICL hoạt động như thế nào về mặt cơ học vẫn là câu hỏi nghiên cứu đang mở; một giả thuyết là các lớp chú ý thực hiện một dạng hạ gradient trong lượt truyền thẳng (forward pass), hiệu quả là "huấn luyện" trên các ví dụ trong ngữ cảnh.
-
Định luật tỷ lệ (Scaling laws) mô tả các quan hệ có thể dự đoán giữa kích thước mô hình, kích thước dữ liệu, ngân sách tính toán, và hiệu suất (đo bằng mất mát). Kaplan và cộng sự (2020) tìm thấy mất mát tuân theo một hàm lũy thừa trong mỗi biến:
-
trong đó \(N\) là số tham số, \(D\) là kích thước tập dữ liệu, và \(C\) là ngân sách tính toán. Các định luật lũy thừa này giữ qua nhiều bậc độ lớn và gợi ý rằng chỉ cần mở rộng quy mô sẽ mang lại các cải thiện có thể dự đoán.
-
-
Định luật tỷ lệ Chinchilla (Hoffmann và cộng sự, 2022) sửa đổi điều này bằng cách chỉ ra rằng hầu hết các mô hình lớn bị huấn luyện thiếu (undertrained). Với một ngân sách tính toán cố định \(C\), sự phân bổ tối ưu mở rộng kích thước mô hình và dữ liệu huấn luyện bằng nhau:
-
Điều này có nghĩa nếu bạn tăng gấp đôi ngân sách tính toán, bạn nên tăng cả kích thước mô hình và kích thước tập dữ liệu lên hệ số \(\sqrt{2}\), không chỉ làm mô hình lớn hơn.
-
Kaplan và cộng sự đã khuyến nghị mở rộng \(N\) nhanh hơn \(D\), dẫn đến các mô hình rất lớn nhưng bị huấn luyện thiếu. Chinchilla (70B tham số, 1,4T token) đạt hiệu suất của Gopher (280B tham số, 300B token) với cùng ngân sách tính toán, chứng minh các mô hình trước đó bị thiếu dữ liệu nghiêm trọng.
-
Quy tắc thực tế: huấn luyện với khoảng 20 token cho mỗi tham số.
-
Hỗn hợp chuyên gia (Mixture of Experts - MoE) là một kiến trúc mở rộng dung lượng mô hình mà không mở rộng tính toán tỷ lệ. Thay vì một lớp truyền thẳng lớn, MoE dùng nhiều lớp FFN chuyên gia (expert) và một mạng cổng (gating network - router) chọn các chuyên gia nào được kích hoạt cho mỗi token.
-
Hàm cổng tính điểm định tuyến cho mỗi chuyên gia và chọn top-\(k\) (thường \(k = 1\) hoặc \(k = 2\)):
-
Chỉ các chuyên gia được chọn xử lý token, vì vậy chi phí tính toán tỷ lệ với \(k\) (số chuyên gia hoạt động) thay vì tổng số chuyên gia \(E\). Một mô hình có 8 chuyên gia và định tuyến top-2 có số tham số gấp 4 lần mô hình dày đặc (dense) nhưng chỉ gấp 2 lần tính toán.
-
-
Một thách thức then chốt trong MoE là cân bằng tải (load balancing): nếu router gửi hầu hết token đến một vài chuyên gia phổ biến, các chuyên gia khác bị lãng phí. Huấn luyện thêm một mất mát cân bằng tải (load balancing loss) phụ trợ khuyến khích sử dụng chuyên gia đều:
-
trong đó \(f_i\) là phân số token được gán cho chuyên gia \(i\) và \(p_i\) là xác suất định tuyến trung bình cho chuyên gia \(i\). Tích này được cực tiểu hoá khi cả phân số token và xác suất đều đều (mỗi cái bằng \(1/E\)).
-
Song song chuyên gia (Expert parallelism) phân phối các chuyên gia khác nhau trên các bộ tăng tốc khác nhau. Trong lượt truyền thẳng, một bước giao tiếp all-to-all định tuyến token đến thiết bị chứa chuyên gia được gán, rồi định tuyến kết quả trở lại. Chi phí giao tiếp này là thách thức kỹ thuật chính của MoE ở quy mô lớn. Các mô hình như Switch Transformer, Mixtral và GShard dùng MoE để đạt hiệu suất mạnh với chi phí suy luận thực tế.
-
Xây dựng mô hình là làm nửa công việc; đo lường xem chúng có hoạt động hay không là nửa còn lại. Đánh giá NLP đặc biệt khó vì ngôn ngữ mơ hồ, chủ quan và mở.
-
Một bản dịch có thể đúng theo nhiều cách khác nhau. Một bản tóm tắt có thể tốt ngay cả khi nó không chia sẻ từ nào chính xác với bản tham chiếu.
-
Câu trả lời của chatbot có thể hữu ích, vô hại và trung thực, nhưng những người hợp lý vẫn sẽ bất đồng.
-
Khớp chính xác (Exact match - EM) là thước đo đơn giản nhất: đầu ra của mô hình có khớp chính xác với đáp án vàng không? Nó được dùng cho các tác vụ có đáp án ngắn, không mơ hồ như trả lời câu hỏi trích xuất (SQuAD) hoặc toán học dạng đóng.
-
EM rất khắt khe; "New York City" và "new york city" thất bại trong việc khớp trừ khi áp dụng chuẩn hoá — nhưng sự đơn giản của nó làm cho nó không mơ hồ.
-
Các thước đo cấp token coi NLP như một bài toán phân loại ở cấp token, dùng precision, recall và F1 từ chương 06.
-
Precision đo phân số các token dự đoán của mô hình là đúng: \(P = \text{TP} / (\text{TP} + \text{FP})\). Một mô hình dự đoán rất ít thực thể nhưng dự đoán đúng hết có precision cao.
-
Recall đo phân số các token vàng mà mô hình tìm thấy: \(R = \text{TP} / (\text{TP} + \text{FN})\). Một mô hình dự đoán mọi token là thực thể có recall hoàn hảo nhưng precision tồi tệ.
-
F1 là trung bình điều hoà (harmonic mean) của precision và recall:
-
Trung bình điều hoà (thay vì cộng) phạt sự mất cân bằng: nếu \(P\) hoặc \(R\) thấp, \(F_1\) thấp. Với NER (file 02), F1 được tính cho mỗi loại thực thể rồi macro-average trên các loại. Với POS tagging, độ chính xác cấp token phổ biến hơn vì mọi token đều nhận một nhãn.
-
Span-level F1 (dùng trong SQuAD) so sánh tập token trong đoạn dự đoán với tập trong đoạn vàng. Nó khoan dung hơn khớp chính xác: nếu đáp án vàng là "the Eiffel Tower" và mô hình dự đoán "Eiffel Tower", span F1 vẫn cao (4 token trùng trong 5) dù EM bằng không.
-
BLEU (Bilingual Evaluation Understudy, Papineni và cộng sự, 2002) là thước đo kinh điển cho dịch máy. Nó đo độ chồng lấp n-gram giữa bản dịch ứng viên và một hoặc nhiều bản dịch tham chiếu. Điểm số kết hợp precision ở nhiều cấp n-gram (unigram đến 4-gram) với một hình phạt độ ngắn (brevity penalty):
-
trong đó \(p_n\) là precision n-gram đã sửa (modified n-gram precision): số đếm mỗi n-gram trong ứng viên bị cắt (clip) về số đếm tối đa của nó trong bất kỳ tham chiếu nào, ngăn một ứng viên suy biến như "the the the the" đạt điểm cao. Các trọng số \(w_n\) thường đều nhau (\(w_n = 1/N\), với \(N = 4\)).
-
Hình phạt độ ngắn (brevity penalty) \(\text{BP} = \min(1, \exp(1 - r/c))\) phạt các ứng viên ngắn hơn tham chiếu (\(c\) là độ dài ứng viên, \(r\) là độ dài tham chiếu). Nếu không có nó, một mô hình có thể đạt precision cao bằng cách xuất ra rất ít từ rất an toàn.
-
BLEU tương quan hợp lý với đánh giá con người ở cấp kho ngữ liệu (trung bình trên nhiều câu) nhưng kém ở cấp câu.
-
Nó thưởng các khớp n-gram chính xác và bỏ sót các cách diễn đạt hợp lệ: "the cat is on the mat" và "a feline sits atop the rug" có độ chồng lấp bigram bằng không dù cùng nghĩa.
-
BLEU cũng bỏ qua hoàn toàn recall — một ứng viên chỉ sinh ra các từ phổ biến nhất vẫn đạt điểm precision tốt.
-
ROUGE (Recall-Oriented Understudy for Gisting Evaluation, Lin, 2004) là thước đo chuẩn cho tóm tắt. Không giống BLEU nhấn mạnh precision, ROUGE nhấn mạnh recall: phân số các n-gram tham chiếu xuất hiện trong ứng viên là bao nhiêu?
-
ROUGE-N tính recall của n-gram: \(\text{ROUGE-N} = \frac{|\text{n-grams}_{\text{ref}} \cap \text{n-grams}_{\text{cand}}|}{|\text{n-grams}_{\text{ref}}|}\). ROUGE-1 (unigram) và ROUGE-2 (bigram) phổ biến nhất.
-
ROUGE-L dùng dãy con chung dài nhất (longest common subsequence - LCS) giữa ứng viên và tham chiếu, nắm bắt thứ tự từ cấp câu mà không đòi khớp liên tiếp.
-
Độ dài LCS được chuẩn hoá theo độ dài tham chiếu cho recall, chuẩn hoá theo độ dài ứng viên cho precision, và F-measure kết hợp chúng.
-
LCS được tính qua quy hoạch động trong thời gian \(O(mn)\) (tương tự khoảng cách sửa từ file 02):
-
trong đó \(m\) và \(n\) là độ dài tham chiếu và ứng viên, và \(\beta\) thường được đặt để ưu tiên recall (\(\beta \to \infty\) cho recall thuần).
-
METEOR (Metric for Evaluation of Translation with Explicit ORdering, Banerjee và Lavie, 2005) giải quyết các điểm yếu của BLEU bằng cách kết hợp đồng nghĩa, rút gọn (stemming) và thứ tự từ.
-
Nó đầu tiên căn chỉnh các từ giữa ứng viên và tham chiếu bằng khớp chính xác, khớp gốc (qua Porter stemming từ file 02), và khớp đồng nghĩa (qua WordNet từ file 01).
-
Sau đó nó tính trung bình điều hoà của precision và recall unigram có trọng số thiên về recall, và áp dụng một hình phạt phân mảnh (fragmentation penalty) phạt các ứng viên có từ đã khớp xuất hiện theo thứ tự khác với tham chiếu.
-
ChrF (Character n-gram F-score) tính F-score trên các n-gram ký tự thay vì n-gram từ. Điều này làm nó bền vững trước sự biến thiên hình thái (quan trọng cho các ngôn ngữ chắp dính từ file 01) và xử lý một phần các khác biệt tokenisation. ChrF++ thêm các bigram từ vào các n-gram ký tự.
-
Nó đã trở thành thước đo được khuyến nghị cho dịch máy bên cạnh BLEU, đặc biệt cho các ngôn ngữ giàu hình thái.
-
Độ rối (Perplexity) (file 02) đo mức độ tốt của mô hình ngôn ngữ khi dự đoán một tập kiểm tra held-out. Nó là thước đo nội tại chuẩn cho mô hình ngôn ngữ: \(\text{PPL} = \exp(-\frac{1}{N} \sum_{i} \log P(w_i \mid w_{<i}))\). Thấp hơn là tốt hơn.
-
Độ rối chỉ có thể so sánh giữa các mô hình dùng cùng tokenisation, vì các bộ tokeniser khác nhau tạo ra độ dài chuỗi \(N\) khác nhau cho cùng một văn bản.
-
Một mô hình có từ vựng lớn hơn có xu hướng có độ rối thấp hơn trên mỗi token nhưng xử lý ít token hơn trên mỗi câu.
-
Bits-per-byte (BPB) chuẩn hoá theo số byte UTF-8 trong văn bản thay vì số token, làm cho nó độc lập với tokenisation:
- BERTScore (Zhang và cộng sự, 2020) vượt ra khỏi việc khớp n-gram bề mặt bằng cách tính độ tương tự trong không gian embedding. Mỗi token trong ứng viên được khớp với token tương tự nhất trong tham chiếu dùng độ tương tự cosine của các embedding ngữ cảnh (thường từ mô hình BERT đã tiền huấn luyện). Các điểm số được tổng hợp thành precision, recall và F1:
-
trong đó \(r_i\) và \(c_j\) là các embedding ngữ cảnh của token tham chiếu và ứng viên. Điều này nắm bắt sự tương tự ngữ nghĩa mà các thước đo n-gram bỏ sót: "automobile" và "car" đạt điểm cao vì embedding BERT của chúng tương tự, dù chúng không chia sẻ ký tự nào.
-
BLEURT (Sellam và cộng sự, 2020) đi xa hơn bằng cách tinh chỉnh trực tiếp một mô hình BERT trên các đánh giá chất lượng của con người. Với một cặp tham chiếu và ứng viên, nó xuất ra một điểm chất lượng vô hướng. BLEURT được huấn luyện trên dữ liệu tổng hợp (các nhiễu loạn ngẫu nhiên của bản dịch tham chiếu được chấm bởi các thước đo như BLEU và METEOR) rồi tinh chỉnh trên đánh giá con người. Nó tương quan tốt hơn với đánh giá con người so với bất kỳ thước đo bề mặt nào.
-
COMET (Crosslingual Optimized Metric for Evaluation of Translation, Rei và cộng sự, 2020) là một thước đo học được cho dịch máy điều kiện trên câu nguồn, tham chiếu và ứng viên — không chỉ tham chiếu và ứng viên. Nó dùng một bộ mã hoá đa ngôn ngữ (XLM-R) để embedding cả ba và dự đoán một điểm chất lượng. Bằng cách thấy câu nguồn, COMET có thể phát hiện các lỗi nghĩa mà các thước đo chỉ dùng tham chiếu bỏ sót (ví dụ: một bản dịch trôi chảy nhưng sai sự thật).
-
LLM-as-judge là cách tiếp cận đánh giá hiện đại ở quy mô. Thay vì tính các thước đo so với tham chiếu, một mô hình ngôn ngữ mạnh (GPT-4, Claude) được yêu cầu đánh giá chất lượng đầu ra của mô hình. Vị quan tòa nhận đầu vào, câu trả lời của mô hình, và tuỳ chọn một đáp án tham chiếu, rồi đưa ra một điểm (ví dụ: 1-5) hoặc một ưu tiên cặp (câu trả lời A tốt hơn B).
-
So sánh cặp (Pairwise comparison) (dùng trong Chatbot Arena) là định dạng LLM-as-judge đáng tin cậy nhất. Vị quan tòa thấy hai câu trả lời và chọn cái tốt hơn, thay vì gán điểm tuyệt đối. Điều này tránh các vấn đề hiệu chuẩn (các quan tòa khác nhau có thể có đường cơ sở khác nhau cho "3 trên 5"). Kết quả được tổng hợp thành xếp hạng Elo (từ cờ vua), trong đó mỗi mô hình bắt đầu với một điểm cơ sở và được cộng hoặc trừ điểm dựa trên thắng thua trước các mô hình khác. Xác suất thắng kỳ vọng của mô hình \(A\) trước \(B\) là:
-
trong đó \(R_A, R_B\) là điểm Elo. Sau mỗi so sánh, điểm được cập nhật: \(R_A' = R_A + K(S - P(A \succ B))\), với \(S \in \{0, 1\}\) là kết quả thực tế và \(K\) kiểm soát độ lớn cập nhật. Các mô hình đánh bại liên tục các đối thủ mạnh tăng nhanh; các mô hình thua các đối thủ yếu thì giảm.
-
Thiên vị vị trí (Position bias) là một vấn đề đã biết với các quan tòa LLM: chúng có xu hướng thích câu trả lời được trình bày trước (hoặc ở một số mô hình, câu trả lời trình bày sau). Hoán đổi (Swapping) (đánh giá mỗi cặp hai lần với thứ tự câu trả lời đảo ngược) và lấy trung bình kết quả làm giảm thiểu điều này.
-
Thiên vị dài dòng (Verbosity bias) là một vấn đề khác: các quan tòa có xu hướng thích các câu trả lời dài hơn, chi tiết hơn ngay cả khi một câu trả lời ngắn gọn hơn tốt hơn.
-
Tự nhất quán (Self-consistency) kiểm tra xem quan tòa có đưa ra cùng điểm đánh giá qua nhiều lần đánh giá của cùng một đầu vào hay không. Phương sai cao chỉ ra tín hiệu đánh giá bị nhiễu.
-
Sự đồng thuận giữa các người chấm (Inter-annotator agreement) (hệ số kappa của Cohen hoặc alpha của Krippendorff) đo lường mức độ các quan tòa đồng ý, cung cấp một giới hạn trên cho độ tin cậy đánh giá.
-
Nhiễm bẩn (Contamination) là một mối lo ngại nghiêm trọng: nếu dữ liệu đánh giá xuất hiện trong tập huấn luyện của mô hình, điểm benchmark bị thổi phồng và vô nghĩa.
-
Điều này đặc biệt có vấn đề cho các LLM huấn luyện trên dữ liệu thu thập từ web, nơi các benchmark phổ biến có khả năng hiện diện. Các chiến lược giảm thiểu bao gồm: dùng các tập kiểm tra held-out không công bố, tạo các benchmark động tái sinh câu hỏi định kỳ, chuỗi canary (canary strings) (các định danh duy nhất được nhúng vào dữ liệu benchmark để phát hiện rò rỉ), và so sánh hiệu suất trên các tập nhiễm bẩn so với sạch.
-
Các benchmark NLU chuẩn đánh giá hiểu ngôn ngữ trên các tác vụ đa dạng.
-
GLUE (General Language Understanding Evaluation) và SuperGLUE là các benchmark đa tác vụ bao phủ cảm xúc (SST-2), độ tương tự văn bản (STS-B), suy luận ngôn ngữ tự nhiên (MNLI, RTE), đồng tham chiếu (WSC), và trả lời câu hỏi (BoolQ).
-
Các mô hình được đánh giá trên từng tác vụ riêng biệt và chấm bằng một thước đo tổng hợp. GLUE giờ được coi là bão hoà (các mô hình vượt hiệu suất con người trên hầu hết tác vụ); SuperGLUE vẫn thách thức hơn.
-
MMLU (Massive Multitask Language Understanding) đánh giá tri thức và lập luận qua 57 môn học thuật (toán học, lịch sử, luật, y khoa, khoa học máy tính, v.v.) dùng các câu hỏi trắc nghiệm.
-
Nó kiểm tra xem một mô hình có hấp thụ tri thức rộng trong tiền huấn luyện hay không. Điểm được báo cáo cho từng môn và như một macro-average.
-
MMLU-Pro thêm các câu hỏi lập luận đa bước khó hơn với 10 lựa chọn đáp án thay vì 4.
-
HellaSwag kiểm tra lập luận thường thức bằng cách yêu cầu mô hình chọn phần tiếp theo hợp lý nhất của một tình huống. Các đáp án sai được sinh ra đối kháng (dùng mô hình) để bề ngoài có vẻ hợp lý nhưng sai về ngữ nghĩa.
-
WinoGrande kiểm tra giải quyết đồng tham chiếu thường thức với các cặp tối thiểu khác nhau bởi một từ.
-
ARC (AI2 Reasoning Challenge) dùng các câu hỏi khoa học cấp tiểu học trong các tập dễ và thách thức, kiểm tra khả năng sự kiện và lập luận.
-
Các benchmark lập luận và toán học đánh giá khả năng giải quyết vấn đề phân biệt các LLM mạnh và yếu.
-
GSM8K (Grade School Math 8K) chứa 8.500 bài toán đố từ vựng toán tiểu học đòi hỏi lập luận số học đa bước. Đây là benchmark chuẩn cho lập luận toán học cơ bản và để đánh giá prompt chuỗi suy nghĩ (file 04).
-
MATH là một tập dữ liệu khó hơn gồm các bài toán toán học cấp thi đấu qua đại số, lý thuyết số, hình học, đếm và xác suất. Các bài toán đòi hỏi lập luận ký hiệu đa bước, và MATH-500 là một tập con 500 bài được báo cáo phổ biến.
-
AIME (American Invitational Mathematics Examination) gồm các bài toán cấp thi đấu: giải đúng chúng đòi hỏi lập luận toán học sâu qua nhiều bước. DeepSeek-R1 đạt 79,8% trên AIME 2024, chứng minh các mô hình lập luận được huấn luyện bằng RL (file 05) có thể tiếp cận các thí sinh giỏi người thật.
-
HumanEval và MBPP (Mostly Basic Programming Problems) đánh giá sinh mã bằng cách kiểm tra xem mã của mô hình có vượt qua các unit test hay không. HumanEval chứa 164 bài toán Python với chữ ký hàm và docstring; mô hình phải sinh phần thân hàm.
-
Thước đo là pass@k: xác suất ít nhất một trong \(k\) giải pháp sinh ra vượt qua mọi test. Với một mẫu đơn:
-
trong đó \(n\) là tổng số mẫu sinh ra và \(c\) là số mẫu vượt qua. Công thức này hiệu chỉnh thiên kiến trong việc đơn giản lấy mẫu tốt nhất trong \(k\) mẫu.
-
SWE-bench đi xa hơn, đánh giá xem các mô hình có thể giải quyết các issue GitHub thật bằng cách sửa đổi các codebase hiện có — một bài kiểm tra khó hơn nhiều về khả năng kỹ thuật phần mềm thực tế.
-
GPQA (Graduate-Level Google-Proof QA) chứa các câu hỏi cấp chuyên gia trong sinh học, vật lý và hoá học, khó ngay cả với các chuyên gia trong ngành. Nó kiểm tra xem các mô hình có sự hiểu biết thực sự thay vì chỉ khớp mẫu. Tập con "Diamond" là khó nhất.
-
Các benchmark an toàn và căn chỉnh đánh giá xem các mô hình có hữu ích, vô hại và trung thực hay không.
-
TruthfulQA kiểm tra xem các mô hình có lặp lại các quan niệm sai phổ biến hay không. Các câu hỏi được thiết kế sao cho các đáp án internet phổ biến nhất là sai (ví dụ: "What happens if you swallow gum?", huyền thoại phổ biến là nó ở lại 7 năm, nhưng đáp án đúng là nó đi qua bình thường). Các mô hình ghi nhớ các tuyên bố phổ biến nhưng sai sẽ đạt điểm kém.
-
BBQ (Bias Benchmark for QA) kiểm tra các thiên kiến xã hội qua các hạng mục như tuổi, giới, chủng tộc và tôn giáo. Các câu hỏi được cấu trúc sao cho một mô hình có thiên kiến sẽ chọn có hệ thống các đáp án định kiến. Toxigen đánh giá xu hướng sinh nội dung độc hại của mô hình về các nhóm nhân khẩu cụ thể.
-
MT-Bench đánh giá khả năng hội thoại đa lượt dùng 80 câu hỏi được thiết kế cẩn thận qua viết, nhập vai, lập luận, toán, mã, trích xuất, STEM và khoa học nhân văn. Một quan tòa LLM (GPT-4) chấm các câu trả lời trên thang 1-10. Định dạng đa lượt kiểm tra xem các mô hình có thể theo dõi, duy trì ngữ cảnh và xử lý các yêu cầu làm rõ hay không.
-
Chatbot Arena (LMSYS) dùng người dùng thật để tiến hành các so sánh cặp mù giữa các mô hình ẩn danh. Người dùng gửi prompt và bình chọn cho câu trả lời tốt hơn mà không biết mô hình nào sinh ra nó. Bảng xếp hạng Elo kết quả được coi là đánh giá có giá trị sinh thái nhất về chất lượng LLM đa năng vì nó phản ánh sở thích người dùng thật trên các prompt đa dạng, chưa qua tuyển chọn.
-
AlpacaEval tự động hoá đánh giá cặp bằng cách so sánh đầu ra mô hình với một mô hình tham chiếu (GPT-4) trên một tập hướng dẫn cố định. Một mô hình quan tòa xác định tỷ lệ thắng.
-
AlpacaEval 2.0 dùng tỷ lệ thắng có kiểm soát độ dài để hiệu chỉnh thiên kiến dài dòng.
-
Đánh giá theo tác vụ cụ thể đòi hỏi các thước đo riêng cho các miền chuyên biệt.
-
Tỷ lệ lỗi từ (Word Error Rate - WER) cho nhận dạng giọng nói: \(\text{WER} = (S + D + I) / N\), với \(S\), \(D\), \(I\) là các lỗi thay thế, xoá và chèn, và \(N\) là số từ tham chiếu. Đây là khoảng cách sửa (file 02) được chuẩn hoá theo độ dài tham chiếu, áp dụng ở cấp từ.
-
Slot F1 cho các hệ thống hội thoại hướng tác vụ đo lường xem mô hình có trích xuất đúng thông tin có cấu trúc từ phát ngôn người dùng hay không (ví dụ: trích xuất "destination: Paris" và "date: tomorrow" từ "Book me a flight to Paris tomorrow").
-
Độ chính xác trích dẫn (Citation accuracy) cho các hệ thống RAG (file 05) kiểm tra xem các trích dẫn được sinh có thực sự hỗ trợ các khẳng định hay không. Một khẳng định được xác minh so với đoạn được truy xuất, và thước đo đếm phân số các khẳng định được hỗ trợ hoàn toàn, một phần hoặc không.
-
Các cạm bẫy đánh giá (Evaluation pitfalls) rất phổ biến và có thể vô hiệu hoá toàn bộ so sánh benchmark.
-
Dạy cho bài kiểm tra (Teaching to the test): tối ưu hoá cho hiệu suất benchmark thay vì năng lực thực sự. Một mô hình tinh chỉnh trên trắc nghiệm kiểu MMLU sẽ đạt điểm tốt trên MMLU nhưng có thể thất bại trên cùng câu hỏi ở dạng mở.
-
Lợi dụng thước đo (Metric gaming): các mô hình có thể được tối ưu hoá để sinh ra đầu ra đạt điểm tốt trên các thước đo tự động (BLEU cao, độ rối thấp) mà không thực sự tốt. Bản dịch tối ưu BLEU thường là một cách diễn đạt an toàn, chung chung thay vì tự nhiên, trôi chảy.
-
Bão hoà benchmark (Benchmark saturation): khi các mô hình tiếp cận hoặc vượt hiệu suất con người trên một benchmark, benchmark ngừng cung cấp thông tin. GLUE, SQuAD 1.1 và một số khác giờ đã bão hoà.
-
Lĩnh vực liên tục tạo ra các benchmark khó hơn, nhưng chu kỳ tạo ra, bão hoà và thay thế làm cho so sánh dọc khó khăn.
-
Đánh giá con người vẫn là tiêu chuẩn vàng nhưng tốn kém, chậm và khó tái tạo. Các nhóm người chấm khác nhau (công nhân đám đông so với chuyên gia, văn hoá khác nhau, ngôn ngữ khác nhau) tạo ra các đánh giá khác nhau. Báo cáo sự đồng thuận giữa người chấm và nhân khẩu học người chấm là thiết yếu cho khả năng tái tạo.
Bài tập Lập trình (dùng CoLab hoặc notebook)¶
-
Triển khai một khối encoder Transformer đầy đủ từ đầu (chú ý đa đầu, truyền thẳng, kết nối dư, chuẩn hoá lớp). Áp dụng nó cho một tác vụ phân loại chuỗi đơn giản.
import jax import jax.numpy as jnp import matplotlib.pyplot as plt def layer_norm(x, gamma, beta, eps=1e-5): mean = x.mean(axis=-1, keepdims=True) var = x.var(axis=-1, keepdims=True) return gamma * (x - mean) / jnp.sqrt(var + eps) + beta def multi_head_attention(Q, K, V, W_q, W_k, W_v, W_o, n_heads): B, T, D = Q.shape head_dim = D // n_heads q = Q @ W_q # (B, T, D) k = K @ W_k v = V @ W_v # Định hình lại thành (B, n_heads, T, head_dim) q = q.reshape(B, T, n_heads, head_dim).transpose(0, 2, 1, 3) k = k.reshape(B, T, n_heads, head_dim).transpose(0, 2, 1, 3) v = v.reshape(B, T, n_heads, head_dim).transpose(0, 2, 1, 3) scores = q @ k.transpose(0, 1, 3, 2) / jnp.sqrt(head_dim) weights = jax.nn.softmax(scores, axis=-1) out = (weights @ v).transpose(0, 2, 1, 3).reshape(B, T, D) return out @ W_o, weights def transformer_block(x, params): # Chú ý tự chú ý đa đầu pre-norm normed = layer_norm(x, params['ln1_g'], params['ln1_b']) attn_out, weights = multi_head_attention( normed, normed, normed, params['W_q'], params['W_k'], params['W_v'], params['W_o'], n_heads=4 ) x = x + attn_out # Truyền thẳng pre-norm normed = layer_norm(x, params['ln2_g'], params['ln2_b']) ff = jax.nn.gelu(normed @ params['W1'] + params['b1']) ff = ff @ params['W2'] + params['b2'] x = x + ff return x, weights # Khởi tạo tham số d_model, d_ff, n_heads = 32, 128, 4 key = jax.random.PRNGKey(42) keys = jax.random.split(key, 10) params = { 'W_q': jax.random.normal(keys[0], (d_model, d_model)) * 0.05, 'W_k': jax.random.normal(keys[1], (d_model, d_model)) * 0.05, 'W_v': jax.random.normal(keys[2], (d_model, d_model)) * 0.05, 'W_o': jax.random.normal(keys[3], (d_model, d_model)) * 0.05, 'ln1_g': jnp.ones(d_model), 'ln1_b': jnp.zeros(d_model), 'ln2_g': jnp.ones(d_model), 'ln2_b': jnp.zeros(d_model), 'W1': jax.random.normal(keys[4], (d_model, d_ff)) * 0.05, 'b1': jnp.zeros(d_ff), 'W2': jax.random.normal(keys[5], (d_ff, d_model)) * 0.05, 'b2': jnp.zeros(d_model), } # Thử nghiệm với đầu vào ngẫu nhiên x = jax.random.normal(keys[6], (2, 8, d_model)) # batch=2, seq_len=8 out, attn_weights = transformer_block(x, params) print(f"Kích thước đầu vào: {x.shape}") print(f"Kích thước đầu ra: {out.shape}") print(f"Kích thước trọng số chú ý: {attn_weights.shape}") # (B, n_heads, T, T) # Trực quan hoá các mẫu chú ý cho mỗi đầu fig, axes = plt.subplots(1, 4, figsize=(16, 3.5)) for h in range(4): im = axes[h].imshow(attn_weights[0, h], cmap='Blues', vmin=0) axes[h].set_title(f"Đầu {h}") axes[h].set_xlabel("Vị trí key"); axes[h].set_ylabel("Vị trí query") plt.suptitle("Các mẫu Chú ý Đa đầu") plt.tight_layout(); plt.show() -
Triển khai mặt nạ chú ý nhân quả (tự hồi quy) và so sánh với chú ý hai chiều. Cho thấy mặt nạ ngăn thông tin chảy từ tương lai về các token quá khứ.
import jax import jax.numpy as jnp import matplotlib.pyplot as plt def attention(Q, K, V, mask=None): d_k = Q.shape[-1] scores = Q @ K.T / jnp.sqrt(d_k) if mask is not None: scores = jnp.where(mask, scores, -1e9) weights = jax.nn.softmax(scores, axis=-1) return weights @ V, weights seq_len, d_model = 6, 8 key = jax.random.PRNGKey(0) k1, k2, k3 = jax.random.split(key, 3) Q = jax.random.normal(k1, (seq_len, d_model)) K = jax.random.normal(k2, (seq_len, d_model)) V = jax.random.normal(k3, (seq_len, d_model)) # Hai chiều (kiểu encoder): mọi vị trí đều nhìn thấy bidir_mask = jnp.ones((seq_len, seq_len), dtype=bool) bidir_out, bidir_weights = attention(Q, K, V, bidir_mask) # Nhân quả (kiểu decoder): chỉ các vị trí quá khứ và hiện tại nhìn thấy causal_mask = jnp.tril(jnp.ones((seq_len, seq_len), dtype=bool)) causal_out, causal_weights = attention(Q, K, V, causal_mask) fig, axes = plt.subplots(1, 3, figsize=(14, 4)) tokens = [f"t{i}" for i in range(seq_len)] axes[0].imshow(bidir_weights, cmap='Blues', vmin=0, vmax=0.5) axes[0].set_title("Chú ý Hai chiều\n(kiểu BERT)") axes[0].set_xticks(range(seq_len)); axes[0].set_xticklabels(tokens) axes[0].set_yticks(range(seq_len)); axes[0].set_yticklabels(tokens) axes[1].imshow(causal_mask.astype(float), cmap='Greys', vmin=0, vmax=1) axes[1].set_title("Mặt nạ Nhân quả\n(1 = cho phép, 0 = chặn)") axes[1].set_xticks(range(seq_len)); axes[1].set_xticklabels(tokens) axes[1].set_yticks(range(seq_len)); axes[1].set_yticklabels(tokens) axes[2].imshow(causal_weights, cmap='Blues', vmin=0, vmax=0.5) axes[2].set_title("Chú ý Nhân quả\n(kiểu GPT)") axes[2].set_xticks(range(seq_len)); axes[2].set_xticklabels(tokens) axes[2].set_yticks(range(seq_len)); axes[2].set_yticklabels(tokens) for ax in axes: ax.set_xlabel("Key"); ax.set_ylabel("Query") plt.tight_layout(); plt.show() # Xác minh: trong chú ý nhân quả, đầu ra tại vị trí i chỉ phụ thuộc vào các vị trí <= i print("Trọng số chú ý nhân quả tại vị trí 2 (chỉ nên chú ý đến 0, 1, 2):") print(f" Trọng số: {causal_weights[2]}") print(f" Tổng trọng số tương lai (nên ~0): {causal_weights[2, 3:].sum():.6f}") -
Triển khai LoRA (Low-Rank Adaptation) và cho thấy nó sửa đổi một ma trận trọng số với số tham số có thể huấn luyện ít hơn nhiều so với tinh chỉnh toàn bộ.
import jax import jax.numpy as jnp d_model = 256 rank = 4 # Hạng LoRA (nhỏ hơn nhiều so với d_model) key = jax.random.PRNGKey(42) k1, k2, k3 = jax.random.split(key, 3) # Ma trận trọng số đóng băng gốc W_frozen = jax.random.normal(k1, (d_model, d_model)) * 0.02 # Các ma trận LoRA (chỉ những cái này có thể huấn luyện) B = jnp.zeros((d_model, rank)) # khởi tạo bằng không A = jax.random.normal(k2, (rank, d_model)) * 0.01 # khởi tạo ngẫu nhiên # Lượt truyền thẳng: W_effective = W_frozen + B @ A x = jax.random.normal(k3, (8, d_model)) # Không dùng LoRA y_original = x @ W_frozen.T # Dùng LoRA W_effective = W_frozen + B @ A y_lora = x @ W_effective.T # Số lượng tham số full_params = d_model * d_model lora_params = d_model * rank + rank * d_model # B + A print(f"Chiều mô hình: {d_model}") print(f"Hạng LoRA: {rank}") print(f"Tham số tinh chỉnh toàn bộ: {full_params:,}") print(f"Tham số LoRA: {lora_params:,}") print(f"Giảm tham số: {full_params / lora_params:.1f}x") print(f"\nVì B được khởi tạo bằng không, đầu ra LoRA ban đầu khớp gốc:") print(f" Độ lệch lớn nhất: {jnp.abs(y_original - y_lora).max():.2e}") # Mô phỏng huấn luyện: chỉ cập nhật A và B def lora_forward(A, B, W_frozen, x): return x @ (W_frozen + B @ A).T def dummy_loss(A, B, W_frozen, x, target): pred = lora_forward(A, B, W_frozen, x) return jnp.mean((pred - target) ** 2) # Mục tiêu: một phép biến đổi của x target = x @ jax.random.normal(jax.random.PRNGKey(99), (d_model, d_model)).T * 0.02 grad_fn = jax.jit(jax.grad(dummy_loss, argnums=(0, 1))) lr = 0.01 for step in range(200): gA, gB = grad_fn(A, B, W_frozen, x, target) A = A - lr * gA B = B - lr * gB loss_before = dummy_loss(jnp.zeros_like(A), jnp.zeros_like(B), W_frozen, x, target) loss_after = dummy_loss(A, B, W_frozen, x, target) print(f"\nMất mát trước LoRA: {loss_before:.6f}") print(f"Mất mát sau LoRA: {loss_after:.6f}") print(f"Hạng thay đổi trọng số hiệu quả: {jnp.linalg.matrix_rank(B @ A)}")