Vision Language Models¶
Các mô hình ngôn ngữ-thị giác (vision language models) hiểu đồng thời cả ảnh và văn bản, cho phép trả lời câu hỏi trực quan, chú thích ảnh và suy luận trực quan. File này bàn về VQA, chú thích ảnh, định vị trực quan (visual grounding), và các kiến trúc như VisualBERT, BLIP, LLaVA, Flamingo, PaLI và Qwen-VL — những mô hình kết hợp bộ mã hóa thị giác với các mô hình ngôn ngữ lớn.
-
Hãy hình dung một hướng dẫn viên bảo tàng có thể nhìn vào một bức tranh và diễn giải mọi thứ về nó: có những vật thể gì, nó kể câu chuyện gì, truyền tải cảm xúc gì, và trả lời bất kỳ câu hỏi nào du khách đặt ra. Một mô hình ngôn ngữ-thị giác (vision language model, VLM) chính là phiên bản tính toán của điều đó — một hệ thống hiểu đồng thời cả ảnh lẫn văn bản, cho phép nó mô tả cảnh trực quan, trả lời câu hỏi về chúng, làm theo chỉ dẫn trực quan, và thậm chí định vị các vật thể cụ thể trong ảnh dựa trên một truy vấn bằng ngôn ngữ tự nhiên.
-
VLM nằm ở giao điểm giữa các bộ mã hóa thị giác mà bạn đã gặp ở Chương 8 và các mô hình ngôn ngữ ở Chương 7. Thách thức kỹ thuật cốt lõi là bắc cầu giữa hai thế giới biểu diễn rất khác nhau: các bản đồ đặc trưng (feature map) liên tục, mang tính không gian của một backbone thị giác, và các embedding token tuần tự, rời rạc của một mô hình ngôn ngữ. Mọi kiến trúc trong file này, về bản chất, đều là một câu trả lời khác nhau cho câu hỏi: làm thế nào để hợp nhất thị giác và ngôn ngữ?
Trả lời câu hỏi trực quan (Visual Question Answering)¶
-
Hãy tưởng tượng ai đó đưa cho bạn một tấm ảnh và hỏi "Có bao nhiêu con chó trong công viên?" Bạn phân tích ảnh một cách dễ dàng, định vị các con chó, đếm chúng và đưa ra câu trả lời. Trả lời câu hỏi trực quan (visual question answering, VQA) hình thức hóa điều này: cho một ảnh \(I\) và một câu hỏi bằng ngôn ngữ tự nhiên \(q\), hãy dự đoán câu trả lời \(a\).
-
Bài toán có thể được đóng khung theo nhiều cách. Cách phổ biến nhất coi VQA như một bài toán phân lớp mở (open-ended classification): mô hình chọn từ một tập từ vựng cố định gồm các câu trả lời thường gặp nhất (ví dụ, top 3.129 câu trả lời trong VQA v2). Ngoài ra, ta có thể coi nó như trả lời sinh (generative answering), trong đó mô hình tạo ra một chuỗi văn bản tự do — đây là cách tiếp cận của các VLM hiện đại.
-
Về mặt hình thức, ta muốn học một hàm \(f(I, q) \to a\) sao cho tối đa hóa khả năng của câu trả lời đúng. Trong thiết lập phân lớp, điều này trở thành:
-
trong đó \(v\) là vector đặc trưng thị giác (từ CNN hoặc ViT), \(h\) là biểu diễn câu hỏi (từ LSTM hoặc Transformer), và \(g\) là một hàm hợp nhất (fusion) kết hợp chúng. Thiết kế của \(g\) chính là nơi thể hiện sự sáng tạo kiến trúc thực sự.
-
VQA v1 (Antol et al., 2015) giới thiệu benchmark với 614.000 câu hỏi trên 204.000 ảnh từ MS COCO. Các nhà nghiên cứu nhanh chóng phát hiện rằng mô hình có thể đạt độ chính xác cao đến bất ngờ bằng cách khai thác định kiến ngôn ngữ (language priors) — trả lời "2" cho các câu hỏi "bao nhiêu" hoặc "yes" cho các câu hỏi "có phải có... không" mà thậm chí không cần nhìn vào ảnh.
-
VQA v2 (Goyal et al., 2017) giải quyết vấn đề này bằng cách ghép mỗi câu hỏi với hai ảnh tương tự nhưng cho ra câu trả lời khác nhau. Điều này buộc mô hình phải thực sự bám vào (ground) nội dung trực quan để suy luận. Thiết lập cặp cân bằng này gần như nhân đôi kích thước bộ dữ liệu và làm cho các lối tắt chỉ dựa trên ngôn ngữ trở nên kém hiệu quả hơn nhiều.
-
Các bộ dữ liệu VQA quan trọng khác bao gồm GQA (Hudson & Manning, 2019) với các câu hỏi mang tính tổ hợp đòi hỏi suy luận nhiều bước, OK-VQA (Marino et al., 2019) đòi hỏi kiến thức bên ngoài vượt ra khỏi ảnh, và TextVQA (Singh et al., 2019) nơi câu trả lời phụ thuộc vào việc đọc văn bản bên trong ảnh.
-
Các mô hình VQA thời kỳ đầu dùng một chiến lược đơn giản: trích xuất đặc trưng ảnh từ một CNN đã tiền huấn luyện (thường là lớp áp chót của ResNet hoặc VGGNet ở Chương 8), mã hóa câu hỏi bằng một LSTM (Chương 6), và kết hợp chúng. Hàm kết hợp \(g\) tiến hóa nhanh chóng: từ phép nhân theo phần tử đơn giản, đến bilinear pooling, rồi đến phân rã Tucker đa phương thức. Bilinear attention tính \(v^T W h\), trong đó \(W\) là ma trận tương tác học được, nhưng dạng bilinear đầy đủ có \(O(d_v \times d_h)\) tham số, quá lớn để chấp nhận được. MLB (multimodal low-rank bilinear pooling) phân tích điều này thành hai phép chiếu hạng thấp, làm cho nó trở nên khả thi.
-
Bước đột phá cho VQA chính là cơ chế chú ý (attention). Stacked Attention Networks (Yang et al., 2016) dùng biểu diễn câu hỏi để chú ý (attend) trên các vùng không gian của ảnh, tinh chỉnh lặp đi lặp lại việc nên tập trung vào những phần nào của ảnh. Ý tưởng này — để câu hỏi "nhìn vào" các vùng ảnh liên quan — đã trở thành chuẩn mực.
Chú thích ảnh (Image Captioning)¶
-
Hãy hình dung một người bạn nhìn vào những tấm ảnh du lịch của bạn và thuật lại những gì họ thấy: "Một chú chó golden retriever đang bắt đĩa bay trên bãi biển đầy nắng." Chú thích ảnh (image captioning) là tác vụ tạo ra một mô tả bằng ngôn ngữ tự nhiên cho một bức ảnh. Khác với VQA, ở đây không có câu hỏi — mô hình phải tự quyết định điều gì đáng để mô tả.
-
Show and Tell (Vinyals et al., 2015) thiết lập kiến trúc encoder-decoder kinh điển cho chú thích ảnh. Một bộ mã hóa CNN (ví dụ Inception hoặc ResNet) tạo ra một vector đặc trưng ảnh duy nhất \(v\). Vector này được dùng làm trạng thái ẩn ban đầu của một bộ giải mã LSTM, sau đó bộ giải mã sinh ra chú thích từng từ một, theo kiểu tự hồi quy (autoregressive):
-
Toàn bộ mô hình được huấn luyện đầu-cuối (end-to-end) bằng cách tối đa hóa log-likelihood của các chú thích chuẩn (ground-truth). Ở thời điểm suy luận, beam search (Chương 7) được dùng để tìm các chú thích có xác suất cao.
-
Vấn đề của Show and Tell là toàn bộ ảnh bị nén vào một vector duy nhất. Với các cảnh phức tạp, một vector đơn lẻ không thể nắm bắt hết mọi chi tiết liên quan. Bạn mất thông tin không gian — mô hình không thể "nhìn lại" các phần cụ thể của ảnh khi sinh ra các từ khác nhau.
-
Show, Attend and Tell (Xu et al., 2015) giải quyết điều này bằng cách giới thiệu cơ chế chú ý trên các vùng ảnh (attention over image regions). Thay vì mã hóa ảnh thành một vector, CNN tạo ra một lưới đặc trưng không gian (ví dụ \(14 \times 14 \times 512\) từ lớp tích chập cuối của VGGNet). Tại mỗi bước giải mã, mô hình tính các trọng số chú ý trên các vị trí không gian này, tạo ra một vector ngữ cảnh làm nổi bật vùng liên quan nhất cho từ hiện tại.
-
Nhớ lại cơ chế chú ý ở Chương 6: trạng thái ẩn của bộ giải mã đóng vai trò truy vấn (query), các đặc trưng không gian đóng vai trò khóa (key) và giá trị (value), và các trọng số chú ý cho mô hình biết nên nhìn vào đâu. Các tác giả đề xuất hai biến thể: soft attention (khả vi, trung bình có trọng số của tất cả các vùng) và hard attention (lấy mẫu ngẫu nhiên một vùng duy nhất, huấn luyện bằng REINFORCE).
-
Các bản đồ chú ý (attention map) mà những mô hình này tạo ra dễ diễn giải một cách đáng kể: khi sinh ra từ "chó", đỉnh chú ý nằm trên vùng con chó; khi sinh ra từ "bãi biển", nó chuyển sang cát và nước. Đây là một trong những minh chứng thuyết phục đầu tiên rằng cơ chế chú ý mang lại khả năng diễn giải sẵn có.
-
CIDEr (Vedantam et al., 2015), METEOR, BLEU và SPICE là các độ đo đánh giá chú thích chuẩn. CIDEr tính độ tương đồng n-gram có trọng số TF-IDF giữa các chú thích được sinh ra và các chú thích tham chiếu, được thiết kế riêng cho việc đánh giá chú thích. Các VLM hiện đại thường được đánh giá bằng CIDEr trên các benchmark chú thích như MS COCO Captions và NoCaps.
-
Các mô hình chú thích về sau tích hợp bottom-up attention (Anderson et al., 2018), trong đó một bộ phát hiện đối tượng (Faster R-CNN, Chương 8) trước tiên đề xuất các vùng ảnh nổi bật, và mô hình chú thích chú ý trên các đặc trưng vùng này thay vì một lưới đồng đều. Đây là cách tiếp cận thống trị trước khi các bộ mã hóa dựa trên ViT lên ngôi.
Các mẫu kiến trúc (Architecture Patterns)¶
- Mọi VLM đều phải trả lời một câu hỏi thiết kế nền tảng: tại thời điểm nào thị giác và ngôn ngữ tương tác với nhau? Câu trả lời định nghĩa họ kiến trúc của mô hình. Có ba mẫu chính, mỗi mẫu có những đánh đổi riêng biệt.
Dual Encoder¶
-
Hãy tưởng tượng hai phiên dịch viên làm việc độc lập — một người đọc tài liệu tiếng Pháp, người kia đọc tài liệu tiếng Anh — và mỗi người tạo ra một bản tóm tắt bằng một "ngôn ngữ phổ quát" chung. Họ không bao giờ trao đổi trong lúc dịch, nhưng các bản tóm tắt của họ có thể so sánh trực tiếp với nhau. Đây chính là mẫu dual encoder.
-
Một bộ mã hóa thị giác \(f_v\) và một bộ mã hóa văn bản \(f_t\) độc lập ánh xạ đầu vào tương ứng của chúng vào một không gian embedding chung có số chiều \(d\). Embedding ảnh là \(v = f_v(I) \in \mathbb{R}^d\) và embedding văn bản là \(t = f_t(q) \in \mathbb{R}^d\). Độ tương đồng được tính qua tích vô hướng hoặc cosine similarity: \(\text{sim}(I, q) = v^T t / (\|v\| \|t\|)\).
-
CLIP (Radford et al., 2021), đã được đề cập ở file trước về biểu diễn đa phương thức, là dual encoder điển hình. Nó được huấn luyện với một mục tiêu tương phản (InfoNCE) trên 400 triệu cặp ảnh-văn bản thu thập từ internet. Vì các bộ mã hóa độc lập, bạn có thể tính trước và lưu cache toàn bộ embedding ảnh, khiến việc truy hồi (retrieval) cực kỳ hiệu quả — bạn chỉ cần mã hóa văn bản truy vấn tại thời điểm tìm kiếm.
-
Điểm yếu của dual encoder là thị giác và ngôn ngữ không bao giờ tương tác ở mức đặc trưng. Mô hình không thể thực hiện suy luận đa phương thức tinh vi: chẳng hạn, nó không thể xác định liệu một từ cụ thể trong chú thích có tương ứng với một vùng cụ thể trong ảnh hay không. Điều này hạn chế tính hữu dụng của nó cho các tác vụ như VQA hay chú thích có định vị (grounded captioning).
Fusion Encoder¶
-
Giờ hãy tưởng tượng hai phiên dịch viên ở cùng một phòng, tích cực thảo luận về cả hai tài liệu. Họ có thể chỉ vào các đoạn cụ thể, đặt câu hỏi cho nhau, và xây dựng một sự hiểu biết chung. Đây chính là mẫu fusion encoder.
-
Cả hai phương thức đều được mã hóa rồi hợp nhất thông qua các lớp cross-attention nơi các token từ một phương thức chú ý đến các token của phương thức kia. Ảnh trước tiên được bộ mã hóa thị giác xử lý thành một chuỗi các token patch hoặc vùng \(V = [v_1, \ldots, v_N]\). Văn bản được token hóa thành \(T = [t_1, \ldots, t_M]\). Trong các lớp hợp nhất, các token văn bản chú ý đến các token ảnh qua cross-attention:
- Điều này cho phép tương tác tinh vi: mỗi token văn bản có thể chú ý đến các vùng ảnh cụ thể mà nó cần. Các mô hình như VisualBERT, VilBERT và UNITER dùng mẫu này. Cái giá phải trả là bạn không thể tính trước các embedding riêng biệt để truy hồi — mỗi cặp ảnh-văn bản đều đòi hỏi một lượt lan truyền tiến (forward pass) đầy đủ qua các lớp hợp nhất.
Encoder-Decoder¶
-
Mẫu encoder-decoder kết hợp bộ mã hóa thị giác với một bộ giải mã văn bản sinh ra các token đầu ra theo kiểu tự hồi quy, tương tự các mô hình seq2seq ở Chương 7. Bộ mã hóa thị giác tạo ra các biểu diễn ảnh có ngữ cảnh, và bộ giải mã văn bản cross-attend đến chúng trong lúc sinh văn bản đầu ra.
-
Mẫu này tự nhiên hỗ trợ các tác vụ sinh (generative): chú thích, VQA với câu trả lời tự do, và đối thoại trực quan. Các mô hình như GIT (Generative Image-to-text Transformer, Wang et al., 2022), CoCa (Contrastive Captioner, Yu et al., 2022) và PaLI dùng kiến trúc này. CoCa khéo léo kết hợp mẫu dual encoder và encoder-decoder: nửa đầu các lớp của bộ giải mã văn bản hoạt động như một bộ mã hóa văn bản đơn phương thức (cho học tương phản), trong khi nửa sau cross-attend đến các đặc trưng ảnh (cho chú thích sinh), tận dụng được ưu điểm của cả hai thế giới.
-
Việc lựa chọn giữa ba mẫu này phụ thuộc vào tác vụ mục tiêu. Dual encoder tối ưu cho truy hồi ở quy mô lớn. Fusion encoder tốt nhất cho các tác vụ hiểu tinh vi. Encoder-decoder linh hoạt nhất cho các tác vụ sinh. Các VLM tiên tiến hiện đại ngày càng áp dụng nhiều paradigm encoder-decoder hoặc decoder-only, coi mọi tác vụ ngôn ngữ-thị giác như một bài toán sinh văn bản.
Flamingo: Học đa phương thức few-shot¶
-
Hãy hình dung một chuyên gia dày dạn, sau nhiều năm nghiên cứu cả nghệ thuật lẫn văn học, có thể nhìn vào một phong cách hội họa hoàn toàn mới và mô tả nó một cách hùng hồn chỉ sau khi xem một hai ví dụ. Flamingo (Alonso et al., 2022, DeepMind) được xây dựng trên cùng nguyên lý đó: nó tận dụng một mô hình ngôn ngữ đã tiền huấn luyện mạnh mẽ và một bộ mã hóa thị giác đã tiền huấn luyện, kết nối chúng bằng các thành phần kiến trúc nhẹ giúp cho phép học few-shot trên các tác vụ đa phương thức.
-
Triết lý thiết kế của Flamingo mang tính thận trọng và hiệu quả: giữ đông cứng (frozen) bộ mã hóa thị giác đã tiền huấn luyện (NFNet) và mô hình ngôn ngữ (Chinchilla), chỉ học phần "keo dán" kết nối chúng. Phần keo này gồm hai thành phần: một Perceiver Resampler và các lớp gated cross-attention.
-
Perceiver Resampler nhận đầu ra có độ dài thay đổi của bộ mã hóa thị giác (tùy thuộc vào độ phân giải ảnh) và nén nó thành một tập cố định gồm \(N\) token thị giác (thường \(N = 64\)). Nó hoạt động bằng cách khởi tạo một tập gồm \(N\) vector truy vấn học được và dùng cross-attention để các truy vấn này chú ý đến toàn bộ tập đầu ra của bộ mã hóa thị giác. Về bản chất, đây là kiến trúc Perceiver (Jaegle et al., 2021) áp dụng như một nút thắt cổ chai (bottleneck) — nó tạo ra một biểu diễn thị giác gọn gàng, kích thước cố định bất kể kích thước ảnh đầu vào.
- Các lớp gated cross-attention được xen kẽ giữa các lớp của mô hình ngôn ngữ đông cứng. Tại mỗi lớp như vậy, các token văn bản của mô hình ngôn ngữ cross-attend đến các token thị giác do Perceiver Resampler tạo ra. Điều mấu chốt là mỗi lớp gated cross-attention có một cổng vô hướng học được \(\alpha\), được khởi tạo bằng không, nhân với đầu ra cross-attention trước khi cộng vào dòng residual:
- Việc khởi tạo \(\alpha = 0\) nghĩa là ở đầu quá trình huấn luyện, cross-attention không đóng góp gì, và mô hình hành xử y hệt như mô hình ngôn ngữ đông cứng ban đầu. Các cổng dần mở ra trong quá trình huấn luyện, tích hợp thông tin thị giác một cách mượt mà mà không phá vỡ các biểu diễn đã tiền huấn luyện của mô hình ngôn ngữ.
-
Flamingo xử lý một cách tự nhiên các chuỗi ảnh-văn bản xen kẽ (interleaved image-text sequences). Bạn có thể đưa cho nó một prompt chứa nhiều ảnh xen với văn bản, chẳng hạn: "[Ảnh 1] Đây là một con mèo. [Ảnh 2] Đây là một con chó. [Ảnh 3] Đây là một ___." Mô hình xử lý mỗi ảnh qua bộ mã hóa thị giác và Perceiver Resampler, và các token thị giác thu được được chèn vào các vị trí tương ứng trong chuỗi văn bản. Mặt nạ chú ý nhân quả (causal attention mask) của mô hình ngôn ngữ đảm bảo mỗi token văn bản chỉ có thể chú ý đến các token thị giác từ ảnh hiện tại và các ảnh trước đó.
-
Việc xen kẽ này cho phép học đa phương thức few-shot mạnh mẽ. Bằng cách cung cấp một vài ví dụ ảnh-văn bản trong ngữ cảnh, Flamingo có thể thực hiện các tác vụ mới mà không cần bất kỳ cập nhật gradient nào. Trên các benchmark như VQAv2, OK-VQA và chú thích, Flamingo với 80 tỷ tham số đạt hiệu năng few-shot tiên tiến nhất, thường sánh ngang hoặc vượt các mô hình chuyên biệt đã tinh chỉnh chỉ với 4 hoặc 32 ví dụ.
LLaVA và tinh chỉnh theo chỉ dẫn trực quan (Visual Instruction Tuning)¶
-
Hãy tưởng tượng bạn có một chuyên gia ngôn ngữ tài ba (một LLM) và một nhà phê bình nghệ thuật tài ba (một bộ mã hóa thị giác). Nếu bạn có thể dạy nhà phê bình nghệ thuật "nói ngôn ngữ của chuyên gia ngôn ngữ", họ có thể cộng tác một cách liền mạch. LLaVA (Large Language and Vision Assistant, Liu et al., 2023) làm chính điều đó: nó chiếu các đặc trưng thị giác vào không gian embedding token của LLM bằng một lớp tuyến tính đơn giản, sau đó tinh chỉnh toàn hệ thống trên dữ liệu làm theo chỉ dẫn.
-
Kiến trúc của LLaVA đơn giản đến kinh ngạc. Một ảnh được bộ mã hóa thị giác CLIP ViT-L/14 đã tiền huấn luyện mã hóa thành một lưới đặc trưng patch \(V \in \mathbb{R}^{N \times d_v}\), với \(N = 256\) patch (cho ảnh 336px với patch 14px). Một lớp chiếu (projection layer) \(W\) ánh xạ các đặc trưng thị giác này vào số chiều embedding của LLM:
- Các token thị giác đã chiếu \(H_v\) đơn giản được nối (concatenate) với các embedding token văn bản và đưa vào LLM (Vicuna, một LLaMA đã tinh chỉnh) dưới dạng một chuỗi duy nhất. LLM xử lý chúng bằng cơ chế self-attention nhân quả tiêu chuẩn của nó — không có lớp cross-attention đặc biệt, không có perceiver, chỉ là phép nối. Các token thị giác được xử lý như thể chúng là các token văn bản tình cờ mã hóa thông tin thị giác.
-
Tinh chỉnh theo chỉ dẫn trực quan (visual instruction tuning) là đổi mới huấn luyện then chốt của LLaVA. Các tác giả dùng GPT-4 để sinh 158.000 ví dụ làm theo chỉ dẫn đa phương thức từ các ảnh COCO. Mỗi ví dụ gồm một ảnh ghép với một chỉ dẫn dạng đối thoại (ví dụ "Hãy mô tả chi tiết ảnh này", "Điều gì bất thường ở ảnh này?", "Nếu tôi là một du khách đến thăm nơi này, tôi nên biết những gì?"). Mô hình được huấn luyện để sinh ra câu trả lời do GPT-4 soạn khi cho ảnh và chỉ dẫn.
-
Việc huấn luyện diễn ra theo hai giai đoạn. Giai đoạn 1 (tiền huấn luyện): chỉ lớp chiếu \(W\) được huấn luyện trên các cặp ảnh-chú thích (595K từ CC3M), trong khi cả bộ mã hóa thị giác lẫn LLM đều đông cứng. Điều này dạy \(W\) căn chỉnh các đặc trưng thị giác với không gian embedding của LLM. Giai đoạn 2 (tinh chỉnh): lớp chiếu và LLM được tinh chỉnh đồng thời trên dữ liệu làm theo chỉ dẫn, trong khi bộ mã hóa thị giác vẫn đông cứng. Điều này dạy mô hình làm theo các chỉ dẫn trực quan phức tạp.
-
LLaVA-1.5 cải tiến bản gốc với ba thay đổi then chốt: thay phép chiếu tuyến tính đơn lẻ bằng một MLP hai lớp (ánh xạ biểu đạt hơn), dùng ảnh độ phân giải cao hơn (336px thay vì 224px, tạo ra nhiều token patch hơn), và bổ sung các bộ dữ liệu VQA học thuật vào hỗn hợp huấn luyện. Những thay đổi tưởng chừng nhỏ này tạo ra một bước nhảy lớn về hiệu năng benchmark.
-
Cách tiếp cận của LLaVA cho thấy bạn không cần các đổi mới kiến trúc phức tạp như Perceiver Resampler hay gated cross-attention của Flamingo. Một phép chiếu tuyến tính đơn giản, kết hợp với dữ liệu tinh chỉnh theo chỉ dẫn chất lượng cao, là đủ để kết nối một bộ mã hóa thị giác với một LLM một cách hiệu quả. Sự đơn giản này khiến LLaVA cực kỳ có ảnh hưởng — hầu hết các VLM mã nguồn mở về sau đều theo một công thức tương tự.
Mở rộng quy mô các mô hình ngôn ngữ-thị giác¶
- Lĩnh vực này chuyển động nhanh chóng từ các VLM chứng minh khái niệm đến các hệ thống quy mô công nghiệp được huấn luyện trên hàng tỷ cặp ảnh-văn bản. Ba họ mô hình minh họa các cách tiếp cận khác nhau đối với việc mở rộng quy mô.
PaLI¶
-
PaLI (Pathways Language and Image model, Chen et al., 2022, Google) mở rộng đồng thời cả bộ mã hóa thị giác lẫn mô hình ngôn ngữ. PaLI dùng một ViT-e (4B tham số) làm bộ mã hóa thị giác và mT5 (13B tham số) làm mô hình ngôn ngữ, tổng cộng 17B tham số. Ảnh được mã hóa thành một chuỗi token patch, được đặt trước các token văn bản và đưa vào mT5 dạng encoder-decoder.
-
Nhận định then chốt của PaLI là việc mở rộng bộ mã hóa thị giác cũng quan trọng như mở rộng mô hình ngôn ngữ. Các công trình trước đó thường dùng một backbone thị giác kích thước cố định, vừa phải (ví dụ ViT-B hoặc ViT-L) và dồn toàn bộ ngân sách tham số vào LLM. PaLI cho thấy một ViT-e 4B tham số, được tiền huấn luyện trên JFT-4B (4 tỷ ảnh đã gán nhãn), cải thiện đáng kể hiệu năng trên các tác vụ thị giác tinh vi như OCR và suy luận không gian.
-
PaLI được huấn luyện trên WebLI, một bộ dữ liệu gồm 10 tỷ cặp ảnh-văn bản trong 109 ngôn ngữ, khiến nó vốn dĩ đa ngôn ngữ. Mô hình được tiền huấn luyện với một hỗn hợp các tác vụ: chú thích ảnh, VQA, và ghép cặp ảnh-văn bản, tất cả đều được đóng khung như bài toán sinh văn-bản-thành-văn-bản (theo paradigm T5 ở Chương 7). PaLI-X (55B tham số) và PaLI-3 (5B, dùng SigLIP làm bộ mã hóa thị giác) là các phiên bản kế tiếp.
Qwen-VL¶
-
Qwen-VL (Bai et al., 2023, Alibaba) xây dựng trên LLM Qwen bằng cách thêm một bộ mã hóa thị giác ViT và một module cross-attention một lớp (tương tự Perceiver Resampler của Flamingo) nén đầu ra của bộ mã hóa thị giác thành một tập cố định gồm 256 token thị giác. Các token thị giác được nối với các token văn bản và xử lý bởi LLM Qwen.
-
Việc huấn luyện Qwen-VL dùng công thức ba giai đoạn. Giai đoạn 1: tiền huấn luyện trên 1,4 tỷ cặp ảnh-văn bản giám sát yếu (weakly-supervised) chỉ với bộ mã hóa thị giác được mở đông cứng. Giai đoạn 2: tiền huấn luyện đa tác vụ trên dữ liệu chất lượng cao hơn bao gồm VQA, chú thích, định vị (grounding) và OCR, với toàn bộ mô hình được mở đông cứng. Giai đoạn 3: tinh chỉnh có giám sát trên dữ liệu làm theo chỉ dẫn và đối thoại. Việc tinh lọc lũy tiến này, từ dữ liệu web nhiễu đến dữ liệu chỉ dẫn được tuyển chọn, là một mẫu hình chung của hầu hết các VLM hiện đại.
-
Qwen2-VL (2024) giới thiệu hỗ trợ độ phân giải động (dynamic resolution): thay vì thay đổi kích thước tất cả ảnh về một kích thước cố định, nó xử lý ảnh ở độ phân giải gốc bằng cách điều chỉnh động số lượng token thị giác. Ảnh độ phân giải cao hơn tạo ra nhiều token hơn, và ảnh độ phân giải thấp hơn tạo ra ít token hơn. Điều này cải thiện hiệu năng trên các tác vụ nhạy với chi tiết như hiểu tài liệu và nhận diện tinh vi mà không lãng phí tính toán cho các đầu vào độ phân giải thấp.
InternVL¶
-
InternVL (Chen et al., 2024, Shanghai AI Lab) mở rộng bộ mã hóa thị giác một cách quyết liệt, dùng InternViT-6B — một vision transformer 6 tỷ tham số — ghép với một mô hình ngôn ngữ. Đóng góp kiến trúc then chốt là xử lý độ phân giải cao động (dynamic high-resolution processing): ảnh được chia thành các ô (tile) 448x448 pixel, mỗi ô được bộ mã hóa thị giác xử lý độc lập, và các đặc trưng ô thu được được nối với một đặc trưng thumbnail của toàn ảnh. Điều này cho phép mô hình xử lý ảnh với tỷ lệ khung hình và độ phân giải bất kỳ.
-
InternVL-2 còn giới thiệu huấn luyện căn chỉnh lũy tiến (progressive alignment training): đầu tiên căn chỉnh bộ mã hóa thị giác với một mục tiêu tương phản (như CLIP), sau đó kết nối nó với LLM qua một bộ nối MLP nhẹ, và cuối cùng tinh chỉnh đầu-cuối trên dữ liệu chỉ dẫn. Chiến lược lũy tiến này ngăn việc quên thảm khốc (catastrophic forgetting) các biểu diễn đã tiền huấn luyện của bộ mã hóa thị giác.
- Một chủ đề chung xuyên suốt cả ba họ là tầm quan trọng của việc tuyển chọn dữ liệu huấn luyện (training data curation). Các cặp ảnh-văn bản thu thập thô từ web thường nhiễu và lệch nhau. Các giai đoạn huấn luyện kế tiếp lọc và tinh lọc dữ liệu một cách lũy tiến, đi từ hàng tỷ cặp nhiễu đến hàng triệu ví dụ chỉ dẫn chất lượng cao. Chất lượng của dữ liệu tinh chỉnh cuối cùng thường quan trọng hơn số lượng tham số thô của mô hình.
Định vị và tham chiếu (Grounding and Referring)¶
-
Hãy tưởng tượng bạn chỉ vào một người trong đám đông và nói "người phụ nữ đội mũ đỏ". Bạn đang dùng ngôn ngữ để tham chiếu đến một vùng không gian cụ thể. Định vị trực quan (visual grounding) là chiều ngược lại: cho một ảnh và một biểu thức bằng ngôn ngữ tự nhiên, mô hình phải xác định (định vị) vật thể được tham chiếu. Hiểu biểu thức tham chiếu (referring expression comprehension) tạo ra một hộp bao (bounding box); phân đoạn biểu thức tham chiếu (referring expression segmentation) tạo ra một mặt nạ pixel.
-
Về mặt hình thức, cho một ảnh \(I\) và một biểu thức tham chiếu \(r\) (ví dụ "con chó nâu to bên trái"), mô hình dự đoán một hộp bao \(b = (x, y, w, h)\) hoặc một tập tọa độ định vị đối tượng được tham chiếu. Các bộ dữ liệu bao gồm RefCOCO, RefCOCO+ và RefCOCOg, mỗi bộ chứa các ảnh có nhiều vật thể và các biểu thức tham chiếu không mơ hồ cho từng vật thể.
-
Các mô hình định vị thời kỳ đầu dùng cách tiếp cận hai giai đoạn: đầu tiên sinh các đề xuất vùng (từ Faster R-CNN hoặc tương tự), sau đó chấm điểm mỗi đề xuất so với truy vấn ngôn ngữ bằng một mô hình hợp nhất. Vùng có điểm cao nhất là dự đoán. Cách này tốn kém tính toán và bị giới hạn bởi chất lượng của các đề xuất.
-
Các VLM hiện đại tích hợp định vị trực tiếp vào khuôn khổ sinh. Ý tưởng then chốt là biểu diễn tọa độ hộp bao dưới dạng token văn bản. Bạn rời rạc hóa không gian tọa độ liên tục thành các bin (ví dụ 1000 bin cho mỗi giá trị \(x, y, w, h\)) và thêm các token vị trí đặc biệt như
<loc_342>vào từ vựng. Sau đó mô hình sinh ra một hộp bao bằng cách xuất ra một chuỗi các token vị trí:
-
Thủ thuật token hóa này cho phép bất kỳ mô hình ngôn ngữ tự hồi quy nào cũng thực hiện được định vị mà không cần thay đổi kiến trúc — nó chỉ đơn giản học cách "nói tọa độ". Pix2Seq (Chen et al., 2022) tiên phong cách tiếp cận này cho phát hiện đối tượng, và các mô hình như Qwen-VL, Ferret và Kosmos-2 mở rộng nó sang hiểu biểu thức tham chiếu và định vị cụm từ (phrase grounding).
-
Kosmos-2 (Peng et al., 2023, Microsoft) thêm khả năng định vị vào một LLM đa phương thức bằng cách biểu diễn các vị trí không gian dưới dạng token đặc biệt nhúng bên trong văn bản được sinh ra. Ví dụ, nó có thể sinh: "Một
<phrase>chú chó golden retriever</phrase><box><loc_102><loc_215><loc_487><loc_398></box>đang bắt một chiếc đĩa bay." Việc xen kẽ văn bản và token không gian này cho phép chú thích và định vị đồng thời.
- Chỉ điểm (Pointing) đẩy việc định vị đi xa hơn: thay vì hộp bao, mô hình dự đoán một điểm duy nhất (thường là tâm của vật thể được tham chiếu). Điều này hữu ích cho các ứng dụng tương tác nơi người dùng hỏi "Lối ra gần nhất ở đâu?" và mô hình đáp bằng một tọa độ phủ lên ảnh. Các mô hình như Shikra và Ferret hỗ trợ tham chiếu dựa trên điểm bên cạnh định vị dựa trên hộp.
Hiểu tài liệu không cần OCR (OCR-Free Document Understanding)¶
-
Các pipeline hiểu tài liệu truyền thống rất phức tạp: đầu tiên chạy một bộ máy OCR để trích xuất văn bản và bố cục, sau đó đưa văn bản đã trích xuất vào một mô hình ngôn ngữ. Cách tiếp cận nhiều giai đoạn này mong manh — lỗi OCR lan truyền xuống hạ nguồn, và thông tin bố cục không gian thường bị mất hoặc biểu diễn kém. Sẽ ra sao nếu mô hình có thể đọc trực tiếp từ pixel, giống như cách bạn làm?
-
Donut (Document Understanding Transformer, Kim et al., 2022) loại bỏ hoàn toàn OCR. Nó dùng một Swin Transformer (Chương 8) làm bộ mã hóa thị giác để xử lý ảnh tài liệu, và một bộ giải mã Transformer kiểu BART để sinh trực tiếp văn bản có cấu trúc từ các đặc trưng thị giác. Bộ giải mã có thể tạo ra JSON, các cặp khóa-giá trị, hoặc văn bản thuần, tùy thuộc vào tác vụ.
-
Việc huấn luyện Donut có hai giai đoạn. Tiền huấn luyện: mô hình học đọc bằng cách thực hiện OCR tổng hợp — cho một ảnh tài liệu, nó sinh ra toàn bộ nội dung văn bản. Điều này được huấn luyện trên hàng triệu ảnh tài liệu tổng hợp được kết xuất từ các kho văn bản, dạy bộ mã hóa thị giác nhận diện ký tự, phông chữ và bố cục. Tinh chỉnh: mô hình được thích ứng với các tác vụ hạ nguồn cụ thể như phân tích hóa đơn, hiểu biểu mẫu, hoặc phân lớp tài liệu, bằng cách huấn luyện nó sinh ra đầu ra có cấu trúc đặc thù cho tác vụ.
-
Bộ giải mã Donut dùng một sơ đồ prompt đặc biệt: tác vụ được chỉ định bằng một token prompt (ví dụ
<doc_class>cho phân lớp hoặc<parse_receipt>cho phân tích hóa đơn), và mô hình sinh đầu ra có điều kiện theo prompt này. Giao diện thống nhất này cho phép một mô hình duy nhất xử lý nhiều tác vụ hiểu tài liệu. -
Pix2Struct (Lee et al., 2023, Google) lấy ý tưởng không-OCR và áp dụng nó vào việc hiểu trang web và hiểu biểu đồ/hình vẽ. Mục tiêu tiền huấn luyện then chốt là phân tích ảnh chụp màn hình (screenshot parsing): cho một ảnh chụp màn hình đã che (masked) của một trang web, mô hình sinh ra mã HTML nền tảng đã tạo ra vùng hiển thị. Điều này dạy mô hình hiểu mối quan hệ giữa cách kết xuất trực quan và markup có cấu trúc.
-
Pix2Struct giới thiệu xử lý đầu vào độ phân giải thay đổi (variable-resolution input processing): thay vì thay đổi kích thước tất cả ảnh về một kích thước cố định (làm méo tỷ lệ khung hình và phá hủy văn bản mảnh), nó đóng gói ảnh thành một số patch cố định trong khi vẫn giữ nguyên tỷ lệ khung hình gốc. Một tài liệu cao và hẹp tạo ra một lưới patch cao và hẹp. Điều này quan trọng cho việc hiểu tài liệu, nơi tỷ lệ khung hình mang thông tin ngữ nghĩa (hóa đơn thì hẹp và cao; bảng tính thì rộng và ngắn).
-
Nougat (Blecher et al., 2023, Meta) áp dụng kiến trúc Donut riêng cho các bài báo học thuật, sinh trực tiếp markup LaTeX đầy đủ từ ảnh trang PDF. Nó có thể xử lý các phương trình toán học phức tạp, bảng và hình — những tác vụ mà các pipeline OCR truyền thống xoay xở rất tệ. Mô hình được huấn luyện trên các cặp ảnh trang PDF và mã nguồn LaTeX tương ứng.
-
Thành công của các mô hình không-OCR minh chứng một nguyên lý rộng hơn trong học sâu: các mô hình đầu-cuối học trực tiếp từ đầu vào thô (pixel) thường vượt trội hơn các pipeline nhiều giai đoạn phức tạp, bởi chúng có thể tối ưu đồng thời tất cả các thành phần và học các biểu diễn được thiết kế riêng cho tác vụ cuối. Bước OCR trung gian là một nút thắt cổ chai hạn chế những gì mô hình có thể học.
Pipeline token thị giác (Visual Token Pipeline)¶
-
Bất kể thuộc họ kiến trúc nào, mọi VLM đều phải chuyển đổi ảnh thành một chuỗi token mà mô hình ngôn ngữ có thể xử lý. Hiểu được pipeline này là điều cốt yếu. Quy trình thay đổi tùy theo mô hình, nhưng luồng chung là:
-
Bước 1: Trích xuất patch. Ảnh (chiều cao \(H\), chiều rộng \(W\)) được chia thành các patch không chồng lấn kích thước \(P \times P\), tạo ra \(N = HW / P^2\) patch. Với ảnh 336x336 và patch 14x14, \(N = 576\).
-
Bước 2: Mã hóa thị giác. Mỗi patch được chiếu tuyến tính và đi qua bộ mã hóa thị giác (thường là ViT). Đầu ra là một chuỗi các patch embedding có ngữ cảnh \(V = [v_1, \ldots, v_N] \in \mathbb{R}^{N \times d_v}\). Các embedding này mang cả thông tin về diện mạo địa phương lẫn ngữ cảnh toàn cục (từ self-attention).
-
Bước 3: Nén token (tùy chọn). Một số mô hình nén \(N\) token thị giác thành một tập nhỏ hơn gồm \(M \ll N\) token để giảm gánh nặng tính toán lên mô hình ngôn ngữ. Flamingo dùng Perceiver Resampler (\(M = 64\)); Qwen-VL dùng cross-attention (\(M = 256\)); Q-Former (dùng trong BLIP-2, Li et al., 2023) dùng một tập \(M = 32\) token truy vấn học được cross-attend đến đầu ra của bộ mã hóa thị giác.
-
Bước 4: Chiếu (Projection). Các token thị giác (hoặc toàn bộ hoặc đã nén) được chiếu vào không gian embedding của mô hình ngôn ngữ qua một lớp tuyến tính hoặc MLP. Sau khi chiếu, các token thị giác có cùng số chiều với embedding token văn bản và có thể được nối với chúng.
-
Bước 5: Tiêm vào LLM. Các token thị giác đã chiếu được chèn vào chuỗi token tại vị trí của token placeholder
<image>đặc biệt, và chuỗi kết hợp được xử lý bởi mô hình ngôn ngữ. Self-attention của LLM cho phép các token văn bản chú ý đến token thị giác và ngược lại.
-
Số lượng token thị giác ảnh hưởng trực tiếp đến chi phí tính toán. Mỗi token thị giác tham gia vào self-attention của LLM, vốn có chi phí bậc hai theo độ dài chuỗi. Một ảnh độ phân giải cao với nhiều patch có thể tạo ra hàng trăm hoặc hàng nghìn token thị giác, chiếm ưu thế trong cửa sổ ngữ cảnh của LLM. Đây là lý do nén token trở nên quan trọng: giảm 576 token thị giác xuống 64 giúp cắt giảm khoảng 9 lần đóng góp thị giác vào cơ chế chú ý.
-
BLIP-2 (Li et al., 2023) nổi bật với chiến lược bắc cầu hiệu quả. Nó giới thiệu một Q-Former nhẹ (một Transformer nhỏ với các truy vấn học được) nằm giữa bộ mã hóa thị giác đông cứng và LLM đông cứng. Q-Former là thành phần duy nhất được huấn luyện — cả bộ mã hóa thị giác và LLM đều giữ nguyên. Nó được tiền huấn luyện qua hai giai đoạn: đầu tiên với học tương phản ảnh-văn bản, ghép cặp và chú thích (kết nối với bộ mã hóa thị giác), sau đó với các mục tiêu sinh ngôn ngữ (kết nối với LLM). Thiết kế mô-đun này cho phép BLIP-2 cắm bất kỳ bộ mã hóa thị giác nào vào bất kỳ LLM nào.
Các mục tiêu huấn luyện (Training Objectives)¶
-
VLM được huấn luyện với sự kết hợp các mục tiêu, tùy theo mẫu kiến trúc:
-
Mất mát tương phản ảnh-văn bản (Image-text contrastive loss, ITC): căn chỉnh biểu diễn ảnh và văn bản trong một không gian embedding chung, như trong CLIP. Đây là mục tiêu chính cho dual encoder và thường được dùng làm mục tiêu tiền huấn luyện cho các mô hình hợp nhất. Mất mát này chính là InfoNCE loss từ file trước.
-
Ghép cặp ảnh-văn bản (Image-text matching, ITM): một mục tiêu phân lớp nhị phân — cho một ảnh và một văn bản, dự đoán xem chúng có khớp không. Các mẫu âm tính khó (hard negatives) — văn bản tương tự nhưng ghép với ảnh khác — khiến tác vụ này trở nên khó khăn và buộc mô hình học sự căn chỉnh tinh vi.
-
Mô hình hóa ngôn ngữ (Language modelling, LM): mục tiêu mô hình hóa ngôn ngữ tự hồi quy chuẩn — dự đoán token tiếp theo từ các token trước đó. Đối với VLM, "các token trước đó" bao gồm cả token thị giác, do đó mô hình học cách sinh văn bản có điều kiện dựa trên đầu vào thị giác. Đây là mục tiêu chính cho các VLM dạng encoder-decoder và decoder-only.
-
Mô hình hóa ngôn ngữ dạng tiền tố (Prefix language modelling): một biến thể trong đó ảnh và tiền tố văn bản được cung cấp dưới dạng ngữ cảnh (không được huấn luyện), và mô hình được huấn luyện chỉ để sinh phần tiếp theo. Được dùng trong các mô hình như PaLI và SimVLM.
-
Hầu hết các VLM hiện đại kết hợp nhiều mục tiêu trong quá trình tiền huấn luyện (ví dụ ITC + ITM + LM trong BLIP, ITC + LM trong CoCa) và sau đó tinh chỉnh chỉ với mục tiêu LM thuần túy trên dữ liệu chỉ dẫn.
Bài tập lập trình (dùng CoLab hoặc notebook)¶
-
Cài đặt một bộ giải mã chú thích ảnh dựa trên attention đơn giản. Dùng "đặc trưng ảnh" ngẫu nhiên làm đầu ra của bộ mã hóa và huấn luyện bộ giải mã để sinh một chú thích cố định, quan sát cách trọng số attention thay đổi qua các vị trí không gian tại mỗi bước giải mã.
import jax import jax.numpy as jnp import matplotlib.pyplot as plt # Simulate a 4x4 spatial grid of image features (16 regions, dim=32) key = jax.random.PRNGKey(42) k1, k2, k3 = jax.random.split(key, 3) img_features = jax.random.normal(k1, (16, 32)) # 16 spatial regions, 32-dim # Vocabulary: 0=<start>, 1="a", 2="red", 3="car", 4=<end> vocab_size, embed_dim, hidden_dim = 5, 16, 32 W_embed = jax.random.normal(k2, (vocab_size, embed_dim)) * 0.1 W_attn_q = jax.random.normal(k3, (hidden_dim, 32)) * 0.1 # query projection def attend(h, img_feats, W_q): """Compute soft attention over image features given decoder state h.""" query = h @ W_q # (32,) scores = img_feats @ query # (16,) weights = jax.nn.softmax(scores) # (16,) context = weights @ img_feats # (32,) return context, weights # Simple GRU-like step (for illustration, just a linear + tanh) W_h = jax.random.normal(jax.random.PRNGKey(0), (embed_dim + 32, hidden_dim)) * 0.1 def decode_step(h, word_idx, img_feats): context, attn_weights = attend(h, img_feats, W_attn_q) word_emb = W_embed[word_idx] # (16,) inp = jnp.concatenate([word_emb, context]) # (48,) h_new = jnp.tanh(inp @ W_h) # (32,) return h_new, attn_weights # Run decoding for the sequence: <start> -> "a" -> "red" -> "car" -> <end> target_seq = [0, 1, 2, 3, 4] h = jnp.zeros(hidden_dim) all_attn = [] for word_idx in target_seq[:-1]: h, attn_w = decode_step(h, word_idx, img_features) all_attn.append(attn_w) # Visualise attention maps (reshaped to 4x4 grid) at each step words = ["<start>", "a", "red", "car"] fig, axes = plt.subplots(1, 4, figsize=(14, 3)) for i, (ax, w) in enumerate(zip(axes, words)): ax.imshow(all_attn[i].reshape(4, 4), cmap='viridis') ax.set_title(f'Attending when\ngenerating after "{w}"') ax.axis('off') plt.suptitle('Attention Over Image Regions at Each Decoding Step') plt.tight_layout(); plt.show() # Try changing img_features to see how attention patterns shift! -
Mô phỏng pipeline token thị giác: chia ảnh thành patch, chiếu các patch vào không gian embedding, nối với các embedding token văn bản, và chạy một lớp self-attention duy nhất trên chuỗi kết hợp.
import jax import jax.numpy as jnp import matplotlib.pyplot as plt key = jax.random.PRNGKey(7) # Create a synthetic 8x8 "image" with 3 channels k1, k2, k3, k4 = jax.random.split(key, 4) image = jax.random.uniform(k1, (8, 8, 3)) # Step 1: Patchify into 4x4 patches -> 4 patches patch_size = 4 patches = image.reshape(2, patch_size, 2, patch_size, 3) patches = patches.transpose(0, 2, 1, 3, 4).reshape(4, patch_size * patch_size * 3) # (4, 48) print(f"Number of patches: {patches.shape[0]}, patch dim: {patches.shape[1]}") # Step 2: Project patches to embedding dim (d=16) d_model = 16 W_patch = jax.random.normal(k2, (patches.shape[1], d_model)) * 0.1 visual_tokens = patches @ W_patch # (4, 16) # Step 3: Create text token embeddings (simulate 3 text tokens) text_tokens = jax.random.normal(k3, (3, d_model)) * 0.1 # Step 4: Concatenate visual + text tokens combined = jnp.concatenate([visual_tokens, text_tokens], axis=0) # (7, 16) print(f"Combined sequence length: {combined.shape[0]} (4 visual + 3 text)") # Step 5: Single-head self-attention over the combined sequence W_Q = jax.random.normal(k4, (d_model, d_model)) * 0.1 k5, k6 = jax.random.split(k4) W_K = jax.random.normal(k5, (d_model, d_model)) * 0.1 W_V = jax.random.normal(k6, (d_model, d_model)) * 0.1 Q = combined @ W_Q K = combined @ W_K V = combined @ W_V attn_scores = (Q @ K.T) / jnp.sqrt(d_model) attn_weights = jax.nn.softmax(attn_scores, axis=-1) # (7, 7) output = attn_weights @ V # (7, 16) # Visualise the cross-modal attention pattern labels = ['V1', 'V2', 'V3', 'V4', 'T1', 'T2', 'T3'] fig, ax = plt.subplots(figsize=(6, 5)) im = ax.imshow(attn_weights, cmap='Blues') ax.set_xticks(range(7)); ax.set_xticklabels(labels) ax.set_yticks(range(7)); ax.set_yticklabels(labels) ax.set_xlabel('Key'); ax.set_ylabel('Query') ax.set_title('Self-Attention: Visual (V) and Text (T) Tokens') plt.colorbar(im, ax=ax); plt.tight_layout(); plt.show() # Observe: text tokens attend to visual tokens (cross-modal attention)! -
Cài đặt token hóa tọa độ cho định vị trực quan (visual grounding). Cho một hộp bao, chuyển đổi nó thành các token rời rạc; cho các token rời rạc, tái tạo hộp bao. Trực quan hóa sai số lượng tử (quantisation error) ở các độ phân giải bin khác nhau.
import jax.numpy as jnp import matplotlib.pyplot as plt def encode_bbox(bbox, num_bins=1000): """Convert continuous bbox (x, y, w, h) in [0,1] to discrete tokens.""" tokens = jnp.round(jnp.array(bbox) * (num_bins - 1)).astype(jnp.int32) return tokens def decode_bbox(tokens, num_bins=1000): """Convert discrete tokens back to continuous bbox.""" return tokens.astype(jnp.float32) / (num_bins - 1) # Ground-truth bounding box (normalised to [0, 1]) gt_bbox = jnp.array([0.123, 0.456, 0.333, 0.222]) # Test quantisation at different bin resolutions bin_sizes = [10, 50, 100, 500, 1000] errors = [] for n_bins in bin_sizes: tokens = encode_bbox(gt_bbox, n_bins) reconstructed = decode_bbox(tokens, n_bins) error = jnp.max(jnp.abs(gt_bbox - reconstructed)) errors.append(float(error)) print(f"Bins={n_bins:>5d} | Tokens={tokens} | " f"Reconstructed={reconstructed} | Max error={error:.6f}") fig, ax = plt.subplots(figsize=(8, 4)) ax.plot(bin_sizes, errors, 'o-', color='#e74c3c', linewidth=2, markersize=8) ax.set_xlabel('Number of Bins'); ax.set_ylabel('Max Quantisation Error') ax.set_title('Bounding Box Quantisation Error vs Bin Resolution') ax.set_xscale('log'); ax.set_yscale('log') ax.grid(True, alpha=0.3); plt.tight_layout(); plt.show() # Try: what happens with very few bins (e.g., 5)? When is the error acceptable?