Neural Network
Từ neuron đến backpropagation: XOR, MLP, forward pass, activation, loss, gradient descent, 4 phương trình BP, vanishing gradient và khởi tạo.
Learning Objectives
- ✓Hiểu vì sao cần NN (bài toán XOR) và neuron = 1 Logistic Regression
- ✓Nắm cấu trúc MLP, forward pass và kiểm tra kích thước ma trận
- ✓Hiểu các activation function và vai trò tạo phi tuyến
- ✓Nắm 4 phương trình backpropagation dựa trên chain rule
- ✓Hiểu vanishing/exploding gradient, khởi tạo He/Xavier và Batch Norm
Tại Sao Cần Neural Network?
Logistic Regression chỉ học được 1 đường phân tách tuyến tính — thất bại với bài toán XOR (4 điểm, không đường thẳng nào tách được). Ý tưởng đột phá: 1 LR không đủ → dùng nhiều LR cùng lúc, mỗi neuron học một "góc nhìn" (ranh giới) khác nhau, kết hợp lại để hiểu cấu trúc phức tạp. Mỗi neuron = 1 bộ Logistic Regression thu nhỏ: a = σ(wᵀx + b). Activation function σ có hai vai trò: (1) tạo phi tuyến — không có σ thì 100 lớp vẫn chỉ tương đương 1 LR; (2) On/Off kiểm soát miền giá trị, quyết định neuron "lên tiếng" hay "im lặng".
Cấu Trúc MLP & Forward Pass
MLP (Multi-Layer Perceptron) xếp chồng: input (a[0]=x) → hidden layers → output. Universal Approximation Theorem (Cybenko, 1989): 1 hidden layer với đủ neurons xấp xỉ được bất kỳ hàm liên tục nào; Deep NN (nhiều tầng) học biểu diễn phân cấp. Forward pass tại lớp l: z[l] = W[l]·a[l-1] + b[l], rồi a[l] = σ(z[l]) — chỉ tính toán, chưa học gì. Kiểm tra kích thước ma trận là kỹ năng debug số 1: W[l] có shape (n[l], n[l-1]), b[l] là (n[l], 1). Lưu cache (z[l], a[l]) để dùng lại trong backprop.
import numpy as np
def forward(X, params):
Z1 = params['W1'] @ X + params['b1'] # (16,2)@(2,m)=(16,m)
A1 = np.tanh(Z1) # hidden: tanh
Z2 = params['W2'] @ A1 + params['b2'] # (1,16)@(16,m)=(1,m)
A2 = 1 / (1 + np.exp(-Z2)) # output: sigmoid
return A2, (Z1, A1, Z2, A2) # cache cho backpropActivation Functions
Sigmoid σ(z)=1/(1+e⁻ᶻ), range (0,1), diễn giải như xác suất — dùng ở output layer nhị phân, nhưng vanishing gradient khi |z| lớn. Tanh, range (−1,1), zero-centered tốt hơn Sigmoid nhưng vẫn vanishing. ReLU(z)=max(0,z), range [0,+∞) — nhanh, ít vanishing gradient, là mặc định cho hidden layer hiện nay, nhưng có thể "dying ReLU" khi z<0 mãi. Softmax σ(zᵢ)=eᶻⁱ/Σeᶻʲ, tổng=1 — chỉ dùng ở output layer cho phân loại đa lớp. Cơ chế On/Off của ReLU: mỗi input kích hoạt một tập con neurons khác nhau → mạng học các "chuyên gia" cho từng vùng dữ liệu.
Hàm Mất Mát & Gradient Descent
Ba hàm mất mát: MSE = (1/m)Σ(y−ŷ)² cho hồi quy (phạt sai số bình phương, nhạy outlier); Binary Cross-Entropy cho phân loại nhị phân (nguồn gốc từ MLE, kết hợp với Sigmoid); Categorical Cross-Entropy cho đa lớp (kết hợp với Softmax, y one-hot). Gradient Descent cập nhật: θ ← θ − η·∇θL, với η là learning rate ("bước đi"). η quá nhỏ hội tụ chậm, kẹt local minimum; η quá lớn dao động, weights phát nổ; η vừa phải thường trong [0.001, 0.1]. Biến thể Mini-batch GD (batch 32–256, lũy thừa của 2 để tận dụng GPU) là chuẩn thực tế.
Optimizers Nâng Cao
SGD cơ bản dễ dao động. Momentum tích lũy "quán tính": v ← βv + (1−β)∇L; θ ← θ − η·v — vượt saddle points nhanh hơn. RMSprop điều chỉnh learning rate theo từng tham số: s ← βs + (1−β)(∇L)²; θ ← θ − η·∇L/√(s+ε) — tốt cho dữ liệu non-stationary. Adam (mặc định) kết hợp Momentum + RMSprop, là lựa chọn cho hầu hết bài toán (biến thể: AdamW, AMSGrad). LR Schedule (step decay, cosine annealing, warm-up) giảm η theo epoch: học nhanh lúc đầu, tinh chỉnh chậm ở cuối.
Backpropagation — 4 Phương Trình Cốt Lõi
Để cập nhật W[l] cần ∂L/∂W[l], nhưng W[l] không ảnh hưởng trực tiếp đến L. Giải pháp là Chain Rule theo chuỗi phụ thuộc W[l]→z[l]→a[l]→…→L. Định nghĩa error signal δ[l] = ∂L/∂z[l], ta có 4 phương trình: BP1: δ[L] = ∇ₐL ⊙ σ′(z[L]) (error tại output); BP2: δ[l] = (W[l+1])ᵀ·δ[l+1] ⊙ σ′(z[l]) (truyền ngược); BP3: ∂L/∂W[l] = δ[l]·(a[l-1])ᵀ (gradient weight); BP4: ∂L/∂b[l] = δ[l] (gradient bias). Backprop tính gradient cho TẤT CẢ layers chỉ trong 1 forward + 1 backward pass.
def backward(X, y, params, cache):
m = X.shape[1]
Z1, A1, Z2, A2 = cache
dZ2 = A2 - y # BP1: BCE+Sigmoid → đơn giản!
dW2 = (1/m) * dZ2 @ A1.T # BP3
db2 = (1/m) * np.sum(dZ2, axis=1, keepdims=True) # BP4
dZ1 = params['W2'].T @ dZ2 * (1 - A1**2) # BP2: đạo hàm tanh
dW1 = (1/m) * dZ1 @ X.T # BP3
db1 = (1/m) * np.sum(dZ1, axis=1, keepdims=True) # BP4
return {'dW1':dW1, 'db1':db1, 'dW2':dW2, 'db2':db2}Vanishing Gradient, Khởi Tạo & Batch Norm
Vanishing Gradient: Sigmoid/Tanh có σ′(z) ≤ 0.25, nhân qua L layers → (0.25)ᴸ → 0, khiến lớp đầu không học được gì. Khắc phục: dùng ReLU, Batch Normalization, Residual connections (ResNet), khởi tạo He/Xavier. Exploding Gradient: gradient tăng cấp số nhân, weights → ∞, Loss = NaN — khắc phục bằng Gradient Clipping, khởi tạo weights nhỏ, giảm learning rate. Khởi tạo tham số: Xavier/Glorot W ~ N(0, 2/(n[l-1]+n[l])) cho Sigmoid/Tanh; He W ~ N(0, 2/n[l-1]) cho ReLU. Batch Normalization chuẩn hóa z[l] theo mini-batch, giảm internal covariate shift, cho phép learning rate lớn hơn và có tác dụng regularization nhẹ.
from tensorflow.keras.layers import Dense, BatchNormalization
# He initialization cho ReLU + Batch Normalization
model.add(Dense(64, activation='relu', kernel_initializer='he_normal'))
model.add(BatchNormalization()) # thêm sau Dense, giảm vanishing gradient
# Quy trình: (1) Overfit trước — chứng minh đủ capacity
# (2) Rồi thêm regularization (L2, Dropout, Early Stopping)