01.22 將距離度量學習應用於購物問題

將距離度量學習應用於購物問題

讓我們先描述我們的購物問題:在用戶圖像中識別時尚商品並在網上商店中找到它。您是否曾經在街上看到某人,並想過:“哇,這是一件漂亮的衣服,我想知道在哪裡可以買到它?”對我而言,嘗試距離度量學習技術是一項很酷的任務。我希望您也會發現它有趣。

數據集

首先,我們需要一個數據集。實際上,當我發現Aliexpress上的用戶拍攝了大量圖像後,便想到了這個想法。我想“哇,我當然可以用這些數據來按圖像搜索”。為了簡單起見,我決定專注於女士上裝。

以下是我使用的類別列表:

  • 洋裝
  • 襯衫和襯衣
  • 帽衫和針織衫
  • 毛衣
  • 外套和大衣

我使用python的requests包和BeautifulSoup包進行了收集數據。賣家圖像可以從商品的主頁獲取,但是對於用戶的圖像,我們需要瀏覽反饋頁面。商品頁面上有一個叫做“顏色”的東西。顏色可以只是商品相同樣式的不同顏色,甚至可以完全是其他商品。因此,我們將不同的顏色視為不同的商品。

將距離度量學習應用於購物問題

您可以通過以下鏈接找到我用來獲取關於一個商品的所有信息的代碼(它甚至比我們的任務所需的還要多)

https://github.com/movchan74/streettoshopexperiments/blob/master/getitem_info.py

我們所需要的是通過每個類別的搜索頁面,獲取所有商品的url,並使用上面的函數來獲取每個商品的信息。

最後,我們將為每個商品提供兩組圖像:來自銷售者的圖像(每個元素item['colors']的字段url)和來自用戶的圖像(每個元素item['feedbacks']的字段imgs)。

對於每種顏色,我們只有一個來自賣方的圖像,但是對於每種顏色,我們可以有多個來自用戶的圖像(有時根本沒有用於顏色的圖像)。

太棒了!我們得到了數據。但是,收集到的數據集是有噪聲的:

  • 有來自用戶的噪聲圖像(包裝盒的照片,紋理的照片或只是一個商品的一部分,未包裝的商品,不相關的照片)。
將距離度量學習應用於購物問題

將距離度量學習應用於購物問題

將距離度量學習應用於購物問題

為了解決這個問題,我把5000張圖片分成兩類:好圖片和噪聲圖片。一開始,我的計劃是訓練兩個類別的分類器並使用它來清理數據集。但是後來我決定把這個想法留到以後的工作中,只是把清理過的圖像添加到測試和驗證集中。

  • 第二個問題是有些商品是由幾個賣家出售的。賣家有時甚至會有相同的圖片(或稍微編輯過的圖片)。但是如何處理呢?最簡單的方法是什麼也不做,使用一個健壯的算法來學習距離度量。但是它會影響驗證,因為我們可以在驗證和訓練數據中有相同的商品。這就導致了不正確。另一種方法是使用一些東西來尋找相似(甚至相同的圖像)並將它們合併到一個商品中。我們可以使用感知哈希來尋找相同的圖像(如phash或whash),或者我們可以在有噪聲的數據上訓練一個模型,並應用該模型來尋找相似的圖像。我選擇了第二個選項,因為它允許合併稍微編輯過的圖像。

距離度量學習

最流行的距離度量學習方法之一是三元組損失:

將距離度量學習應用於購物問題

其中max(x,0)是鉸鏈函數,d(x,y)是x與y之間的距離函數,F(x)是深層神經網絡,M是間隔,a是錨點,p是正樣本,n是負樣本。

F(a),F(p),F(n)是由深層神經網絡產生的高維空間(嵌入)中的點。值得一提的是,通常需要將embedding標準化為具有單位長度,即 ||x|| = 1,以便對照明和對比度變化具有魯棒性,並具有訓練穩定性。錨和正樣本屬於同一個類,負樣本是另一個類的樣本。

但如何選擇(a, p, n)呢?我們可以隨機選擇樣本作為三元組,但這會導致以下問題。首先,可能有N³三元組。這意味著我們需要很多時間來研究所有可能的三元組。但實際上,我們不需要這樣做,因為經過幾次反覆的訓練後,會有許多三元組不違反三元組約束(零損失)。這意味著這些三元組對於訓練來說是無用的。

三元組選擇的最常見方式之一是難負樣本挖掘(hard negative mining):

將距離度量學習應用於購物問題

在實踐中,選擇最困難的負樣本會在訓練的早期導致糟糕的局部最小值。具體來說,它可以導致一個崩潰的模型(即F(x) = 0)。

半難負樣本(Semi-hard negative samples)比陽性樣本離錨點更遠,但它們仍然是難的(違反約束),因為它們位於間隔M之內。

將距離度量學習應用於購物問題

有兩種方法可以生成半難(和難)負樣本:在線和離線。

  • 在線意味著我們從訓練數據集中隨機選擇一個大batch,並從其中的樣本中選擇三元組。然而,我們需要一個大的batch。這在我的情況下是不可能的,因為我只有一個帶有8Gb RAM的GTX 1070。
  • 在離線方法中,我們需要在一段時間後停止訓練,預測一定數量樣本的嵌入,選擇三個一組,用這些三個一組訓練模型。這意味著我們需要向前傳遞兩次,但這是離線方法的代價。

好!我們已經可以用triple損失和離線半難負樣本挖掘來訓練模型。但是,我們還需要一個技巧來成功地解決我們原本的問題。我們的任務是找到最接近用戶形象的賣家形象。然而,通常賣方的圖像比用戶的圖像有更好的質量(在照明,相機,位置),所以我們有兩個域:賣方的圖像和用戶的圖像。為了得到有效的模型,我們需要縮小這兩個域之間的差距。這個問題稱為域適應。

將距離度量學習應用於購物問題

將距離度量學習應用於購物問題

上:用戶的圖像,下:賣方的圖像

我提出了一種非常簡單的技術來縮小域差距:讓我們從賣方的圖像中選擇錨點,從用戶的圖像中選擇正樣本和負樣本。就這樣!簡單而有效。

實現

為了實現我的想法和做實驗我已經使用Tensorflow後端的Keras庫。

我選擇了Inception V3模型作為模型的基礎CNN。和往常一樣,我使用ImageNet權重初始化了CNN。在網絡末端使用L2標準化進行全局池化之後,我添加了兩個完全連接的層。嵌入的大小為128。

<code>def get_model():
no_top_model = InceptionV3(include_top=False, weights='imagenet', pooling='avg')

x = no_top_model.output
x = Dense(512, activation='elu', name='fc1')(x)
x = Dense(128, name='fc2')(x)
x = Lambda(lambda x: K.l2_normalize(x, axis=1), name='l2_norm')(x)
return Model(no_top_model.inputs, x)/<code>

我們還需要實現triple損失功能。我們將錨點,正/負樣本作為單個小批量傳遞,並將其分為損失函數內的3個張量。距離函數是歐幾里德距離的平方。

<code>def margin_triplet_loss(y_true, y_pred, margin, batch_size):
out_a = tf.gather(y_pred, tf.range(0, batch_size, 3))
out_p = tf.gather(y_pred, tf.range(1, batch_size, 3))
out_n = tf.gather(y_pred, tf.range(2, batch_size, 3))

loss = K.maximum(margin
+ K.sum(K.square(out_a-out_p), axis=1)
- K.sum(K.square(out_a-out_n), axis=1),
0.0)
return K.mean(loss)/<code>

編譯模型:

<code>from functools import partial, update_wrapper
def wrapped_partial(func, *args, **kwargs):
partial_func = partial(func, *args, **kwargs)
update_wrapper(partial_func, func)
return partial_func

opt = keras.optimizers.Adam(lr=0.0001)
model.compile(loss=wrapped_partial(margin_triplet_loss, margin=margin, batch_size=batch_size), optimizer=opt)/<code>


實驗結果

將距離度量學習應用於購物問題

績效以召回率K(R@K)進行衡量。讓我們看一下如何計算R@K。每個用戶的圖像驗證集作為一個查詢,我們需要找到相應的賣家的圖像。我們取一個查詢圖像,計算嵌入向量,並在所有賣方圖像的向量中搜索該向量的最近鄰居。我們不僅使用來自驗證集的賣方圖像,還使用來自訓練集的圖像,因為它允許增加干擾物,使我們的任務更具挑戰性。

我們有一個查詢圖像和一個最相似的賣家圖像列表。如果在K個最相似的圖像中有對應的銷售者圖像,那麼我們為這個查詢返回1,否則返回0。現在,我們需要為驗證集中的每個用戶的圖像創建它,並從每個查詢中找到平均得分為R@K。

正如我之前所說的,我已經從有噪聲的圖像中清除了少量的用戶圖像。因此,我在兩個驗證數據集上測量了模型的性能,分別是完整的驗證集和只有乾淨圖像的子集。

將距離度量學習應用於購物問題

結果遠非理想,有很多事情要做:

  • 清除用戶圖像中的噪聲。我已經在這個方向上邁出了第一步,清理了一小部分。
  • 更準確地合併項目(至少在驗證集中)。
  • 減少域差距。我認為可以通過特定領域的增強(例如燈光增強)和使用專門的方法(比如https://arxiv.org/abs/1409.7495)來實現。
  • 應用另一種距離度量學習技術。我試過這個https://arxiv.org/abs/1703.07464,但在我的情況下效果更差。
  • 收集更多的數據。

Demo,代碼和訓練好的模型

我已經對該模型進行了演示。您可以在這裡查看:http://vps389544.ovh.net:5555/

您可以上傳自己的圖片進行搜索,也可以使用驗證集中的隨機圖片。

代碼和訓練好的模型:http://vps389544.ovh.net:5555/.


分享到:


相關文章: