Last Updated on 2024-10-01 by Clay
我第一次聽到向量量化(Vector Quantization, VQ)是在做音訊處理的朋友的口中,因此模糊地得知了向量量化是一種用於資料特徵壓縮和特徵表示的技術;當然那時,我還不清楚這與像是 PCA 等等降維技巧有什麼不同。
不過昨天在看到 BAAI 所提出的 Emu3 架構後,驚豔於他們所設想的全部模態(影片、圖片、文字)都是相同 Token 單位的生成方式,不依賴其他影像模型架構(如 Stable Diffusion、GAN…),純以 Transformer 架構預測 Token 生成圖片與文字的多模態模型,深感興趣於是探究了一下底層圖片最小 patch 編碼解碼的方式,於是追到最底找到了向量量化這一技術。
說來慚愧,雖然自詡是熟悉許多模型架構的 AI 工程師,然而至今仍有許多技術是不夠熟悉、不夠了解,只能積極努力學習、別無他法。
簡單來說,向量量化的技術其實被廣泛應用於深度學習領域中,除了音訊外其實自然語言處理和計算機視覺領域通通都有所應用,更進一步地說明,向量量化本身就是將『高維資料映射到有限的離散編碼本(codebook)』這一動作,減少了資料儲存量、減少了計算複雜度。
老實說我一開始有點疑惑為什麼是強調『離散』,但後來想想編碼本本來就是像字典格式(dictionary)一樣的映射,而高維資料所對應的向量本來就是有限、預先定義好、獨立且互不影響的。
動手測試
最簡單的測試方法就是 Kmeans 的分群,每個群的中心點就是編碼本所壓縮儲存的元素
首先,我們先隨機生成四群資料。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
# Generate dataset
X, y = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=2999)
# Plot original data
plt.scatter(X[:, 0], X[:, 1], s=30, color="blue", label="Original Data")
plt.title("Original Data")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.legend()
plt.show()
Output:
接著使用 Kmeans 找出集群的中心點,同時繪製出來。
from sklearn.cluster import KMeans
k = 4
kmeans = KMeans(n_clusters=k, random_state=2999)
kmeans.fit(X)
# Get codebook
codebook = kmeans.cluster_centers_
# Get labels
labels = kmeans.labels_
# Plot
plt.scatter(X[:, 0], X[:, 1], c=labels, s=30, cmap="viridis", label="Quantized Data")
plt.scatter(codebook[:, 0], codebook[:, 1], s=200, c="red", marker="X", label="Codebook")
plt.title("Vector Quantization using K-Means")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.legend()
plt.show()
Output:
感覺上,圖片中相似的紋路、方向、佈置,在 16x16 的單一 patch 上確實可能可以使用三萬多個左右的 codebook 覆蓋大部分的類型。換句話說,可以想像成 16x16 的圖片細節大概用三萬多個左右的低維向量作為特徵即可。
當然,這種從高維空間映射到低維空間的轉換,勢必無法是無損壓縮的。看了一些 VQ 後續的發展,感覺上還得惡補許多知識才能理解 Emu 架構呢,畢竟人家的 codebook 甚至是用學習出來的、特徵也遠非二維的 toy dataset 可以相比的。