Hệ khuyến nghị 3 — Matrix Factorization & Embeddings

13 thg 7, 2026 2 lượt xem
#ai
#embeddings
#recommender-systems
#matrix-factorization
#als

Từ "hàng xóm" sang "yếu tố ẩn"

bài 2 về collaborative filtering chúng ta dựa vào memory-based CF: muốn gợi ý cho khách A, ta đi tìm những khách "hàng xóm" giống A rồi bỏ phiếu. Cách này trực quan nhưng gặp hai bức tường khi lên quy mô ngân hàng:

  • Sparsity (thưa): ma trận tương tác user-item có hàng triệu khách × hàng nghìn sản phẩm, nhưng mỗi khách chỉ dùng vài sản phẩm. 99,9% ô là rỗng. Đo độ tương đồng trên dữ liệu quá thưa cho kết quả nhiễu.
  • Scalability (mở rộng): tính similarity giữa mọi cặp khách là chi phí bậc hai — không kham nổi ở quy mô hàng triệu.

Matrix Factorization (MF — phân rã ma trận) là bước nhảy về tư duy: thay vì lưu và so khớp trực tiếp toàn bộ ma trận tương tác, ta học một biểu diễn nén cho từng khách và từng sản phẩm dưới dạng vector số ít chiều — gọi là latent factors (yếu tố ẩn) hay embedding. Sở thích của khách và đặc tính của sản phẩm được "gói" vào các vector này một cách tự động, không cần con người định nghĩa thủ công "khách này thích tiết kiệm", "sản phẩm kia rủi ro cao".

MF nổi tiếng nhờ Netflix Prize (2006–2009) — cuộc thi thưởng 1 triệu USD cho ai cải thiện độ chính xác đề xuất phim. Đội thắng cuộc đặt MF làm trụ cột, biến nó thành kỹ thuật kinh điển của recommender system suốt hơn một thập kỷ.

Ý tưởng cốt lõi: R ≈ P × Qᵀ

Gọi R là ma trận tương tác kích thước m × n (m khách, n sản phẩm). Ô R[u][i] là mức độ tương tác của khách u với sản phẩm i (điểm đánh giá, số lần dùng, hoặc 0/1 đã-dùng).

MF tìm hai ma trận nhỏ:

  • P kích thước m × k: mỗi hàng là embedding của một khách (k chiều ẩn).
  • Q kích thước n × k: mỗi hàng là embedding của một sản phẩm.

Sao cho tích của chúng xấp xỉ ma trận gốc:

$$R \approx P \times Q^\top$$

Dự đoán tương tác giữa khách u và sản phẩm i chính là tích vô hướng (dot product) hai vector:

$$\hat{r}{ui} = p_u \cdot q_i = \sum{f=1}^{k} p_{u,f} , q_{i,f}$$

Con số k (số chiều ẩn, thường 20–200) nhỏ hơn rất nhiều so với m hay n. Đây là mấu chốt: ép mô hình nén thông tin qua một "nút thắt cổ chai" k chiều buộc nó phải học các khái niệm khái quát thay vì ghi nhớ từng ô. Mỗi chiều ẩn có thể tương ứng (một cách mờ, không tường minh) với một xu hướng như "ưa sản phẩm dài hạn", "nhạy cảm phí", "thích số hoá" — nhưng ta không đặt tên; mô hình tự khám phá.

Vì sao latent factor giải quyết sparsity

Điểm đẹp: hai khách chưa từng dùng chung sản phẩm nào vẫn có thể có embedding gần nhau, nếu mỗi người dùng những sản phẩm tương tự các sản phẩm người kia dùng. Latent space "bắc cầu" qua các tương tác gián tiếp — điều memory-based CF không làm được vì nó đòi hỏi overlap trực tiếp. Nhờ vậy MF chịu được ma trận thưa tốt hơn nhiều.

Học P và Q như thế nào

Ta không có sẵn P, Q; phải học chúng bằng cách tối thiểu hoá sai số giữa dự đoán và các ô đã quan sát (chỉ các ô có dữ liệu, không phải toàn ma trận). Hàm mất mát điển hình (cho dữ liệu rating tường minh):

$$\min_{P,Q} \sum_{(u,i)\in \mathcal{K}} (r_{ui} - p_u \cdot q_i)^2 + \lambda(\lVert p_u \rVert^2 + \lVert q_i \rVert^2)$$

Trong đó $\mathcal{K}$ là tập ô đã biết, $\lambda$ là hệ số regularization (điều chuẩn).

Vai trò của regularization

Nếu để tự do, mô hình sẽ "học vẹt" khớp hoàn hảo dữ liệu huấn luyện (kể cả nhiễu) → overfit, dự đoán tệ trên dữ liệu mới. Số hạng $\lambda \lVert \cdot \rVert^2$ phạt các vector có độ lớn quá lớn, giữ embedding "khiêm tốn" và khái quát hơn. $\lambda$ quá nhỏ → overfit; quá lớn → underfit (mọi embedding bị kéo về gần 0, mất khả năng phân biệt). Đây là siêu tham số cần dò (grid search / validation).

Số chiều latent — đánh đổi

k nhỏ (vd 10–20)k lớn (vd 100–200)
Nhanh, ít bộ nhớChậm, tốn bộ nhớ hơn
Ít overfitDễ overfit nếu thiếu regularization
Có thể thiếu biểu đạt (underfit)Bắt được sắc thái tinh vi hơn

Không có k "đúng" tuyệt đối — chọn qua đánh giá offline trên tập validation (xem bài 6 về ranking & đánh giá).

Các biến thể chính

SVD / FunkSVD — cho rating tường minh

SVD (Singular Value Decomposition) là phân rã đại số kinh điển, nhưng SVD "thuần" đòi hỏi ma trận đầy đủ (không ô trống) — vô nghĩa với dữ liệu thưa. FunkSVD (Simon Funk, Netflix Prize) là biến thể thực dụng: chỉ phân rã trên các ô đã quan sát, học bằng SGD (gradient descent ngẫu nhiên), thường kèm bias theo user và item:

$$\hat{r}_{ui} = \mu + b_u + b_i + p_u \cdot q_i$$

với $\mu$ là trung bình toàn cục, $b_u, b_i$ là độ lệch của khách và sản phẩm. Bias quan trọng: có khách vốn "khó tính" (điểm luôn thấp), có sản phẩm vốn được ưa chuộng — tách phần này ra giúp $p_u \cdot q_i$ tập trung học tương tác thực sự.

ALS — Alternating Least Squares

ALS (bình phương tối thiểu luân phiên) giải bài toán tối ưu bằng cách cố định luân phiên: giữ Q cố định, giải P dạng bài toán bình phương tối thiểu (có nghiệm đóng cho từng hàng); rồi giữ P cố định, giải Q; lặp lại cho tới hội tụ.

Ưu điểm khiến ALS được ưa dùng trong doanh nghiệp:

  • Song song hoá dễ: khi Q cố định, việc cập nhật $p_u$ của từng khách độc lập nhau → chia đều cho nhiều máy. Đây là lý do ALS là thuật toán MF mặc định trong Apache Spark MLlib (spark.ml.recommendation.ALS) — hợp cho quy mô phân tán.
  • Hợp với implicit feedback (xem dưới).

BPR — Bayesian Personalized Ranking

FunkSVD/ALS tối ưu để dự đoán đúng giá trị (regression). Nhưng thực tế recommender chỉ cần xếp hạng đúng thứ tự top-N. BPR tối ưu trực tiếp cho ranking: với mỗi khách, nó học sao cho sản phẩm khách đã tương tác được điểm cao hơn sản phẩm chưa tương tác — tối ưu theo cặp (pairwise). BPR đặc biệt hợp implicit feedback và bài toán "gợi ý top-N" hơn là "đoán điểm số".

Implicit feedback MF — dạng phổ biến nhất ở ngân hàng

Ngân hàng hiếm khi có "rating 1–5 sao". Cái ta có là implicit feedback (phản hồi ngầm): khách mở sản phẩm nào, dùng bao nhiêu lần, click gì trên app. Đặc thù:

  • Chỉ có tín hiệu dương: biết khách đã dùng sản phẩm A, nhưng "không dùng B" không chắc là "không thích B" — có thể chỉ là chưa biết tới. Đây là dữ liệu one-class.
  • Cần biến "số lần tương tác" thành confidence (độ tin cậy), không phải rating.

Công thức implicit MF (Hu, Koren, Volinsky — thường gọi là "iALS") tách hai đại lượng:

  • Preference $p_{ui} = 1$ nếu có bất kỳ tương tác, $0$ nếu không.
  • Confidence $c_{ui} = 1 + \alpha \cdot n_{ui}$, với $n_{ui}$ là số lần tương tác. Càng tương tác nhiều, mô hình càng "tin" đó là sở thích thật.

Hàm mất mát cân theo confidence, và tính trên toàn bộ ma trận (kể cả ô 0, với confidence thấp) — khác rating MF chỉ tính ô đã quan sát:

$$\min_{P,Q} \sum_{u,i} c_{ui}(p_{ui} - x_u \cdot y_i)^2 + \lambda(\dots)$$

Negative sampling (lấy mẫu âm): vì ô 0 nhiều vô kể, các cài đặt SGD/BPR thường không duyệt hết mà lấy mẫu ngẫu nhiên một số ô "chưa tương tác" làm ví dụ âm cho mỗi ví dụ dương — vừa nhanh vừa hiệu quả.

Pseudocode minh hoạ (implicit ALS)

Đoạn dưới là pseudocode minh hoạ ý tưởng huấn luyện, KHÔNG phải mã chạy được và không phải SQL.

# MINH HOẠ — không phải mã sản xuất
# R: ma trận thưa (khách x sản phẩm), giá trị = số lần tương tác
# k: số chiều latent; alpha: khuếch đại confidence; reg: lambda

P = random_matrix(num_users, k)   # user embeddings
Q = random_matrix(num_items, k)   # item embeddings

for epoch in range(num_epochs):
    C = 1 + alpha * R             # confidence
    Pref = (R > 0).astype(int)    # preference nhị phân

    # Bước 1: cố định Q, giải P từng khách (least squares có nghiệm đóng)
    for u in users:
        P[u] = solve_user_factor(Q, C[u], Pref[u], reg)

    # Bước 2: cố định P, giải Q từng sản phẩm
    for i in items:
        Q[i] = solve_item_factor(P, C[:, i], Pref[:, i], reg)

# Gợi ý top-N cho khách u: điểm = P[u] · Q[i] cho mọi i, lấy N cao nhất
scores = P[u] @ Q.T
top_n = argsort(scores)[-N:]

Suy luận nhanh: dot product + ANN

Sau huấn luyện, gợi ý cho một khách = tính $p_u \cdot q_i$ với mọi sản phẩm rồi lấy top-N. Với vài nghìn sản phẩm, quét tuyến tính là ổn. Nhưng khi "sản phẩm" là hàng triệu (vd gợi ý nội dung, merchant, ưu đãi), quét hết là quá chậm.

Đây là lúc latent factors chính là embedding vector, và bài toán "tìm item có dot product lớn nhất" trở thành maximum inner product search / nearest neighbor. Ta nạp toàn bộ Q vào một chỉ mục ANN (Approximate Nearest Neighbor) — xem bài về embedding & similarity search — để lấy top-N trong mili-giây thay vì quét tuyến tính. Nói cách khác: MF sản sinh embedding, hạ tầng vector phục vụ embedding đó ở tốc độ cao.

MF so với memory-based CF

Tiêu chíMemory-based CF (bài 2)Matrix Factorization
Cách hoạt độngSo khớp trực tiếp hàng xómHọc embedding nén
Chịu sparsityKém (cần overlap trực tiếp)Tốt (bắc cầu qua latent space)
Mở rộngChi phí bậc hai theo userHuấn luyện offline, suy luận O(k)
Bộ nhớ khi phục vụLưu toàn ma trận/similarityChỉ lưu P, Q nhỏ gọn
Giải thíchDễ ("vì khách giống bạn đã dùng")Khó (chiều ẩn không tường minh)
Cập nhật realtimeLinh hoạtCần huấn luyện lại định kỳ

Hạn chế — và đường dẫn tới deep learning

MF mạnh nhưng không phải liều thuốc vạn năng:

  • Cold start vẫn còn: khách mới / sản phẩm mới chưa có tương tác → chưa có embedding học được. MF thuần không dùng được đặc trưng (tuổi, thu nhập, danh mục sản phẩm). Giải pháp lai (hybrid) ở bài 4.
  • Tuyến tính: dot product chỉ mô hình hoá tương tác tuyến tính giữa user và item. Các quan hệ phi tuyến phức tạp (vd "khách thích A B nhưng không phải chỉ một trong hai") vượt khả năng của nó. Đây chính là động lực chuyển sang mô hình deep learningbài 5 — dùng mạng neural thay dot product để bắt tương tác phi tuyến.

Factorization Machines — bước khái quát hoá

Factorization Machines (FM) khái quát MF: thay vì chỉ có id-user và id-item, FM cho phép nhét bất kỳ đặc trưng nào (thành phố, độ tuổi, kênh giao dịch, thời điểm) vào và tự học tương tác bậc hai giữa mọi cặp đặc trưng qua các vector latent. FM vừa giữ ưu điểm latent factor, vừa xử lý được feature phụ → giảm cold start. Nó là cầu nối tự nhiên giữa MF và các mô hình neural.

Use case thực tế

Bài toán: NCB muốn gợi ý sản phẩm tiếp theo (thẻ, tiết kiệm online, bảo hiểm liên kết, vay tiêu dùng…) cho khách hàng cá nhân dựa trên lịch sử sử dụng, phục vụ đội bán chéo và banner cá nhân hoá trên app.

Dữ liệu: 3 triệu khách × 40 sản phẩm. Ma trận tương tác từ log 24 tháng: giá trị = số lần khách dùng/kích hoạt sản phẩm (implicit). Độ thưa ~98%.

Cách làm:

  1. Dựng ma trận R từ kho giao dịch/sản phẩm; $n_{ui}$ = số tháng khách có phát sinh với sản phẩm i.
  2. Huấn luyện implicit ALS trên Spark MLlib: $k = 64$, $\alpha = 40$, $\lambda = 0{,}1$, 15 vòng lặp. Kết quả: 3 triệu vector khách (P) và 40 vector sản phẩm (Q).
  3. Sinh top-5 cho mỗi khách bằng $p_u \cdot q_i$. Với 40 sản phẩm, quét tuyến tính đủ nhanh; nhưng nhóm gợi ý merchant ưu đãi (200k merchant) thì nạp Q vào chỉ mục ANN.
  4. Lọc hậu kỳ: bỏ sản phẩm khách đã sở hữu, áp quy tắc tuân thủ (không gợi vay cho khách nợ xấu).
  5. Đánh giá offline trên 1 tháng giữ lại: Precision@5, Recall@5, MAP (xem bài 6); rồi A/B test online.

Kết quả minh hoạ (mô phỏng): so với heuristic "gợi sản phẩm phổ biến nhất", MF cải thiện Recall@5 từ ~0,18 lên ~0,31 và tăng tỷ lệ click banner ~1,7 lần trong A/B test. Embedding sản phẩm học được cũng dùng lại cho phân tích: cụm sản phẩm gần nhau trong latent space trùng khớp trực giác nghiệp vụ (nhóm tiết kiệm, nhóm tín dụng).

Vận hành: huấn luyện lại hàng tuần theo lịch batch; embedding lưu vào feature store để phục vụ realtime qua API gợi ý.

Ghi nhớ

  • MF phân rã ma trận user-item thưa $R$ thành hai ma trận nhỏ $P$ (user embedding) × $Q$ (item embedding); dự đoán = dot product $p_u \cdot q_i$.
  • Latent factors (k chiều, thường 20–200) học tự động sở thích/đặc tính; nút thắt cổ chai k buộc mô hình khái quát → chịu sparsity tốt hơn memory-based CF nhờ "bắc cầu" gián tiếp.
  • Biến thể: FunkSVD/SVD (rating + bias), ALS (luân phiên, dễ song song, mặc định trên Spark, hợp implicit), BPR (tối ưu ranking pairwise).
  • Implicit MF: dùng confidence $c = 1 + \alpha n$ và negative sampling; "chưa dùng" ≠ "không thích".
  • Regularization ($\lambda$) chống overfit; số chiều k là đánh đổi biểu đạt ↔ overfit/chi phí.
  • Suy luận top-N: nạp $Q$ vào ANN (xem vec-01) để lấy nhanh khi item nhiều.
  • Hạn chế: cold start vẫn còn (thuần id, không feature) và tuyến tính → dẫn tới hybrid (bài 4) và deep learning (bài 5); Factorization Machines khái quát bằng cách thêm feature.

Bài viết liên quan

Phân biệt AI/ML/DL, các kiểu học máy, quy trình ML end-to-end và thuật ngữ nền tảng.

13 thg 7, 2026 15

Chất lượng dữ liệu, xử lý thiếu/ngoại lai, mã hoá, chuẩn hoá, tạo đặc trưng và tránh data leakage.

13 thg 7, 2026 13

Mô hình ngôn ngữ lớn hoạt động ra sao, token, context window, tham số sinh, và kỹ thuật viết prompt.

13 thg 7, 2026 13

Retrieval-Augmented Generation, vector database, tool calling, agent và MCP để xây ứng dụng LLM thực tế.

13 thg 7, 2026 11