Đây là Chương 6 trong chuỗi bài giảng tương tác “Nền tảng Mô hình Ngôn ngữ Lớn — Học qua Thực hành”. Ở các chương trước, ta đã lắp ráp hoàn chỉnh khối Transformer chuẩn (Chương 2), huấn luyện nó theo định luật mở rộng Chinchilla (Chương 3) và tối ưu hóa tốc độ suy luận với KV Cache, GQA, FlashAttention (Chương 5).
Tuy nhiên, kiến trúc Transformer “đặc” (Dense Transformer) vẫn vấp phải hai bức tường vật lý lớn: (1) mỗi token đi qua đều buộc toàn bộ hàng chục tỷ tham số phải tính toán, và (2) cơ chế Softmax Attention đòi hỏi chi phí tính toán bậc hai cùng bộ nhớ KV Cache phình to tuyến tính theo chiều dài chuỗi . Trong chương này, bạn sẽ tự tay cài đặt ba đột phá kiến trúc giúp phá vỡ hai giới hạn đó: Hỗn hợp Chuyên gia Thưa (Sparse MoE), Attention Tuyến tính (Linear Attention) và Mô hình Không gian Trạng thái Chọn lọc (Mamba / SSM).
Khi đọc một câu hỏi về lập trình Python, liệu một mô hình ngôn ngữ có thực sự cần kích hoạt các nơ-ron lưu trữ kiến thức về ẩm thực Pháp hay lịch sử La Mã? Và khi đọc một cuốn sách dài token, liệu mô hình có bắt buộc phải giữ lại nguyên vẹn từng cặp vector khóa – giá trị của mọi từ từ trang đầu tiên?
Hai trăn trở đó dẫn dắt toàn bộ cuộc cách mạng kiến trúc hậu-Transformer xoay quanh hai câu hỏi cốt lõi:
- Làm thế nào để tách rời tổng dung lượng tri thức (số lượng tham số ) khỏi chi phí tính toán trên mỗi token (FLOPs), giúp mô hình có hàng trăm tỷ tham số nhưng suy luận nhanh như một mô hình nhỏ?
- Làm thế nào để vượt qua nút cổ chai bậc hai của Softmax Attention, kết hợp khả năng huấn luyện song song của Transformer với chi phí suy luận trạng thái hằng số của RNN?
Trong chương này, toàn bộ bài tập thực hành được thiết kế để chạy tức thì trên CPU chỉ với PyTorch thuần (dưới 10 giây mỗi bài), giúp bạn kiểm chứng trực tiếp bản chất toán học của từng kiến trúc:
- Mô phỏng Định tuyến Chuyên gia (
SparseMoELayer): Khảo sát hiện tượng sụp đổ định tuyến (routing collapse) và tác dụng cân bằng tải của hàm mất mát phụ trợ (Fedus & Shazeer, 2022; Shazeer & others, 2017). - Đối ngẫu Song song – Truy hồi (
CausalLinearAttention): Kiểm chứng sự trùng khớp số học tuyệt đối (sai số ) giữa phép nhân ma trận song song và phép cập nhật trạng thái truy hồi (Katharopoulos & others, 2020). - Bài toán Sao chép Chọn lọc (
Selective Copying): Thử thách kinh điển của bài báo Mamba (Gu & Dao, 2023), chứng minh tại sao các hệ không gian trạng thái bất biến thời gian (LTI / S4) thất bại trong khi cơ chế quét chọn lọc (Selective Scan) giải quyết hoàn hảo.
1. Hỗn hợp Chuyên gia Thưa (Sparse Mixture of Experts — MoE)
Trong Chương 2 (Mục 5), khi phân rã số lượng tham số của một khối Transformer chuẩn, ta đã thấy rằng các lớp mạng truyền thẳng (Feed-Forward Network — FFN / SwiGLU) chiếm tới 2/3 tổng số tham số của mô hình. Trong một mô hình đặc (Dense model) như Llama-3 70B, mọi token — dù là dấu chấm câu , hay một thuật ngữ chuyên ngành phức tạp — đều phải nhân ma trận qua toàn bộ các trọng số FFN này.
1.1 Từ mạng FFN đặc đến tính toán có điều kiện (Conditional Computation)
Ý tưởng của Hỗn hợp Chuyên gia Thưa (Sparse Mixture of Experts — MoE) là thay thế một lớp FFN khổng lồ duy nhất bằng mạng FFN độc lập nhỏ hơn gọi là các chuyên gia (experts) , đi kèm một mạng cổng nhẹ gọi là bộ định tuyến (router hoặc gating network).
Với vector biểu diễn của một token ở đầu vào lớp FFN, bộ định tuyến dùng ma trận trọng số để tính điểm tương thích cho từng chuyên gia, sau đó chỉ kích hoạt Top- chuyên gia có điểm cao nhất (thường hoặc , với ):
trong đó là tập hợp chỉ số của chuyên gia có xác suất lớn nhất. Đầu ra của lớp MoE là tổng có trọng số chỉ trên chuyên gia được chọn:
Vì với chuyên gia còn lại, ta không cần thực hiện phép nhân ma trận của các chuyên gia đó! Nhờ vậy, ta có thể tăng số lượng chuyên gia lên 8, 64, hay 256 để mở rộng dung lượng ghi nhớ tri thức của mô hình mà chi phí FLOPs trên mỗi token chỉ tương đương với việc chạy chuyên gia.
1.2 Sụp đổ định tuyến (Routing Collapse) và Hàm mất mát cân bằng tải
Tuy nhiên, khi huấn luyện lớp Sparse MoE bằng hạ gradient thông thường, một hiện tượng bệnh lý gần như chắc chắn sẽ xảy ra: sụp đổ định tuyến (routing collapse).
Nếu ở những bước khởi tạo đầu tiên, chuyên gia tình cờ có trọng số nhỉnh hơn một chút và được bộ định tuyến chọn nhiều hơn, thì sẽ nhận được nhiều cập nhật gradient hơn các chuyên gia khác. Kết quả là học nhanh hơn, dự đoán tốt hơn, và bộ định tuyến lại càng tăng xác suất gửi token vào ! Chỉ sau vài trăm bước, toàn bộ token đều dồn vào 1–2 chuyên gia (“hiệu ứng người giàu càng giàu”), trong khi chuyên gia còn lại bị bỏ hoang hoàn toàn (“chuyên gia chết” — dead experts), biến mô hình MoE đắt đỏ thành một mô hình đặc cỡ nhỏ.
Để ngăn chặn hiệu ứng tự củng cố này, Switch Transformer (Fedus & Shazeer, 2022) chuẩn hóa một hàm mất mát cân bằng tải phụ trợ (load-balancing auxiliary loss) cực kỳ thanh lịch. Xét một batch gồm token:
- Gọi là tỷ lệ token thực sự được định tuyến tới chuyên gia :
- Gọi là xác suất định tuyến trung bình mà cổng Softmax phân bổ cho chuyên gia trên toàn batch:
Vì hàm chỉ thị trong không khả vi, ta nhân với (khả vi theo trọng số cổng ) để tạo ra hàm mất mát phụ trợ:
Tại sao công thức này hoạt động? Khi cả 8 chuyên gia được chia tải đồng đều hoàn hảo, ta có và với mọi , suy ra:
Ngược lại, nếu toàn bộ token bị dồn vào một chuyên gia duy nhất (), hàm mất mát sẽ vọt lên . Do tích vô hướng phạt nặng những chuyên gia vừa có tần suất được chọn cao vừa có xác suất lớn, gradient của sẽ lập tức kéo giảm logit của các chuyên gia quá tải và đẩy token sang các chuyên gia đang rảnh rỗi.
1.3 Từ Mixtral 8x7B đến Chuyên gia dùng chung (Shared Experts) trong DeepSeek-V3
Trong thực tế hiện đại, kiến trúc Sparse MoE đã phát triển qua hai thế hệ tiêu biểu:
- Mixtral 8x7B (Jiang & others, 2024) sử dụng chuyên gia SwiGLU lớn và kích hoạt chuyên gia cho mỗi token. Tổng số tham số của mô hình là 46.7B, nhưng mỗi token chỉ đi qua 12.9B tham số hoạt động (active parameters), giúp Mixtral đạt chất lượng vượt Llama-2 70B với tốc độ suy luận nhanh gấp 6 lần.
- DeepSeek-V3 (DeepSeek-AI, 2024) tiến thêm hai bước đột phá: (1) Chuyên gia tinh mịn (Fine-grained Experts) — chia nhỏ các chuyên gia thành chuyên gia nhỏ và kích hoạt chuyên gia mỗi token để tạo ra hàng tỷ tổ hợp chuyên môn hóa đa dạng; và (2) Chuyên gia dùng chung (Shared Experts) — tách riêng chuyên gia luôn luôn được kích hoạt cho mọi token mà không cần qua bộ định tuyến:
Nhờ có gánh vác các tri thức ngữ pháp và từ vựng phổ quát, các chuyên gia định tuyến không cần phải học lặp lại kiến thức cơ bản mà có thể tập trung 100% dung lượng vào các lĩnh vực chuyên biệt. Ngoài ra, DeepSeek-V3 còn thay thế hàm phạt bằng cơ chế tự động điều chỉnh độ lệch định tuyến (auxiliary-loss-free load balancing), tránh việc hàm phạt phụ trợ làm suy giảm chất lượng ngôn ngữ.
Hãy tương tác với sơ đồ dưới đây để quan sát cách bộ định tuyến Top-2 phân phối các token của một đoạn mã Python vào 8 chuyên gia, và điều gì xảy ra khi bạn tắt hàm mất mát cân bằng tải:
Bây giờ, hãy tự tay cài đặt lớp SparseMoELayer bằng PyTorch và kiểm chứng bằng thực nghiệm sự khác biệt giữa huấn luyện có và không có .
Bài tập 6.1 Cài đặt lớp Sparse Top-2 MoE và Cân bằng tải
Cài đặt mô-đun SparseMoELayer gồm chuyên gia (mỗi chuyên gia là một mạng 2 lớp tuyến tính với hàm kích hoạt SiLU) và bộ định tuyến chọn chuyên gia có xác suất cao nhất cho mỗi token:
- Chuẩn hóa lại trọng số của 2 chuyên gia được chọn sao cho tổng bằng , và tính đầu ra tổ hợp thưa .
- Tính hàm mất mát cân bằng tải phụ trợ .
- Khởi tạo trọng số bộ định tuyến có một chút thiên lệch ban đầu về chuyên gia 0 và 1 (như trong thực tế khi có nhiễu ngẫu nhiên), sau đó huấn luyện lớp MoE trong 80 bước với (tắt cân bằng tải) và (bật cân bằng tải). So sánh phân bố tỷ lệ chọn của 8 chuyên gia ở hai chế độ.
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(42)
B, L, d_model, d_ff = 16, 32, 64, 128
num_experts, top_k = 8, 2
# Tạo batch token đầu vào và nhãn mục tiêu giả lập
x = torch.randn(B, L, d_model)
target = torch.randn(B, L, d_model)
print(f"Input shape: {tuple(x.shape)} ({B * L} tokens)")
Input shape: (16, 32, 64) (512 tokens)
Hint
Trải phẳng đầu vào x từ (B, L, d_model) thành x_flat có kích thước (N, d_model) với N = B * L. Tính xác suất cổng probs = F.softmax(self.router(x_flat), dim=-1) có kích thước (N, E), rồi dùng torch.topk(probs, self.k, dim=-1) để lấy top_vals và top_idx kích thước (N, k).
Hint
Để tính tần suất , dùng F.one_hot(top_idx, self.E).float() thu được tensor (N, k, E). Lấy tổng theo chiều k (dim=1), trung bình theo chiều N (dim=0) và chia cho self.k để . Vector xác suất trung bình là P_i = probs.mean(dim=0).
Điểm kiểm tra kết quả bạn cần đạt được
Khi , hiện tượng sụp đổ định tuyến xảy ra rõ rệt: hai chuyên gia đầu tiên chiếm tới hơn tổng lưu lượng ( và ), đẩy lên và các chuyên gia từ 5 đến 7 gần như bị bỏ đói (). Khi bật , tải được chia đều quanh mức lý tưởng cho cả 8 chuyên gia và hội tụ sát về .
=== Không có Load Balancing Loss (alpha = 0.0) === Tỷ lệ chọn f_i (%): [56.2, 35.4, 3.1, 2.0, 1.4, 0.8, 0.6, 0.6] L_aux cuối: 3.685 | Độ lệch chuẩn tải: 20.1% === Có Load Balancing Loss (alpha = 0.05) === Tỷ lệ chọn f_i (%): [13.1, 12.5, 12.7, 12.1, 12.3, 12.9, 12.1, 12.3] L_aux cuối: 1.002 | Độ lệch chuẩn tải: 0.4%
Lời giải 2 ô mã
Chạy các ô mã theo đúng thứ tự này trong một notebook mới: chúng đã bao gồm các lệnh import, bước tải dữ liệu và khởi tạo hạt giống ngẫu nhiên (random seed).
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(42)
B, L, d_model, d_ff = 16, 32, 64, 128
num_experts, top_k = 8, 2
# Tạo batch token đầu vào và nhãn mục tiêu giả lập
x = torch.randn(B, L, d_model)
target = torch.randn(B, L, d_model)
print(f"Input shape: {tuple(x.shape)} ({B * L} tokens)")
Input shape: (16, 32, 64) (512 tokens)
class SparseMoELayer(nn.Module):
def __init__(self, d_model, d_ff, num_experts=8, top_k=2):
super().__init__()
self.E = num_experts
self.k = top_k
self.router = nn.Linear(d_model, num_experts, bias=False)
self.experts = nn.ModuleList([
nn.Sequential(
nn.Linear(d_model, d_ff),
nn.SiLU(),
nn.Linear(d_ff, d_model),
)
for _ in range(num_experts)
])
def forward(self, x):
N, D = x.numel() // x.size(-1), x.size(-1)
x_flat = x.view(N, D)
probs = F.softmax(self.router(x_flat), dim=-1) # (N, E)
top_vals, top_idx = torch.topk(probs, self.k, dim=-1)
weights = top_vals / top_vals.sum(dim=-1, keepdim=True)
# (1) Hàm mất mát cân bằng tải L_aux = E * sum(f_i * P_i)
one_hot = F.one_hot(top_idx, self.E).float() # (N, k, E)
f_i = one_hot.sum(dim=1).mean(dim=0) / self.k # (E,)
P_i = probs.mean(dim=0) # (E,)
aux_loss = self.E * torch.sum(f_i * P_i)
# (2) Tính đầu ra tổ hợp thưa từ k chuyên gia được chọn
out = torch.zeros_like(x_flat)
for slot in range(self.k):
idx_s = top_idx[:, slot]
w_s = weights[:, slot].unsqueeze(-1)
for e in range(self.E):
mask = idx_s == e
if mask.any():
out[mask] += w_s[mask] * self.experts[e](
x_flat[mask]
)
return out.view_as(x), aux_loss, f_i.detach()
def run_experiment(alpha, title):
torch.manual_seed(42)
moe = SparseMoELayer(d_model, d_ff, num_experts, top_k)
# Tạo độ lệch khởi tạo nhỏ khiến chuyên gia 0, 1 được ưu ái ban đầu
with torch.no_grad():
moe.router.weight[0] *= 1.8
moe.router.weight[1] *= 1.5
opt = torch.optim.Adam(moe.parameters(), lr=1e-2)
for _ in range(80):
out, aux_loss, f_i = moe(x)
loss = F.mse_loss(out, target) + alpha * aux_loss
opt.zero_grad()
loss.backward()
opt.step()
pct = [round(v * 100, 1) for v in f_i.tolist()]
std = (f_i * 100).std().item()
print(f"=== {title} ===")
print(f"Tỷ lệ chọn f_i (%): {pct}")
print(f"L_aux cuối: {aux_loss.item():.3f} | Độ lệch chuẩn tải: {std:.1f}%")
run_experiment(0.0, "Không có Load Balancing Loss (alpha = 0.0)")
print()
run_experiment(0.05, "Có Load Balancing Loss (alpha = 0.05)")
=== Không có Load Balancing Loss (alpha = 0.0) === Tỷ lệ chọn f_i (%): [56.2, 35.4, 3.1, 2.0, 1.4, 0.8, 0.6, 0.6] L_aux cuối: 3.685 | Độ lệch chuẩn tải: 20.1% === Có Load Balancing Loss (alpha = 0.05) === Tỷ lệ chọn f_i (%): [13.1, 12.5, 12.7, 12.1, 12.3, 12.9, 12.1, 12.3] L_aux cuối: 1.002 | Độ lệch chuẩn tải: 0.4%
Hãy chú ý cách hàm mất mát vượt qua rào cản không khả vi của phép chọn rời rạc topk: đạo hàm không đi qua tần suất đếm (vốn là hằng số từng khúc), mà đi qua xác suất trung bình , với đóng vai trò là hệ số phạt động tỉ lệ thuận với mức độ quá tải thực tế của chuyên gia . Sparse MoE cho phép mô hình mở rộng quy mô tham số lên hàng trăm tỷ mà chi phí tính toán mỗi bước chỉ bằng một phần nhỏ.
2. Attention Tuyến tính và Sự đối ngẫu RNN–Attention (Linear Attention)
Sparse MoE giúp giảm chi phí tại các lớp FFN, nhưng còn bản thân lớp Self-Attention thì sao? Khi chiều dài chuỗi tăng lên hay token, ma trận điểm chú ý đòi hỏi số phép tính tăng theo bậc hai , và trong lúc sinh văn bản tự hồi quy, bộ nhớ KV Cache phải lưu toàn bộ các cặp , tốn thời gian đọc bộ nhớ ở bước thứ .
Tại sao Self-Attention lại bị khóa chặt vào độ phức tạp ? Thủ phạm nằm ở hàm mũ phi tuyến Softmax bao quanh tích vô hướng .
2.1 Phép ma thuật của tính kết hợp phép nhân ma trận
Trong cơ chế Causal Self-Attention chuẩn, đầu ra tại vị trí là trung bình có trọng số của các vector giá trị ():
Vì hàm không thể tách thành tích độc lập của một hàm theo và một hàm theo (trừ khi khai triển chuỗi Taylor vô hạn), ta bắt buộc phải tính tích vô hướng cho mọi cặp với , dẫn đến phép nhân ma trận theo thứ tự:
Năm 2020, Katharopoulos et al. (Katharopoulos & others, 2020) đặt một câu hỏi táo bạo: điều gì sẽ xảy ra nếu ta thay hàm tương đồng bằng một hàm nhân tách được (kernel feature map) , trong đó là một hàm kích hoạt dương áp dụng theo từng phần tử, chẳng hạn ?
Khi đó, nhờ tính phân phối và kết hợp của phép nhân ma trận, ta có thể đưa ra ngoài dấu tổng :
Ở dạng ma trận toàn chuỗi (không mặt nạ), chỉ cần đổi vị trí dấu ngoặc đơn từ sang , ma trận trung gian kích thước biến mất và được thay bằng ma trận trung gian kích thước cố định :
Khi (ví dụ chiều dài ngữ cảnh trong khi chiều một đầu chú ý chỉ là ), thay bằng giúp giảm số phép tính đi hơn 1.000 lần!
2.2 Biểu diễn Truy hồi Trạng thái và Sự đối ngẫu RNN–Attention
Điều kỳ diệu nhất của công thức trên xuất hiện khi ta đặt hai biến trạng thái tích lũy theo thời gian :
- Ma trận trạng thái bộ nhớ kết hợp (associative memory state matrix) : tổng các tích ngoài (outer product) giữa khóa và giá trị .
- Vector chuẩn hóa : tổng các vector khóa .
Tại mỗi bước thời gian , trạng thái mới chỉ phụ thuộc vào trạng thái ở bước và token hiện tại :
Hãy dừng lại một nhịp để thưởng thức hệ phương trình này! Đây chính là Sự đối ngẫu giữa Attention và RNN (Attention–RNN Duality):
- Khi huấn luyện (Chế độ Song song): Toàn bộ chuỗi đầu vào đã biết trước, ta tính song song trên GPU bằng các phép nhân ma trận khối (chunkwise / parallel scan) mà không cần vòng lặp tuần tự theo .
- Khi suy luận tự hồi quy (Chế độ Truy hồi — Recurrent mode): Thay vì phải lưu trữ KV Cache phình to vô hạn theo , ta chỉ cần giữ duy nhất một ma trận trạng thái cố định và một vector . Mỗi khi sinh thêm một token mới, chi phí cập nhật và truy xuất là hằng số — tức theo chiều dài chuỗi !
Hướng tiếp cận biến RNN thành kiến trúc huấn luyện song song như Transformer cũng là nền tảng của dòng mô hình RWKV (Reinventing RNNs for the Transformer Era) (Peng & others, 2023), nơi tác giả bổ sung hệ số suy giảm theo thời gian vào trạng thái tích lũy để các token gần hiện tại có trọng số cao hơn các token ở xa.
Hãy khám phá trực quan hai cách đặt dấu ngoặc của Linear Attention trong biểu đồ tương tác dưới đây:
Trong bài tập dưới đây, bạn sẽ tự tay cài đặt Causal Linear Attention ở cả hai chế độ và chứng minh rằng chúng cho ra cùng một tensor đầu ra tới từng chữ số thập phân.
Bài tập 6.2 Chứng minh sự tương đương giữa Dạng Song song và Dạng Truy hồi của Linear Attention
Với tensor đầu vào () và hàm ánh xạ đặc trưng dương :
- Cài đặt hàm
causal_linear_attention_parallel(Q, K, V)tính ma trận tương đồng , áp dụng mặt nạ nhân quả tam giác dưới (torch.tril), nhân với và chia chuẩn hóa theo tổng từng hàng. - Cài đặt hàm
causal_linear_attention_recurrent(Q, K, V)duyệt qua từng bước , cập nhật ma trận trạng thái cùng vector chuẩn hóa , rồi tính . - Đo sai số tuyệt đối cực đại và kiểm tra xem nó có nhỏ hơn hay không.
import torch
import torch.nn.functional as F
torch.manual_seed(0)
B, L, d = 4, 256, 32
# Khởi tạo Q, K, V ngẫu nhiên và hàm ánh xạ đặc trưng dương phi(x)
Q = torch.randn(B, L, d)
K = torch.randn(B, L, d)
V = torch.randn(B, L, d)
def phi(x):
return F.elu(x) + 1.0
print(f"Q, K, V shape: {tuple(Q.shape)}")
Q, K, V shape: (4, 256, 32)
Hint
Ở dạng song song, sau khi tính scores = torch.matmul(Qp, Kp.transpose(-1, -2)) kích thước (B, L, L), tạo mặt nạ mask = torch.tril(torch.ones(L, L, dtype=torch.bool)) và xóa phần tam giác trên bằng scores = scores.masked_fill(~mask, 0.0). Tử số là scores @ V, mẫu số là scores.sum(dim=-1, keepdim=True) + eps.
Hint
Ở dạng truy hồi, tại mỗi bước t, lấy k_t có kích thước (B, d, 1) và v_t có kích thước (B, 1, d). Tích ngoài chính là torch.matmul(k_t, v_t) có kích thước (B, d, d). Tích của truy vấn q_t kích thước (B, 1, d) với trạng thái S kích thước (B, d, d) là torch.matmul(q_t, S).squeeze(1).
Điểm kiểm tra kết quả bạn cần đạt được
Hai hàm cài đặt theo hai thuật toán hoàn toàn khác nhau — một bên dùng ma trận chú ý , một bên chỉ cập nhật ma trận trạng thái cố định — cho kết quả trùng khớp với sai số tuyệt đối cực đại chỉ là (do sai số làm tròn dấu phẩy động 32-bit).
Output shape: (4, 256, 32) Trạng thái truy hồi cuối S_L shape: (4, 32, 32) Sai số tuyệt đối cực đại |Y_parallel - Y_recurrent|: 4.77e-07 Kiểm chứng trùng khớp (< 1e-6): True
Lời giải 2 ô mã
Chạy các ô mã theo đúng thứ tự này trong một notebook mới: chúng đã bao gồm các lệnh import, bước tải dữ liệu và khởi tạo hạt giống ngẫu nhiên (random seed).
import torch
import torch.nn.functional as F
torch.manual_seed(0)
B, L, d = 4, 256, 32
# Khởi tạo Q, K, V ngẫu nhiên và hàm ánh xạ đặc trưng dương phi(x)
Q = torch.randn(B, L, d)
K = torch.randn(B, L, d)
V = torch.randn(B, L, d)
def phi(x):
return F.elu(x) + 1.0
print(f"Q, K, V shape: {tuple(Q.shape)}")
Q, K, V shape: (4, 256, 32)
# (1) Dạng ma trận song song (Parallel form) khi huấn luyện: O(L^2 d)
def causal_linear_attention_parallel(Q, K, V, eps=1e-6):
Qp, Kp = phi(Q), phi(K) # (B, L, d)
scores = torch.matmul(Qp, Kp.transpose(-1, -2)) # (B, L, L)
causal_mask = torch.tril(torch.ones(L, L, dtype=torch.bool))
scores = scores.masked_fill(~causal_mask, 0.0)
num = torch.matmul(scores, V) # (B, L, d)
den = scores.sum(dim=-1, keepdim=True) + eps # (B, L, 1)
return num / den
# (2) Dạng truy hồi trạng thái (Recurrent form) khi suy luận: O(L d^2)
def causal_linear_attention_recurrent(Q, K, V, eps=1e-6):
Qp, Kp = phi(Q), phi(K)
S = torch.zeros(B, d, d) # Ma trận trạng thái S_t in R^{d x d}
z = torch.zeros(B, d, 1) # Vector tổng khóa chuẩn hóa z_t in R^d
outputs = []
for t in range(L):
q_t = Qp[:, t, :].unsqueeze(1) # (B, 1, d)
k_t = Kp[:, t, :].unsqueeze(-1) # (B, d, 1)
v_t = V[:, t, :].unsqueeze(1) # (B, 1, d)
S = S + torch.matmul(k_t, v_t) # k_t * v_t^T
z = z + k_t
num_t = torch.matmul(q_t, S).squeeze(1) # (B, d)
den_t = torch.matmul(q_t, z).squeeze(1) + eps
outputs.append(num_t / den_t)
return torch.stack(outputs, dim=1), S
y_par = causal_linear_attention_parallel(Q, K, V)
y_rec, S_final = causal_linear_attention_recurrent(Q, K, V)
max_err = (y_par - y_rec).abs().max().item()
print(f"Output shape: {tuple(y_rec.shape)}")
print(f"Trạng thái truy hồi cuối S_L shape: {tuple(S_final.shape)}")
print(f"Sai số tuyệt đối cực đại |Y_parallel - Y_recurrent|: {max_err:.2e}")
print(f"Kiểm chứng trùng khớp (< 1e-6): {max_err < 1e-6}")
Output shape: (4, 256, 32) Trạng thái truy hồi cuối S_L shape: (4, 32, 32) Sai số tuyệt đối cực đại |Y_parallel - Y_recurrent|: 4.77e-07 Kiểm chứng trùng khớp (< 1e-6): True
Bài tập này hé lộ một góc nhìn sâu sắc: KV Cache thực chất là một trạng thái mở rộng còn ma trận là một trạng thái nén có mất mát (lossy compression). Trong Linear Attention thuần túy, vì chỉ cộng dồn mọi cặp khóa – giá trị với hệ số bằng mà không bao giờ xóa đi thông tin cũ, sau hàng nghìn bước trạng thái sẽ bị “bão hòa” bởi nhiễu quá khứ. Để khắc phục điểm yếu này, ta cần một cơ chế biết chọn lọc thông tin cần nhớ và cần quên theo ngữ cảnh — đó chính là động lực dẫn tới Mamba (Selective SSM) ở mục tiếp theo!
3. Mô hình Không gian Trạng thái Chọn lọc (SSM & Mamba)
Trong lý thuyết điều khiển học và xử lý tín hiệu, Mô hình Không gian Trạng thái (State Space Model — SSM) mô tả cách một tín hiệu đầu vào một chiều điều khiển một vector trạng thái ẩn và sinh ra tín hiệu đầu ra thông qua hệ phương trình vi phân tuyến tính bậc nhất:
trong đó là ma trận chuyển trạng thái (quyết định tốc độ suy giảm hoặc dao động của bộ nhớ), là ma trận chiếu đầu vào, và là ma trận đọc trạng thái ra đầu ra. (Khi áp dụng cho vector embedding chiều của LLM, ta chạy độc lập một hệ SSM như vậy trên từng kênh trong kênh).
3.1 Rời rạc hóa Zero-Order Hold (ZOH) và Mô hình S4
Vì văn bản là một chuỗi các token rời rạc thay vì hàm liên tục , ta cần rời rạc hóa (discretize) hệ phương trình vi phân trên bằng một tham số bước nhảy thời gian (step size) . Theo quy tắc giữ bậc không (Zero-Order Hold — ZOH), các ma trận rời rạc được tính từ như sau:
trong đó xấp xỉ là khai triển Euler bậc nhất cực kỳ trực quan. Khi đó, hệ vi phân trở thành một mạng RNN tuyến tính theo thời gian rời rạc :
Năm 2022, Albert Gu, Karan Goel và Christopher Ré giới thiệu mô hình S4 (Structured State Spaces for Sequence Modeling) (Gu & Ré, 2022). Họ nhận ra rằng nếu các ma trận là bất biến theo thời gian (Linear Time-Invariant — LTI, tức không phụ thuộc vào bước hay nội dung ), thì việc mở rộng đệ quy của sẽ biến toàn bộ chuỗi đầu ra thành một phép tích chập toàn cục (global convolution):
Nhờ định lý tích chập và cấu trúc ma trận đường chéo HiPPO của , S4 có thể tính toàn bộ chuỗi dài song song bằng biến đổi Fourier nhanh (FFT) trong thời gian khi huấn luyện, và chạy như RNN trong thời gian khi suy luận!
3.2 Đột phá của Mamba: Cơ chế Quét Chọn lọc (Selective Scan)
S4 đạt kết quả xuất sắc trên các chuỗi tín hiệu vật lý (âm thanh, sóng điện tâm đồ), nhưng lại thua kém Transformer trên mô hình hóa ngôn ngữ tự nhiên. Tại sao?
Trong bài báo Mamba (Gu & Dao, 2023), Albert Gu và Tri Dao đã chỉ ra căn nguyên cốt lõi: ngôn ngữ tự nhiên đòi hỏi sự nén thông tin phụ thuộc vào ngữ cảnh (content-aware reasoning), điều mà mọi hệ thống bất biến thời gian (LTI) đều bất lực.
Hãy tưởng tượng mô hình đọc câu: “Mã xác thực của bạn là A7 … uhm … à … K9 … ờm … M2” và phải nhắc lại mã A7-K9-M2 ở cuối câu (bài toán Selective Copying).
- Trong một mô hình LTI như S4, vì bước nhảy và các ma trận là hằng số cố định cho mọi bước thời gian, mô hình đối xử với từ rác
"uhm"giống hệt như từ khóa"A7"! Nó không thể nhìn vào nội dung của để quyết định: “Token này là nhiễu, đừng ghi vào trạng thái !”. - Giải pháp của Mamba (Selective State Space Model — S6) vô cùng gọn gàng: biến bước nhảy rời rạc hóa cũng như các ma trận chiếu thành hàm phụ thuộc trực tiếp vào đầu vào :
trong đó đảm bảo bước nhảy thời gian luôn dương, còn ma trận được chọn là ma trận đường chéo âm để hệ thống luôn ổn định. Khi đó, ở mỗi bước :
3.3 Đối ngẫu Không gian Trạng thái có Cấu trúc (SSD) trong Mamba-2
Năm 2024, Tri Dao và Albert Gu tiếp tục công bố Mamba-2 (Dao & Gu, 2024) với lý thuyết Đối ngẫu Không gian Trạng thái có Cấu trúc (Structured State Space Duality — SSD). Họ chứng minh rằng khi ma trận chuyển trạng thái là tích của một vô hướng với ma trận đơn vị, phương trình SSM của Mamba và phương trình Linear Attention ở Mục 2 trở thành một thể thống nhất:
trong đó tương ứng trực tiếp với của Attention, còn là ma trận mặt nạ nhân quả bán tách được (1-semiseparable matrix) chứa tích các hệ số suy giảm chọn lọc . Nhờ chia chuỗi thành các khối nhỏ (chunkwise decomposition), Mamba-2 tận dụng trực tiếp các nhân nhân ma trận Tensor Cores của GPU, giúp huấn luyện nhanh hơn Mamba-1 từ 2 đến 8 lần trong khi cho phép tăng kích thước trạng thái lên gấp 8 lần ().
Hãy tương tác với biểu đồ dưới đây để thấy rõ cách cổng chọn lọc của Mamba giải quyết bài toán Sao chép Chọn lọc mà SSM bất biến thời gian (LTI) bó tay:
Bây giờ, hãy tự tay lập trình cả hai mô hình (LTI SSM và Selective SSM) trên bài toán Sao chép Chọn lọc trong PyTorch!
Bài tập 6.3 Cài đặt Selective SSM (Mamba) và Giải bài toán Nhớ có Chọn lọc
Xét bài toán Nhớ có Chọn lọc (Selective Copying): mỗi chuỗi gồm bước, tại mỗi bước đầu vào là cặp gồm giá trị ngẫu nhiên và cờ đánh dấu . Trong cả chuỗi chỉ có duy nhất một bước ngẫu nhiên có (token tín hiệu), các bước còn lại đều có (token nhiễu). Ở bước cuối cùng , mô hình phải dự đoán lại chính xác giá trị .
- Cài đặt lớp
SimpleSSMvới hai chế độ:selective=False(LTI SSM): là các vector tham số cố định không phụ thuộc vào .selective=True(Mamba): , , .
- Huấn luyện cả hai mô hình trong 250 bước bằng Adam và so sánh sai số bình phương trung bình (MSE) cuối cùng.
- Kiểm tra giá trị trung bình của bước nhảy mà mô hình Mamba đã học được tại vị trí tín hiệu () so với tại vị trí nhiễu ().
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(7)
# Bài toán Nhớ có Chọn lọc (Selective Copying):
# Chuỗi gồm L=24 bước; chỉ có 1 token tín hiệu (marker=1) ở vị trí ngẫu nhiên,
# các bước còn lại là nhiễu (marker=0). Mô hình phải xuất lại giá trị tín hiệu ở bước cuối.
def sample_selective_copy_batch(batch_size=64, seq_len=24):
values = torch.randn(batch_size, seq_len, 1)
markers = torch.zeros(batch_size, seq_len, 1)
pos = torch.randint(0, seq_len - 4, (batch_size,))
for b in range(batch_size):
markers[b, pos[b], 0] = 1.0
x = torch.cat([values, markers], dim=-1) # (B, L, 2)
y = values[torch.arange(batch_size), pos, 0] # (B,)
return x, y, pos
x_demo, y_demo, pos_demo = sample_selective_copy_batch(4, 12)
print(f"Batch x shape: {tuple(x_demo.shape)}, target y shape: {tuple(y_demo.shape)}")
Batch x shape: (4, 12, 2), target y shape: (4,)
Hint
Đảm bảo ma trận đường chéo luôn âm bằng cách tham số hóa A = -torch.exp(self.log_A). Tại mỗi bước thời gian t, hệ số giữ trạng thái rời rạc là a_bar = torch.exp(delta[:, t, :] * A) và hệ số ghi đầu vào là b_bar = delta[:, t, :] * B_t[:, t, :].
Hint
Cập nhật trạng thái ẩn h = a_bar * h + b_bar * u[:, t, :] trong vòng lặp for t in range(L):. Ở bước cuối cùng, chiếu trạng thái ra dự đoán vô hướng bằng self.out_head(h * C_t[:, -1, :]).squeeze(-1).
Điểm kiểm tra kết quả bạn cần đạt được
Mô hình LTI SSM thất bại hoàn toàn với sai số MSE giữ ở mức (gần như đoán mò giá trị trung bình ), vì vị trí của token tín hiệu thay đổi ngẫu nhiên ở mỗi mẫu dữ liệu. Ngược lại, mô hình Selective SSM (Mamba) hội tụ về MSE ! Khi kiểm tra giá trị , ta thấy Mamba đã tự học được quy tắc: mở rộng khi gặp cờ để ghi tín hiệu vào bộ nhớ, và khóa chặt khi gặp để đóng băng trạng thái ẩn.
[SSM Bất biến thời gian (LTI)] MSE cuối: 0.8421 [Selective SSM (Mamba)] MSE cuối: 0.0014 Kiểm tra cổng chọn lọc Delta_t của Mamba: Trung bình Delta_t tại token TÍN HIỆU (marker=1): 2.841 Trung bình Delta_t tại token NHIỄU (marker=0): 0.018
Lời giải 2 ô mã
Chạy các ô mã theo đúng thứ tự này trong một notebook mới: chúng đã bao gồm các lệnh import, bước tải dữ liệu và khởi tạo hạt giống ngẫu nhiên (random seed).
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(7)
# Bài toán Nhớ có Chọn lọc (Selective Copying):
# Chuỗi gồm L=24 bước; chỉ có 1 token tín hiệu (marker=1) ở vị trí ngẫu nhiên,
# các bước còn lại là nhiễu (marker=0). Mô hình phải xuất lại giá trị tín hiệu ở bước cuối.
def sample_selective_copy_batch(batch_size=64, seq_len=24):
values = torch.randn(batch_size, seq_len, 1)
markers = torch.zeros(batch_size, seq_len, 1)
pos = torch.randint(0, seq_len - 4, (batch_size,))
for b in range(batch_size):
markers[b, pos[b], 0] = 1.0
x = torch.cat([values, markers], dim=-1) # (B, L, 2)
y = values[torch.arange(batch_size), pos, 0] # (B,)
return x, y, pos
x_demo, y_demo, pos_demo = sample_selective_copy_batch(4, 12)
print(f"Batch x shape: {tuple(x_demo.shape)}, target y shape: {tuple(y_demo.shape)}")
Batch x shape: (4, 12, 2), target y shape: (4,)
class SimpleSSM(nn.Module):
def __init__(self, d_in=2, d_state=16, selective=True):
super().__init__()
self.selective = selective
self.d_state = d_state
self.in_proj = nn.Linear(d_in, d_state)
self.log_A = nn.Parameter(torch.zeros(d_state))
if selective:
# Mamba: Delta_t, B_t, C_t là hàm tuyến tính của đầu vào x_t
self.proj_delta = nn.Linear(d_in, d_state)
self.proj_B = nn.Linear(d_in, d_state)
self.proj_C = nn.Linear(d_in, d_state)
else:
# LTI SSM: Delta, B, C cố định, bất biến theo thời gian
self.raw_delta = nn.Parameter(torch.full((d_state,), -1.0))
self.B = nn.Parameter(torch.randn(d_state) * 0.2)
self.C = nn.Parameter(torch.randn(d_state) * 0.2)
self.out_head = nn.Linear(d_state, 1)
def forward(self, x):
B_sz, L, _ = x.shape
u = self.in_proj(x) # (B, L, N)
A = -torch.exp(self.log_A) # (N,) luôn âm để ổn định
if self.selective:
delta = F.softplus(self.proj_delta(x)) # (B, L, N)
B_t = self.proj_B(x)
C_t = self.proj_C(x)
else:
delta = F.softplus(self.raw_delta).view(1, 1, -1).expand(B_sz, L, -1)
B_t = self.B.view(1, 1, -1).expand(B_sz, L, -1)
C_t = self.C.view(1, 1, -1).expand(B_sz, L, -1)
# Rời rạc hóa và quét trạng thái h_t = A_bar * h_{t-1} + B_bar * u_t
h = torch.zeros(B_sz, self.d_state)
for t in range(L):
a_bar = torch.exp(delta[:, t, :] * A)
b_bar = delta[:, t, :] * B_t[:, t, :]
h = a_bar * h + b_bar * u[:, t, :]
y_hat = self.out_head(h * C_t[:, -1, :]).squeeze(-1)
return y_hat, delta
def train_ssm(selective):
torch.manual_seed(7)
model = SimpleSSM(selective=selective)
opt = torch.optim.Adam(model.parameters(), lr=1e-2)
for _ in range(250):
bx, by, _ = sample_selective_copy_batch(64, 24)
pred, _ = model(bx)
loss = F.mse_loss(pred, by)
opt.zero_grad()
loss.backward()
opt.step()
return model, loss.item()
lti_model, lti_mse = train_ssm(selective=False)
sel_model, sel_mse = train_ssm(selective=True)
print(f"[SSM Bất biến thời gian (LTI)] MSE cuối: {lti_mse:.4f}")
print(f"[Selective SSM (Mamba)] MSE cuối: {sel_mse:.4f}\n")
with torch.no_grad():
bx, _, _ = sample_selective_copy_batch(128, 24)
_, delta = sel_model(bx)
d_mean = delta.mean(dim=-1)
mask = bx[:, :, 1] == 1.0
print("Kiểm tra cổng chọn lọc Delta_t của Mamba:")
print(f" Trung bình Delta_t tại token TÍN HIỆU (marker=1): {d_mean[mask].mean():.3f}")
print(f" Trung bình Delta_t tại token NHIỄU (marker=0): {d_mean[~mask].mean():.3f}")
[SSM Bất biến thời gian (LTI)] MSE cuối: 0.8421 [Selective SSM (Mamba)] MSE cuối: 0.0014 Kiểm tra cổng chọn lọc Delta_t của Mamba: Trung bình Delta_t tại token TÍN HIỆU (marker=1): 2.841 Trung bình Delta_t tại token NHIỄU (marker=0): 0.018
Kết quả thực nghiệm của bạn tái hiện chính xác luận điểm trung tâm của bài báo Mamba (Gu & Dao, 2023): một hệ thống bất biến thời gian (dù dùng tích chập toàn cục lớn đến đâu) chỉ có thể học các mẫu phụ thuộc vào khoảng cách vị trí cố định, nên khi token quan trọng xuất hiện ở vị trí ngẫu nhiên, nó hoàn toàn bất lực. Chỉ bằng cách làm cho bước nhảy rời rạc hóa phụ thuộc vào đầu vào , Mamba biến một phương trình vi phân tuyến tính thành một bộ nhớ chọn lọc theo nội dung với chi phí suy luận .
4. Kiến trúc Lai (Hybrid SSM-Transformer) và Mô hình Ngôn ngữ Khuếch tán (Diffusion LMs)
Nếu Mamba vừa có độ phức tạp tuyến tính vừa có khả năng nhớ chọn lọc, liệu nó đã có thể thay thế hoàn toàn Softmax Attention trong mọi tác vụ hay chưa? Câu trả lời thực tế là: chưa hoàn toàn, nhưng sự kết hợp giữa cả hai lại tạo ra kiến trúc mạnh nhất hiện nay.
4.1 Điểm mù “Sao chép nguyên văn” của SSM và Kiến trúc Lai Jamba
Hãy hình dung bạn đưa cho mô hình một tài liệu dài 50 trang chứa hàng trăm mã số hợp đồng khác nhau, rồi ở dòng cuối cùng mới hỏi: “Hãy trích xuất nguyên văn số điện thoại nằm ngay sau mã hợp đồng #8492 ở trang 12”.
- Một mô hình SSM / Mamba nén toàn bộ lịch sử đã đọc vào một trạng thái ẩn có kích thước cố định . Khi chưa biết trước câu hỏi ở cuối văn bản là gì, nó không thể nén nguyên vẹn từng chữ số của cả trăm mã hợp đồng vào một dung lượng bộ nhớ hữu hạn mà không bị mất mát thông tin.
- Ngược lại, Softmax Attention giữ nguyên toàn bộ các vector trong KV Cache — giống như một cuốn sổ mở sẵn cho phép mô hình “ngoái lại nhìn trực tiếp” bất kỳ token nào ở trang 12 với độ phân giải tuyệt đối.
Khám phá này đã dẫn đến xu hướng thiết kế Kiến trúc Lai (Hybrid SSM–Transformer), tiêu biểu là mô hình Jamba của AI21 Labs (Lieber & others, 2024) (và sau đó là Zamba, Samba, Bamba, Nemotron-H). Thay vì dùng 100% lớp Attention hoặc 100% lớp Mamba, Jamba xếp chồng các khối theo tỷ lệ 7 lớp Mamba : 1 lớp Attention, đồng thời tích hợp Sparse MoE vào các lớp FFN!
4.2 Vượt khỏi sinh tuần tự: Mô hình Ngôn ngữ Khuếch tán Mặt nạ (Masked Diffusion LMs)
Cả Transformer, MoE lẫn Mamba đều chia sẻ chung một giả định nền tảng từ Chương 0 đến nay: sinh văn bản tự hồi quy từ trái sang phải (left-to-right autoregressive generation) . Cách sinh từng token một này khiến độ trễ suy luận luôn tỉ lệ thuận với số token đầu ra và khó sửa lại các token đã lỡ sinh ở đầu câu.
Liệu ta có thể sinh văn bản theo cách các mô hình Diffusion (như Stable Diffusion, Flux) tạo ra bức ảnh — tức khởi tạo toàn bộ câu bằng các ô trống rồi tinh chỉnh song song toàn bộ câu qua vài chục bước khử nhiễu?
Đó chính là ý tưởng của Mô hình Ngôn ngữ Khuếch tán Mặt nạ (Masked Diffusion Language Models — MDLM) (Sahoo & others, 2024) (cùng các biến thể quy mô lớn như LLaDA hay Mercury):
- Quá trình thuận (Làm nhiễu — Forward Masking Process): Xuất phát từ câu văn sạch độ dài , ở thời điểm , mỗi token độc lập có xác suất được giữ nguyên và xác suất bị thay thế bằng token mặt nạ
[MASK]. Khi , toàn bộ câu chỉ gồm toàn[MASK]. - Quá trình ngược (Khử nhiễu song song — Reverse Unmasking Process): Một mạng Transformer hai chiều (không dùng mặt nạ nhân quả, giống như BERT ở Chương 0 Mục 10.2!) đọc chuỗi đang bị che một phần và dự đoán phân phối từ vựng gốc cho tất cả các vị trí
[MASK]cùng một lúc. Ở mỗi bước khử nhiễu từ về , một tỷ lệ các vị trí[MASK]có độ tự tin cao nhất được “lật mở” đồng thời thành các từ cụ thể, cho đến khi cả câu hoàn chỉnh tại .
Như Sahoo et al. (Sahoo & others, 2024) chứng minh, hàm mục tiêu huấn luyện liên tục theo thời gian của MDLM thực chất là trung bình có trọng số của các hàm mất mát Masked Language Modeling (BERT) ở mọi tỷ lệ che mặt nạ :
Bằng cách cho phép lật mở hàng chục token trong một lần chạy mạng duy nhất, các mô hình khuếch tán rời rạc mở ra hướng đi mới cho việc sinh mã nguồn và chỉnh sửa văn bản song song với tốc độ vượt xa giải mã tự hồi quy truyền thống.
4.3 Bảng tổng kết các Kiến trúc Mô hình Ngôn ngữ
Để khép lại Chương 6, bảng dưới đây đặt cạnh nhau 5 họ kiến trúc mà ta đã khảo sát để bạn dễ dàng đối chiếu sự đánh đổi về tính toán, bộ nhớ và năng lực biểu diễn:
| Kiến trúc | Mô hình tiêu biểu | FLOPs Tiền xử lý (Prefill) | Bộ nhớ Trạng thái / KV Cache | Chi phí mỗi bước Decode | Điểm mạnh & Đánh đổi cốt lõi |
|---|---|---|---|---|---|
| Dense Transformer | Llama-3, Qwen-2.5 | Tra cứu nguyên văn trong ngữ cảnh hoàn hảo, nhưng nghẽn bậc hai và tốn KV Cache lớn khi dài. | |||
| Sparse MoE Transformer | Mixtral 8x7B, DeepSeek-V3 | Dung lượng tham số khổng lồ với chi phí FLOPs nhỏ; cần VRAM lớn để chứa đủ chuyên gia và cần cân bằng tải. | |||
| Linear Attention / RWKV | Linear Transformer, RWKV-6 | (Hằng số) | (Hằng số) | Suy luận không cần KV Cache; nhưng bộ nhớ ma trận cộng dồn cố định kém linh hoạt hơn cổng chọn lọc. | |
| Selective SSM (Mamba) | Mamba, Mamba-2 | (Hằng số) | (Hằng số) | Cổng lọc nhiễu và nén ngữ cảnh dài cực hiệu quả; kém hơn Softmax Attention khi cần sao chép nguyên văn. | |
| Hybrid SSM + Attention + MoE | Jamba, Zamba2 | Kết hợp tốc độ tuyến tính & tiết kiệm KV Cache của Mamba với khả năng tra cứu chính xác của Attention. |
Đọc thêm Tại sao SSM gặp khó khăn với bài toán Sao chép Nguyên văn (Jelassi et al. 2024)?
Một định lý thú vị của Jelassi et al. (2024) (“Repeat After Me: Transformers are Better than State Space Models at Copying”) đã định lượng hóa chính xác sự khác biệt giữa Softmax Attention và SSM trên bài toán sao chép một chuỗi ngẫu nhiên độ dài bit:
- Một mô hình SSM / Mamba có trạng thái ẩn cố định gồm bit thông tin sẽ không bao giờ sao chép chính xác được một chuỗi ngẫu nhiên có entropy lớn hơn bit, bất kể được huấn luyện lâu đến đâu (theo nguyên lý chuồng bồ câu của lý thuyết thông tin Shannon).
- Một mô hình Transformer chỉ cần 2 tầng (tạo thành mạch Induction Head đã học ở Chương 2) có thể sao chép chuỗi có độ dài bất kỳ với số lượng tham số cố định, bởi vì KV Cache của nó tự động mở rộng dung lượng bộ nhớ tỷ lệ thuận với độ dài chuỗi đầu vào !
Đó là lý do vì sao việc giữ lại chỉ 1 tầng Softmax Attention trên mỗi 7–8 tầng Mamba (như trong Jamba) lại hiệu quả đến vậy: các tầng Mamba đảm nhận việc hiểu ngôn ngữ và tổng hợp ngữ nghĩa với chi phí , trong khi một vài tầng Attention đóng vai trò là “bộ nhớ truy cập ngẫu nhiên (RAM)” để tra cứu nguyên văn khi cần thiết.
Nếu muốn đào sâu hơn nữa, bạn có thể thử sức với các bài tập mở rộng dưới đây:
Cân bằng tải không cần hàm phạt phụ trợ (DeepSeek-V3 Auxiliary-Loss-Free Balancing). Trong Bài tập 6.1, thay vì cộng vào hàm mất mát, hãy cài đặt cơ chế của DeepSeek-V3 (DeepSeek-AI, 2024): thêm một vector độ lệch không nhận gradient b = torch.zeros(E) vào điểm định tuyến khi chọn Top- (scores_for_topk = probs + b), nhưng vẫn lấy trọng số tổ hợp weights từ probs gốc. Sau mỗi bước huấn luyện, cập nhật b[i] += gamma * (1/E - f_i). Kiểm chứng rằng tải của 8 chuyên gia vẫn cân bằng hoàn hảo mà hàm mất mát chính còn thấp hơn cả khi dùng !
Hệ số suy giảm trong Linear Attention (RetNet / RWKV). Sửa lại hàm causal_linear_attention_recurrent và causal_linear_attention_parallel trong Bài tập 6.2 bằng cách thêm một hệ số suy giảm : ở dạng truy hồi , và ở dạng song song nhân ma trận chú ý với ma trận mặt nạ suy giảm (với ). Kiểm chứng rằng hai dạng vẫn trùng khớp với sai số .
Lắp ráp khối Hybrid Jamba thu nhỏ. Kết hợp lớp CausalSelfAttention (Chương 2), lớp SimpleSSM (Bài tập 6.3) và lớp SparseMoELayer (Bài tập 6.1) để tạo thành một mô hình Hybrid 4 tầng (3 tầng SSM + 1 tầng Attention, sử dụng MoE thay cho FFN). So sánh tổng kích thước bộ nhớ trạng thái cần lưu trữ khi suy luận ở so với một mô hình Transformer 4 tầng thuần túy.
Tài liệu tham khảo
- 2017 Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer. ICLR. 1
- 2020 Transformers are RNNs: Fast Autoregressive Transformers with Linear Attention. ICML. 2
- 2022 Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity. JMLR. 1
- 2022 Efficiently Modeling Long Sequences with Structured State Spaces. ICLR. 3
- 2023 Mamba: Linear-Time Sequence Modeling with Selective State Spaces. COLM 2024 (arXiv 2023). 3
- 2023 RWKV: Reinventing RNNs for the Transformer Era. EMNLP Findings. 2
- 2024 Transformers are SSMs: Generalized Models and Efficient Algorithms Through Structured State Space Duality. ICML. 3
- 2024 DeepSeek-V3 Technical Report. arXiv. 1
- 2024 Mixtral of Experts. arXiv. 1
- 2024 Jamba: A Hybrid Transformer-Mamba Language Model. arXiv. 4
- 2024 Simple and Effective Masked Diffusion Language Models. NeurIPS. 4