比賽 | 京東AI時尚單品檢索:一次小小的嘗試

一 寫在前面

未經(jīng)允許狡耻,不得轉(zhuǎn)載,謝謝猴凹。

前前后后大概集中做了20來天夷狰,第一次嘗試競賽類型的項目,終于磕磕碰碰的走完了整個過程郊霎,雖然沒有取得一個好結(jié)果沼头,但也學(xué)習(xí)了很多的東西。

想來想去還是將整個項目的開展情況以及重點做一個梳理吧书劝,就當(dāng)畫個句號进倍。

期待后期能學(xué)習(xí)到獲獎團(tuán)隊的方案方法,用以反思借鑒购对。

本著不能浪費(fèi)小伙伴寶貴的閱讀時間的原則猾昆,再說一下本篇文章僅僅是個人對于比賽的一次嘗試,是否值得借鑒就請小伙伴自己評估啦~~~

如果有同樣做過這個比賽的大佬路過骡苞,還希望不吝賜教哇垂蜗。(〃'▽'〃)

二 題目介紹及理解

1主要任務(wù)

  1. 主要想法:以圖搜圖楷扬;
  2. 找到與實拍圖最相近的電商展示圖,返回匹配度最高的10個ID贴见;
  3. 每個時尚單品都屬于{上衣烘苹,鞋子,箱包}中的一類片部;
  4. 每個時尚單品均需要根據(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 基本思路

  1. 根據(jù)提供的URL獲取所有的圖片廊鸥;
  2. 根據(jù)給出的坐標(biāo),摳出圖像中的物體小圖片站粟;
  3. 對所有的物品通過網(wǎng)絡(luò)模型提取特征黍图;
  4. 找出跟自己特征最相似的圖片作為檢索結(jié)果;
  5. 根據(jù)測試數(shù)據(jù)對用深度學(xué)習(xí)調(diào)整模型結(jié)構(gòu)及參數(shù)奴烙;

處理這類問題的幾個大步驟都是類似的,基本可以分成:

  1. 數(shù)據(jù)集處理助被;
  2. 模型設(shè)計與實現(xiàn);
  3. 訓(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會有RGBA4個通道甚至有些圖片只有一個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. 主要參考資料

2. 論文重點整理博客

把兩篇論文的重點整理在這里了,如果不想看原文的話也可以看看這2篇博客:

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挣郭,并給出鏈接迄埃。

  1. a_utils_fyq.py
    用于放一些經(jīng)常會被使用的,便于減少其他代碼文件的工作量兑障,增強(qiáng)代碼可讀性侄非。包括:

    • 全局路徑
    • 一些通用函數(shù)(例如根據(jù)圖片地址獲取圖片)
    • 或者完全可以獨(dú)立于其他類的函數(shù)(例如多行向量之間余弦距離的計算)。
  2. 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
  1. a_dataloader_val_fyq.py
    • 用于在驗證時加載單張圖片叠赦;
    • 同時適用于query和rep的圖片加載;
  2. a_dataloader_train_fyq.py
  3. 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
  1. 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
  1. 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)室琢。

這或許就是科研本來的樣子,希望自己能不斷接納挫折盈滴,接納失敗,然后接納成果巢钓。

能想到可以分享的大概就這些了病苗。

與你們共勉症汹。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市烈菌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芽世,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诡壁,死亡現(xiàn)場離奇詭異济瓢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)妹卿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門旺矾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人夺克,你說我怎么就攤上這事箕宙。” “怎么了铺纽?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵柬帕,是天一觀的道長。 經(jīng)常有香客問我狡门,道長陷寝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任其馏,我火速辦了婚禮凤跑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘叛复。我一直安慰自己仔引,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布褐奥。 她就那樣靜靜地躺著咖耘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抖僵。 梳的紋絲不亂的頭發(fā)上鲤看,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機(jī)與錄音耍群,去河邊找鬼义桂。 笑死找筝,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的慷吊。 我是一名探鬼主播袖裕,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼溉瓶!你這毒婦竟也來了急鳄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤堰酿,失蹤者是張志新(化名)和其女友劉穎疾宏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坎藐,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岩馍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年蛀恩,在試婚紗的時候發(fā)現(xiàn)自己被綠了双谆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片励稳。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡驹尼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出程帕,到底是詐尸還是另有隱情地啰,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布亏吝,位于F島的核電站,受9級特大地震影響惜论,放射性物質(zhì)發(fā)生泄漏馆类。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一句喜、第九天 我趴在偏房一處隱蔽的房頂上張望咳胃。 院中可真熱鬧旷太,春花似錦、人聲如沸泳秀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贞瞒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棕洋,已是汗流浹背掰盘。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工愧捕, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人次绘。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓管跺,卻偏偏與公主長得像钢猛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子贩绕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容