Ảnh + văn bản (1): CLIP, BLIP, GLIP
Mục tiêu
Phần tiêu đề “Mục tiêu”Sau bài này, bạn sẽ:
- Hiểu học đối chiếu (contrastive learning) giữa ảnh và chữ: hai bộ mã hóa, ma trận độ tương đồng , đường chéo là các cặp đúng.
- Tự dẫn được hàm mất mát InfoNCE đối xứng của CLIP, và giải thích được vai trò của nhiệt độ (temperature) .
- Dùng được CLIP để phân loại zero-shot (không cần ảnh có nhãn) bằng prompt
"a photo of a {label}", và biết vì sao gộp nhiều prompt giúp ích. - Phân biệt được CLIP, BLIP và GLIP: mỗi mô hình học gì, cho ra gì, dùng cho việc gì; nhận ra các giới hạn đã biết của CLIP (đếm, quan hệ vị trí, chữ trong ảnh).
Cần biết trước
Phần tiêu đề “Cần biết trước”- Phân loại ảnh với Transformer: Attention, ViT, thuộc phần Thị giác máy tính (Đã học)
Trực giác
Phần tiêu đề “Trực giác”Bộ phân loại bị khóa vào danh sách nhãn
Phần tiêu đề “Bộ phân loại bị khóa vào danh sách nhãn”Một mô hình phân loại ảnh học trên ImageNet có đúng 1 000 đầu ra. Nó biết “golden retriever” và “tabby cat”. Nhưng bạn hỏi “ảnh này có phải xe đạp gấp không?” thì nó chịu: không có đầu ra nào cho nhãn đó. Muốn thêm nhãn, bạn phải gom ảnh, gán nhãn, rồi huấn luyện lại.
Trong khi đó, Internet có hàng trăm triệu ảnh đã có chữ đi kèm: chú thích, alt-text, tiêu đề bài viết. Chữ đó lộn xộn, nhưng mô tả nội dung ảnh bằng ngôn ngữ tự do, không bị khóa vào một danh sách.
Trò chơi ghép đôi
Phần tiêu đề “Trò chơi ghép đôi”Hãy tưởng tượng một trò chơi. Bạn có một xấp 4 tấm ảnh và 4 mẩu chú thích, bị xáo trộn. Việc của bạn: ghép mỗi ảnh với đúng chú thích của nó.
Để chơi giỏi, bạn không cần biết “nhãn lớp” nào. Bạn chỉ cần hiểu ảnh và hiểu chữ đủ để thấy chúng nói cùng một chuyện. Chơi trò này với 32 768 ảnh và 32 768 chú thích mỗi lượt, hàng tỉ lượt, bạn sẽ học được rất nhiều khái niệm về thế giới.
Khi đã chơi giỏi, phân loại trở thành một ván ghép đôi: viết mỗi nhãn thành một câu (“a photo of a folding bike”, “a photo of a cat”), rồi xem ảnh ghép với câu nào nhất. Muốn thêm nhãn mới thì chỉ cần viết thêm một câu.
Ghép xong rồi, làm gì nữa?
Phần tiêu đề “Ghép xong rồi, làm gì nữa?”Ghép đôi mới chỉ trả lời “ảnh và câu có khớp không”. Hai việc khác còn bỏ ngỏ: viết câu mô tả cho ảnh (không chỉ chọn câu có sẵn), và chỉ ra vật nằm ở đâu trong ảnh. BLIP lo việc thứ nhất, GLIP lo việc thứ hai.
Bài toán của bài này là: làm sao học từ các cặp ảnh và chữ trên mạng một không gian chung, trong đó ảnh và câu cùng nghĩa nằm gần nhau, rồi dùng nó để phân loại theo nhãn tùy ý, viết chú thích, và tìm vật theo cụm từ?
Lý thuyết
Phần tiêu đề “Lý thuyết”Ký hiệu
Phần tiêu đề “Ký hiệu”Một lô (batch) có cặp (ảnh, chú thích). Ở bài này là số cặp trong lô, không phải số patch như bài ViT. Bộ mã hóa ảnh (một ViT hoặc ResNet) và bộ mã hóa chữ (một Transformer) đưa ảnh thứ và chú thích thứ về hai vectơ cùng số chiều , gọi là không gian embedding chung (joint embedding space). Chia mỗi vectơ cho độ dài của nó, ta được:
Vì và đều dài 1, tích vô hướng của chúng chính là độ tương tự cosine (cosine similarity), nằm trong .
Bước 1: ma trận độ tương đồng
Phần tiêu đề “Bước 1: ma trận độ tương đồng N×NN \times NN×N”Xếp mọi tích vô hướng thành một ma trận :
Hàng là ảnh so với mọi chú thích; cột là chú thích so với mọi ảnh. Đường chéo là cặp đúng; ô còn lại là các cặp ghép sai. Ta không cần ai gán nhãn: chính cách lô được tạo ra cho biết đáp án.
Bước 2: mỗi hàng là một bài phân loại lớp
Phần tiêu đề “Bước 2: mỗi hàng là một bài phân loại NNN lớp”Nhìn hàng : “trong chú thích, cái nào thuộc về ảnh ?”. Đó là phân loại lớp với đáp án là cột . Ta đổi điểm thành xác suất bằng softmax, sau khi chia cho nhiệt độ :
Mất mát của hàng là cross-entropy với đáp án là cột , tức của xác suất gán cho cặp đúng:
Dạng “một mẫu đúng giữa nhiều mẫu sai, chấm bằng softmax” này có tên là InfoNCE (van den Oord và cộng sự, 2018).
Bước 3: làm đối xứng theo cột
Phần tiêu đề “Bước 3: làm đối xứng theo cột”Chiều ngược lại cũng là một trò chơi: “trong ảnh, ảnh nào thuộc về chú thích ?”. Đó là softmax theo cột của cùng ma trận:
Mẫu số giờ cộng theo cột (đổi chỉ số hàng ), còn tử số vẫn là ô trên đường chéo. CLIP lấy trung bình của hai chiều, mỗi chiều trung bình trên cả lô:
Trong code, đây chỉ là cross-entropy trên và trên , với nhãn là . Bài báo CLIP có giả mã chưa tới mười dòng cho đúng việc này.
Bước 4: gradient kéo đường chéo lên, đẩy phần còn lại xuống
Phần tiêu đề “Bước 4: gradient kéo đường chéo lên, đẩy phần còn lại xuống”Vì sao hàm này làm đúng điều ta muốn? Viết lại mất mát hàng bằng cách tách log của phân số thành hiệu hai log:
Lấy đạo hàm theo một ô của hàng đó. Số hạng đầu chỉ chứa , nên cho khi và 0 khi . Số hạng sau là log của một tổng mũ; đạo hàm của nó theo là . Cộng lại:
Ở đây bằng 1 khi , bằng 0 khi khác. Gradient descent đi ngược dấu gradient, nên:
- Ô đường chéo có gradient : ô này được kéo lên, cho tới khi gần 1.
- Ô ngoài đường chéo có gradient : ô này bị đẩy xuống, và bị đẩy mạnh hơn khi lớn. Chú thích sai nhưng “trông giống” (gọi là mẫu âm khó, hard negative) bị đẩy nhiều nhất.
Lô càng lớn thì mỗi ảnh có càng nhiều mẫu sai để phân biệt. CLIP dùng lô 32 768 cặp.
Bước 5: nhiệt độ
Phần tiêu đề “Bước 5: nhiệt độ τ\tauτ”Cosine nằm trong , nên với hai logit chỉ chênh nhau tối đa 2. Softmax trên những logit gần nhau như vậy luôn khá phẳng: dù ghép đúng hoàn toàn, mất mát vẫn không xuống thấp được. Chia cho nhỏ kéo giãn khoảng cách: với , khoảng chênh tối đa thành 200.
Nhưng quá nhỏ thì một cặp sai có cosine nhỉnh hơn cặp đúng một chút đã làm mất mát rất lớn, và huấn luyện dễ mất ổn định. CLIP không chọn tay mà học , qua tham số với (học thì luôn dương). Theo bài báo, khởi tạo ở 0.07 và bị chặn để không vượt quá 100, vì vượt quá làm huấn luyện mất ổn định. Ô LocalCode ở dưới in ra của checkpoint đã học: chạm đúng mức chặn.
Chú ý: ở đây cùng vai trò với nhiệt độ của phần LLM (chia logit trước softmax), chỉ khác ký hiệu theo bài báo.
CLIP: dữ liệu và kết quả
Phần tiêu đề “CLIP: dữ liệu và kết quả”CLIP (Radford và cộng sự, 2021) huấn luyện từ đầu trên 400 triệu cặp (ảnh, chữ) thu từ Internet. Nhóm tác giả thử năm bộ mã hóa ảnh ResNet và ba ViT (ViT-B/32, ViT-B/16, ViT-L/14); bộ mã hóa chữ là một Transformer. Mô hình tốt nhất (ViT-L/14 ở ảnh ) đạt 76.2% độ chính xác top-1 zero-shot trên ImageNet, ngang ResNet-50 gốc mà không dùng ảnh nào trong 1.28 triệu ảnh có nhãn của ImageNet (số theo bài báo, 2021).
Phân loại zero-shot
Phần tiêu đề “Phân loại zero-shot”Có nhãn. Viết mỗi nhãn thành một câu, đưa qua bộ mã hóa chữ, được . Với ảnh mới có embedding :
Đây đúng là một hàng của ma trận , với các câu nhãn đứng ở vị trí chú thích. Bài báo CLIP nhìn nó như một hồi quy logistic nhiều lớp không có hệ số tự do: các chính là trọng số của lớp phân loại, và bộ mã hóa chữ là thứ sinh ra trọng số từ tên nhãn.
Vì sao cần prompt. Chú thích trong dữ liệu hiếm khi là một từ đơn, nên chỉ đưa tên nhãn “crane” vừa lệch phân phối, vừa mơ hồ (cần cẩu hay con sếu?). Bài báo dùng mẫu "A photo of a {label}." làm mặc định, giúp tăng 1.3% trên ImageNet; với từng bộ dữ liệu còn thêm ngữ cảnh, ví dụ "A photo of a {label}, a type of pet.".
Gộp nhiều prompt (prompt ensembling). Viết mỗi nhãn bằng mẫu khác nhau ("a photo of a big {label}", "a blurry photo of a {label}"…), lấy trung bình các embedding chữ rồi chuẩn hóa lại:
Chia cho rồi chuẩn hóa cho cùng kết quả như chuẩn hóa thẳng tổng, nên công thức bỏ . Gộp trong không gian embedding nên chỉ tính một lần cho mỗi nhãn, chi phí lúc dự đoán như một prompt. Với 80 mẫu, bài báo báo cáo thêm 3.5% trên ImageNet so với một prompt mặc định; cộng cả hai cách là gần 5%.
Giới hạn của CLIP
Phần tiêu đề “Giới hạn của CLIP”- Đếm và việc trừu tượng. Bài báo ghi CLIP zero-shot yếu với đếm số vật thể (CLEVRCounts) và đoán khoảng cách tới xe gần nhất (KITTI Distance), có lúc gần như đoán mò. Ô
LocalCodethử đếm ba hình tròn. - Quan hệ và vị trí. Embedding ảnh là một vectơ cho cả ảnh, và học đối chiếu trên chú thích web ít khi buộc mô hình phân biệt thứ tự từ. Yuksekgonul và cộng sự (2023) cho thấy nhiều mô hình kiểu này, có CLIP, cư xử như “túi từ” (bag of words): khó chọn giữa “the horse is eating the grass” và “the grass is eating the horse”, và với các câu quan hệ, phần lớn mô hình gần hoặc dưới mức đoán mò.
- Chữ trong ảnh. CLIP đọc được chữ in khá tốt, đến mức chữ có thể đánh lừa nó: Goh và cộng sự (2021) mô tả tấn công bằng chữ (typographic attack), dán chữ ghi tên một vật khác lên ảnh là có thể làm đổi nhãn. Ngược lại, với chữ số viết tay của MNIST, CLIP zero-shot chỉ đạt 88%, thua cả hồi quy logistic trên điểm ảnh thô (theo bài báo CLIP).
- Từ đa nghĩa và phân biệt chi tiết. “Boxer” là giống chó hay võ sĩ? Phân biệt các đời xe hay các loài hoa cũng là điểm yếu được bài báo ghi nhận.
BLIP: vừa hiểu vừa viết
Phần tiêu đề “BLIP: vừa hiểu vừa viết”CLIP chỉ chấm điểm cặp, không sinh câu nào. BLIP (Li và cộng sự, 2022) muốn một mô hình làm được cả việc hiểu (truy xuất, hỏi đáp về ảnh) lẫn việc sinh (viết chú thích). Nó dựng một hỗn hợp encoder–decoder đa phương thức (multimodal mixture of encoder-decoder, MED), chạy được ở ba chế độ, mỗi chế độ một mục tiêu học:
| Chế độ | Mục tiêu học | Làm gì |
|---|---|---|
| Hai bộ mã hóa riêng (ảnh, chữ) | ITC (image-text contrastive): học đối chiếu như CLIP | Kéo cặp đúng lại gần trong không gian chung |
| Bộ mã hóa chữ có điều kiện ảnh: thêm cross-attention nhìn sang đặc trưng ảnh | ITM (image-text matching): phân loại nhị phân “khớp” hay “không khớp” | Xét kỹ từng cặp; cặp âm được lấy mẫu trong lô, ưu tiên cặp có điểm ITC cao (mẫu âm khó) |
| Bộ giải mã chữ có điều kiện ảnh: self-attention nhân quả | LM (language modeling): dự đoán token kế tiếp | Viết chú thích cho ảnh |
Bộ mã hóa chữ và bộ giải mã chữ dùng chung mọi tham số trừ các lớp self-attention, vì theo tác giả, khác biệt giữa “đọc” và “viết” nằm chủ yếu ở đó. ITC của BLIP theo ALBEF (Li và cộng sự, 2021): thêm một bộ mã hóa động lượng (momentum encoder) để tạo nhãn mềm, vì trong lô có thể có cặp “sai” mà thật ra khớp.
CapFilt: lọc chú thích nhiễu. Chữ đi kèm ảnh web thường không mô tả ảnh (“IMG_2031.jpg”, “sale 50%”). BLIP tách mô hình đã pre-train thành hai, fine-tune riêng trên COCO (bộ dữ liệu ảnh có chú thích do người viết):
- Bộ sinh chú thích (captioner, chế độ LM) viết một câu mới cho mỗi ảnh web, bằng top-p sampling. Tác giả thấy câu đa dạng giúp nhiều hơn câu “an toàn” của beam search.
- Bộ lọc (filter, chế độ ITM) chấm cả câu gốc lẫn câu mới; câu nào đầu ITM đoán là không khớp ảnh thì bị bỏ.
Các cặp còn lại, cộng dữ liệu do người gán nhãn, thành bộ dữ liệu mới để pre-train một mô hình mới. Bộ dữ liệu gốc có 14 triệu ảnh; bài báo thử thêm tới 129 triệu ảnh (có LAION).
BLIP-2 (Li và cộng sự, 2023) đi bước tiếp: đóng băng cả một bộ mã hóa ảnh có sẵn lẫn một LLM có sẵn, chỉ học một cầu nối nhỏ là Q-Former (188 triệu tham số). Q-Former có 32 vectơ truy vấn học được, mỗi vectơ 768 chiều; chúng nhìn sang đặc trưng ảnh qua cross-attention và rút ra một bản tóm tắt , nhỏ hơn nhiều so với của ViT-L/14. Một lớp tuyến tính chiếu 32 vectơ đó sang số chiều embedding của LLM rồi đặt trước token chữ, như “prompt mềm” bằng ảnh. Cách nối ảnh vào LLM này, và cách đơn giản hơn của LLaVA, là chủ đề của bài Ảnh + văn bản (2): LLaVA và các biến thể.
GLIP: tìm vật theo cụm từ
Phần tiêu đề “GLIP: tìm vật theo cụm từ”CLIP và BLIP làm việc với cả ảnh. Phát hiện vật thể (object detection) thì cần biết vật nằm ở đâu: mỗi vật một hộp bao (bounding box) kèm nhãn. Một bộ phát hiện kinh điển lấy đặc trưng của vùng ảnh, , nhân với ma trận trọng số của lớp cố định:
GLIP (Li và cộng sự, 2022) nhận ra phát hiện vật thể là một trường hợp riêng của grounding (phrase grounding, định vị cụm từ): cho một câu, tìm vùng ảnh ứng với từng cụm từ trong câu. Cách làm: viết danh sách lớp thành một prompt, ví dụ “person. bicycle. car. … toothbrush”, đưa qua bộ mã hóa chữ thành ( token), rồi thay bằng :
Mỗi ô là điểm khớp giữa một vùng và một token. Đây là cùng ý với ma trận của CLIP, nhưng ở mức vùng–từ thay vì ảnh–câu. Vì prompt là chữ tự do, đổi danh sách lớp không cần đổi kiến trúc.
Hai điểm khác CLIP:
- Fusion sâu (deep fusion). CLIP chỉ gặp nhau ở tích vô hướng cuối cùng; GLIP trộn đặc trưng ảnh và chữ qua cross-attention ở vài lớp cuối của hai bộ mã hóa, nên đặc trưng ảnh “biết” câu đang hỏi gì. Tác giả cho rằng điều này quan trọng cho chất lượng.
- Dữ liệu grounding mở rộng bằng nhãn giả. Một mô hình GLIP “thầy” học trên dữ liệu có người gán, rồi tự vẽ khung cho các cụm danh từ trong 24 triệu cặp ảnh và chữ từ web; mô hình “trò” học trên tổng cộng 27 triệu mẫu grounding (3 triệu có người gán).
Theo bài báo (2022), GLIP-L chưa thấy ảnh COCO nào khi pre-train vẫn đạt 49.8 AP zero-shot trên COCO và 26.9 AP trên LVIS (AP, average precision, là thước đo chuẩn của phát hiện vật thể).
Giới hạn của bài
Phần tiêu đề “Giới hạn của bài”- Bài chỉ nói ý chính của ba mô hình; kiến trúc phát hiện vật thể (đề xuất vùng, khớp khung) thuộc phần phát hiện vật thể, chưa có bài riêng.
- Ảnh vào LLM (LLaVA, BLIP-2 nối với LLM) thuộc bài Ảnh + văn bản (2): LLaVA và các biến thể.
- Học đối chiếu không cần chữ, chỉ dùng hai góc nhìn của cùng một ảnh, thuộc bài Self-supervised learning với ảnh.
Minh họa
Phần tiêu đề “Minh họa”Hình dưới vẽ một lô cặp của CLIP. Hãy nhìn vào ma trận ở giữa: các ô trên đường chéo là cặp đúng và được kéo lên, mọi ô còn lại bị đẩy xuống. Mỗi hàng là một bài “chọn chú thích cho ảnh”, mỗi cột là một bài “chọn ảnh cho chú thích”.
Bảng dưới đặt ba mô hình cạnh nhau. Cột “Mục tiêu học” cho biết vì sao đầu ra của mỗi mô hình khác nhau.
| Tiêu chí | CLIP (2021) | BLIP (2022) | GLIP (2022) |
|---|---|---|---|
| Mục tiêu học | Đối chiếu ảnh–câu (InfoNCE đối xứng) | ITC, ITM và LM cùng lúc | Khớp vùng–từ (grounding), gộp cả dữ liệu phát hiện vật thể |
| Ảnh và chữ gặp nhau ở đâu | Chỉ ở tích vô hướng cuối | Cross-attention trong bộ mã hóa và bộ giải mã chữ | Fusion sâu ở các lớp cuối của hai bộ mã hóa |
| Đầu ra | Một vectơ cho ảnh, một vectơ cho câu | Điểm khớp ảnh–câu, hoặc một câu chú thích | Hộp bao kèm cụm từ trong prompt |
| Dữ liệu (theo bài báo) | 400 triệu cặp từ web | 14 triệu ảnh (tới 129 triệu), chú thích lọc bằng CapFilt | 27 triệu mẫu grounding (24 triệu có nhãn giả) |
| Dùng cho | Phân loại zero-shot, tìm ảnh bằng chữ, bộ mã hóa ảnh cho LLM | Viết chú thích, hỏi đáp về ảnh, truy xuất | Phát hiện vật thể theo nhãn tùy ý, tìm vật theo câu |
Ví dụ code
Phần tiêu đề “Ví dụ code”Code trong bài chạy thử lần cuối tháng 11/2026: ô NumPy với Python 3.14 và NumPy 2.4 (bản có trong Pyodide), ô CLIP với Python 3.14, PyTorch 2.15 và transformers 5.22 trên CPU. Ô NumPy chạy ngay trên trang, ô CLIP chạy trên máy bạn. Hai ô độc lập, không dùng biến của nhau.
Ma trận tương đồng và InfoNCE bằng NumPy
Phần tiêu đề “Ma trận tương đồng và InfoNCE bằng NumPy”Ô dưới đây tạo 4 “ý” ngẫu nhiên (hạt giống 0), mỗi ý sinh một embedding ảnh và một embedding chữ bằng cách cộng hai nhiễu khác nhau, nên cặp cùng ý có tương quan. Ô chuẩn hóa, tính ma trận , tính mất mát đối xứng với ba giá trị cho cách ghép đúng và cho một cách ghép sai (ảnh với chú thích ), rồi phân loại zero-shot một “ảnh” mới của ý “dog”.
Ma trận tương đồng, InfoNCE và zero-shot
import numpy as np
rng = np.random.default_rng(0)N, D = 4, 8 # 4 cặp (ảnh, chú thích), embedding 8 chiềulabels = ["cat", "dog", "car", "tree"]
# Mỗi cặp có một "ý" chung; ảnh và chữ là hai bản có nhiễu của ý đóconcept = rng.normal(size=(N, D))img = concept + 0.5 * rng.normal(size=(N, D))txt = concept + 0.5 * rng.normal(size=(N, D))
def normalize(a): # chia mỗi hàng cho độ dài của nó return a / np.linalg.norm(a, axis=1, keepdims=True)
def cross_entropy(logits): # nhãn đúng của hàng i là cột i z = logits - logits.max(axis=1, keepdims=True) log_p = z - np.log(np.exp(z).sum(axis=1, keepdims=True)) return -np.diag(log_p).mean()
def clip_loss(S, tau): # trung bình của chiều hàng và chiều cột return (cross_entropy(S / tau) + cross_entropy(S.T / tau)) / 2
I, T = normalize(img), normalize(txt)S = I @ T.T # ma trận cosine N x Nnp.set_printoptions(precision=2, suppress=True)print(S)
S_wrong = I @ T[[1, 2, 3, 0]].T # ghép sai: ảnh i với chú thích i+1print(f"log N = {np.log(N):.3f}")for tau in [1.0, 0.1, 0.01]: print(f"tau={tau}: right={clip_loss(S, tau):.3f}" f" wrong={clip_loss(S_wrong, tau):.3f}")
# Zero-shot: ảnh mới của "dog", so với 4 câu nhãnnew_img = normalize(concept[[1]] + 0.5 * rng.normal(size=(1, D)))cos = (new_img @ T.T)[0]z = cos / 0.07 # tau khởi tạo của CLIPp = np.exp(z - z.max()) / np.exp(z - z.max()).sum()print("cos: ", cos)print("probs:", " ".join(f"{x:.4f}" for x in p), "->", labels[p.argmax()])print("argmax per row:", [labels[k] for k in S.argmax(axis=1)])Lần chạy đầu cần tải Python, khoảng 10 MB.
Đọc kết quả:
- Ma trận : ô lớn nhất của mỗi hàng nằm trên đường chéo (0.81, 0.77, 0.71, 0.66), dù vài ô ngoài đường chéo không nhỏ, như 0.41 ở hàng 2.
log N = 1.386: mức mất mát khi mô hình đoán đều, .tau=1.0: ghép đúng chỉ được 0.930, không xa , vì logit chênh nhau quá ít. Đúng điều Bước 5 nói.tau=0.1vàtau=0.01: ghép đúng xuống 0.023 rồi 0.000, nhưng ghép sai vọt lên 6.815 rồi 67.923. nhỏ làm mô hình “tự tin”, thưởng lớn khi đúng và phạt nặng khi sai.- Zero-shot: cosine của ảnh mới với 4 câu nhãn là
[-0.57 0.78 0.23 0.25]; chia cho rồi softmax cho xác suất 0.9991 ở “dog”. Dòng cuối lấy argmax theo từng hàng của và ra đúng thứ tựcat, dog, car, tree.
CLIP thật: phân loại zero-shot ảnh tự vẽ
Phần tiêu đề “CLIP thật: phân loại zero-shot ảnh tự vẽ”File dưới đây tải checkpoint openai/clip-vit-base-patch32 (bộ mã hóa ảnh ViT-B/32) qua thư viện transformers. Trọng số khoảng 600 MB; trên máy chạy thử, thư viện tải cả bản pytorch_model.bin lẫn model.safetensors, nên bộ nhớ đệm chiếm khoảng 1.2 GB. File vẽ ba ảnh bằng PIL (tròn đỏ, vuông xanh dương, tam giác vàng), phân loại với 5 nhãn trong đó có nhãn “bẫy” cùng màu khác hình và cùng hình khác màu, rồi thử đếm một ảnh có ba hình tròn đỏ. Cách cài PyTorch bản CPU có ở bài Xây dựng LLM đầu tiên.
Chạy trên máy bạn
CLIP phân loại zero-shot hình tự vẽ
- Cần cài
pip install torch transformers pillow- Phần cứng
- CPU là đủ. Lần đầu mất vài phút để tải trọng số; các lần sau khoảng 1 phút trên máy chạy thử, phần lớn là nạp thư viện và mô hình
import torchfrom PIL import Image, ImageDrawfrom transformers import CLIPModel, CLIPProcessor
torch.manual_seed(0)NAME = "openai/clip-vit-base-patch32" # lần đầu tải 0.6 tới 1.2 GBmodel = CLIPModel.from_pretrained(NAME).eval()processor = CLIPProcessor.from_pretrained(NAME)
def draw(shape, color, n=1): # Ảnh 224 x 224 nền trắng, n hình cùng loại xếp thành hàng ngang img = Image.new("RGB", (224, 224), "white") d = ImageDraw.Draw(img) step = 180 // n size = step * 3 // 4 for k in range(n): x0, y0 = 22 + k * step + (step - size) // 2, 112 - size // 2 x1, y1 = x0 + size, y0 + size if shape == "circle": d.ellipse((x0, y0, x1, y1), fill=color) elif shape == "square": d.rectangle((x0, y0, x1, y1), fill=color) else: d.polygon([((x0 + x1) // 2, y0), (x1, y1), (x0, y1)], fill=color) return img
def zero_shot(images, labels): prompts = [f"a photo of {label}" for label in labels] inputs = processor(text=prompts, images=images, return_tensors="pt", padding=True) with torch.no_grad(): out = model(**inputs) # logits = cosine / tau; softmax theo hàng: mỗi ảnh một phân phối return out.logits_per_image.softmax(dim=1)
print(f"1/tau = {model.logit_scale.exp().item():.1f}")shapes = [("circle", "red"), ("square", "blue"), ("triangle", "yellow")]labels = ["a red circle", "a blue circle", "a red square", "a blue square", "a yellow triangle"]probs = zero_shot([draw(s, c) for s, c in shapes], labels)for (s, c), row in zip(shapes, probs): cells = " ".join(f"{p:.3f}" for p in row.tolist()) print(f"{c} {s}: {cells} -> {labels[row.argmax()]}")
# Đếm: ảnh có 3 hình tròn đỏ, hỏi có mấy hìnhcounts = ["one red circle", "two red circles", "three red circles", "four red circles"]row = zero_shot([draw("circle", "red", n=3)], counts)[0]cells = " ".join(f"{p:.3f}" for p in row.tolist())print(f"3 circles: {cells} -> {counts[row.argmax()]}")Kết quả mẫu
Lấy từ một lần chạy thật.
1/tau = 100.0red circle: 0.940 0.056 0.001 0.002 0.001 -> a red circleblue square: 0.000 0.042 0.000 0.957 0.000 -> a blue squareyellow triangle: 0.000 0.000 0.000 0.000 1.000 -> a yellow triangle3 circles: 0.043 0.070 0.504 0.384 -> three red circlesĐọc kết quả:
1/tau = 100.0:logit_scalecủa checkpoint là , đúng mức chặn của bài báo.logits_per_imagecủa thư viện chính là , nênsoftmax(dim=1)là softmax theo hàng như công thức zero-shot.- Ba hình đơn: cả ba đều đúng. Năm số trên mỗi dòng theo thứ tự nhãn “a red circle”, “a blue circle”, “a red square”, “a blue square”, “a yellow triangle”. Nhãn bẫy nhận nhiều xác suất nhất là “a blue circle”: 0.056 cho hình tròn đỏ (cùng hình, khác màu) và 0.042 cho hình vuông xanh (cùng màu, khác hình).
- Đếm: “three red circles” thắng với 0.504, nhưng “four red circles” vẫn nhận 0.384. So với 0.94–1.00 ở các dòng trên, mô hình kém chắc chắn hẳn khi phải đếm, khớp với giới hạn bài báo ghi nhận. Đây chỉ là một ảnh, không phải phép đo: bạn thử đổi
n=3thành 5 hay 6 để xem.
Lỗi hay gặp
Phần tiêu đề “Lỗi hay gặp”Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Tóm tắt và đọc thêm
Phần tiêu đề “Tóm tắt và đọc thêm”Ý chính:
- CLIP học bằng trò ghép đôi: trong lô cặp, ma trận có đáp án trên đường chéo; mất mát là cross-entropy theo hàng và theo cột trên (InfoNCE đối xứng). Gradient kéo đường chéo lên, đẩy mạnh nhất các mẫu âm khó.
- quyết định softmax sắc hay phẳng: lớn quá thì không học được, nhỏ quá thì mất ổn định. CLIP học , khởi tạo 0.07, chặn .
- Zero-shot: viết nhãn thành câu (
"a photo of a {label}"), lấy argmax cosine. Gộp nhiều prompt thêm vài phần trăm. Giới hạn: đếm, quan hệ, chữ trong ảnh, khái niệm hiếm. - BLIP thêm ITM và LM để vừa hiểu vừa viết, và lọc chú thích web bằng CapFilt; BLIP-2 nối bộ mã hóa ảnh và LLM đóng băng qua Q-Former. GLIP coi phát hiện vật thể là grounding: giữa vùng và từ.
Đọc thêm:
- Radford, A. và cộng sự (2021). Learning Transferable Visual Models From Natural Language Supervision, arXiv:2103.00020, mục 2.3 (hình 3: giả mã hàm mất mát), mục 3.1.4 (prompt và gộp prompt) và mục 6 (giới hạn). Bài gốc của CLIP, viết dễ đọc.
- van den Oord, A., Li, Y., Vinyals, O. (2018). Representation Learning with Contrastive Predictive Coding, arXiv:1807.03748, mục 2.3. Nguồn của tên InfoNCE; bối cảnh khác (dự đoán chuỗi), cùng dạng hàm mất mát.
- Li, J., Li, D., Xiong, C., Hoi, S. (2022). BLIP: Bootstrapping Language-Image Pre-training for Unified Vision-Language Understanding and Generation, arXiv:2201.12086, mục 3. Ba mục tiêu ITC, ITM, LM và CapFilt. Phần tiếp theo: Li, J., Li, D., Savarese, S., Hoi, S. (2023). BLIP-2, arXiv:2301.12597, mục 3 (Q-Former).
- Li, L. H., Zhang, P., Zhang, H. và cộng sự (2022). Grounded Language-Image Pre-training, arXiv:2112.03857, mục 3.1–3.3. Cách viết phát hiện vật thể thành grounding và cách mở rộng dữ liệu bằng nhãn giả.
- Yuksekgonul, M., Bianchi, F., Kalluri, P., Jurafsky, D., Zou, J. (2023). When and Why Vision-Language Models Behave like Bags-Of-Words, and What to Do About It?, arXiv:2210.01936, mục 2. Bộ kiểm tra ARO về quan hệ và thứ tự từ; giải thích vì sao học đối chiếu trên dữ liệu truy xuất bỏ qua thứ tự. Đọc cùng: Goh, G. và cộng sự (2021), Multimodal Neurons in Artificial Neural Networks, Distill, về tấn công bằng chữ.
Trình duyệt đang chặn lưu dữ liệu. Tiến độ sẽ mất khi bạn tải lại trang.
Nội dung theo giấy phép CC BY-NC-SA 4.0. Mã nguồn theo giấy phép MIT.Giới thiệu