Quay lại Portfolio

Blog & Ghi chú

Khám phá về học sâu, thị giác máy tính và ước lượng độ sâu.

Học sâu
Brainstorm về Knowledge Distillation
4 Tháng 1, 2026
Thị giác máy tính
Các công cụ Thị giác 2D
4 Tháng 1, 2026
Ước lượng độ sâu
Rolling in the Deep
4 Tháng 1, 2026
Ước lượng độ sâu
Từ Ước lượng Độ sâu đến Pseudo-LIDAR
24 Tháng 3, 2025
Thị giác máy tính
Perspective Transform và Affine Transform
24 Tháng 11, 2025
Thị giác máy tính
Thuật toán đơn giản Phát hiện Nhìn Điện thoại
24 Tháng 11, 2025
Phát hiện đối tượng
Tiền xử lý lấy cảm hứng từ Slicing cho Recall Vật thể Nhỏ
21 Tháng 7, 2026
Học sâu

Brainstorm về Knowledge Distillation

Tài liệu tham khảo hữu ích

Brainstorm

Trong bối cảnh knowledge distillation của machine learning, việc huấn luyện song song cả mô hình giáo viên (teacher model) và mô hình học sinh (student model) nhìn chung không phải là cách tiếp cận chuẩn hay hiệu quả nhất, mặc dù nó có thể hợp lý trong một số kịch bản cụ thể tùy vào mục tiêu và ràng buộc.

1. Quy trình Knowledge Distillation chuẩn

Knowledge distillation thường bao gồm một quy trình hai giai đoạn:

  1. Huấn luyện mô hình giáo viên: Một mô hình lớn, phức tạp (giáo viên) được huấn luyện trước trên tác vụ mục tiêu bằng tập dữ liệu sẵn có. Mô hình giáo viên thường được tham số hóa dư thừa (overparameterized) và đạt hiệu năng cao, nhưng có thể tốn kém về mặt tính toán.
  2. Huấn luyện mô hình học sinh: Một mô hình nhỏ hơn, hiệu quả hơn (học sinh) sau đó được huấn luyện để bắt chước hành vi của giáo viên. Việc này được thực hiện bằng cách dùng đầu ra của giáo viên (ví dụ: logit đã làm mềm hoặc biểu diễn đặc trưng) làm mục tiêu mềm (soft targets), thêm vào hoặc thay cho nhãn ground-truth. Học sinh được huấn luyện để tối thiểu hóa một hàm mất mát bao gồm mất mát chưng cất (distillation loss, ví dụ: phân kỳ Kullback-Leibler giữa đầu ra của giáo viên và học sinh) và, thường là, một mất mát riêng cho tác vụ (ví dụ: cross-entropy với nhãn ground-truth).

Giáo viên thường được huấn luyện trước và giữ cố định trong quá trình huấn luyện học sinh vì mục tiêu là truyền tri thức đã học của giáo viên sang học sinh. Đầu ra của giáo viên cung cấp tín hiệu giám sát phong phú hơn (ví dụ: nắm bắt mối quan hệ giữa các lớp thông qua xác suất mềm) so với chỉ dùng nhãn cứng.

2. Vì sao huấn luyện song song không phổ biến

Huấn luyện đồng thời mô hình giáo viên và học sinh (tức cập nhật cả hai mô hình cùng lúc trong quá trình huấn luyện) không phải là cách làm chuẩn vì một số lý do sau:

  1. Tính ổn định của giáo viên: Mô hình giáo viên được kỳ vọng cung cấp đầu ra đáng tin cậy và chất lượng cao để dẫn dắt học sinh. Nếu giáo viên vẫn đang huấn luyện và các tham số của nó vẫn đang thay đổi, đầu ra của nó có thể nhiễu hoặc không nhất quán, gây mất ổn định cho quá trình học của học sinh.
  2. Chi phí tính toán: Huấn luyện đồng thời cả hai mô hình làm tăng yêu cầu tính toán, vì cả hai mô hình đều cần thực hiện lượt truyền xuôi và truyền ngược. Knowledge distillation nhằm tạo ra một mô hình học sinh nhẹ để tăng hiệu quả, nên việc thêm chi phí huấn luyện song song một giáo viên lớn đi ngược lại mục tiêu này.
  3. Lệch mục tiêu: Giáo viên thường được tối ưu cho hiệu năng tác vụ (ví dụ: tối thiểu hóa mất mát cross-entropy), trong khi học sinh được tối ưu để bắt chước đầu ra của giáo viên (mất mát chưng cất) và, tùy chọn, nhãn ground-truth. Tối ưu đồng thời cả hai mô hình có thể dẫn đến gradient hoặc mục tiêu xung đột, khiến việc hội tụ khó khăn hơn.
  4. Phụ thuộc tuần tự: Học sinh phụ thuộc vào tri thức của giáo viên, điều này hiệu quả nhất khi giáo viên đã hội tụ về một lời giải tốt. Huấn luyện song song làm suy yếu sự phụ thuộc này, vì giáo viên có thể chưa có tri thức đáng tin cậy để truyền đạt.

Các kịch bản mà huấn luyện song song có thể hợp lý

Có một số trường hợp cụ thể mà việc huấn luyện song song giáo viên và học sinh có thể được xem xét, dù ít phổ biến hơn và thường đòi hỏi thay đổi so với khung distillation chuẩn:

  1. Online Knowledge Distillation (OKD): Trong online distillation (ví dụ: như được đề xuất trong các phương pháp như Deep Mutual Learning), nhiều mô hình (có thể xem như các đồng đẳng (peers) thay vì một hệ thống phân cấp giáo viên-học sinh nghiêm ngặt) được huấn luyện đồng thời và học lẫn nhau từ đầu ra của nhau. Thay vì một giáo viên đã huấn luyện trước, tất cả các mô hình đều đóng vai trò vừa là giáo viên vừa là học sinh, chia sẻ tri thức qua các dự đoán của chúng. Trường hợp sử dụng: Các kịch bản có quyền truy cập hạn chế vào một giáo viên đã huấn luyện trước, hoặc khi huấn luyện nhiều mô hình có năng lực tương đương để cải thiện khả năng tổng quát hóa.
  2. Cập nhật giáo viên động: Trong một số thiết lập, mô hình giáo viên có thể được tinh chỉnh (fine-tune) hoặc cập nhật trong quá trình huấn luyện để thích ứng với nhu cầu của học sinh hoặc để tiếp nhận dữ liệu mới. Điều này đòi hỏi thiết kế cẩn thận để đảm bảo giáo viên vẫn là một nguồn tri thức ổn định, chẳng hạn dùng tốc độ học chậm hơn cho giáo viên hoặc luân phiên cập nhật. Trường hợp sử dụng: Continual learning, online learning, hoặc các kịch bản với dữ liệu dạng luồng (streaming) mà việc huấn luyện trước một giáo viên là không khả thi.
  3. Co-Training để tăng hiệu quả: Nếu tài nguyên tính toán cho phép, huấn luyện song song có thể được khám phá để giảm tổng thời gian huấn luyện so với huấn luyện tuần tự. Ví dụ, giáo viên và học sinh có thể chia sẻ một số đồ thị tính toán (ví dụ: trong một backbone trích xuất đặc trưng dùng chung) để tiết kiệm tài nguyên. Trường hợp sử dụng: Môi trường giàu tài nguyên tính toán, nơi thời gian huấn luyện là nút thắt cổ chai.
  4. Học tăng cường hoặc thiết lập đối kháng: Trong một số thiết lập nâng cao, chẳng hạn lấy cảm hứng từ GAN hoặc học tăng cường (reinforcement learning), giáo viên và học sinh có thể được huấn luyện theo kiểu cạnh tranh hoặc hợp tác. Trường hợp sử dụng: Các thiết lập nghiên cứu khám phá động lực huấn luyện mới hoặc truyền tri thức đối kháng.

Thách thức của huấn luyện song song

  • Ổn định hóa đầu ra của giáo viên: Đầu ra của giáo viên có thể nhiễu ở giai đoạn đầu huấn luyện, nên cần các kỹ thuật như làm mượt đầu ra, ensemble giáo viên, hoặc trì hoãn distillation.
  • Cân bằng mục tiêu: Giáo viên và học sinh có thể có tốc độ học, trọng số mất mát, hoặc mục tiêu khác nhau, đòi hỏi điều chỉnh cẩn thận.
  • Tăng độ phức tạp: Huấn luyện song song đòi hỏi nhiều bộ nhớ và tính toán hơn, điều này có thể không khả thi với các mô hình giáo viên lớn.
  • Chỉ số đánh giá: Bạn cần định nghĩa cách đánh giá mức độ sẵn sàng của giáo viên trong việc cung cấp tri thức hữu ích.

Các cách tiếp cận thay thế

  • Self-Distillation: Mô hình học sinh chưng cất tri thức từ chính nó (ví dụ: từ các lớp hoặc epoch trước đó) thay vì từ một giáo viên riêng biệt.
  • Tái sử dụng giáo viên đã huấn luyện trước: Dùng một mô hình đã huấn luyện trước có sẵn (ví dụ: một foundation model như BERT hoặc một checkpoint công khai) làm giáo viên.
  • Các biến thể Online Distillation: Khám phá các phương pháp như Deep Mutual Learning hoặc Collaborative Learning, trong đó nhiều mô hình học cùng nhau mà không có một hệ thống phân cấp giáo viên-học sinh cố định.

Khuyến nghị thực tiễn

Trong hầu hết các trường hợp, huấn luyện tuần tự (huấn luyện trước giáo viên, rồi huấn luyện học sinh) là cách tiếp cận hiệu quả và đơn giản nhất cho knowledge distillation. Nó đảm bảo giáo viên cung cấp đầu ra ổn định, chất lượng cao và phù hợp để tạo ra một mô hình học sinh hiệu quả. Huấn luyện song song có thể được khám phá trong các thiết lập nghiên cứu hoặc trường hợp sử dụng cụ thể (ví dụ: online distillation hoặc continual learning), nhưng đòi hỏi thiết kế cẩn thận để xử lý các thách thức đã nêu ở trên.

3. Vì sao huấn luyện trước giáo viên và huấn luyện học sinh trên cùng một tập dữ liệu là hợp lý

Tính nhất quán trong phân bố dữ liệu

Sử dụng cùng một tập dữ liệu cho cả giáo viên và học sinh đảm bảo rằng tri thức được truyền đạt là phù hợp với tác vụ và phân bố dữ liệu mà học sinh sẽ gặp phải. Giáo viên học các mẫu hình, mối quan hệ và cấu trúc của tập dữ liệu, và học sinh hưởng lợi từ việc bắt chước các biểu diễn đã học này. Nếu giáo viên được huấn luyện trên một tập dữ liệu khác, tri thức của nó có thể không tổng quát hóa tốt sang tập dữ liệu mục tiêu của học sinh, dẫn đến hiệu năng dưới mức tối ưu.

Giáo viên như một tham chiếu chất lượng cao

Huấn luyện trước mô hình giáo viên trên cùng một tập dữ liệu cho phép nó hội tụ về một lời giải hiệu năng cao, nắm bắt thông tin phong phú về tác vụ (ví dụ: xác suất lớp, biểu diễn đặc trưng, hoặc ranh giới quyết định). Học sinh sau đó có thể tận dụng tri thức chất lượng cao này thông qua đầu ra mềm của giáo viên (ví dụ: logit đã làm mềm hoặc đặc trưng trung gian), cung cấp nhiều thông tin hơn so với chỉ dùng nhãn cứng. Ví dụ, trong các tác vụ phân loại, đầu ra softmax của giáo viên (với một tham số nhiệt độ) tiết lộ mối quan hệ giữa các lớp, giúp học sinh học được các ranh giới quyết định tinh tế hơn.

Thực hành chuẩn trong Knowledge Distillation

Khung knowledge distillation kinh điển, được giới thiệu bởi Hinton et al. (2015), giả định giáo viên được huấn luyện trước trên tập dữ liệu mục tiêu, và học sinh được huấn luyện để khớp với đầu ra của giáo viên trên cùng tập dữ liệu đó. Thiết lập này được sử dụng rộng rãi trong các ứng dụng như nén mô hình cho phân loại ảnh, xử lý ngôn ngữ tự nhiên, và nhận dạng giọng nói. Học sinh thường tối ưu một tổ hợp của mất mát chưng cất (ví dụ: phân kỳ KL giữa logit của giáo viên và học sinh) và mất mát riêng cho tác vụ (ví dụ: cross-entropy với nhãn ground-truth) trên cùng tập dữ liệu.

Sử dụng dữ liệu hiệu quả

Trong nhiều kịch bản thực tế, tập dữ liệu là cố định và có giới hạn. Sử dụng cùng một tập dữ liệu cho cả hai mô hình tránh được nhu cầu thu thập dữ liệu bổ sung hoặc nguy cơ lệch miền (domain mismatch). Giáo viên trích xuất càng nhiều tri thức càng tốt từ tập dữ liệu, và học sinh chưng cất tri thức này vào một mô hình gọn nhẹ hơn.

Lợi ích của cách tiếp cận này

  • Cải thiện hiệu năng học sinh: Học sinh hưởng lợi từ tri thức đã học của giáo viên, thường đạt hiệu năng tốt hơn so với chỉ huấn luyện trên nhãn ground-truth.
  • Khả năng tổng quát hóa: Mục tiêu mềm của giáo viên đóng vai trò như một hình thức chính quy hóa (regularization), giúp học sinh tổng quát hóa tốt hơn bằng cách học các ranh giới quyết định mượt hơn.
  • Tính linh hoạt: Cách tiếp cận này hoạt động trên nhiều tác vụ khác nhau (ví dụ: phân loại, hồi quy, mô hình hóa chuỗi) và kiến trúc mô hình.
  • Hiệu quả dữ liệu: Ngay cả với dữ liệu gán nhãn hạn chế, đầu ra của giáo viên cung cấp thêm giám sát, giúp học sinh học hiệu quả hơn.

Cân nhắc và thực hành tốt nhất

  1. Chất lượng giáo viên: Giáo viên phải được huấn luyện tốthoạt động tốt trên tập dữ liệu. Một giáo viên huấn luyện kém sẽ cung cấp đầu ra nhiễu hoặc không đáng tin cậy, dẫn đến hiệu năng học sinh dưới mức tối ưu.
  2. Thiết kế mất mát chưng cất: Hàm mất mát của học sinh thường kết hợp mất mát chưng cất (khớp với đầu ra của giáo viên) và mất mát riêng cho tác vụ (khớp với nhãn ground-truth). Sự cân bằng (được kiểm soát bởi một siêu tham số trọng số, ví dụ: α trong L = α * L_distillation + (1-α) * L_task) là yếu tố then chốt. Tham số nhiệt độ trong hàm softmax cũng cần được điều chỉnh — nhiệt độ cao hơn (ví dụ: T = 2 hoặc T = 4) làm cho đầu ra của giáo viên mượt hơn.
  3. Nguy cơ overfitting: Nếu tập dữ liệu nhỏ, giáo viên có thể bị overfit. Hãy dùng các kỹ thuật chính quy hóa khi huấn luyện giáo viên (ví dụ: dropout, weight decay), tăng cường dữ liệu (data augmentation), và theo dõi hiệu năng tổng quát hóa của giáo viên.
  4. Kích thước và tính đa dạng của tập dữ liệu: Với các tập dữ liệu rất nhỏ, tri thức của giáo viên có thể bị hạn chế. Cân nhắc dùng một giáo viên đã huấn luyện trước hoặc tăng cường tập dữ liệu.
  5. Tính tương thích kiến trúc mô hình: Đảm bảo mô hình giáo viên và học sinh tương thích về không gian đầu ra. Nếu học sinh có kiến trúc khác, có thể cần thêm các kỹ thuật như distillation dựa trên đặc trưng (feature-based distillation).
  6. Hiệu quả tính toán: Vì giáo viên đã được huấn luyện trước, các tham số của nó cố định trong khi huấn luyện học sinh. Học sinh chỉ cần đầu ra của giáo viên, có thể được tính trước và lưu cache cho toàn bộ tập dữ liệu để tiết kiệm thời gian.

Các phương án thay thế hoặc biến thể tiềm năng

  • Transfer Learning hoặc Domain Adaptation: Nếu giáo viên được huấn luyện trước trên một tập dữ liệu lớn hơn, có liên quan (ví dụ: ImageNet), nó có thể được tinh chỉnh trên tập dữ liệu mục tiêu trước khi distillation.
  • Dữ liệu không nhãn hoặc đã tăng cường: Trong một số trường hợp, học sinh có thể được huấn luyện trên một hỗn hợp dữ liệu có nhãn và dữ liệu không nhãn, trong đó giáo viên cung cấp nhãn giả (pseudo-labels) cho phần không nhãn.
  • Online Distillation: Nếu bạn muốn tránh hoàn toàn việc huấn luyện trước giáo viên, bạn có thể khám phá online knowledge distillation (ví dụ: Deep Mutual Learning).

Ví dụ thực tế

Giả sử bạn đang làm việc với một tác vụ phân loại ảnh trên tập dữ liệu CIFAR-10:

  • Huấn luyện giáo viên: Huấn luyện một mô hình lớn (ví dụ: ResNet-50) trên CIFAR-10 cho đến khi đạt độ chính xác cao (ví dụ: 95% trên tập test).
  • Huấn luyện học sinh: Huấn luyện một mô hình nhỏ hơn (ví dụ: MobileNet) trên CIFAR-10, dùng một hàm mất mát kết hợp phân kỳ KL giữa logit đã làm mềm của giáo viên (nhiệt độ T=4) và logit của học sinh, cộng với mất mát cross-entropy với nhãn ground-truth.
  • Kết quả: Học sinh đạt độ chính xác gần bằng giáo viên (ví dụ: 93%) trong khi nhỏ hơn và nhanh hơn nhiều.

4. Các trường hợp sử dụng tập dữ liệu khác nhau

4.1. Transfer Learning hoặc Domain Adaptation

  • Kịch bản: Giáo viên được huấn luyện trước trên một tập dữ liệu lớn, tổng quát (ví dụ: ImageNet cho ảnh, Wikipedia hoặc Common Crawl cho văn bản), trong khi học sinh được huấn luyện trên một tập dữ liệu nhỏ hơn, đặc thù cho tác vụ hoặc miền.
  • Cơ sở lý luận: Giáo viên, thường là một foundation model lớn, học các đặc trưng rộng, có thể tổng quát hóa từ một tập dữ liệu đa dạng. Các đặc trưng này có thể được chưng cất vào một mô hình học sinh nhỏ hơn, phù hợp với một miền hoặc tác vụ cụ thể, ngay cả khi tập dữ liệu mục tiêu bị giới hạn.
  • Ví dụ: Trong NLP, một giáo viên như BERT được huấn luyện trước trên một kho ngữ liệu văn bản khổng lồ (ví dụ: Wikipedia + BookCorpus). Học sinh (ví dụ: DistilBERT) được huấn luyện trên một tập dữ liệu nhỏ hơn, đặc thù cho tác vụ (ví dụ: phân tích cảm xúc trên các đánh giá IMDb), dùng đầu ra của giáo viên để dẫn dắt việc học.
  • Lợi ích: Tận dụng tri thức tổng quát của giáo viên để cải thiện hiệu năng học sinh trên các tác vụ chuyên biệt với dữ liệu hạn chế.
  • Thách thức: Tri thức của giáo viên có thể không hoàn toàn phù hợp với miền mục tiêu, đòi hỏi điều chỉnh cẩn thận quá trình distillation.

4.2. Semi-Supervised Learning với dữ liệu không nhãn

  • Kịch bản: Giáo viên được huấn luyện trên một tập dữ liệu có nhãn, trong khi học sinh được huấn luyện trên một kết hợp giữa cùng tập dữ liệu có nhãn đó và dữ liệu không nhãn bổ sung, dùng dự đoán của giáo viên (nhãn giả) cho phần không nhãn.
  • Cơ sở lý luận: Giáo viên cung cấp nhãn giả chất lượng cao cho dữ liệu không nhãn, mở rộng hiệu quả tập huấn luyện của học sinh. Đặc biệt hữu ích khi dữ liệu có nhãn khan hiếm nhưng dữ liệu không nhãn dồi dào.
  • Ví dụ: Trong phân loại ảnh, giáo viên được huấn luyện trên một tập con có nhãn của CIFAR-100. Học sinh được huấn luyện trên cả tập con có nhãn và một tập lớn ảnh không nhãn.
  • Lợi ích: Cải thiện hiệu năng học sinh bằng cách tận dụng dữ liệu không nhãn.
  • Thách thức: Nhãn giả của giáo viên có thể chứa lỗi, đặc biệt với dữ liệu không nhãn nằm ngoài phân bố (out-of-distribution); có thể cần ngưỡng độ tin cậy (confidence thresholding) hoặc chính quy hóa nhất quán (consistency regularization).

4.3. Thiết lập bảo mật quyền riêng tư hoặc ràng buộc dữ liệu

  • Kịch bản: Giáo viên được huấn luyện trên một tập dữ liệu nhạy cảm hoặc độc quyền không thể chia sẻ, trong khi học sinh được huấn luyện trên một tập dữ liệu khác, công khai, hoặc tổng hợp.
  • Cơ sở lý luận: Knowledge distillation cho phép truyền tri thức của giáo viên mà không trực tiếp phơi bày dữ liệu huấn luyện gốc.
  • Ví dụ: Một mô hình giáo viên được huấn luyện trên hồ sơ y tế riêng tư được dùng để chưng cất tri thức vào một mô hình học sinh được huấn luyện trên một tập dữ liệu y tế tổng hợp hoặc công khai.
  • Lợi ích: Cho phép truyền tri thức trong các thiết lập có ràng buộc nghiêm ngặt về quyền riêng tư hoặc quyền truy cập dữ liệu.
  • Thách thức: Tập dữ liệu proxy phải đủ tương đồng với tập dữ liệu của giáo viên để đảm bảo distillation hiệu quả.

4.4. Tăng cường dữ liệu hoặc tập dữ liệu nhiễu loạn

  • Kịch bản: Giáo viên được huấn luyện trên tập dữ liệu gốc, trong khi học sinh được huấn luyện trên một phiên bản đã tăng cường hoặc nhiễu loạn (ví dụ: có thêm nhiễu, phép biến đổi, hoặc mẫu đối kháng).
  • Cơ sở lý luận: Huấn luyện học sinh trên dữ liệu đã tăng cường có thể cải thiện độ bền vững hoặc khả năng tổng quát hóa, trong khi giáo viên cung cấp mục tiêu ổn định, chất lượng cao.
  • Ví dụ: Trong thị giác máy tính, giáo viên được huấn luyện trên ảnh ImageNet sạch, trong khi học sinh được huấn luyện trên ImageNet với các phép tăng cường ngẫu nhiên (xoay, lật, jitter màu).
  • Lợi ích: Tăng cường độ bền vững của học sinh trước các biến thể trong dữ liệu đầu vào.
  • Thách thức: Các phép tăng cường phải được lựa chọn cẩn thận để tránh đưa vào nhiễu không liên quan hoặc có hại.

4.5. Distillation đa phương thức hoặc đa nhiệm vụ

  • Kịch bản: Giáo viên được huấn luyện trên một phương thức hoặc tác vụ, trong khi học sinh được huấn luyện trên một phương thức hoặc tác vụ khác, dùng tri thức chung hoặc đã được căn chỉnh (aligned).
  • Cơ sở lý luận: Tri thức của giáo viên từ một miền hoặc phương thức có thể dẫn dắt học sinh trong một miền liên quan nhưng khác, đặc biệt khi các tác vụ chia sẻ các mẫu hình nền tảng.
  • Ví dụ: Trong các mô hình thị giác-ngôn ngữ, một giáo viên được huấn luyện trên một tập dữ liệu ảnh-chú thích lớn chưng cất tri thức vào một học sinh được huấn luyện trên một tập dữ liệu chỉ-văn-bản hoặc chỉ-ảnh cho một tác vụ cụ thể.
  • Lợi ích: Cho phép truyền tri thức giữa các phương thức hoặc tác vụ.
  • Thách thức: Đòi hỏi sự căn chỉnh giữa không gian đầu ra của giáo viên và học sinh, thường cần thêm các lớp ánh xạ hoặc hàm mất mát.

4.6. Continual Learning hoặc phân bố dữ liệu thay đổi theo thời gian

  • Kịch bản: Giáo viên được huấn luyện trên tập dữ liệu ban đầu, trong khi học sinh được huấn luyện trên một tập dữ liệu mới phản ánh sự dịch chuyển hoặc cập nhật trong phân bố dữ liệu.
  • Cơ sở lý luận: Giáo viên cung cấp một nền tảng tri thức ổn định từ dữ liệu gốc, trong khi học sinh thích ứng với phân bố mới.
  • Ví dụ: Trong một hệ thống gợi ý, giáo viên được huấn luyện trên dữ liệu tương tác người dùng trong quá khứ, trong khi học sinh được huấn luyện trên dữ liệu gần đây với hành vi người dùng hoặc mặt hàng mới.
  • Lợi ích: Hỗ trợ thích ứng với môi trường thay đổi trong khi vẫn giữ được tri thức trước đó.
  • Thách thức: Tri thức của giáo viên có thể trở nên lỗi thời, nên có thể cần các kỹ thuật như tinh chỉnh giáo viên hoặc dùng một ensemble các giáo viên.

Cân nhắc khi sử dụng các tập dữ liệu khác nhau

  1. Căn chỉnh miền (Domain Alignment): Các tập dữ liệu nên đủ liên quan để đảm bảo tri thức của giáo viên phù hợp với tác vụ của học sinh. Các kỹ thuật như căn chỉnh đặc trưng (feature alignment) hoặc huấn luyện đối kháng (adversarial training) có thể giúp thu hẹp khác biệt miền.
  2. Chất lượng đầu ra của giáo viên: Đầu ra của giáo viên phải đáng tin cậy đối với tập dữ liệu của học sinh. Kiểm chứng hiệu năng của giáo viên trên một tập con dữ liệu của học sinh, hoặc dùng lọc dựa trên độ tin cậy để loại bỏ các dự đoán chất lượng thấp.
  3. Thiết kế mất mát chưng cất: Mất mát chưng cất nên tính đến các khác biệt tiềm ẩn trong phân bố dữ liệu. Giảm trọng số của mất mát chưng cất so với mất mát riêng cho tác vụ có thể hữu ích khi đầu ra của giáo viên kém tin cậy hơn.
  4. Tính sẵn có của dữ liệu và quyền riêng tư: Đảm bảo tập dữ liệu của học sinh đủ để huấn luyện, và trong các trường hợp nhạy cảm về quyền riêng tư, xác minh rằng quy trình distillation tuân thủ các quy định về dữ liệu (ví dụ: GDPR hoặc HIPAA).
  5. Đánh giá và kiểm chứng: Theo dõi hiệu năng của học sinh trên một tập kiểm chứng từ tập dữ liệu mục tiêu của nó và so sánh với một baseline được huấn luyện không có distillation.

Khi nào nên tránh dùng các tập dữ liệu khác nhau

Sử dụng các tập dữ liệu khác nhau có thể tạo ra sự phức tạp và rủi ro. Tránh cách tiếp cận này nếu:

  • Các tập dữ liệu không liên quan hoặc có khoảng cách miền đáng kể, và việc tinh chỉnh giáo viên là không khả thi.
  • Tập dữ liệu của học sinh lớn và chất lượng cao, khiến việc distillation từ một giáo viên được huấn luyện khác trở nên không cần thiết.
  • Hiệu năng của giáo viên trên phân bố dữ liệu của học sinh kém, và không có cách nào để kiểm chứng hoặc cải thiện nó.

5. Self-Training

Self-Training là gì?

Self-Training là một cách tiếp cận học bán giám sát (semi-supervised learning) trong đó một mô hình (thường được gọi là giáo viên) được huấn luyện trước trên một tập dữ liệu có nhãn, sau đó được dùng để tạo nhãn giả cho một tập dữ liệu không nhãn. Các nhãn giả này được kết hợp với dữ liệu có nhãn để huấn luyện một mô hình mới (thường được gọi là học sinh), có thể cùng hoặc khác kiến trúc. Quá trình này có thể lặp lại, với học sinh trở thành giáo viên ở các vòng tiếp theo.

Self-Training hoạt động như thế nào

  1. Huấn luyện giáo viên: Huấn luyện một mô hình trên tập dữ liệu có nhãn $D_L = \{(x_i, y_i)\}$, trong đó $x_i$ là đầu vào và $y_i$ là nhãn ground-truth.
  2. Tạo nhãn giả: Dùng giáo viên đã huấn luyện để dự đoán nhãn (hoặc xác suất) cho một tập dữ liệu không nhãn $D_U = \{(x_j)\}$. Các dự đoán này được gọi là nhãn giả, ký hiệu $\hat{y}_j$.
  3. Chọn nhãn giả có độ tin cậy cao: Thường chỉ các nhãn giả có độ tin cậy cao (ví dụ: trên một ngưỡng) mới được dùng để lọc bỏ các dự đoán nhiễu.
  4. Huấn luyện học sinh: Huấn luyện một mô hình mới trên tập dữ liệu kết hợp $D_L \cup \{(x_j, \hat{y}_j)\}$, trong đó học sinh học từ cả nhãn ground-truthnhãn giả.
  5. Lặp lại (tùy chọn): Học sinh trở thành giáo viên, tạo ra các nhãn giả mới, và quá trình lặp lại qua nhiều vòng.

Self-Training cải thiện hiệu năng mô hình như thế nào

  • Tận dụng dữ liệu không nhãn: Self-Training tận dụng nguồn dữ liệu không nhãn dồi dào, tăng kích thước tập huấn luyện hiệu quả và giúp mô hình học các đặc trưng bền vững hơn.
  • Hiệu ứng chính quy hóa: Nhãn giả cung cấp một hình thức chính quy hóa, khuyến khích mô hình đưa ra các dự đoán nhất quán trên cả dữ liệu có nhãn và không nhãn.
  • Cải thiện khả năng tổng quát hóa: Bằng cách cho mô hình tiếp xúc với một tập dữ liệu lớn hơn và đa dạng hơn, Self-Training có thể cải thiện hiệu năng trên các mẫu ngoài phân bố hoặc khó.
  • Tinh chỉnh lặp lại: Trong Self-Training lặp lại, mỗi vòng tinh chỉnh các nhãn giả, có khả năng cải thiện chất lượng của chúng.

Thách thức

  • Lan truyền lỗi: Nếu nhãn giả của giáo viên sai, học sinh có thể học từ các nhãn nhiễu hoặc thiên lệch. Ngưỡng độ tin cậy hoặc nhãn mềm (xác suất) có thể giảm thiểu điều này.
  • Chất lượng giáo viên hạn chế: Nếu giáo viên ban đầu được huấn luyện trên một tập dữ liệu có nhãn nhỏ, nhãn giả của nó có thể không đáng tin cậy.
  • Dịch chuyển miền (Domain Shift): Nếu dữ liệu không nhãn khác biệt đáng kể so với dữ liệu có nhãn, nhãn giả có thể không phù hợp với tác vụ mục tiêu.

6. Noisy Student Training

Noisy Student Training là gì?

Noisy Student Training (Xie et al., 2020) là một phương pháp self-training nâng cao, kết hợp nhiễu và chính quy hóa để cải thiện hiệu năng của mô hình học sinh vượt trên giáo viên. Không giống Self-Training thông thường, Noisy Student chủ động thêm các yếu tố ngẫu nhiên (ví dụ: tăng cường dữ liệu, dropout) vào quá trình huấn luyện học sinh để làm cho nó bền vững hơn và ngăn nó chỉ đơn thuần ghi nhớ các dự đoán của giáo viên.

Noisy Student Training hoạt động như thế nào

  1. Huấn luyện giáo viên: Huấn luyện một mô hình giáo viên trên tập dữ liệu có nhãn $D_L$, tương tự như Self-Training.
  2. Tạo nhãn giả: Dùng giáo viên để dự đoán nhãn giả cho một tập dữ liệu không nhãn lớn $D_U$. Nhãn cứng (dự đoán lớp) thường được dùng thay vì nhãn mềm để đơn giản hóa quá trình.
  3. Huấn luyện học sinh với nhiễu: Huấn luyện một mô hình học sinh (thường có năng lực lớn hơn hoặc bằng giáo viên) trên $D_L \cup \{(x_j, \hat{y}_j)\}$, nhưng đưa thêm nhiễu và chính quy hóa trong quá trình huấn luyện:
    • Tăng cường dữ liệu: Áp dụng các phép tăng cường mạnh (ví dụ: RandAugment cho ảnh) cho cả đầu vào có nhãn và không nhãn.
    • Nhiễu mô hình: Dùng các kỹ thuật như dropout, stochastic depth, hoặc đóng băng lớp ngẫu nhiên trong mô hình học sinh.
    • Tập dữ liệu cân bằng: Đảm bảo dữ liệu có nhãn và không nhãn được cân bằng.
  4. Lặp lại: Dùng học sinh làm giáo viên mới, tạo ra các nhãn giả cập nhật, và lặp lại. Mỗi vòng lặp thường cải thiện hiệu năng mô hình.

Khác biệt chính so với Self-Training

  • Đưa thêm nhiễu (Noise Injection): Noisy Student chủ động thêm nhiễu để tránh overfitting với nhãn giả của giáo viên và khuyến khích độ bền vững.
  • Học sinh có năng lực bằng hoặc lớn hơn: Không giống knowledge distillation, nơi học sinh nhỏ hơn, Noisy Student thường dùng một học sinh có năng lực bằng hoặc lớn hơn giáo viên.
  • Cải thiện lặp lại: Noisy Student nhấn mạnh vào nhiều vòng lặp, với mỗi học sinh có khả năng vượt trội hơn giáo viên trước đó.

Noisy Student cải thiện hiệu năng mô hình như thế nào

  • Độ bền vững nhờ nhiễu: Nhiễu được thêm vào buộc học sinh học các đặc trưng tổng quát hơn, ngăn overfitting với các dự đoán hoặc thiên lệch trong nhãn giả của giáo viên.
  • Mở rộng theo dữ liệu không nhãn: Noisy Student tận dụng lượng lớn dữ liệu không nhãn, điều quan trọng để cải thiện hiệu năng trong các thiết lập khan hiếm dữ liệu.
  • Tinh chỉnh lặp lại: Mỗi vòng lặp tinh chỉnh các nhãn giả, khi học sinh-trở-thành-giáo-viên trở nên chính xác hơn, dẫn đến một vòng lặp cải thiện tích cực (virtuous cycle).
  • Vượt qua giáo viên: Bằng cách kết hợp nhiễu, một mô hình học sinh lớn hơn, và huấn luyện lặp lại, Noisy Student có thể tạo ra các mô hình vượt trội hơn giáo viên ban đầu.

Ví dụ

Trong bài báo Noisy Student, một giáo viên EfficientNet được huấn luyện trên tập dữ liệu ImageNet có nhãn. Nó tạo ra nhãn giả cho 300 triệu ảnh không nhãn từ JFT-300M. Một học sinh EfficientNet lớn hơn được huấn luyện trên tập dữ liệu kết hợp với các phép tăng cường mạnh (RandAugment) và dropout, đạt độ chính xác cao hơn giáo viên. Sau nhiều vòng lặp, mô hình cuối cùng thiết lập các benchmark mới trên ImageNet.

Thách thức

  • Chi phí tính toán: Noisy Student đòi hỏi tài nguyên tính toán đáng kể, vì nó liên quan đến việc huấn luyện các mô hình lớn và lặp lại nhiều lần trên các tập dữ liệu lớn.
  • Điều chỉnh nhiễu: Loại và cường độ nhiễu (tăng cường, dropout) phải được điều chỉnh cẩn thận để cân bằng giữa độ bền vững và tính ổn định khi học.
  • Chất lượng nhãn giả: Cũng như Self-Training, nhãn giả kém chất lượng có thể gây hại cho hiệu năng, đặc biệt ở các vòng lặp đầu.

7. Liên hệ với Knowledge Distillation và các tập dữ liệu khác nhau

Cả Self-TrainingNoisy Student đều có liên hệ chặt chẽ với knowledge distillation, đặc biệt trong các kịch bản mà giáo viên và học sinh được huấn luyện trên các tập dữ liệu khác nhau (ví dụ: dữ liệu có nhãn so với không nhãn):

  • Các tập dữ liệu khác nhau: Trong cả hai phương pháp, giáo viên thường được huấn luyện trên một tập dữ liệu có nhãn, trong khi học sinh được huấn luyện trên một kết hợp giữa tập dữ liệu có nhãn và một tập dữ liệu không nhãn (hoặc một tập dữ liệu khác với nhãn giả).
  • Truyền tri thức: Giống như knowledge distillation, Self-Training và Noisy Student truyền tri thức từ giáo viên sang học sinh thông qua nhãn giả (cứng hoặc mềm).
  • Cải thiện hiệu năng: Các phương pháp này đặc biệt hiệu quả khi tập dữ liệu có nhãn nhỏ nhưng dữ liệu không nhãn dồi dào.

Các kỹ thuật này cải thiện hiệu năng mô hình như thế nào

  1. Tăng cường sử dụng dữ liệu: Cả hai phương pháp đều tận dụng dữ liệu không nhãn, thường dồi dào, để mở rộng tập huấn luyện. Điều này giúp mô hình tiếp xúc với các mẫu hình đa dạng hơn, cải thiện khả năng tổng quát hóa.
  2. Chính quy hóa: Nhãn giả và nhiễu (trong Noisy Student) đóng vai trò như các bộ chính quy hóa, ngăn overfitting với dữ liệu có nhãn.
  3. Cải thiện lặp lại: Huấn luyện lặp lại tinh chỉnh nhãn giả, dẫn đến các mô hình ngày càng tốt hơn.
  4. Xử lý dữ liệu có nhãn hạn chế: Trong các thiết lập có ít mẫu có nhãn, các phương pháp này dùng dữ liệu không nhãn để bù đắp, đạt hiệu năng gần với các mô hình được giám sát đầy đủ.
  5. Thích ứng miền: Khi dữ liệu không nhãn đến từ một phân bố hơi khác, các phương pháp này có thể giúp học sinh thích ứng với miền mục tiêu.

Cân nhắc thực tiễn

  • Khi nào dùng Self-Training: Self-Training hiệu quả cho các tập dữ liệu không nhãn nhỏ đến trung bình và được dùng cho các tác vụ bán giám sát đơn giản hơn với tài nguyên tính toán hạn chế hoặc khi mô hình học sinh tương tự giáo viên.
  • Khi nào dùng Noisy Student: Dùng Noisy Student khi bạn có quyền truy cập vào các tập dữ liệu không nhãn lớn, đủ tài nguyên tính toán, và muốn tối đa hóa hiệu năng, có khả năng vượt qua giáo viên.
  • Mẹo triển khai:
    • Ngưỡng độ tin cậy: Lọc nhãn giả theo độ tin cậy (ví dụ: giữ các dự đoán có xác suất > 0.9) để giảm nhiễu.
    • Giáo viên mạnh: Bắt đầu với một giáo viên chất lượng cao (ví dụ: đã huấn luyện trước trên một tập dữ liệu lớn) để đảm bảo nhãn giả đáng tin cậy.
    • Điều chỉnh nhiễu: Trong Noisy Student, thử nghiệm với các chính sách tăng cường (ví dụ: RandAugment) và cường độ chính quy hóa.
    • Chiến lược lặp lại: Giới hạn số vòng lặp để tránh tích lũy lỗi, và theo dõi hiệu năng kiểm chứng để dừng sớm nếu cần.
Thị giác máy tính

Các công cụ Thị giác 2D

1. Sân chơi hình Ellipse (Ellipse Playground)

Cho hệ tọa độ ảnh $Oxy$, với $O(0, 0)$ là tâm tọa độ:

Sơ đồ hệ tọa độ ảnh Oxy

1.1. Phương trình tổng quát

Phương trình tổng quát của một hình ellipse đã xoay:

$$\frac{[(x-c_x)\cos(-\theta)+(y-c_y)\sin(-\theta)]^2}{a^2}+\frac{[(x-c_x)\sin(-\theta)-(y-c_y)\cos(-\theta)]^2}{b^2}=1$$

trong đó:

  • $C(c_x, c_y)$ là tâm của hình ellipse
  • $a, b$ là bán trục lớn và bán trục nhỏ
  • $\theta$ là góc xoay đo từ trục $Cx$ (không phải trục $Ox$) (theo chiều kim đồng hồ)

1.2. Phương trình tham số

$$x(\alpha) = a\cos(\alpha)\cos(\theta) - b\sin(\alpha)\sin(\theta) + c_x$$ $$y(\alpha) = a\cos(\alpha)\sin(\theta) + b\sin(\alpha)\cos(\theta) + c_y$$

trong đó:

  • $C(c_x, c_y)$ là tâm của hình ellipse
  • $a, b$ là bán trục lớn và bán trục nhỏ
  • $\theta$ là góc xoay đo từ trục $Cx$ (không phải trục $Ox$) (theo chiều kim đồng hồ)
  • $\alpha$ là tham số, có giá trị (radian) từ $0$ đến $2\pi$

Minh họa hình ellipse đã xoay, với $Cx$ và $Cy$ tương ứng song song và cùng hướng với $Ox$ và $Oy$:

Minh họa hình ellipse đã xoay

2. Xoay điểm (Rotate Point)

Nếu bạn xoay một điểm $B(x_B, y_B)$ quanh một điểm $A(x_A, y_A)$ theo góc $\theta$ (ngược chiều kim đồng hồ), bạn sẽ được một điểm $C(x_C, y_C)$, trong đó:

$$x_C = (x_B - x_A)\cos(\theta) - (y_B - y_A)\sin(\theta) + x_A$$ $$y_C = (x_B - x_A)\sin(\theta) + (y_B - y_A)\cos(\theta) + y_A$$

Triển khai Python:

def get_rotation(start_point, center_point, rad):
    """Rotate start_point around center_point by rad radians (counterclockwise).

    Args:
        start_point:  (x, y)
        center_point: (x, y)
        rad:          rotation angle in radians, counterclockwise

    Returns:
        [x_T, y_T]
    """
    T = [0, 0]
    T[0] = (start_point[0] - center_point[0]) * math.cos(rad) \
         - (start_point[1] - center_point[1]) * math.sin(rad) \
         + center_point[0]
    T[1] = (start_point[0] - center_point[0]) * math.sin(rad) \
         + (start_point[1] - center_point[1]) * math.cos(rad) \
         + center_point[1]
    return T
Ước lượng độ sâu

Rolling in the Deep

Benchmark (Cập nhật mới nhất)

Benchmark công khai

Tuyên bố miễn trừ trách nhiệm:

  • Đây chỉ là một benchmark trên một số tập dữ liệu chuẩn, nghĩa là mô hình không nhất thiết trở thành "SOTA" thực sự cho các ứng dụng trong-thực-tế (in-the-wild).
  • Benchmark này tập trung vào các chỉ số độ chính xác nhưng không có chỉ số độ trễ (latency), vốn cũng là một phần thiết yếu của các ứng dụng thời gian thực.

Ghi chú cá nhân

Các công trình nổi bật

Các công trình này có thể không phải là "SOTA" trên một số tập dữ liệu cụ thể nhưng có tiềm năng cao cho các ứng dụng thực tế, trong-thực-tế.

Depth Any Camera: Zero-Shot Metric Depth Estimation from Any Camera (2025)
Prompting Depth Anything for 4K Resolution Accurate Metric Depth Estimation (PromptDA, 2024)
Lotus: Diffusion-based Visual Foundation Model for High-quality Dense Prediction (2024)
World-consistent Video Diffusion with Explicit 3D Modeling (WVD, 2024)
RollingDepth: Video Depth without Video Models (2024)
Depth Anything V2 – CVPR 2024
DepthCrafter: Generating Consistent Long Depth Sequences for Open-world Videos (2024)
Depth Anywhere: Enhancing 360 Monocular Depth Estimation via Perspective Distillation and Unlabeled Data Augmentation – NeurIPS 2024
Depth Pro: Sharp Monocular Metric Depth in Less Than a Second (2024)
UniDepth: Universal Monocular Metric Depth Estimation – CVPR 2024
Marigold: Repurposing Diffusion-Based Image Generators for Monocular Depth Estimation – CVPR 2024
Booster: A Benchmark for Depth from Images of Specular and Transparent Surfaces (2023)
Deep Depth from Focus with Differential Focus Volume – CVPR 2022
Towards Robust Monocular Depth Estimation: Mixing Datasets for Zero-shot Cross-dataset Transfer (MiDaS, 2020)

Tập dữ liệu & Trình mô phỏng

RGBD Objects in the Wild: Scaling Real-World 3D Object Learning from RGB-D Videos
CARLA Simulator

Tài liệu tham khảo khác

Ước lượng độ sâu

Từ Ước lượng Độ sâu đến Pseudo-LIDAR

Nhận thức độ sâu ở con người

Các nghiên cứu về nhận thức độ sâu ở con người cung cấp cái nhìn sâu sắc về các gợi ý hình ảnh (pictorial cues) có thể dùng để ước lượng khoảng cách. Các gợi ý sau thường có thể tìm thấy trong ảnh đơn:

  • Vị trí trong ảnh: các vật thể ở xa hơn có xu hướng gần đường chân trời hơn. Khi nằm trên mặt đất, các vật thể cũng xuất hiện cao hơn trong ảnh.
  • Sự che khuất (Occlusion): các vật thể gần che khuất các vật thể phía sau — cho biết thứ tự độ sâu nhưng không cho biết khoảng cách chính xác.
  • Mật độ họa tiết (Texture density): các bề mặt có họa tiết ở xa hơn xuất hiện mịn hơn (chi tiết nhỏ hơn).
  • Phối cảnh tuyến tính (Linear perspective): các đường thẳng, song song trong thế giới thực xuất hiện hội tụ trong ảnh.
  • Kích thước biểu kiến của vật thể: các vật thể ở xa hơn xuất hiện nhỏ hơn.
  • Hiệu ứng chuyển động: các vật thể trở nên mờ và ngả xanh khi chúng di chuyển ra xa.
  • Bóng đổ & chiếu sáng: một bề mặt xuất hiện sáng hơn khi pháp tuyến của nó hướng về phía nguồn sáng. Bóng đổ cung cấp thông tin về sự thay đổi độ sâu trong một bề mặt.
  • Độ mờ do lấy nét (Focus blur): các vật thể ở phía trước hoặc phía sau mặt phẳng lấy nét xuất hiện mờ.
  • Phối cảnh khí quyển (Aerial perspective): các vật thể rất xa có độ tương phản thấp hơn và ngả sắc xanh.

Các cách tiếp cận Ước lượng Độ sâu

Có 2 cách tiếp cận ước lượng độ sâu đơn mắt (monocular): ước lượng độ sâu tuyệt đốiước lượng độ sâu tương đối.

1. Ước lượng độ sâu tuyệt đối

Ước lượng độ sâu tuyệt đối (hay theo đơn vị mét - metric) dự đoán giá trị độ sâu cho từng pixel theo đơn vị vật lý tuyệt đối (mét).

  • Ưu điểm: các dự đoán có thể được dùng trực tiếp cho các ứng dụng downstream.
  • Nhược điểm: huấn luyện trên nhiều tập dữ liệu thường làm giảm hiệu năng, đặc biệt khi thang độ sâu khác nhau nhiều (ví dụ trong nhà so với ngoài trời). Các phương pháp này thường bị overfit với một tập dữ liệu cụ thể.

2. Ước lượng độ sâu tương đối

Ước lượng độ sâu tương đối loại bỏ yếu tố thang đo (scale), ước lượng độ sâu của các pixel tương đối với nhau. Hệ số thang đo tuyệt đối là không xác định.

  • Ưu điểm: cho phép tổng quát hóa trên nhiều miền dữ liệu — thang đo mét và tham số camera không cần nhất quán.
  • Nhược điểm: độ sâu dự đoán không có ý nghĩa theo đơn vị mét.

Từ Ước lượng Độ sâu đến Tái tạo 3D

Mối quan hệ giữa một tọa độ 2D $p$ (mặt phẳng ảnh) và tọa độ 3D tương ứng $P_c$ (hệ tọa độ camera) là:

$$s\,p = A P_c \quad (1)$$

trong đó $p = \begin{bmatrix} u\\ v \end{bmatrix}$, $P_c = \begin{bmatrix} X_c\\ Y_c \\ Z_c \end{bmatrix}$, $s$ là hệ số thang đo phối cảnh (projective scaling factor), và $A$ là ma trận nội tại (intrinsic) camera (lý tưởng):

$$A = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \quad (2)$$

Trong thực tế, mọi camera đều có hiện tượng méo ảnh (distortion), vì vậy ta cần hiệu chỉnh (calibrate) trước và tính toán $A$ tối ưu bằng OpenCV:

camera_matrix = np.zeros(shape=(3, 3))
camera_matrix[0, 0] = 3.618627944978409e+02
camera_matrix[0, 2] = 3.140828758355781e+02
camera_matrix[1, 1] = 3.611479934228698e+02
camera_matrix[1, 2] = 1.674230039961440e+02
camera_matrix[2, 2] = 1

dist_coeffs = np.array([-0.115065515143958, 0.023076954804581, 0, 0, 0])

# W, H = image width and height
A, _ = cv2.getOptimalNewCameraMatrix(camera_matrix, dist_coeffs, (W, H), 1)
💡 Hiệu chỉnh camera là một quá trình xấp xỉ — tương tự như machine learning. Chúng ta hiếm khi có được ma trận camera lý tưởng thực sự, nhưng xem kết quả thu được là $A$ để đơn giản hóa.

Bản đồ độ sâu tuyệt đối cho ta $Z_c$. Các tọa độ còn lại được suy ra từ (1) và (2):

$$X_c = \frac{Z_c(u - c_x)}{f_x} \quad (3) \qquad Y_c = \frac{Z_c(v - c_y)}{f_y} \quad (4)$$

Triển khai Python:

def depth_to_3d(D, fx, fy, cx, cy):
    """Convert absolute depth map to 3D coordinates in camera coordinate system.

    Args:
        D:  absolute depth map, shape (H, W)
        fx, fy: focal lengths; cx, cy: principal point

    Returns:
        3D coordinates, shape (H*W, 3) — each row is (Xc, Yc, Zc)
    """
    H, W = D.shape
    xx, yy = np.tile(range(W), H), np.repeat(range(H), W)
    Z = D.reshape(-1)
    Xc = (xx - cx) * Z / fx
    Yc = (yy - cy) * Z / fy
    return np.stack([Xc, Yc, Z], axis=1)

Tái tạo LIDAR bằng Pseudo-LIDAR

💡 Để kiểm chứng đề xuất này, thiết lập 4 camera1 LIDAR trong môi trường mô phỏng CARLA, ghi lại dữ liệu, và thử nghiệm với pipeline đầu-cuối (end-to-end).

Cho một LIDAR $L$ tạo ra một point cloud 360°, ta tái tạo nó bằng các camera $C_i$. Pipeline đề xuất:

  1. Suy luận bản đồ độ sâu tuyệt đối $D_i$ của mỗi ảnh $I_i$.
  2. Tính toán tọa độ 3D $P_{C_i}$ trong hệ tọa độ mỗi camera bằng $D_i$ và ma trận nội tại $A_i$.
  3. Chiếu lại (re-project) sang hệ tọa độ LIDAR thông qua phép quay $R_i$ và phép tịnh tiến $t_i$:
    $$P_{L_i} = [R_i \mid t_i]\,P_{C_i} \quad (5)$$

Ưu điểm so với LIDAR thực: chi phí thấp hơn, point cloud màu dày đặc hơn, tiềm năng tốc độ khung hình cao hơn.

Nhược điểm: giới hạn do méo ảnh camera, nhạy cảm với ánh sáng và thời tiết, hiện tượng che khuất thường xuyên, cần ghép nhiều camera (multi-camera stitching), và việc hiệu chỉnh/đồng bộ hóa khó khăn.


Tài liệu tham khảo

Thị giác máy tính

Perspective Transform và Affine Transform

Perspective Transform

Homography (perspective transform) là một phép biến đổi hình học liên hệ giữa 2 mặt phẳng khác nhau. Các đường thẳng vẫn giữ thẳng sau khi biến đổi.

Minh họa Perspective Transform

Mỗi điểm $(x, y)$ trên mặt phẳng $\pi$ ánh xạ sang $(x', y')$ trên mặt phẳng $\pi'$:

$$s \begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} = \mathbf{H} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = \begin{bmatrix} h_{11} & h_{12} & h_{13} \\ h_{21} & h_{22} & h_{23} \\ h_{31} & h_{32} & h_{33} \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}$$

trong đó $s$ là hệ số thang đo và $\mathbf{H}$ là ma trận homography 3×3 với 8 bậc tự do (DoF). Để tính $\mathbf{H}$ bạn cần 4 cặp điểm tương ứng, trong đó không có 3 điểm nào thẳng hàng.


Affine Transform

Định nghĩa

Một phép biến đổi affine (affine transformation) bảo toàn đường thẳng và tính song song, nhưng không nhất thiết bảo toàn khoảng cách Euclid và góc:

  • Các điểm nằm trên cùng một đường thẳng vẫn thẳng hàng sau khi biến đổi.
  • Các đường thẳng song song vẫn song song sau khi biến đổi.
  • Tỉ lệ của bất kỳ cặp đoạn thẳng nào được bảo toàn; trung điểm vẫn là trung điểm.

Ví dụ

  • Tịnh tiến (Translation): di chuyển một hình mà không thay đổi hướng hoặc kích thước.
  • Xoay (Rotation): xoay một hình quanh một điểm.
  • Co giãn (Scaling): phóng to hoặc thu nhỏ một hình.
  • Cắt xén (Shearing): làm nghiêng một hình.

Phương trình

Minh họa Affine Transform
Thị giác máy tính

Thuật toán đơn giản Phát hiện Nhìn Điện thoại

Giới thiệu

Một thuật toán đơn giản (naive) để kiểm tra liệu một người có đang nhìn vào điện thoại của họ hay không từ ảnh đầu vào, cho trước một Mô hình Phát hiện Đối tượng (Object Detection Model) và một Mô hình Ước lượng Ánh nhìn (Gaze Estimation Model).


Ý tưởng

Giả định:

  • Mô hình Phát hiện Đối tượng phát hiện các đối tượng thuộc lớp Phone (Điện thoại) và Human (Người).
  • Mô hình Ước lượng Ánh nhìn dự đoán một vector ánh nhìn (gaze vector) bắt đầu tại gaze_start hướng đến gaze_end.

Con người không nhìn theo một tia đơn lẻ mà theo một trường nhìn hình nón (cone-like FOV). Ta định nghĩa FOV ánh nhìn là hình nón nhận vector ánh nhìn làm đường phân giác góc của nó, sau đó kiểm tra xem có đối tượng Phone nào giao với FOV hay không. Một đối tượng được xem là giao nếu:

  1. Điểm tin cậy (confidence score) của nó cao hơn conf_thres (giảm các phát hiện điện thoại dương tính giả).
  2. FOV giao với ít nhất count_thres cạnh của bounding box của đối tượng.

Nếu có ít nhất một Phone thỏa cả hai điều kiện, người đó đang nhìn vào điện thoại.


Cấu hình

  • conf_thres: 0.5  (0 < conf_thres <= 1)
  • count_thres: 1  (1 <= count_thres <= 4)
  • fov_degree: 30  (độ lớn FOV tính bằng độ, 0 <= fov_degree <= 90)

Demo

Ảnh minh họa thuật toán hoạt động với các vector ánh nhìn và đối tượng điện thoại được sinh ngẫu nhiên:

Mất tập trung — người đang nhìn vào điện thoại Tập trung — người không nhìn vào điện thoại

Chú thích:

  • Vector xanh lá: ranh giới FOV
  • Vector xanh dương nhạt: vector ánh nhìn
  • Hình chữ nhật trắng: đối tượng dưới ngưỡng conf_thres
  • Hình chữ nhật vàng: đối tượng nằm trong bbox của người nhưng ngoài FOV
  • Hình chữ nhật đỏ: đối tượng thỏa cả hai điều kiện (điện thoại đang được nhìn vào)
import math
import cv2
import numpy as np
from loguru import logger


def get_rotation(start_point, center_point, rad):
    """Rotate start_point around center_point by rad radians (counter-clockwise)."""
    T = [0, 0]
    T[0] = (start_point[0] - center_point[0]) * math.cos(rad) \
         - (start_point[1] - center_point[1]) * math.sin(rad) \
         + center_point[0]
    T[1] = (start_point[0] - center_point[0]) * math.sin(rad) \
         + (start_point[1] - center_point[1]) * math.cos(rad) \
         + center_point[1]
    return T


def find_angle(start_point, end_point):
    """Angle of vector start_point->end_point w.r.t. Ox axis (clockwise)."""
    return math.atan2(end_point[1] - start_point[1], end_point[0] - start_point[0])


def is_anglerange_in_fovrange(fov_min, fov_max, angle_1, angle_2):
    """Check if [min(angle_1,angle_2), max(angle_1,angle_2)] overlaps [fov_min, fov_max].

    Constraints:
        0 <= fov <= math.pi / 2   (fov_min <= fov_max)
        -math.pi <= angles <= math.pi
    """
    angle_min = min(angle_1, angle_2)
    angle_max = max(angle_1, angle_2)

    if fov_min <= 0 and fov_max >= 0:
        if fov_min >= -math.pi / 2:         # -pi/2 <= fov_min <= 0, 0 <= fov_max <= pi/2
            if angle_max < fov_min:
                return False
            elif angle_max <= fov_max:
                return True
            elif angle_max <= fov_min + math.pi:
                return angle_max - math.pi <= angle_min <= fov_max
            else:
                return fov_min <= angle_min <= fov_max
        else:                                # -pi <= fov_min < -pi/2
            if angle_max <= fov_min:
                return True
            elif angle_max <= 0:
                return angle_min <= fov_min
            elif angle_max < fov_max:
                return angle_min <= angle_max - math.pi
            else:
                return True
    else:
        if fov_max <= 0:                     # fov_min <= fov_max <= 0
            if angle_max < fov_min:
                return False
            elif angle_max <= fov_max:
                return True
            elif angle_max <= fov_max + math.pi:
                return angle_max - math.pi <= angle_min <= fov_max
            else:
                return fov_min <= angle_min <= angle_max - math.pi
        else:                                # 0 <= fov_min <= fov_max
            if angle_max < 0:
                return False
            elif angle_max < fov_min:
                return angle_min <= angle_max - math.pi
            elif angle_max <= fov_max:
                return True
            else:
                return angle_max - math.pi <= angle_min <= fov_max
    return False


def is_overlapped(bbox1, bbox2):
    """Check if two bounding boxes [xmin, ymin, xmax, ymax] overlap."""
    h = (bbox1[0] <= bbox2[2] and bbox1[0] >= bbox2[0]) or \
        (bbox2[0] <= bbox1[2] and bbox2[0] >= bbox1[0])
    v = (bbox1[1] <= bbox2[3] and bbox1[1] >= bbox2[1]) or \
        (bbox2[1] <= bbox1[3] and bbox2[1] >= bbox1[1])
    return h and v


def find_intersect_obj_indices(gaze_start, gaze_end, objects, bbox,
                               fov_degree=30, conf_thres=0.5, count_thres=1):
    """Return indices of objects whose bounding boxes intersect the gaze FOV.

    Args:
        gaze_start, gaze_end: gaze vector endpoints (x, y)
        objects: list of [xmin, ymin, xmax, ymax, conf]
        bbox: human bounding box [xmin, ymin, xmax, ymax]
        fov_degree: FOV half-angle in degrees (0 <= fov_degree <= 90)
        conf_thres: minimum object confidence (0 < conf_thres <= 1)
        count_thres: minimum intersecting edges (1 <= count_thres <= 4)
    """
    rad = math.pi * fov_degree / 360
    fov_p1 = get_rotation(gaze_end, gaze_start, rad)
    fov_p2 = get_rotation(gaze_end, gaze_start, -rad)

    fov_a1 = find_angle(gaze_start, fov_p1)
    fov_a2 = find_angle(gaze_start, fov_p2)
    fov_amin, fov_amax = min(fov_a1, fov_a2), max(fov_a1, fov_a2)

    intersect_idx, outside_idx, unseen_idx = [], [], []

    for idx, obj in enumerate(objects):
        if not is_overlapped(obj, bbox):
            outside_idx.append(idx)
            continue

        if obj[4] >= conf_thres:
            corners = [(obj[0], obj[1]), (obj[0], obj[3]),
                       (obj[2], obj[1]), (obj[2], obj[3])]
            angles = [find_angle(gaze_start, c) for c in corners]

            count = sum([
                is_anglerange_in_fovrange(fov_amin, fov_amax, angles[0], angles[1]),  # top
                is_anglerange_in_fovrange(fov_amin, fov_amax, angles[2], angles[3]),  # bottom
                is_anglerange_in_fovrange(fov_amin, fov_amax, angles[0], angles[2]),  # left
                is_anglerange_in_fovrange(fov_amin, fov_amax, angles[1], angles[3]),  # right
            ])

            if count >= count_thres:
                intersect_idx.append(idx)
            else:
                unseen_idx.append(idx)

    return fov_p1, fov_p2, intersect_idx, outside_idx, unseen_idx


def generate_object(image_size):
    xmax = np.random.randint(1, image_size)
    xmin = np.random.randint(xmax)
    ymax = np.random.randint(1, image_size)
    ymin = np.random.randint(ymax)
    return [xmin, ymin, xmax, ymax, np.random.rand()]


def generate_gaze(bbox):
    while True:
        sx = np.random.randint(bbox[0], bbox[2])
        sy = np.random.randint(bbox[1], bbox[3])
        ex = np.random.randint(bbox[0], bbox[2])
        ey = np.random.randint(bbox[1], bbox[3])
        if sx != ex or sy != ey:
            break
    return (sx, sy), (ex, ey)


if __name__ == "__main__":
    fov_degree    = np.random.randint(30, 91)
    conf_thres    = 0.5
    count_thres   = 1
    image_size    = 700
    num_objects   = 5

    objects     = [generate_object(image_size) for _ in range(num_objects)]
    human       = generate_object(image_size)
    gaze_start, gaze_end = generate_gaze(human)

    fov_p1, fov_p2, inter, outside, unseen = find_intersect_obj_indices(
        gaze_start, gaze_end, objects, human,
        fov_degree=fov_degree, conf_thres=conf_thres, count_thres=count_thres)

    image = np.zeros((image_size, image_size, 3), dtype=np.uint8)
    cv2.rectangle(image, (human[0], human[1]), (human[2], human[3]), (255, 0, 0))
    cv2.arrowedLine(image, gaze_start, (int(fov_p1[0]), int(fov_p1[1])), (0, 255, 0), 3)
    cv2.arrowedLine(image, gaze_start, (int(fov_p2[0]), int(fov_p2[1])), (0, 255, 0), 3)
    cv2.arrowedLine(image, gaze_start, gaze_end, (255, 255, 0), 1)

    color_map = {tuple(inter): (0, 0, 255), tuple(outside): (255, 255, 255), tuple(unseen): (0, 255, 255)}
    for idx, obj in enumerate(objects):
        for group, color in color_map.items():
            if idx in group:
                cv2.rectangle(image, (obj[0], obj[1]), (obj[2], obj[3]), color)
                break

    if len(inter) > 0:
        cv2.putText(image, "LOOKING AT PHONE!", (10, 30),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 255, 255))

    cv2.imshow("preview", image)
    cv2.waitKey()
    cv2.imwrite("example.png", image)
Phát hiện đối tượng

Tiền xử lý lấy cảm hứng từ Slicing cho Recall Vật thể Nhỏ

Vấn đề

Các bộ phát hiện đối tượng (object detector) tiêu chuẩn được huấn luyện trên ảnh đã resize về một độ phân giải đầu vào cố định (ví dụ 640×640). Khi ảnh nguồn có độ phân giải cao và các đối tượng quan tâm nhỏ hoặc ở xa camera — một người đi bộ ở xa, một mã container nhỏ, một công nhân gần rìa sân ga đường sắt — bước resize đó thu nhỏ chúng xuống chỉ còn vài pixel. Phần lớn tín hiệu huấn luyện bị chi phối bởi các đối tượng lớn, dễ nhận diện, và recall trên các đối tượng nhỏ bị suy giảm.


SAHI trong một câu

SAHI (Slicing Aided Hyper Inference) giải quyết vấn đề này tại thời điểm suy luận (inference time): thay vì đưa cho bộ phát hiện một ảnh đã giảm độ phân giải, nó cắt ảnh độ phân giải đầy đủ thành các tile chồng lấp nhau, chạy phát hiện độc lập trên mỗi tile ở độ phân giải đầy đủ, sau đó gộp tất cả các phát hiện cấp-tile trở lại tọa độ ảnh gốc bằng NMS. Các đối tượng nhỏ vốn sẽ bị mất khi giảm độ phân giải giờ đây chiếm một phần lớn hơn nhiều trong mỗi tile, nên bộ phát hiện thực sự có đủ pixel để xử lý.


Điều chỉnh ý tưởng này cho dữ liệu huấn luyện thay vì suy luận

Chạy nhiều lượt cắt (slice) tại thời điểm suy luận rất tốn kém — nó nhân số lượt truyền xuôi (forward pass) trên mỗi ảnh lên nhiều lần, điều này xung đột với ngân sách triển khai thời gian thực. Vì vậy, thay vì cắt tại thời điểm suy luận, tôi đã chuyển ý tưởng tương tự lên sớm hơn trong pipeline: dùng cách cắt kiểu SAHI để xây dựng một tập huấn luyện tốt hơn, và giữ cho bản thân bước suy luận vẫn là một lượt truyền xuôi ảnh-đầy-đủ duy nhất.

Ở mức tổng quan, bước tiền xử lý:

  1. Cắt mỗi ảnh huấn luyện thành các tile chồng lấp nhau (với kích thước tile và tỉ lệ chồng lấp có thể cấu hình).
  2. Ánh xạ lại các bounding box ground-truth vào tọa độ tile, giữ lại các box trên một ngưỡng khả kiến/IoU và loại bỏ hoặc cắt xén phần còn lại.
  3. Lấy mẫu vượt mức (oversample) các tile chứa các thực thể đối tượng nhỏ, để phân bố huấn luyện không bị chi phối bởi các crop đối tượng lớn, dễ nhận diện.
  4. Trộn các crop đã cắt trở lại với ảnh gốc độ phân giải đầy đủ, để mô hình vẫn thấy được ngữ cảnh cảnh toàn cục (global scene context) và không bị overfit với các thống kê ở thang đo tile.

Kết hợp với YOLOv8-p2YOLOv9n — cả hai đều đã được mở rộng với một đầu phát hiện P2 độ phân giải cao hơn để tăng độ nhạy với đối tượng nhỏ — bước tiền xử lý này mang lại một mức tăng recall đáng kể trên các đối tượng nhỏ, ở xa, trong khi suy luận vẫn là một lượt truyền xuôi ảnh-đầy-đủ duy nhất, giữ nguyên độ trễ thời gian thực.


Phác thảo minh họa

Một phác thảo đơn giản hóa của bước cắt + ánh xạ lại (minh họa, không phải triển khai thực tế):

def slice_image(image, boxes, tile_size=640, overlap=0.2, min_visibility=0.3):
    """Slice an image into overlapping tiles, remapping ground-truth boxes."""
    stride = int(tile_size * (1 - overlap))
    tiles = []

    for y in range(0, image.height, stride):
        for x in range(0, image.width, stride):
            tile_box = (x, y, x + tile_size, y + tile_size)
            tile_img = image.crop(tile_box)

            tile_boxes = []
            for box in boxes:
                clipped = clip_box(box, tile_box)
                if visibility(clipped, box) >= min_visibility:
                    tile_boxes.append(to_tile_coords(clipped, tile_box))

            tiles.append((tile_img, tile_boxes))

    return tiles

Tài liệu tham khảo: Akyon et al., “Slicing Aided Hyper Inference and Fine-tuning for Small Object Detection” (2022).