手把手教你從零起步構建自己的快速語義搜索模型
雷鋒網按:本文為 AI研習社 編譯的技術博客,原標題 The unreasonable effectiveness of Deep Learning Representations,作者為 Emmanuel Ameisen 。
翻譯 | 付騰 王飛 汪鵬 校對 | 餘杭 整理 | MY
訓練電腦以人類的方式去看圖片
為什麼從相似性搜索做起?
一張圖片勝千言,甚至千行代碼。
很多的產品是基於我們的感知來吸引我們的。比如在瀏覽服裝網站上的服裝,尋找 Airbnb 上的假期租房,或者領養寵物時,物品的顏值往往是我們做決定的重要因素。想要預測我們喜歡什麼樣的東西,看看我們對於事物的感知方法大概就能知道了,因此,這也是一個非常有價值的考量。
但是,如何讓計算機以人類的視角來理解圖片長久以來是計算機科學領域的一大挑戰。直到 2012 年,深度學習在某些感知類任務(比如圖像分類或者目標探測)中開始慢慢地超過了傳統的機器學習方法(比如 方向梯度直方圖,HOG)。關於學界的這次轉變,一個主要的原因就要歸功於深度學習對於在足夠大訓練數據集上面自動提取出有意義的表徵的能力。
Pinterest 中的視覺搜索
此外,這些表徵允許消費者有效地搜索圖像庫,(通過圖像查詢)來獲取與他們剛拍攝的自拍相似的圖像,或者搜索某些特定物品的照片,比如汽車(通過文本查詢)。這方面的常見示例包括 Google 反向圖片搜索服務以及 Google 圖片搜索服務。
根據我們為許多語義理解項目提供技術指導的經驗,我們編寫了一個教程,讓讀者了解如何構建自己的表徵模型,包括圖像和文本數據,以及如何有效地進行基於相似性的搜索。到本文結束時,讀者自己應該能夠從零起步構建自己的快速語義搜索模型,無論數據集的大小如何。
我們的計劃是什麼?
來聊聊優化吧
在機器學習中,有時也和軟體工程一樣,方法總比問題多,每種方法都有不同的權衡。如果我們正在進行研究或本地的產品原型設計,我們可以暫時擺脫效率非常低的解決方案。但是如果我們的目標是要構建一個可維護和可擴展的相似圖像搜索引擎,我們必須考慮到兩點:1. 如何適應數據演變 2. 模型的運行速度。
讓我們先想像幾種解決方案:
方案 1 的工作流程
方案 1:我們建立一個端對端的模型,這個模型使用了我們所有的模型進行訓練。這個模型的輸入是一個圖片,輸出一個數組,這個數組裡的每個元素是輸入圖片和圖片訓練集中的每一個圖片的相似性數值。模型的預測過程運行速度快(因為是單獨的前向計算),但是我們每次添加了新的圖片到圖片訓練集中就需要重新訓練一個新的模型。我們同樣會在模型迭代的過程中碰到一個大問題就是模型的輸出包含太多的類,導致模型的正確優化極端困難。這的確是一個很快的方案,但是在可擴展性上有限制,不能擴展到比較大的數據集上。此外,我們還需要手動給我們的訓練集進行圖片相似性的標定,這將是極其耗時的一項工作。
方案 2 的工作流程
方案 2:另外一種方案是建一個相似性預測模型,這個模型的輸入是兩張圖片,輸出是一個落在區間 0 到 1 範圍內的相似性配對值。這些模型在大型數據集上也能比較準確,但是卻受限於另一個可擴展問題。我們經常需要從一大堆的圖片集中找到相似的圖片,因此我們需要對我們的數據集中的所有可能圖片配對集運行一次相似性模型。假設我們的模型是卷積神經網路(CNN),而且我們有不小的圖片量,那麼整個系統的處理速度就太慢了,簡直無法忍受。此外,這種方案只能用於基於圖片相似性搜索,不能擴展到基於文本的相似性搜索。這種方案可以擴展到大數據集,但是總體的運行時間太慢了。
方法3的工作流程圖
方案 3:有一種更簡單的方法,類似於字嵌入。如果我們為圖像找到一個很有代表性的表示或者嵌入,我們就可以通過觀察它們的矢量彼此之間的距離來計算它們的相似性。這種類型,許多庫都實現了快速解決方案(我們將在這裡使用 Annoy)。此外,如果我們能提前計算出我們資料庫中所有圖像的這些向量,那麼這種方法便可表現出既快速(一次正向傳遞,一種有效的相似性搜索),又可擴展的特點。最後,如果我們設法為我們的圖像和單詞找到常見的嵌入,我們可以使用它們來進行文本到圖像的搜索!
由於其簡單性和高效性,第三種方法將成為本文的重點。
我們該怎樣實現這個過程?
那麼,我們該如何在實際中使用深度學習表示來創建搜索引擎?
我們的最終目標是擁有一個搜索引擎,它可以接收圖像並輸出相似的圖像或標籤,可以接收文本並輸出類似的單詞或圖像。為實現這一目標,我們將經歷以下三個連續的步驟:
為輸入圖片尋找相似的圖片 (圖片 圖片)
為輸入的文字尋找相似的文字 (文本 文本)
為圖像生成標籤,並使用文本搜索圖像 (圖像 文本)
為此,我們將使用嵌入 (embeddings),圖像和文本的矢量表示。一旦我們有嵌入 (embeddings),搜索只是找到靠近我們的輸入向量的向量。
尋找這個向量的方法是計算我們的圖像的嵌入和其他圖像之間的嵌入之間的餘弦相似度。類似的圖像將具有類似的嵌入,意味著嵌入之間的高餘弦相似性。
讓我們從一個數據集開始試驗。
數據集
圖片
我們的圖像數據集由總共 1000 張圖像組成,分為 20 個類別,每個類別下 50 張圖像。此數據集可在此處找到。您可以隨意使用鏈接代碼中的腳本自動下載所有圖像文件。另外感謝 Cyrus Rashtchian,Peter Young,Micah Hodosh 和 Julia Hockenmaier 的數據集。
此數據集包含每個圖像的類別和一組標題。為了使問題的難度增加,並且為了驗證我們的方法的泛化性能,我們將只使用類別,而忽略標題。數據集中總共有 20 個類,如下所示:
圖像示例,我們能看到,標籤很繁雜
我們可以看到我們的標籤非常繁雜:許多照片包含多個類別,標籤並不總是來自最突出的標籤。例如,在右下角,圖像被標記為 chair 而不是 person,雖然 3 人站在圖像的中心,椅子幾乎看不見。
文本
圖像 -> 圖像
從簡單的開始。
我們現在要載入一個在大型數據集(Imagenet)上預先訓練過的模型,這個模型可以在線免費獲取。我們在這裡使用 VGG16,但這種方法適用於任何最近的 CNN 架構。我們使用此模型為我們的圖像生成嵌入。
VGG16 (感謝 Data Wow 博客)
生成嵌入是什麼意思?我們將使用我們預先訓練的模型直到倒數第二層,並存儲激活的值。在下圖中,這過程由綠色突出顯示的嵌入層表示,該嵌入層位於最終分類層之前。
對於我們的嵌入,我們在最終分類層之前使用該層。
一旦我們使用該模型生成圖像特徵,我們就可以將它們存儲到磁碟並重新使用它們而無需再次進行推理!這是嵌入在實際應用中如此受歡迎的原因之一,因為它們可以實現巨大的效率提升。除了將它們存儲到磁碟之外,我們將使用Annoy構建嵌入的快速索引,這將允許我們非常快速地找到任何給定嵌入的最近嵌入。
以下是我們的嵌入。現在每個圖像都由一個大小為 4096 的稀疏向量表示。注意:向量稀疏的原因是我們在激活函數之後取了值,這會將負數歸零。
圖像嵌入
使用我們的嵌入來搜索圖像
我們現在可以簡單地接收圖像,獲取其嵌入,並查看我們的快速索引以查找類似的嵌入,從而找到類似的圖像。
這特別有用,因為圖像標籤通常很嘈雜,並且一般來說圖像比標籤的信息更多。
比如,在我們的數據集中,我們有 cat 和 bottle 這兩個類你覺得這張圖片該標記成哪一個類?
Cat 還是 Bottle? (圖像被縮放到了神經網路下的 224*224 的大小)
正確答案是瓶子。這是實際數據集中經常遇到的問題。將圖像標記為唯一類別的情況是很少的,這就是為什麼我們希望使用更細微的表示。幸運的是,這正是深度學習所擅長的!
讓我們看看使用嵌入的圖像搜索是否比人類標籤更好。
為 dataset/bottle/2008_000112.jpg…這張圖片尋找相似的圖片:
太棒了,我們大多得到更多貓的圖像,這看起來很合理!我們的預訓練網路已經過各種圖像的訓練,包括貓,因此它能夠準確地找到相似的圖像,即使它之前從未接受過這個特定數據集的訓練。
但是,底行中間的一幅圖像顯示了瓶架。一般而言,這種方法能夠很好地找到類似的圖像,但有時我們僅對圖像的一部分感興趣。
例如,給一張貓和瓶子的圖像,我們可能只對相似的貓感興趣,而不是類似的瓶子。
半監督搜索
解決此問題的常用方法是首先使用對象檢測模型,檢測我們的貓,然後對原始圖像的裁剪版本進行圖像搜索。
這增加了巨大的計算開銷,如果可能的話我們希望避免這種開銷。
有一種更簡單的「hacky」方法,包括重新賦予激活的權重。我們通過載入我們最初丟棄的最後一層權重來做到這一點,並且僅使用與我們正在尋找的類的索引相關聯的權重來重新對嵌入進行加權。這個很棒的方法最初是從 Insight 研究員 Daweon Ryu 那裡看到的。例如,在下圖中,我們使用 Siamese cat 類的權重來重新賦予我們數據集上的激活(以綠色突出顯示)的權重。請隨意查看附錄中的筆記,了解實現的細節。
快速獲得加權嵌入。 分類層僅供參考。
讓我們根據 Imagenet 中的第 284 類 Siamese cat 來給我們的激活賦予權值,以此來研究它是如何工作的。
使用加權後的特徵來為 dataset/bottle/2008_000112.jpg 尋找相似的圖片。
我們可以看到搜索一直偏向於尋找孿生類貓物體。我們不再顯示任何瓶子,這個結果很棒。你可能會注意到我們的最後一張照片是一隻羊!這非常有趣,原因更偏向於我們的模型導致了一種不同類型的錯誤,這更適合我們的當前域。
我們已經看到,我們可以通過廣泛的方式搜索類似的圖像,或者通過調整我們的模型所訓練的特定類。
這是一個非常大的進步,但由於我們使用的是一個在 Imagenet 上預訓練的模型,因此我們僅限於 1000 個 Imagenet 的類別。這些類遠非包羅萬象(例如他們缺少一個人的類別),所以我們希望找到更靈活的方式。另外,如果我們只是想在不提供輸入圖像的情況下搜索貓呢?
為了做到這一點,我們不僅僅使用了一些簡單的技巧,還利用了一個能夠理解單詞語義能力的模型。
文本 -> 文本
畢竟沒什麼不同
嵌入文本
繞道自然語言處理(NLP)的領域,我們可以使用類似的方法來索引和搜索單詞。
我們基於GloVe模型載入了一組預先訓練的矢量,這些矢量是通過爬取維基百科的所有內容並學習該數據集中單詞之間的語義關係而獲得的。
就像之前一樣,我們將創建一個索引,這次包含所有 GloVe 向量。然後,我們可以在嵌入層中搜索類似的單詞。
舉個例子,搜索 said , 將會返回一個形如【word, distance】的列表:
["said", 0.0]
["told", 0.688713550567627]
["spokesman", 0.7859575152397156]
["asked", 0.872875452041626]
["noting", 0.9151610732078552]
["warned", 0.915908694267273]
["referring", 0.9276227951049805]
["reporters", 0.9325974583625793]
["stressed", 0.9445104002952576]
["tuesday", 0.9446316957473755]
這似乎非常合理,大多數單詞在含義上與我們的原始單詞非常相似,或代表一個合適的概念。最後的結果(tuesday)也表明這個模型遠非完美,但它會讓我們有一個好的開始。現在,讓我們嘗試在我們的模型中包含單詞和圖像。
一個相當大的問題
使用嵌入層之間的距離作為搜索方法是一種非常通用的方法,但這讓我們對單詞和圖像的表示看使用嵌入層之間的距離作為搜索方法是一種非常通用的方法,但這讓我們對單詞和圖像的表示看起來似乎並不兼容。圖像的嵌入層大小為 4096,而單詞的嵌入大小為 300——我們如何使用一個來搜索另一個?此外,即使兩個嵌入層都是相同的大小,它們也會以完全不同的方式進行訓練,因此圖像和與其相關的單詞很可能不會隨機情況下產生相同的嵌入層。我們需要訓練一個聯合模型。
圖像文本
兩個世界的碰撞融合
現在讓我們創建一個混合模型,可以實現從單詞到圖像,反之亦然。
我們的想法是綜合通過重新訓練我們的圖像模型並改變其標籤的類型這兩種表現。
通常,圖像分類器被訓練為從許多類中選擇一個類別(Imagenet 的 1000 個種類)。這可以轉化為——使用 Imagenet 的示例——最後一層是一個大小為 1000 的向量,表示每個類的概率。這意味著我們的模型沒有語義理解哪些類與其他類相似:將 cat 的圖像識別為 dog 將會導致與將其識別為 airplane. 一樣多的錯誤。
對於我們的混合模型,我們用我們已知類的詞向量替換模型的最後一層。這允許我們的模型學習將圖像的語義映射到單詞的語義,並且意味著類似的類將彼此更接近 (因為 cat 的詞向量比 airplane 更靠近 dog )。我們將預測一個大小為 300 的語義豐富的詞向量,而不是大小為 1000 的目標除了一個全部為 0。
我們通過添加兩個全連接層來實現此目的:
一個大小為 2000 的中間層
一個大小為 300 的輸出層(GloVe 的詞向量的大小)。
這是模型在 Imagenet 上訓練時的樣子:
這是模型現在的樣子:
訓練模型
接著,我們需要在數據集分割成的訓練集上重新訓練我們的模型,以學習預測與圖像標籤相關聯的詞向量。例如,對於一張屬於類別 cat 的圖像,我們嘗試預測與 cat 相關聯的 300 長度的詞向量。
這種訓練需要花費一些時間,但仍然比在 Imagenet 上快得多。作為參考,我的筆記本電腦上沒有 GPU 的情況下需要大約 6-7 個小時。
重要的是要注意這種方法是多麼浪費資源的。與通常的數據集相比,我們在這裡使用的訓練數據(我們數據集的 80%,因此共有 800 張圖像)是微不足道的(Imagenet 有一百萬張圖像,大 3 個數量級)。如果我們使用傳統的分類訓練技術,我們不能指望我們的模型在測試集上表現得非常好,並且肯定不會期望它在全新的示例上表現出色。
一旦我們的模型訓練完成,我們就可以從上面獲得 GloVe 的單詞索引,並通過運行數據集中的所有圖像,將它保存到磁碟,構建新的關於我們的圖像特徵的快速索引。
標記
我們現在只需將我們的圖像提供給我們訓練有素的網路,就可以輕鬆地從任何圖像中提取標籤,並保存輸出成大小為 300 的矢量,並從 GloVe 中找到我們的英語單詞索引中最接近的單詞。讓我們試試這張圖片——雖然它包含各種各樣的物品,但它在 bottle 類中。
以下是生成的標籤:
這是一個非常優秀的結果,因為大多數標籤都非常相關。這種方法雖然還有很大的成長空間,但它現在已經可以很好地掌握圖像中的大多數內容。這個模型學習提取許多相關標籤,甚至從那些未經過訓練的類別中提取!
使用文本搜索圖像
最重要的是,我們可以使用我們的聯合嵌入層來使用任何單詞搜索我們的圖像資料庫。我們只需要從 GloVe 獲取我們預先訓練好的單詞嵌入層,並找到具有最相似嵌入層的圖像(我們通過在模型中運行它們得到)。
使用最少數據進行廣義圖像搜索。
讓我們首先從搜索在我們的訓練集中的「dog」開始:
搜索 「dog"的結果
可以,相當不錯的結果——但是我們可以從任何一個經由這些標籤訓練的分類器中得到這個!讓我們來搜索更困難的關鍵字 「ocean」,這不在我們的數據集中。
搜索 "ocean"的結果
這太棒了——我們的模型理解到 ocean 與 water 類似,並從 boat 類中返回了許多物品。
那麼搜索 "street"的結果又如何呢?
搜索 "street"的結果
在這裡,我們返回的圖像來自許多不同的類別(car, dog, bicycles, bus, person),但大多數都包含或靠近街道,儘管我們在訓練模型時從未使用過這個概念。因為我們通過預先訓練的詞向量來利用外部知識庫來學習從圖像到比簡單類別在語義上更豐富的向量的映射,所以我們的模型可以很好地理解外部知識。
可意會不可言傳
英語已經發展了很久,但還不足以為任何東西都發明一個詞。例如,在發表這篇文章時,沒有英文單詞用來形容「一隻躺在沙發上的貓」,這是一個輸入搜索引擎的完全有效的查詢。如果我們想要同時搜索多個單詞,我們可以使用一種非常簡單的方法,利用詞向量的算術屬性。事實證明,總結兩個詞向量通常非常有效。因此,如果我們只是通過使用 cat 和 sofa 的平均詞向量來搜索我們的圖像,我們會希望獲得一張非常像貓,非常像沙發一樣的圖像,或者在沙發上有貓的圖像。
獲得多個單詞的混合嵌入層
讓我們嘗試使用這種混合嵌入層並進行搜索!
搜索"cat"+"sofa"的結果
這是一個很棒的結果,因為大多數這些圖像都包含一些毛茸茸的動物和一個沙發(我特別喜歡第二排最左邊的圖像,這看起來像沙發旁邊的一堆毛巾)!我們的模型只訓練單個單詞,但可以處理兩個單詞的組合。雖然我們沒有構建像谷歌搜圖這樣的大工程,但對於相對簡單的架構來說,這絕對令人印象深刻。
這種方法實際上可以很自然地擴展到各種領域(請參閱此示例以獲取嵌入層代碼),因此我們很樂意聽到您最終將他實際應用的消息。
結論
我希望你發現這篇文章內容豐富,它揭開了一些基於內容的推薦和語義搜索世界的神秘面紗。如果你有任何問題或意見,或想要分享您使用本教程構建的內容,請在 Twitter 上與我聯繫!
想要從矽谷或紐約的頂級專業人士那裡學習人工智慧?了解有關人工智慧領域的更多信息。
如果您是一家從事 AI 領域的公司,並希望參與進 Insight AI Fellows Program 嗎? 請隨時與我們聯繫。.
感謝 Stephanie Mari, Bastian Haase, Adrien Treuille, and Matthew Rubashkin。
雷鋒網雷鋒網
※小米終於進軍韓國智能手機市場了,然而三星的內心毫無波動
※5G第一版標準凍結不到24小時 首個異廠商新空口實現互通
TAG:雷鋒網 |