一 寫在前面
未經(jīng)允許狡耻,不得轉(zhuǎn)載,謝謝猴凹。
前前后后大概集中做了20來天夷狰,第一次嘗試競賽類型的項目,終于磕磕碰碰的走完了整個過程郊霎,雖然沒有取得一個好結(jié)果沼头,但也學(xué)習(xí)了很多的東西。
想來想去還是將整個項目的開展情況以及重點做一個梳理吧书劝,就當(dāng)畫個句號进倍。
期待后期能學(xué)習(xí)到獲獎團(tuán)隊的方案方法,用以反思借鑒购对。
本著不能浪費(fèi)小伙伴寶貴的閱讀時間的原則猾昆,再說一下本篇文章僅僅是個人對于比賽的一次嘗試,是否值得借鑒就請小伙伴自己評估啦~~~
如果有同樣做過這個比賽的大佬路過骡苞,還希望不吝賜教哇垂蜗。(〃'▽'〃)
二 題目介紹及理解
- 官網(wǎng)介紹: 京東AI時尚挑戰(zhàn)賽-單品檢索
1主要任務(wù)
- 主要想法:以圖搜圖楷扬;
- 找到與實拍圖最相近的電商展示圖,返回匹配度最高的10個ID贴见;
- 每個時尚單品都屬于{上衣烘苹,鞋子,箱包}中的一類片部;
- 每個時尚單品均需要根據(jù)單品坐標(biāo)進(jìn)行摳圖處理镣衡,每張圖片的給定區(qū)域只有一個物品;
2 數(shù)據(jù)集
- 訓(xùn)練數(shù)據(jù):1.2萬個真實的京東時尚單品圖片對P
- 訓(xùn)練數(shù)據(jù):{電商展示圖+用戶實拍圖}
- 測試數(shù)據(jù):2000張用戶實拍圖
- 15萬張全部電商展示圖S
- 都經(jīng)過摳圖档悠,指定好時尚單品的位置坐標(biāo)
3 基本思路
- 根據(jù)提供的URL獲取所有的圖片廊鸥;
- 根據(jù)給出的坐標(biāo),摳出圖像中的物體小圖片站粟;
- 對所有的物品通過網(wǎng)絡(luò)模型提取特征黍图;
- 找出跟自己特征最相似的圖片作為檢索結(jié)果;
- 根據(jù)測試數(shù)據(jù)對用深度學(xué)習(xí)調(diào)整模型結(jié)構(gòu)及參數(shù)奴烙;
處理這類問題的幾個大步驟都是類似的,基本可以分成:
- 數(shù)據(jù)集處理助被;
- 模型設(shè)計與實現(xiàn);
- 訓(xùn)練切诀、測試揩环、優(yōu)化、再重復(fù)2.3
篇幅有限幅虑,太細(xì)節(jié)的東西就不再寫了丰滑。挑一些覺得對自己以后做項目或者對大家會有幫助的東西吧。
三 數(shù)據(jù)集準(zhǔn)備及預(yù)處理
1. 根據(jù)url下載圖片
數(shù)據(jù)集很大的情況倒庵,常常需要我們自己去下載圖片褒墨,這個時候就需要有個程序幫我們自動下載了。
- 用urllib獲取圖片并保存
import urllib
# img_url: the url of image
# img_path: the path you want to save image
urllib.urlretrieve(img_url,img_path)
2. 圖片加載與處理
1. 用PIL加載圖像
from PIL import Image
def get_image_from_path(img_path,img_region):
image = Image.open(img_path)
image = process_image_channels(image, img_path)
image = image.crop(img_region)
return image
2. 關(guān)于crop函數(shù)
- 一定要注意bounding_box的傳入?yún)?shù)擎宝;
- crop接受的參數(shù)為(左上x郁妈,左上y,右下x绍申,右下y)
- python的坐標(biāo)系為最左上角為(0,0)噩咪,橫向x,縱向y极阅;
- 這里踩了好久的坑胃碾。╮(╯﹏╰)╭
3. 關(guān)于處理圖像通道
- 在這次處理的數(shù)據(jù)集中有jpg的圖像,也有png的圖像筋搏;
- 以前從來不知道png會有
RGBA
4個通道甚至有些圖片只有一個A
通道仆百,所以如果沒有提前處理后面訓(xùn)練或者換測試的時候會時不時的給你一個bug小彩蛋哈哈哈。 - 關(guān)鍵語句:
def process_image_channels(image, image_path):
# process the 4 channels .png
if image.mode == 'RGBA':
r, g, b, a = image.split()
image = Image.merge("RGB", (r, g, b))
# process the 1 channel image
elif image.mode != 'RGB':
image = image.convert("RGB")
os.remove(image_path)
image.save(image_path)
return image
3. 訓(xùn)練數(shù)據(jù)集劃分
- 在這類具體的情況中我們往往之后只有訓(xùn)練數(shù)據(jù)奔脐;
- 通常將訓(xùn)練數(shù)據(jù)分成:90%訓(xùn)練集 + 10%測試集儒旬;
- 這一點對于新手還是比較容易被忽略的栏账。
四 理論學(xué)習(xí)與模型確定
1. 主要參考資料
- [TPAMI重磅綜述]SIFT與CNN的碰撞:萬字長文回顧圖像檢索任務(wù)十年探索歷程(上篇)
- [TPAMI重磅綜述]SIFT與CNN的碰撞:萬字長文回顧圖像檢索任務(wù)十年探索歷程(下篇)
- 論文:Learning visual similarity for product design with convolutional neural networks
- 論文:FaceNet: A Unified Embedding for Face Recognition and Clustering
2. 論文重點整理博客
把兩篇論文的重點整理在這里了,如果不想看原文的話也可以看看這2篇博客:
- 論文 | 圖像檢索經(jīng)典論文解讀《Learning visual similarity for product design with convolutional neural networks》
- 論文 | FaceNet臉部識別《FaceNet:A unified embedding for face recognition and clustering》
3 確定baseline模型及基本方案
1. baseline模型
-
選擇了facenet中的網(wǎng)絡(luò)結(jié)果作為基本的baseline;
2. 基本方案
- 深度網(wǎng)絡(luò)模型: 采用在ImageNet上預(yù)訓(xùn)練過的DenseNet161
- 用Densenet161對輸入圖像提取特征栈源;
- 訓(xùn)練過程用triplet loss進(jìn)行訓(xùn)練;
- 驗證及測試直接用向量之間的余弦相似度來表示竖般,選擇最相似的top-10作為輸出結(jié)果甚垦。
五 代碼設(shè)計與編寫
1. 代碼構(gòu)成
-
先上一張整個項目的構(gòu)成圖吧。
- 其中以
a_
開頭的是重構(gòu)后的代碼涣雕,也就是最終使用的艰亮。
2. 各個文件說明
我會對各個文件的構(gòu)成做一個簡單的介紹,然后將重點的部分單獨(dú)整理成blog挣郭,并給出鏈接迄埃。
-
a_utils_fyq.py
用于放一些經(jīng)常會被使用的,便于減少其他代碼文件的工作量兑障,增強(qiáng)代碼可讀性侄非。包括:- 全局路徑
- 一些通用函數(shù)(例如根據(jù)圖片地址獲取圖片)
- 或者完全可以獨(dú)立于其他類的函數(shù)(例如多行向量之間余弦距離的計算)。
-
a_network_fyq.py
- 定義了圖像檢索任務(wù)中用來提取圖像特征的網(wǎng)絡(luò)結(jié)構(gòu)流译。
- 直接用了預(yù)訓(xùn)練好的densenet161逞怨,然后提取它的
features
作為輸出。 - 用pytorch可以很簡單的實現(xiàn)網(wǎng)絡(luò)模型的定義福澡;
- 關(guān)鍵代碼:
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.denseNet161=torchvision.models.densenet161(pretrained=True)
def forward(self,x):
x = self.denseNet161.features(x)
out = x.view(x.size(0), -1)
return out
-
a_dataloader_val_fyq.py
- 用于在驗證時加載單張圖片叠赦;
- 同時適用于query和rep的圖片加載;
-
a_dataloader_train_fyq.py
- 用于在訓(xùn)練時返回(anchor_img,positive_img,negative_img)
- 加載函數(shù)的實現(xiàn)具體參見之間的博客:視頻數(shù)據(jù)集UCF101的處理與加載(用PyTorch實現(xiàn))
-
a_train_nework_fyq.py
- 用于訓(xùn)練圖像檢索神經(jīng)網(wǎng)絡(luò)
- 網(wǎng)絡(luò)訓(xùn)練主要包括:獲取到批量數(shù)據(jù)革砸,然后前向傳播除秀、計算loss值,更新參數(shù)即可算利。
- 可以參見:Pytorch入門學(xué)習(xí)(四)-training a classifier
- triplet_loss的實現(xiàn)也可以通過pytorch自帶的函數(shù)很方便的實現(xiàn)册踩。
- 關(guān)鍵代碼:
def triplets_loss(self,anchor,positive,negative):
triplet_loss=nn.TripletMarginLoss(margin=self.margin,p=2)
output_loss=triplet_loss(anchor,positive,negative)
return output_loss
-
a_image_retrieval.fy
- 用于通過模型得到query以及rep的特征值、計算多行向量之間的余弦距離笔时,然后排序得到top-10結(jié)果棍好。
- 網(wǎng)上有很多向量之間計算余弦距離的代碼可以參考,但是我還沒有找到基于矩陣的允耿。所以就自己琢磨著寫了一下借笙,也分享給大家。
- 多行向量求余弦距離:
def cosine_distance(self, matrix1, matrix2):
matrix1_matrix2 = np.dot(matrix1, matrix2.transpose())
matrix1_norm = np.sqrt(np.multiply(matrix1, matrix1).sum(axis=1))
matrix1_norm = matrix1_norm[:, np.newaxis]
matrix2_norm = np.sqrt(np.multiply(matrix2, matrix2).sum(axis=1))
matrix2_norm = matrix2_norm[:, np.newaxis]
cosine_distance = np.divide(matrix1_matrix2, np.dot(matrix1_norm, matrix2_norm.transpose()))
return cosine_distance
-
a_classifer_fyq.py
- 訓(xùn)練了一個分類器
- 這個文件像是一個小型的項目较锡,囊括了分類任務(wù)的模型定義业稼、數(shù)據(jù)加載、網(wǎng)絡(luò)訓(xùn)練蚂蕴、網(wǎng)絡(luò)測試低散。不過這個也都是大同小異的過程俯邓,寫過一個就可以觸類旁通了。
六 寫在最后
整體的實現(xiàn)過程就是這樣熔号,感覺應(yīng)該也已經(jīng)把最具有學(xué)習(xí)價值的東西提煉出來了稽鞭。
模型最后的精確度并不高,所以細(xì)節(jié)的訓(xùn)練以及測試的結(jié)果并不具有什么可參考的價值引镊,就不再整理了朦蕴。
1. 關(guān)于triplet loss訓(xùn)練中樣本的選擇問題
- 隨機(jī)選擇負(fù)樣本真的效果很不好,親測弟头!
- 在minibatch中在線選擇semi-hard或者h(yuǎn)ard負(fù)樣本的效果也不好吩抓,因為常常會受制于batch_size的大小,也是親測赴恨!
- 建議采用線下選擇負(fù)樣本的方式疹娶。
- 總的來說,用triplet loss來訓(xùn)練檢索模型對于樣本的選擇很重要伦连,不然可能會出現(xiàn)像我一樣越train越差的尷尬局面...
2. 關(guān)于項目運(yùn)行的一點經(jīng)驗
- 有的時候需要對同一個模型做條件不同的測試雨饺,就可以用多腳本的方式,不容易搞混除师。
- 在多塊GPU的機(jī)器上運(yùn)行代碼沛膳,可以用
CUDA_VISIBLE_DEVICES=" "
的方式指定使用某一塊GPU; - 數(shù)據(jù)量很大如果導(dǎo)致顯卡溢出了汛聚,可以采用將數(shù)據(jù)移到CPU的解決方式锹安,
myVariable.cpu().numpy()
; - CPU如果還是內(nèi)存溢出,那就只能選擇手動分段來結(jié)果問題了倚舀。
3. 關(guān)于項目代碼的一點小感觸
這是我自己第一次完完全全一行一行地編寫完一個完整的項目叹哭,算是這次學(xué)到的很寶貴的財富了吧。
自己重構(gòu)過幾遍代碼真的很重要痕貌,會更好的知道怎么樣把一個大的事情一點一點的拆小风罩,也會慢慢形成一個自己寫代碼的風(fēng)格與習(xí)慣。
看自己寫的東西最酥糊了嘻嘻?(????ω????)?
4. 關(guān)于科研的一點感悟
想點子舵稠、編程實現(xiàn)超升、實驗,然后重復(fù)循環(huán)室琢。
這或許就是科研本來的樣子,希望自己能不斷接納挫折盈滴,接納失敗,然后接納成果巢钓。
能想到可以分享的大概就這些了病苗。
與你們共勉症汹。