Chương 9·Bài 9.3

Bài tập lý thuyết

Một số đề thi AI có phần lý thuyết: không cần code, chỉ cần lời giải viết ra kiểm được từng bước. Ví dụ: một bộ phát hiện bài nộp có lỗi “phát hiện được 90% bài lỗi”; vậy một bài bị cảnh báo có xác suất lỗi 90% không? Không nhất thiết, và phải dùng công thức Bayes để giải thích.

Bài này luyện các dạng bài lý thuyết về xác suất, đại số tuyến tính, tối ưu, kiến trúc mạng và đánh giá model; mỗi mục có ví dụ giải tay và một đoạn code ngắn để đối chiếu.

Một lời giải cần cho người đọc kiểm được

Trong CP, chứng minh thuật toán thường có invariant và độ phức tạp. Với AI, lời giải cũng cần một đường kiểm tra: đề cho gì, mô hình giả định gì, dùng định nghĩa nào và kết quả có ý nghĩa gì. Chẳng hạn “p=0.9p=0.9” chưa đủ; phải nói đây là P(cảnh baˊo∣coˊ loˆ˜i)P(\text{cảnh báo}\mid\text{có lỗi}) hay P(coˊ loˆ˜i∣cảnh baˊo)P(\text{có lỗi}\mid\text{cảnh báo}).

Ta dùng quy trình bốn bước:

  1. Xác định đại lượng cần trả lời, không tính ngay số dễ có nhất.
  2. Viết ký hiệu cùng miền giá trị, shape hoặc đơn vị.
  3. Biến đổi công thức trước khi thế số, để người đọc nhận ra phép tính dùng định nghĩa nào.
  4. Kiểm bằng một trường hợp nhỏ hoặc code độc lập, rồi diễn giải kết quả.

Code là công cụ đối chiếu; dòng True không thay thế lời giải thích vì sao.

Hai chiều của việc kiểm không cân nhau. Một khẳng định “với mọi w\mathbf w” không được chứng minh bằng hữu hạn lần chạy, dù nhiều đến đâu. Ngược lại, một phản ví dụ nhỏ, chạy đúng, đủ để bác bỏ nó.

Hỏi nhanh

Đề yêu cầu chứng minh MSE 1n∑i(y^i−yi)2\frac1n\sum_i(\hat y_i - y_i)^2 không âm với mọi w\mathbf w. Một bạn chạy 1000 bộ w\mathbf w ngẫu nhiên và thấy loss luôn từ 0 trở lên. Phần này có giá trị gì?

Xác suất: điều kiện nằm ở phía nào?

Giả sử một tập kiểm có đúng 1000 bài nộp: 20 bài có lỗi và 980 bài không lỗi. Detector cảnh báo 18 trong 20 bài lỗi, đồng thời cảnh báo nhầm 98 trong 980 bài sạch.

Trong 116 cảnh báo chỉ có 18 bài thật sự lỗi.lỗi, bị cảnh báo: 18lỗi, bị sót: 2sạch, cảnh báo nhầm: 98sạch: 882P(lỗi | cảnh báo)= 18 / 116 ≈ 0.155
Trong 116 cảnh báo chỉ có 18 bài thật sự lỗi.

Chọn ngẫu nhiên đều một bài trong tập này. Gọi BB là biến cố “bài có lỗi”, FF là “bị cảnh báo”. Ta có P(B)=20/1000=0.02P(B)=20/1000=0.02, P(F∣B)=18/20=0.9P(F\mid B)=18/20=0.9 và P(F∣¬B)=98/980=0.1P(F\mid\neg B)=98/980=0.1. Bayes đảo chiều điều kiện:

P(B∣F)=P(F∣B)P(B)P(F).P(B\mid F)=\frac{P(F\mid B)P(B)}{P(F)}.

Mẫu số dùng total probability:

P(F)=P(F∣B)P(B)+P(F∣¬B)P(¬B)=0.018+0.098=0.116.P(F)=P(F\mid B)P(B)+P(F\mid\neg B)P(\neg B)=0.018+0.098=0.116.

Vậy P(B∣F)=0.018/0.116=18/116≈0.1552P(B\mid F)=0.018/0.116=18/116\approx0.1552, chỉ khoảng 15.5%. Khi lỗi hiếm, một tỉ lệ báo nhầm nhỏ trên nhóm sạch lớn vẫn sinh nhiều cảnh báo hơn nhóm lỗi. Không có mâu thuẫn với recall 90%; hai câu hỏi dùng hai tập làm mẫu số khác nhau. Recall và tỉ lệ báo nhầm là tính chất của detector; P(B∣F)P(B\mid F) còn phụ thuộc tỉ lệ lỗi P(B)P(B) của nơi đem detector ra dùng.

Bộ phân loại Bayes chọn lớp có xác suất hậu nghiệm lớn nhất; không có đặc trưng nào thì chỉ còn tiền nghiệm, nên với hai lớp chiếm 2/3 và 1/3 ta đoán lớp đông.

Python
import numpy as np

tp, fn, fp, tn = 18, 2, 98, 882
total = tp + fn + fp + tn
prior = (tp + fn) / total
sensitivity = tp / (tp + fn)
false_alarm_rate = fp / (fp + tn)
alarm_probability = sensitivity * prior + false_alarm_rate * (1 - prior)
posterior = sensitivity * prior / alarm_probability
print(f"P(lỗi)={prior:.4f}, P(cảnh báo)={alarm_probability:.4f}")
print(f"P(lỗi | cảnh báo)={posterior:.4f}")
assert np.isclose(posterior, tp / (tp + fp))

Muốn nhân hai xác suất cho hai thuộc tính, phải kiểm điều kiện độc lập tương ứng. Công thức luôn đúng là P(A∩B)=P(A∣B)P(B)P(A\cap B)=P(A\mid B)P(B); chỉ khi độc lập mới đổi thành P(A)P(B)P(A)P(B). Một feature xuất hiện nhiều trong bài lỗi không tự động độc lập với feature khác, cũng không chứng minh quan hệ nhân quả.

Vài phép đếm cơ bản: xúc xắc cân đối ra mặt từ 5 trở lên có xác suất 2/62/6; xác suất có điều kiện chỉ đếm trong nhóm điều kiện, nên lớp có 12 bạn nữ, 3 bạn nữ đeo kính cho P(kıˊnh∣nữ)=3/12P(\text{kính} \mid \text{nữ}) = 3/12.

Naive Bayes (bài 6.1) dùng đúng giả định độc lập khi đã biết lớp, nên chỉ ước lượng từng P(xj∣y)P(x_j \mid y): dd đặc trưng nhị phân, hai lớp cần 2d+12d + 1 tham số. Nếu không có giả định này, ta phải đếm mọi tổ hợp, mà tổ hợp đủ nn từ khóa của một thư mới thường không có thư nào trong train. Cái giá: nhân đôi một cột thì bằng chứng ấy bị đếm hai lần và xác suất thành quá tự tin.

Hỏi nhanh

Gọi BB là bài có lỗi, FF là bài bị cảnh báo. Trong 20 bài đã biết là có lỗi, có 18 bài được cảnh báo. Tỉ lệ 18/2018/20 ước lượng xác suất nào?

Hỏi nhanh

Giữ nguyên detector, bắt được 90% bài lỗi và báo nhầm 10% bài sạch. Đem dùng ở một lớp mà một nửa số bài có lỗi. Ở lớp này, một bài bị cảnh báo có lỗi với xác suất bao nhiêu?

Tỉ lệ lỗi càng thấp, phần cảnh báo đúng càng nhỏ.00.510.020.250.50.751tỉ lệ bài lỗi P(B)0.1550.900recall 0.9P(lỗi | cảnh báo)
Tỉ lệ lỗi càng thấp, phần cảnh báo đúng càng nhỏ.
Tỉ lệ lỗi càng thấp, phần cảnh báo đúng trong mọi cảnh báo càng nhỏ.

Kỳ vọng và log-loss: trước khi biết đáp án

Một biến Bernoulli Y∈{0,1}Y\in\{0,1\} có P(Y=1)=qP(Y=1)=q thì E[Y]=q\E[Y]=q, vì 0(1−q)+1q=q0(1-q)+1q=q. Do Y2=YY^2=Y, phương sai là Var⁡(Y)=q−q2=q(1−q)\operatorname{Var}(Y)=q-q^2=q(1-q). Với q=0.02q=0.02, hai số lần lượt là 0.020.02 và 0.01960.0196. Kỳ vọng mô tả trung bình qua nhiều lần rút; một nhóm 50 bài cụ thể vẫn có thể có 0, 1 hay 3 bài lỗi.

Nếu model xuất xác suất pp của lớp 1 và nhãn thật là yy, binary cross-entropy là

L(p,y)=−ylog⁡p−(1−y)log⁡(1−p).L(p,y)=-y\log p-(1-y)\log(1-p).

Ta dùng logarithm tự nhiên nên loss có đơn vị nats. Khi y=1y=1, p=0.8p=0.8 cho loss −log⁡0.8≈0.2231-\log0.8\approx0.2231; dự đoán tự tin sai p=0.2p=0.2 cho khoảng 1.60941.6094. Accuracy không thấy mức tự tin này nếu hai xác suất vẫn ở cùng một phía threshold.

BCE chính là −log⁡-\log của xác suất mà model gán cho nhãn thật, tức negative log-likelihood của một mẫu Bernoulli. Vì log⁡\log tăng ngặt, tham số làm likelihood của cả tập lớn nhất cũng làm tổng log-loss nhỏ nhất: maximum likelihood và tối thiểu log-loss là cùng một bài toán.

Trước khi biết YY, kỳ vọng loss của dự đoán cố định pp là −qlog⁡p−(1−q)log⁡(1−p)-q\log p-(1-q)\log(1-p). Giá trị nhỏ nhất đạt tại p=qp=q khi 0<q<10<q<1; thay vào cho entropy H(q)H(q). Nói cách khác, biết tỉ lệ lớp thật thì xác suất phản ánh tỉ lệ đó là dự đoán tối ưu cho log-loss, chưa chắc là quyết định tối ưu cho mọi chi phí hành động.

Python
def expected_log_loss(q, p):
    return -q * np.log(p) - (1 - q) * np.log(1 - p)

q = 0.02
print(f"E[Y]={q:.4f}, Var(Y)={q * (1 - q):.4f}")
print(f"y=1: loss tại p=0.8 là {-np.log(0.8):.4f}; tại p=0.2 là {-np.log(0.2):.4f}")
print(f"E[loss] tại p=0.02: {expected_log_loss(q, 0.02):.4f}")
print(f"E[loss] tại p=0.50: {expected_log_loss(q, 0.50):.4f}")
assert expected_log_loss(q, q) < expected_log_loss(q, 0.5)

Không lấy log(0) trong code tính tay; nó cho vô cùng. Với logits, thư viện có loss gộp sigmoid hoặc softmax để tính ổn định hơn. Một vector xác suất phải không âm và tổng bằng 1; một vector logits không có hai điều kiện này. Khi trình bày, cần nói model đang xuất đại lượng nào.

Hỏi nhanh

Trong tập train, 30% nhãn là 1. Model chỉ được xuất một xác suất pp cho mọi mẫu. Giá trị pp nào cho log-loss trung bình nhỏ nhất?

Log loss kỳ vọng nhỏ nhất khi dự đoán đúng bằng tỉ lệ thật.00.511.50.020.30.51xác suất dự đoán pq = 0.02: 0.098q = 0.3: 0.611kỳ vọng log-loss
Log loss kỳ vọng nhỏ nhất khi dự đoán đúng bằng tỉ lệ thật.

Đại số tuyến tính: phép nhân mô tả việc gì?

Ta có hai mẫu, mỗi mẫu hai feature, xếp thành hàng của XX. Linear model với w=(2,−1)\mathbf w=(2,-1) và b=1b=1 cho

X=[1234],y^=Xw+b=[13].X=\begin{bmatrix}1&2\\3&4\end{bmatrix},\qquad\hat{\mathbf y}=X\mathbf w+b=\begin{bmatrix}1\\3\end{bmatrix}.

Hàng đầu có 1⋅2+2⋅(−1)+1=11\cdot2+2\cdot(-1)+1=1; hàng sau có 3⋅2+4⋅(−1)+1=33\cdot2+4\cdot(-1)+1=3. Bias cộng vào mỗi mẫu. Shape của XX là (2, 2), của w\mathbf w là (2,), của kết quả là (2,). Vector một chiều trong NumPy không tự thành cột hai chiều như cách vẽ trên giấy.

Python
X = np.array([[1.0, 2.0], [3.0, 4.0]])
w_linear = np.array([2.0, -1.0])
b_linear = 1.0
prediction = X @ w_linear + b_linear
print("Shape:", X.shape, w_linear.shape, prediction.shape)
print("Dự đoán:", prediction)
assert np.allclose(prediction, [1.0, 3.0])

dependent = np.array([[1.0, 2.0], [2.0, 4.0]])
null_direction = np.array([2.0, -1.0])
print("Hướng không thay đổi dự đoán:", dependent @ null_direction)
print("Hạng ma trận:", np.linalg.matrix_rank(dependent))

Ma trận dependent có cột thứ hai gấp đôi cột thứ nhất, nên hạng bằng 1. Thêm t(2,−1)t(2,-1) vào trọng số không đổi dự đoán, vì tích với hướng ấy bằng 0. Bởi vậy một nghiệm hệ số chưa chắc duy nhất; muốn dùng nghịch đảo hay nói “nghiệm duy nhất”, phải kiểm điều kiện hạng. Đây là lý do ở bài 2.1 ta cần least squares và regularization khi feature phụ thuộc.

Cột thứ hai gấp đôi cột thứ nhất nên hệ số không duy nhất.-202024w₁w₂X = [[1, 2], [2, 4]]X (2, −1) = (0, 0)mọi w trên đường camcho cùng dự đoán Xw
Cột thứ hai gấp đôi cột thứ nhất nên hệ số không duy nhất.

Tích vô hướng u⊤v\mathbf u^\top\mathbf v vừa dùng để dự đoán, vừa đo quan hệ hình học. Với hai vector khác 0, cosine similarity chia tích vô hướng cho tích độ dài. Nó không đổi khi nhân một vector với số dương; khoảng cách Euclidean thường đổi.

Vì vậy similarity và khoảng cách cần được chọn theo ý nghĩa của embedding, không chỉ theo công thức thuận tay. Vector 0 không có hướng nên cosine của nó không được định nghĩa bằng phép chia thông thường.

Hỏi nhanh

X có shape (5, 3), w có shape (3,), còn b là một số. X @ w + b có shape gì?

Gradient: chia sai số về đúng tham số

Giờ dùng một mẫu phân loại: x=(1,2)\mathbf x=(1,2), nhãn y=1y=1, trọng số w=(0.2,−0.1)\mathbf w=(0.2,-0.1), bias b=0b=0. Logit z=w⊤x+b=0z=\mathbf w^\top\mathbf x+b=0, xác suất p=σ(z)=0.5p=\sigma(z)=0.5. Loss là log⁡2≈0.6931\log2\approx0.6931.

Lượt xuôi cho loss 0.693; một bước gradient hạ còn 0.554.x = (1, 2)z = w·x + b = 0p = σ(z) = 0.5L = 0.693∂L/∂z = p − y = −0.5∇_w L = (p − y)·x = (−0.5, −1)∂L/∂b = −0.5bước η = 0.1: L → 0.554
Lượt xuôi cho loss 0.693; một bước gradient hạ còn 0.554.

Chain rule nói đạo hàm qua nhiều phép tính là tích các đạo hàm cục bộ. Với binary cross-entropy và sigmoid ghép đúng, các số hạng rút gọn thành

∂L∂z=p−y,∇wL=(p−y)x,∂L∂b=p−y.\frac{\partial L}{\partial z}=p-y,\qquad\nabla_{\mathbf w}L=(p-y)\mathbf x,\qquad\frac{\partial L}{\partial b}=p-y.

Vậy gradient của w\mathbf w là (−0.5,−1)(-0.5,-1), của bb là −0.5-0.5. Gradient descent với η=0.1\eta=0.1 cho w′=(0.25,0)\mathbf w'=(0.25,0), b′=0.05b'=0.05. Logit mới bằng 0.30.3, xác suất tăng lên khoảng 0.57440.5744, loss giảm còn khoảng 0.55440.5544. Nhãn là 1 nên dấu thay đổi có nghĩa: model cần tăng xác suất lớp 1.

Ta gộp θ=(w1,w2,b)\boldsymbol\theta=(w_1,w_2,b) để kiểm cả ba thành phần bằng sai phân trung tâm. logaddexp(0, z) tính log⁡(1+ez)\log(1+e^z) ổn định; loss từ logit là biểu thức đó trừ yzyz.

Python
x = np.array([1.0, 2.0])
y = 1.0
theta = np.array([0.2, -0.1, 0.0])

def logistic_loss(parameters):
    z = x @ parameters[:2] + parameters[2]
    return float(np.logaddexp(0.0, z) - y * z)

def logistic_gradient(parameters):
    z = x @ parameters[:2] + parameters[2]
    p = 1.0 / (1.0 + np.exp(-z))
    return np.append((p - y) * x, p - y)

gradient = logistic_gradient(theta)
h = 1e-5
numerical = np.zeros_like(theta)
for j in range(len(theta)):
    shift = np.zeros_like(theta)
    shift[j] = h
    numerical[j] = (logistic_loss(theta + shift) - logistic_loss(theta - shift)) / (2 * h)
new_theta = theta - 0.1 * gradient
print("Gradient:", gradient)
print("Tham số mới:", new_theta)
print(f"Loss: {logistic_loss(theta):.4f} -> {logistic_loss(new_theta):.4f}")
print("Sai phân khớp:", np.allclose(gradient, numerical, atol=1e-8))
assert np.allclose(gradient, [-0.5, -1.0, -0.5])
assert logistic_loss(new_theta) < logistic_loss(theta)

Gradient cho xấp xỉ bậc nhất L(θ+Δ)≈L(θ)+∇L⊤ΔL(\boldsymbol\theta+\boldsymbol\Delta)\approx L(\boldsymbol\theta)+\nabla L^\top\boldsymbol\Delta khi Δ\boldsymbol\Delta nhỏ. Đạo hàm âm theo một tham số nghĩa là tăng tham số ấy một chút thì loss giảm, nên bước descent Δ=−η∇L\boldsymbol\Delta=-\eta\nabla L làm nó tăng.

Tình huống loss tăng ở đầu bài thường có một trong hai nguyên nhân: cộng gradient thay vì trừ, hoặc bước quá lớn, vượt khỏi vùng mà xấp xỉ tuyến tính còn dùng được.

Hỏi nhanh

Tại w1=3w_1 = 3, đạo hàm ∂L/∂w1=−2\partial L/\partial w_1 = -2. Tăng w1w_1 lên 3.0013.001, giữ nguyên các tham số khác. Loss thay đổi xấp xỉ bao nhiêu?

Gradient bằng 0 là điểm dừng, không tự chứng minh đó là cực tiểu toàn cục của một mạng phi tuyến. Với loss lồi, như MSE của linear regression hay log-loss của logistic regression, mọi điểm dừng đều là cực tiểu toàn cục; cần nói rõ lớp hàm đang xét.

Nếu thêm penalty λ∥w∥2\lambda\lVert\mathbf w\rVert^2 thì gradient theo w\mathbf w có thêm 2λw2\lambda\mathbf w. Nếu đề dùng λ∥w∥2/2\lambda\lVert\mathbf w\rVert^2/2, số 2 biến mất. Trên một batch, loss lấy trung bình cũng làm gradient có hệ số 1/n1/n. Viết rõ loss trước khi đạo hàm là cách tránh chép nhầm quy ước.

Hỏi nhanh

Gradient theo bias là −0.6-0.6, learning rate là 0.20.2, và bias ban đầu là 11. Sau một bước gradient descent, bias mới bằng bao nhiêu?

Kiến trúc mạng: đếm shape trước khi đếm tham số

Một câu lý thuyết về CNN thường chỉ cần phân biệt số mẫu, channel và không gian. Với convolution không dilation, input cao HH, kernel kk, padding pp, stride ss, chiều cao đầu ra là

Hout=⌊H+2p−ks⌋+1.H_{\text{out}}=\left\lfloor\frac{H+2p-k}{s}\right\rfloor+1.

Input (N, C, H, W) = (4, 3, 8, 8), hai output channel, k=3k=3, p=1p=1, s=2s=2 cho Hout=Wout=4H_{\text{out}}=W_{\text{out}}=4. Shape output là (4, 2, 4, 4). Mỗi output channel dùng 3⋅3⋅3=273\cdot3\cdot3=27 weight và một bias, tổng 2(27+1)=562(27+1)=56 tham số.

Tổng quát, Conv2d có Cout(Cink2+1)C_{\text{out}}(C_{\text{in}}k^2+1) tham số, bỏ số 1 khi bias=False; cách đặt này thường gặp khi BatchNorm đứng ngay sau, vì BatchNorm đã có tham số dịch riêng. Batch size và số vị trí ảnh không nhân vào số tham số: các weight được dùng lại ở nhiều vị trí.

Conv2d: input (4, 3, 8, 8) ra (4, 2, 4, 4), 56 tham số.(4, 3, 8, 8)3 channel, 8 × 8k = 3, p = 1, s = 2(4, 2, 4, 4)⌊(8 + 2 − 3)/2⌋ + 1 = 4tham số2 × (3·3·3 + 1) = 56batch 4 không nhân vào
Conv2d: input (4, 3, 8, 8) ra (4, 2, 4, 4), 56 tham số.
Python
import torch

torch.manual_seed(0)
conv = torch.nn.Conv2d(3, 2, kernel_size=3, stride=2, padding=1)
images = torch.zeros(4, 3, 8, 8)
with torch.no_grad():
    conv_output = conv(images)
parameter_count = sum(parameter.numel() for parameter in conv.parameters())
print("Output shape:", tuple(conv_output.shape))
print("Số tham số:", parameter_count)
assert tuple(conv_output.shape) == (4, 2, 4, 4)
assert parameter_count == 56

Một forward trên tensor toàn 0 đủ để kiểm shape và số tham số; không cần train. Nếu đề có dilation dd, thay kk bằng effective size d(k−1)+1d(k-1)+1. Kernel 1×11\times1 vẫn có CinCoutC_{\text{in}}C_{\text{out}} weight: nó không nhìn lân cận nhưng trộn các channel tại từng vị trí. Pooling thường không có weight học được; residual addition yêu cầu shape hai nhánh khớp hoặc có projection để đưa về cùng shape.

Hỏi nhanh

Input (8, 16, 32, 32) đi qua Conv2d(16, 32, kernel_size=3, padding=1), stride 1, có bias. Output có shape gì, và lớp có bao nhiêu tham số?

Attention: một hàng là một cách lấy trung bình

Với một head, QQ có shape (Tq, dk), KK có shape (Tk, dk), VV có shape (Tk, dv). Ma trận score QK⊤/dkQK^\top/\sqrt{d_k} có shape (Tq, Tk). Softmax theo trục key tạo một phân phối cho mỗi query, rồi nhân VV để lấy tổng có trọng số:

O=softmax⁡(QK⊤dk)V.O=\operatorname{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V.

Ta chọn Q=K=I2Q=K=I_2, tức ma trận đơn vị 2 chiều, và hai value là (2,0)(2,0), (0,4)(0,4). Score của query đầu là (1/2,0)(1/\sqrt2,0). Softmax cho trọng số khoảng (0.6698,0.3302)(0.6698,0.3302), nên output đầu là (1.3395,1.3210)(1.3395,1.3210). Đây là vector giá trị pha trộn, không phải index của một token được chọn.

Mỗi hàng trọng số cộng thành 1; causal mask chặn key tương lai.không maskkey 1key 20.670.33q1→ (1.34, 1.32)0.330.67q2→ (0.66, 2.68)causal maskkey 1key 21.000.00q1→ (2, 0)0.330.67q2→ (0.66, 2.68)mỗi hàng là một phân phối trên key, nhân với value (2, 0) và (0, 4)
Mỗi hàng trọng số cộng thành 1; causal mask chặn key tương lai.
Python
Q = np.eye(2)
K = np.eye(2)
values = np.array([[2.0, 0.0], [0.0, 4.0]])

def row_softmax(scores):
    shifted = scores - scores.max(axis=1, keepdims=True)
    exponentials = np.exp(shifted)
    return exponentials / exponentials.sum(axis=1, keepdims=True)

scores = Q @ K.T / np.sqrt(Q.shape[1])
weights = row_softmax(scores)
attention_output = weights @ values
print("Trọng số:\n", weights.round(4))
print("Output:\n", attention_output.round(4))
assert np.allclose(weights.sum(axis=1), 1.0)

masked_scores = scores.copy()
masked_scores[0, 1] = -np.inf       # query đầu không nhìn token tương lai
causal_weights = row_softmax(masked_scores)
print("Output đầu với causal mask:", (causal_weights @ values)[0])
assert np.allclose(causal_weights[0], [1.0, 0.0])

Đặt mask vào score trước softmax làm xác suất bị cấm bằng 0 rồi chuẩn hóa lại phần được phép. Đặt một weight về 0 sau softmax mà không chuẩn hóa lại làm tổng hàng nhỏ hơn 1. Nếu một query bị mask toàn bộ key, softmax không có phân phối hợp lệ; cần xử lý theo thiết kế của model, không mong phép tính tự hiểu padding.

Trong một layer thật, Q=XWQQ=XW_Q, K=XWKK=XW_K, V=XWVV=XW_V với XX shape (T, d_model), rồi các head được nối lại và đi qua một phép chiếu ra. Tham số nằm ở các ma trận chiếu, nên số tham số không phụ thuộc độ dài chuỗi TT; ngược lại, ma trận score (T, T) tăng theo T2T^2. Đếm tham số và đếm bộ nhớ là hai câu hỏi khác nhau.

Hỏi nhanh

Q có shape (3, 2), K có shape (5, 2), V có shape (5, 4). Output của một head có shape gì?

Hỏi nhanh

Query thứ hai chỉ được nhìn key 1 và key 2. Score cho ba key là (0,log⁡3,log⁡2)(0, \log 3, \log 2), với log tự nhiên. Đặt score của key 3 thành −∞-\infty trước khi softmax. Bộ trọng số thu được là gì?

Đánh giá: trở lại detector đầu bài

Bảng 1000 bài có TP=18TP=18, FN=2FN=2, FP=98FP=98, TN=882TN=882. Recall bằng TP/(TP+FN)=0.9TP/(TP+FN)=0.9, trả lời “bắt được bao nhiêu bài lỗi?”. Precision bằng TP/(TP+FP)=18/116≈0.1552TP/(TP+FP)=18/116\approx0.1552, trả lời “cảnh báo đáng tin tới đâu?”. Hai số đúng là hai xác suất có điều kiện đã gặp ở đầu bài.

Accuracy bằng (TP+TN)/1000=0.9(TP+TN)/1000=0.9. Nhưng baseline luôn đoán sạch có accuracy 0.980.98 và recall 0. Không thể từ một số 0.98 kết luận baseline giải quyết mục tiêu tìm lỗi tốt hơn; cũng không thể bỏ qua 98 cảnh báo nhầm vì recall cao. Metric cần phản ánh yêu cầu và chi phí kiểm thủ công của bài.

F1 dùng trung bình điều hòa của precision và recall, tương đương

F1=2TP2TP+FP+FN=36136≈0.2647.F1=\frac{2TP}{2TP+FP+FN}=\frac{36}{136}\approx0.2647.

Để đối chiếu với scikit-learn, ta dựng lại vector nhãn và vector dự đoán đúng theo bốn ô của bảng.

Python
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

labels = np.array([1] * (tp + fn) + [0] * (fp + tn))
predicted = np.array([1] * tp + [0] * fn + [1] * fp + [0] * tn)
accuracy = (tp + tn) / total
precision = tp / (tp + fp)
recall = tp / (tp + fn)
f1 = 2 * tp / (2 * tp + fp + fn)
library = np.array([
    accuracy_score(labels, predicted), precision_score(labels, predicted),
    recall_score(labels, predicted), f1_score(labels, predicted),
])
assert np.allclose(library, [accuracy, precision, recall, f1])
print(f"Accuracy={accuracy:.4f}, precision={precision:.4f}, recall={recall:.4f}, F1={f1:.4f}")
print(f"Baseline sạch: accuracy={(fp + tn) / total:.4f}, recall=0.0000")
print("Tính tay khớp thư viện:", True)
Recall 0.9 nhưng precision chỉ 0.155; luôn đoán sạch vẫn có accuracy 0.98.18298882cảnh báokhôngcó lỗisạchrecall 18/20 = 0.900precision 18/116 = 0.155accuracy 900/1000 = 0.900F1 36/136 = 0.265luôn đoán sạch: acc 0.98, recall 0
Recall 0.9 nhưng precision chỉ 0.155; luôn đoán sạch vẫn có accuracy 0.98.

Khi chấm model thật, chỉ dùng train để fit tham số; chọn threshold, kiến trúc và hyperparameter bằng validation phù hợp, rồi giữ test để đánh giá cuối.

Với nhiều bài của cùng một người hoặc cùng một nguồn, random split có thể lọt kiểu viết giữa train và validation; lúc ấy cần group split. Nếu mục tiêu dự đoán ở tương lai, cách chia theo thời gian có thể phù hợp hơn. Stratification giữ tỉ lệ lớp nhưng không tự chữa leakage theo nhóm.

Hỏi nhanh

Mỗi học sinh nộp nhiều bài, và bài của cùng một người có mặt ở cả train lẫn validation. Mục tiêu là dự đoán cho học sinh mới. Stratification theo nhãn có xử lý được rủi ro này không?

Một điểm trên tập nhỏ có sai số lấy mẫu. Nếu 1000 kết quả đúng hay sai thật sự độc lập và cùng xác suất đúng 0.9, độ lệch chuẩn của accuracy mẫu là 0.9⋅0.1/1000≈0.0095\sqrt{0.9\cdot0.1/1000}\approx0.0095. Giả thiết độc lập là phần quan trọng: nếu nhiều mẫu đến từ cùng một người, chúng tương quan và độ bất định thật lớn hơn con số này.

Hai model nên được so trên cùng split và đọc loại lỗi của chúng, không chỉ xếp hạng một điểm duy nhất.

Hỏi nhanh

Với 1000 mẫu độc lập và accuracy thật là 0.9, độ lệch chuẩn của accuracy đo được khoảng 0.00950.0095. Nếu validation chỉ có 100 mẫu thì khoảng bao nhiêu?

Giảm số mẫu 10 lần làm độ lệch chuẩn của accuracy tăng √10 lần.0.000.010.020.030.041002505007501000số mẫu validation n0.03000.0095độ lệch chuẩn của accuracy (p = 0.9)
Giảm số mẫu 10 lần làm độ lệch chuẩn của accuracy tăng √10 lần.

Khi đi thi

  • Viết đại lượng cần tìm trước khi thế số, nhất là điều kiện nằm ở phía nào: P(B∣F)P(B\mid F) hay P(F∣B)P(F\mid B).
  • Đạo hàm từ loss viết đầy đủ, ghi rõ hệ số 1/n1/n; rồi kiểm dấu trên một mẫu.
  • Bài kiến trúc thì tính shape từng lớp trước, rồi mới đếm tham số.

Tóm tắt

  • Điều kiện xác suất quyết định mẫu số; Bayes, confusion matrix và precision có thể mô tả cùng một câu hỏi.
  • Log-loss là negative log-likelihood; xác suất khớp tỉ lệ thật cho log-loss kỳ vọng nhỏ nhất.
  • Đại số tuyến tính mô tả phép gộp feature, shape và tính duy nhất của nghiệm. Không nghịch đảo khi chưa kiểm điều kiện.
  • Gradient đi qua từng phép tính; loss, dấu và phép lấy trung bình phải nhất quán với code.
  • Convolution dùng lại tham số; attention chuẩn hóa theo key cho mỗi query. Shape giúp kiểm cả hai.
  • Metric trả lời một mục tiêu cụ thể. Một điểm validation chỉ có ý nghĩa cùng cách chia, baseline và phạm vi dữ liệu.

Kiểm tra cuối bài

Câu 1

Trong 1000 bài nộp, có 200 bài dùng đệ quy, gọi là biến cố AA, 100 bài bị quá thời gian, gọi là biến cố TT, và 40 bài vừa dùng đệ quy vừa quá thời gian. AA và TT có độc lập không?

Phỏng theoNOAI 2026 Singapore · Vòng sơ loại · Câu 62

Câu 2

Hàm f(θ)f(\theta) có argmax duy nhất là θ∗\theta^*, và có thể nhận giá trị âm, như một log-likelihood. Hàm nào không chắc có cùng argmax θ∗\theta^*?

Phỏng theoCMU 10-601 · Exam 1 Practice · Q5.1

Câu 3

Hai model có cùng accuracy 95% trên một tập nhị phân. Model A luôn báo xác suất 0.999 cho lớp nó chọn, còn model B luôn báo 0.95. Log-loss trung bình, với log tự nhiên, của hai model là bao nhiêu?

Câu 4

Linear regression với MSE, và ma trận dữ liệu có cột thứ hai gấp đôi cột thứ nhất. Kết luận nào đúng?

Phỏng theoCMU 10-601 · Exam 2 Practice · Q1.2

Câu 5

Logistic regression trên ba điểm: (1,1)(1, 1) nhãn 0, (1,0)(1, 0) nhãn 1, (0,0)(0, 0) nhãn 0. Model 1 là σ(w1x1+w2x2)\sigma(w_1x_1 + w_2x_2), còn model 2 có thêm bias w0w_0. Đổi nhãn của (0,0)(0, 0) thành 1, rồi chạy GD từ cùng khởi tạo, với cùng learning rate. Chuyện gì xảy ra?

Phỏng theoCMU 10-601 · Exam 2 Practice · Q2.2

Câu 6

Logistic regression viết mục tiêu dạng tổng như scikit-learn: J(w)=∑i=1mℓi+λ2∥w1:∥2J(\mathbf w) = \sum_{i=1}^m\ell_i + \frac\lambda2\lVert\mathbf w_{1:}\rVert^2, trong đó bias w[0] không bị phạt. Code tối ưu J/mJ/m, và đã có g = X.T @ (p - y) / m. Dòng nào cộng phần phạt vào cho đúng?

Phỏng theoNOAI 2026 Singapore · Chung kết · Câu 5

Câu 7

Đội dự đoán số khán giả g=θ⊤xg = \boldsymbol\theta^\top\mathbf x, và chịu chi phí L=αg+βmax⁡(0,y−g)L = \alpha g + \beta\max(0, y - g): thuê gg ghế với giá α\alpha mỗi ghế, và mất β\beta cho mỗi người phải từ chối. Với α=1\alpha = 1, β=4\beta = 4, x=(1,3)\mathbf x = (1, 3), y=20y = 20, và hiện tại g=12g = 12, gradient ∇θL\nabla_{\boldsymbol\theta}L là gì?

Phỏng theoMIT 6.036 · Final, Spring 2022 · Q5(d)

Câu 8

Một bottleneck block của ResNet-50, trong layer3, có ba convolution không bias, mỗi cái theo sau bởi BatchNorm: 1×11\times 1 từ 1024 xuống 256 channel, 3×33\times 3 từ 256 sang 256, và 1×11\times 1 từ 256 lên 1024. Ba convolution này có tổng cộng bao nhiêu tham số?

Phỏng theoUSA-NA-AIO 2026 · Vòng 1 · Part 8.3

Câu 9

Một layer multi-head attention có dmodel=64d_{\text{model}} = 64, H=4H = 4 head, mỗi head có d=16d = 16. Ba phép chiếu QQ, KK, VV đi từ dmodeld_{\text{model}} lên HdHd, phép chiếu ra đi từ HdHd về dmodeld_{\text{model}}, tất cả đều không bias. Thêm relative positional encoding: mỗi head học một vector rj−i∈Rd\mathbf r_{j-i} \in \mathbb R^{d} cho mỗi độ lệch j−ij - i, với chuỗi dài T=10T = 10. Tổng số tham số là bao nhiêu?

Phỏng theoUSA-NA-AIO 2026 · Vòng 2 · Ngày 1 · Part 1.3.1

Câu 10

Detector A có precision 0.5 và recall 0.5. Detector B có precision 0.9 và recall 0.1. Trung bình cộng hai chỉ số của cả hai đều bằng 0.5. F1 của mỗi detector bằng bao nhiêu?

Phỏng theoNOAI 2026 Singapore · Vòng sơ loại · Câu 68

Đọc thêm