iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0

過去十幾天,我們所介紹的所有模型,基本上都建立在 CNN 上。CNN 在電腦視覺領域統治了約 10 年之久,但來自自然語言處理 (Natural Language Processing, NLP) 挑戰者,在過去幾年撼動了這個地位。

Transformer 與自注意力機制

Transformer,它最初是為了解決機器翻譯等 NLP 任務而設計的,它運用了自注意力機制 (self-attention) 來解決傳統循環神經網路 (Recurrent Neural Network, RNN) 不易捕捉到相距很遠的單詞之間依賴關係的問題。

自注意力機制的思想是:在處理一個序列中的某個元素(例如一個單詞)時,模型應該能夠動態地、有選擇性地「關注」到序列中所有其他與其最相關的元素,並根據這些相關性來更新自身的表示。

它的計算流程大致如下:

  1. 生成 Q, K, V:對於序列中的每一個輸入 token(例如,每個單詞的嵌入向量),都通過三個不同的線性變換,生成三個向量:查詢 (Query, Q)、鍵 (Key, K) 和 值 (Value, V)。

    • Q 代表:「我正在尋找什麼?」

    • K 代表:「我擁有什麼樣的資訊?」

    • V 代表:「我實際攜帶的內容是什麼?」

  2. 計算注意力分數:用每個 token 的 Q 向量,去和所有其他 token 的 K 向量進行點積運算。這個點積的結果,就代表了這兩個 token 之間的「相關性分數」或「注意力權重」。

  3. Softmax 歸一化:將這些分數通過一個 Softmax 函數,將其轉換為總和為 1 的機率分佈。

  4. 加權求和:用這些歸一化後的注意力權重,去對所有 token 的 V 向量進行加權求和。

最終,每個 token 的輸出,都包含了整個序列中所有其他 token 的資訊,並且是根據「相關性」動態加權融合後的結果。這種機制使得 Transformer 具有強大的全局感受域 (global receptive field),能夠捕捉長距離的依賴關係。

ViT

那麼,如何才能將一張二維的圖像,轉換成 Transformer 可以處理的一維序列呢?Google Brain 團隊在 2020 年提出了一個簡單有效的方案:Vision Transformer (ViT)。

ViT 的工作流程如下:

  1. 圖像分塊 (Image Patching):這是 ViT 的核心思想。將一張輸入的圖片(例如 224×224),像切蛋糕一樣,分割成 N 個不重疊的、固定大小的小圖像塊 (Patch)。例如,如果每個 Patch 的大小是 16×16,那麼我們就會得到 (224/16) × (224/16) = 14 × 14 = 196 個 Patch。

  2. 展平與線性投射:將每個 16×16×3 的 Patch,「攤平」成一個一維的向量,然後通過一個線性投射層(全連接層),將其嵌入到一個固定的維度 D 中。現在我們得到了一個長度為 196 的、由 D 維向量組成的序列。一張圖片,就這樣被轉換成了一句句子,而每個 Patch 就是一個單詞

  3. [CLS] Token:借鑒 BERT 模型的思想,在序列的最前面,額外加入一個可學習的 [class] 嵌入向量。在經過 Transformer 編碼後,這個 [class] token 對應的最終輸出,將被用作整張圖片的聚合特徵,送入分類頭進行分類。

  4. 位置編碼 (positional encoding):Transformer 本身並不包含任何關於序列順序的資訊。為了讓模型知道每個 Patch 的原始空間位置,我們需要為每個 Patch 嵌入向量,都加上一個可學習的「位置編碼」,來保留其空間資訊。

  5. Transformer 編碼器:將這個帶有位置編碼的 Patch 序列,送入一個標準的 Transformer 編碼器(由多個自注意力層和 ANN 層堆疊而成)進行處理。

  6. 分類頭:最後,取出 [class] token 對應的輸出,通過一個小型的 ANN(分類頭),得到最終的分類結果。

ViT 與 CNN 的比較

  • 歸納偏置:CNN 具有很強的歸納偏置(局部性、平移不變性),這使得它在數據量較小時,也能學得很好。而 ViT 的歸納偏置則弱得多,它對數據的結構幾乎沒有任何先驗假設,因此需要極其龐大的數據集(例如 Google 內部的 JFT-300M,包含 3 億張圖片)進行預訓練,才能學到普適的視覺模式。

  • 性能:當在超大規模的數據集上進行預訓練,然後遷移到中等規模的下游任務(如 ImageNet)上時,ViT 的表現超越了當時所有最先進的 CNN 模型。

使用 Hugging Face 運行預訓練的 ViT

首先安裝 transformers

pip install transformers 
from transformers import ViTFeatureExtractor, ViTForImageClassification
from PIL import Image
import requests

# --- 1. 載入預訓練的 ViT 模型和特徵提取器 ---
# 我們使用 Google 在 ImageNet-21k 上預訓練,並在 ImageNet-1k 上微調的版本
model_name = 'google/vit-base-patch16-224'
print(f"正在從 Hugging Face Hub 下載模型: {model_name}...")

# 特徵提取器負責處理圖片的預處理 (尺寸調整、正規化等)
feature_extractor = ViTFeatureExtractor.from_pretrained(model_name)
model = ViTForImageClassification.from_pretrained(model_name)
print("模型載入完成!")

# --- 2. 準備輸入圖片 ---
image_url = "http://images.cocodataset.org/val2017/000000039769.jpg" # 兩隻貓
response = requests.get(image_url, stream=True)
image = Image.open(response.raw)

# --- 3. 進行預測 ---
# 特徵提取器會將 PIL 圖片轉換為模型需要的 Tensor 格式
inputs = feature_extractor(images=image, return_tensors="pt")

# 進行前向傳播
outputs = model(**inputs)
logits = outputs.logits

# --- 4. 解讀輸出結果 ---
# 模型在 ImageNet-1k (1000類) 上微調過
# 找出分數最高的那個類別的索引
predicted_class_idx = logits.argmax(-1).item()

# model.config.id2label 是一個字典,可以將索引映射到類別名稱
predicted_class = model.config.id2label[predicted_class_idx]

print(f"\n--- 預測結果 ---")
print(f"模型預測的類別是: {predicted_class}")

# 顯示圖片
import matplotlib.pyplot as plt
plt.imshow(image)
plt.title(f"Prediction: {predicted_class}")
plt.axis('off')
plt.show()

結果
https://ithelp.ithome.com.tw/upload/images/20250905/20178100q74Tp0rU37.png


上一篇
Day 25 – cGAN 與 StyleGAN
系列文
從0開始:傳統圖像處理到深度學習模型26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言