邊學(xué)邊做:圖片識(shí)別技術(shù)的學(xué)習(xí)與應(yīng)用
1 寫(xiě)在前面
2 學(xué)習(xí)圖片相似度的基礎(chǔ)知識(shí)
2.1 從向量開(kāi)始理解
2.2 向量化算法的學(xué)習(xí)
2.3 向量數(shù)據(jù)庫(kù)的學(xué)習(xí)
2.4 HNSW索引算法的理解
2.5 相似性度量:從語(yǔ)義理解到數(shù)學(xué)計(jì)算
3 解決實(shí)際應(yīng)用問(wèn)題
3.1 目標(biāo)檢測(cè)的必要性
3.2 數(shù)據(jù)標(biāo)注的挑戰(zhàn)
3.3 訓(xùn)練實(shí)踐經(jīng)驗(yàn)
4 未來(lái)規(guī)劃
4.1 理想中的系統(tǒng)架構(gòu)
4.2 當(dāng)前進(jìn)展與挑戰(zhàn)
5 寫(xiě)在最后
1.寫(xiě)在前面
最近在做二次元商品項(xiàng)目,遇到了拍照識(shí)別商品的需求。一開(kāi)始完全不懂,只能邊學(xué)邊做。這篇文章記錄了學(xué)習(xí)和實(shí)踐過(guò)程,希望能給同樣在探索圖片識(shí)別技術(shù)的朋友一些參考。
2.學(xué)習(xí)圖片相似度的基礎(chǔ)知識(shí)
在開(kāi)始動(dòng)手之前,我花了不少時(shí)間去理解圖片相似度是怎么回事。
2.1 從向量開(kāi)始理解
最初不理解圖片和向量的關(guān)系,后來(lái)發(fā)現(xiàn)就是把圖片轉(zhuǎn)換成數(shù)字。計(jì)算機(jī)視覺(jué)中,圖片需要轉(zhuǎn)換為數(shù)學(xué)形式才能處理。向量化是將圖片轉(zhuǎn)換為高維數(shù)值向量的過(guò)程,每個(gè)向量包含圖片的特征信息。
圖片向量通常包含512維、1024維或更高維度的特征,每一維代表圖片的某個(gè)特征屬性,如顏色、紋理、形狀等。通過(guò)向量化,圖片相似度問(wèn)題轉(zhuǎn)化為向量相似度問(wèn)題。
小卡向量示意圖
說(shuō)明:為了便于理解,上圖簡(jiǎn)化為3維向量展示。實(shí)際應(yīng)用中,每張圖片會(huì)被轉(zhuǎn)換為512維或1024維的高維向量,包含顏色、紋理、形狀、邊緣等數(shù)百個(gè)特征維度。
2.2 向量化算法的學(xué)習(xí)
這部分是我學(xué)習(xí)曲線最陡峭的地方。CNN(卷積神經(jīng)網(wǎng)絡(luò))聽(tīng)起來(lái)很高大上,但當(dāng)我深入了解后發(fā)現(xiàn),它的核心思想其實(shí)很直觀。
卷積層是CNN的核心組件,它通過(guò)一系列可學(xué)習(xí)的濾波器(卷積核)在圖片上滑動(dòng),提取不同的特征。
卷積層計(jì)算過(guò)程
每個(gè)卷積核就像一個(gè)特征檢測(cè)器,通過(guò)多層卷積的堆疊,CNN模型能夠從簡(jiǎn)單的像素信息中逐步提取出高層的語(yǔ)義特征。
強(qiáng)烈推薦 Image Kernels Explained Visually,你可以實(shí)時(shí)看到不同卷積核(模糊、銳化、邊緣檢測(cè)等)對(duì)圖片的處理效果。
在實(shí)際應(yīng)用中,我選擇了市面上常用的預(yù)訓(xùn)練模型ResNet。使用ResNet-50作為特征提取器,能夠?qū)⑤斎氲膱D片轉(zhuǎn)換為一個(gè)2048維的特征向量。
下面是一個(gè)簡(jiǎn)單的代碼示例,展示如何使用ResNet提取圖片特征:
import torch
from torchvision.models import resnet50, ResNet50_Weights
from torchvision import transforms
from PIL import Image
# 加載預(yù)訓(xùn)練模型,去掉分類層
model = resnet50(weights=ResNet50_Weights.IMAGENET1K_V1)
model = torch.nn.Sequential(*list(model.children())[:-1])
model.eval()
# 預(yù)處理圖片
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
])
# 提取特征
image = Image.open('小卡.png')
image_tensor = transform(image).unsqueeze(0)
features = model(image_tensor)
print(f"特征向量維度: {features.shape}") # 輸出: (1, 2048, 1, 1)
2.3 向量數(shù)據(jù)庫(kù)的學(xué)習(xí)
在圖片相似度檢索中,傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)無(wú)法勝任。向量數(shù)據(jù)庫(kù)專門為高維向量的相似度搜索而優(yōu)化,能在千萬(wàn)級(jí)數(shù)據(jù)中快速響應(yīng),這是傳統(tǒng)數(shù)據(jù)庫(kù)無(wú)法比擬的。
在實(shí)際應(yīng)用中,我選擇了Milvus作為向量數(shù)據(jù)庫(kù)。除了Milvus,市面上還有其他不錯(cuò)的選擇:
- Pinecone: 云原生向量數(shù)據(jù)庫(kù)服務(wù)
- Weaviate: 支持多模態(tài)搜索的向量數(shù)據(jù)庫(kù)
- Qdrant: 高性能的向量搜索引擎
2.4 HNSW索引算法的理解
在深入了解向量數(shù)據(jù)庫(kù)時(shí),我發(fā)現(xiàn)了一個(gè)關(guān)鍵技術(shù):HNSW(Hierarchical Navigable Small World)索引。需要說(shuō)明的是,HNSW并不保證100%精確的結(jié)果,它是一種近似最近鄰搜索算法,通過(guò)犧牲少量精度來(lái)?yè)Q取巨大的性能提升。
HNSW索引結(jié)構(gòu)示意圖
HNSW索引結(jié)構(gòu)示意圖
如上圖所示,HNSW構(gòu)建了多層圖結(jié)構(gòu):
- 頂層(Layer 2):少量節(jié)點(diǎn),紅色路徑快速縮小搜索范圍
- 中層(Layer 1):節(jié)點(diǎn)適中,進(jìn)一步細(xì)化搜索
- 底層(Layer 0):包含所有數(shù)據(jù)點(diǎn),進(jìn)行精確搜索
搜索過(guò)程沿著紅色路徑:從頂層入口快速跳躍到目標(biāo)區(qū)域,然后逐層下降細(xì)化搜索。這種"先粗后細(xì)"的策略實(shí)現(xiàn)了亞秒級(jí)的相似度檢索。
2.5 相似性度量:從語(yǔ)義理解到數(shù)學(xué)計(jì)算
在學(xué)習(xí)過(guò)程中,我發(fā)現(xiàn)了一個(gè)很有意思的轉(zhuǎn)換:如何將人類對(duì)圖片相似性的主觀判斷轉(zhuǎn)換為計(jì)算機(jī)可以處理的數(shù)學(xué)問(wèn)題。
經(jīng)過(guò)網(wǎng)上搜索和學(xué)習(xí),我找到了幾種常用的向量距離計(jì)算算法,并做了對(duì)比分析:
算法名稱 | 計(jì)算原理 | 特點(diǎn) | 適用場(chǎng)景 |
余弦相似度(Cosine) | 計(jì)算向量夾角余弦值 | 不受向量長(zhǎng)度影響,關(guān)注方向性 | 文本相似度、圖片特征匹配 |
歐幾里得距離(L2) | 計(jì)算兩點(diǎn)間直線距離 | 幾何意義明確,高維空間易受維度詛咒影響 | 低維數(shù)據(jù)、精確匹配 |
曼哈頓距離(L1) | 計(jì)算坐標(biāo)軸方向距離之和 | 計(jì)算簡(jiǎn)單,對(duì)異常值魯棒,不考慮對(duì)角線距離 | 網(wǎng)格化數(shù)據(jù)、城市距離 |
內(nèi)積相似度(IP) | 計(jì)算向量?jī)?nèi)積 | 計(jì)算高效,同時(shí)考慮方向和大小,受向量長(zhǎng)度影響 | 推薦系統(tǒng)、特征權(quán)重敏感場(chǎng)景 |
漢明距離(Hamming) | 計(jì)算不同位置的數(shù)量 | 適合二進(jìn)制數(shù)據(jù),僅限等長(zhǎng)序列 | 二進(jìn)制特征、錯(cuò)誤檢測(cè) |
通過(guò)這種"語(yǔ)義→向量→數(shù)學(xué)計(jì)算"的轉(zhuǎn)換,我們成功地將人類的視覺(jué)判斷能力賦予了計(jì)算機(jī)系統(tǒng),實(shí)現(xiàn)了從主觀的"像不像"到客觀的數(shù)值計(jì)算。
3.解決實(shí)際應(yīng)用問(wèn)題
3.1 目標(biāo)檢測(cè)的必要性
在實(shí)際測(cè)試中,我發(fā)現(xiàn)用戶上傳的圖片往往包含大量無(wú)關(guān)信息。比如識(shí)別小卡時(shí),圖片中還有桌子、手機(jī)等干擾元素。直接對(duì)整張圖片向量化,識(shí)別效果很差。
需要先把商品從復(fù)雜背景中"摳"出來(lái),再進(jìn)行相似度計(jì)算。經(jīng)過(guò)調(diào)研,我選擇了YOLO(You Only Look Once)作為目標(biāo)檢測(cè)的解決方案,YOLO能夠在保證準(zhǔn)確性的同時(shí)實(shí)現(xiàn)實(shí)時(shí)檢測(cè)。
下面是一個(gè)簡(jiǎn)單的YOLO目標(biāo)檢測(cè)代碼示例:
from ultralytics import YOLO
model = YOLO('yolov8n.pt')
# 檢測(cè)圖片中的物體
results = model('小卡.png')
# 顯示結(jié)果
results[0].show()
yolo目標(biāo)檢測(cè)
3.2 數(shù)據(jù)標(biāo)注的挑戰(zhàn)
我們的業(yè)務(wù)場(chǎng)景比較特殊,主要是二次元相關(guān)物品(明星小卡、手辦、徽章等),通用模型識(shí)別不了,只能自己標(biāo)注數(shù)據(jù)。
選擇了Label Studio作為標(biāo)注工具:
- 界面直觀,學(xué)習(xí)成本低
- 支持團(tuán)隊(duì)協(xié)作
- 導(dǎo)出格式兼容YOLO
# 1. 安裝Label Studio
pip install label-studio
# 2. 啟動(dòng)服務(wù)
label-studio start
# 3. 瀏覽器訪問(wèn) http://localhost:8080
# 首次使用需要注冊(cè)賬號(hào)
Label Studio標(biāo)注演示
標(biāo)注了大概200張圖片后,發(fā)現(xiàn)這活兒比想象中累多了,簡(jiǎn)直是"鼠標(biāo)點(diǎn)到手抽筋"?? 標(biāo)注工作完成后就可以進(jìn)行數(shù)據(jù)導(dǎo)出了,為后續(xù)模型訓(xùn)練提供基礎(chǔ)。
Label Studio數(shù)據(jù)導(dǎo)出
3.3 訓(xùn)練實(shí)踐經(jīng)驗(yàn)
有了標(biāo)注數(shù)據(jù)后,就可以開(kāi)始訓(xùn)練了。說(shuō)實(shí)話,之前看到Y(jié)OLO訓(xùn)練的教程都覺(jué)得很復(fù)雜,各種參數(shù)配置讓人頭大。但實(shí)際動(dòng)手后發(fā)現(xiàn),核心代碼其實(shí)很簡(jiǎn)潔:
from ultralytics import YOLO
# 準(zhǔn)備訓(xùn)練和驗(yàn)證數(shù)據(jù)集(整理圖片和標(biāo)注文件)
prepare_dataset()
# 開(kāi)始訓(xùn)練
model = YOLO('yolov8n.pt')
results = model.train(
data='dataset/dataset.yaml', # 數(shù)據(jù)集配置文件
epochs=200, # 訓(xùn)練輪數(shù)
imgsz=640, # 輸入圖片尺寸
batch=32, # 批次大小
device=0, # GPU設(shè)備號(hào)(0=第一塊GPU, 'cpu'=使用CPU)
patience=20 # 早停輪數(shù)
)
yolo訓(xùn)練日志輸出
第一次運(yùn)行的時(shí)候心情還挺忐忑的,畢竟只有200多張圖片,不知道能不能訓(xùn)練出什么效果。結(jié)果讓我挺意外的:
- 訓(xùn)練速度比想象中快,RTX 4090跑了2分多鐘就完成了
- 最終mAP達(dá)到了97.6%,這個(gè)數(shù)字看起來(lái)還不錯(cuò)
- 模型文件只有6MB左右,很輕量
關(guān)于訓(xùn)練速度:一開(kāi)始用CPU訓(xùn)練,慢得我懷疑程序卡死了?? 后來(lái)花幾塊錢租了個(gè)GPU,嘿,2分鐘搞定!果然貧窮限制了想象力...
關(guān)于mAP指標(biāo):mAP可以理解為檢測(cè)準(zhǔn)確率,97.6%意味著模型在識(shí)別小卡方面表現(xiàn)很優(yōu)秀,90%以上就算是實(shí)用級(jí)別了。
訓(xùn)練完成后,迫不及待地測(cè)試了一下效果。寫(xiě)了個(gè)簡(jiǎn)單的檢測(cè)腳本:
from ultralytics import YOLO
model = YOLO('best.pt')
results = model('test_model_image.jpg')
results[0].show() # 顯示檢測(cè)結(jié)果
yolo訓(xùn)練后結(jié)果
看到檢測(cè)框準(zhǔn)確地框出了小卡,那一刻還是挺有成就感的。雖然數(shù)據(jù)量不大,但至少證明了這個(gè)思路是可行的。
第一次訓(xùn)練的幾個(gè)收獲:
- 數(shù)據(jù)質(zhì)量比數(shù)量重要 - 200張精心標(biāo)注的圖片效果已經(jīng)不錯(cuò)
- GPU確實(shí)快 - 相比CPU訓(xùn)練,速度提升明顯
- YOLO真的很好用 - 幾行代碼就能完成整個(gè)訓(xùn)練流程
4.未來(lái)規(guī)劃
學(xué)完了這些技術(shù),腦子里已經(jīng)有了一個(gè)完整系統(tǒng)的雛形。雖然現(xiàn)在還停留在理論和實(shí)驗(yàn)階段,但我覺(jué)得可以分享一下我的規(guī)劃思路。
4.1 理想中的系統(tǒng)架構(gòu)
我畫(huà)了一個(gè)理想化的系統(tǒng)流程圖,把前面學(xué)到的技術(shù)都串聯(lián)起來(lái):
商品拍圖識(shí)款系統(tǒng)完整流程圖
整個(gè)系統(tǒng)分成四個(gè)核心環(huán)節(jié):
- 模型訓(xùn)練環(huán)節(jié):通過(guò)Label Studio標(biāo)注數(shù)據(jù),訓(xùn)練出專門的YOLO檢測(cè)模型
- 數(shù)據(jù)預(yù)處理環(huán)節(jié):用訓(xùn)練好的模型批量處理存量商品圖片,提取特征向量存入向量數(shù)據(jù)庫(kù)
- 實(shí)時(shí)檢索環(huán)節(jié):用戶上傳圖片時(shí),先用YOLO檢測(cè)出商品區(qū)域,再提取特征進(jìn)行相似度搜索
- 反饋優(yōu)化環(huán)節(jié):收集用戶反饋,分析錯(cuò)誤樣本,持續(xù)優(yōu)化模型效果
這個(gè)架構(gòu)看起來(lái)挺完美的,但實(shí)際落地肯定會(huì)遇到各種意想不到的問(wèn)題。
4.2 當(dāng)前進(jìn)展與挑戰(zhàn)
坦率地說(shuō),目前這些都還是紙上談兵。雖然各個(gè)技術(shù)環(huán)節(jié)我都單獨(dú)跑通了,但要組裝成一個(gè)穩(wěn)定可用的系統(tǒng),還有很多工作要做:
技術(shù)挑戰(zhàn):
- 數(shù)據(jù)質(zhì)量瓶頸:200張標(biāo)注數(shù)據(jù)還是太少,需要更多樣化的訓(xùn)練樣本
- 訓(xùn)練參數(shù)調(diào)優(yōu):學(xué)習(xí)率、批次大小、數(shù)據(jù)增強(qiáng)策略等超參數(shù)需要反復(fù)試驗(yàn),這個(gè)過(guò)程很耗時(shí)間和算力
- 模型泛化:目前只在小卡上測(cè)試過(guò),其他商品類型的效果未知
- 邊界case處理:模糊圖片、遮擋嚴(yán)重、光線不足等極端情況下的識(shí)別準(zhǔn)確率還需要提升
- 性能優(yōu)化:向量檢索在大規(guī)模數(shù)據(jù)下的響應(yīng)速度還需要優(yōu)化
每解決一個(gè)技術(shù)問(wèn)題,就感覺(jué)離目標(biāo)更近了一步。雖然現(xiàn)在還在實(shí)驗(yàn)室階段,但我相信距離真正可用的產(chǎn)品不會(huì)太遠(yuǎn)。
到時(shí)候真實(shí)用戶的使用場(chǎng)景肯定比我閉門造車想象的更復(fù)雜,也能發(fā)現(xiàn)很多現(xiàn)在想不到的問(wèn)題。這才是最有價(jià)值的學(xué)習(xí)機(jī)會(huì)!
5 寫(xiě)在最后
這次的學(xué)習(xí)和實(shí)踐讓我對(duì)圖片識(shí)別技術(shù)的應(yīng)用有了更深的理解。雖然過(guò)程中遇到了很多困難,但邊學(xué)邊做的過(guò)程還是很有收獲的。
這篇文章記錄的只是我個(gè)人的學(xué)習(xí)過(guò)程和思考,肯定有很多不足的地方。如果有經(jīng)驗(yàn)更豐富的朋友看到了,歡迎指正和交流!
我們也會(huì)持續(xù)分享更多的技術(shù)實(shí)踐經(jīng)驗(yàn),希望能和大家一起進(jìn)步。
關(guān)于作者:曹建濤,轉(zhuǎn)轉(zhuǎn)C2C&寄賣業(yè)務(wù)研發(fā)工程師