版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
摘要圖像數(shù)據(jù)集有幾種來源:一是網(wǎng)絡(luò)公開數(shù)據(jù)集,數(shù)量少、針對性弱;二是向圖片提供商購買,價(jià)格昂貴;三是雇專人進(jìn)行圖像采集,采集周期長、特殊場景難。各有優(yōu)劣、搭配使用,但仍經(jīng)常出現(xiàn)數(shù)據(jù)集較小導(dǎo)致模型訓(xùn)練效果一般的情況。因此,需要一個(gè)成本較低同時(shí)效果較好的高性價(jià)比解決方案。常用的幾種圖像數(shù)據(jù)集來源均是新入數(shù)據(jù),而舊數(shù)據(jù)集即被棄置。由此入手,可以將以前項(xiàng)目的圖像數(shù)據(jù)集進(jìn)行整理、再利用,生成一個(gè)可以適用新項(xiàng)目的數(shù)據(jù)集。以前項(xiàng)目使用的數(shù)據(jù)集通常是只使用圖像中的一部分信息,而翻新使用需要全部信息,因此仍需要將舊數(shù)據(jù)集重新整理,通過特征提取將圖片信息按照統(tǒng)一標(biāo)準(zhǔn)存儲到數(shù)據(jù)庫中。另外,項(xiàng)目中的數(shù)據(jù)集通常數(shù)量巨大,檢索速度也是亟待解決的問題,因此可以通過乘積量化器度量相似性的方式,犧牲小部分不重要的特征而大幅度提高檢索效率。通過以上兩方面優(yōu)化,可以實(shí)現(xiàn)千萬甚至上億級別的圖像數(shù)據(jù)庫在毫秒級別的時(shí)間內(nèi)完成檢索,并重新整理為新數(shù)據(jù)集,供新項(xiàng)目使用。關(guān)鍵詞:數(shù)據(jù)集復(fù)用;圖像檢索;特征提取;索引存儲
引言隨著科技的不斷進(jìn)步,Web1.0的簡單的通過瀏覽器獲取信息的時(shí)代已經(jīng)過去,迎來了交互性更強(qiáng)的Web2.0,我們用戶既是內(nèi)容的消費(fèi)者,同時(shí)又扮演了生產(chǎn)者的重要角色。在這種情況下,催生出了許多社交媒體網(wǎng)站,存儲的數(shù)據(jù)量也在迅速增長。臉書至今已有超過30億月活用戶,作為全球最火爆的社交系統(tǒng),中國最大的電商阿里巴巴旗下淘寶,后臺存儲了數(shù)以百萬計(jì)的圖像資料;而在知名圖片社交網(wǎng)站Flickr上,用戶上傳的圖片數(shù)目已達(dá)十億級別,平均每日圖片上傳量也已將近千萬級。面對如此巨大的圖像數(shù)據(jù)庫,如何在浩瀚無垠的圖像“海洋”中精準(zhǔn)定位并提取出用戶所需要的圖像數(shù)據(jù),便是現(xiàn)在圖像識別、視頻檢索領(lǐng)域研究的熱點(diǎn)方向。眾所周知,人工圖像標(biāo)注需要消耗大量的人力、物力和財(cái)力,最后獲得的結(jié)果可能也不是很準(zhǔn)確,造成了許多資源的浪費(fèi),因此,我們需要不斷探索更加先進(jìn)智能化的圖像檢索方法,利用高性能服務(wù)器可以進(jìn)行高并發(fā)任務(wù)的巨大優(yōu)勢,用機(jī)器標(biāo)注代替人工標(biāo)注,同時(shí)也可以減少一些因?yàn)槿斯ざ鴰淼牟槐匾氖д`。歷經(jīng)十多年的不斷發(fā)展,一些圖像檢索技術(shù)已經(jīng)廣泛地應(yīng)用于我們的生活的方方面面,尤其是在搜索引擎、電子商務(wù)、生物醫(yī)學(xué)、工業(yè)紡織等與我們生活息息相關(guān)的領(lǐng)域。開發(fā)環(huán)境配置本地環(huán)境搭建Faiss庫使用C++編寫,并提供了Python接口,支持高維度搜索、速度快且對GPU優(yōu)化較好。如需使用C++庫,需要自行編譯,而Python版本在conda庫中直接提供[1]。以下會一一介紹安裝:源碼編譯安裝源代碼編譯主要分為配置、編譯安裝C++庫、編譯安裝Python庫三個(gè)步驟[2]。圖2.1通過源代碼編譯過程如圖2.1所示,通過源代碼編譯總共分為以下幾步:(1)Line1:為Makefile生成與系統(tǒng)有關(guān)的配置文件,并存儲在當(dāng)前目錄下名為makefile.inc的文件中。在配置時(shí),有幾個(gè)可選項(xiàng)可通過額外參數(shù)進(jìn)行設(shè)置:–without-cuda:這個(gè)參數(shù)被用于只構(gòu)建CPU部分,而不構(gòu)建GPU部分[3];–with-cuda=“$cuda_path”:輸入cuda-toolkit的路徑;–with-cuda-arch=”-gencode=arch=compute_75,code=sm_75-gencode=arch=compute_72,code=sm_72:輸入需要構(gòu)建的GPU架構(gòu)型號編碼–with-python=“$python_version_path”:設(shè)置不同于默認(rèn)版本的Python版本路徑信息,以建立特定Python版本地接口;LDFLAGS=“$LD_LIBRARY_PATH”:設(shè)置LD_LIBRARY_PATH以便configure時(shí)可以檢測到MKL_BLAS配置;(2)Line2:這將構(gòu)建C++庫(如果找到了合適的cuda工具包,則為整個(gè)庫,否則為CPU部分)??梢允褂?j4進(jìn)行CPU的多線程加速,并使用-w選項(xiàng)不輸出warning提示信息。Makeinstall實(shí)際為可選項(xiàng),用于安裝頭文件和庫文件。(3)Line3:這個(gè)會構(gòu)建Python層并安裝Python庫。其中值得注意的是,如果需要構(gòu)建Python層,需要安裝C++的swig,這是一個(gè)用于把C/C++代碼封裝為庫的工具。使用Conda安裝FacebookResearch團(tuán)隊(duì)已設(shè)置在pytorch的conda倉庫自動推送更新stablerelease(穩(wěn)定發(fā)布版本)文件庫,可以直接從Anaconda中安裝Faiss庫。其中,可以為Linux和macOS系統(tǒng)下載到CPU版本的Faiss庫,同時(shí)還提供了GPU版本的Faiss庫,并配有可以直接在Linux操作系統(tǒng)上運(yùn)行的CUDA8/CUDA9/CUDA10不同的已經(jīng)編譯好的版本[4]。圖2.2使用conda庫安裝Faiss庫如圖2.2所示,可以輕松地通過以上命令進(jìn)行安裝,只需要注意好CPU還是GPU版本即可。圖2.3使用pip進(jìn)行安裝當(dāng)然,也可以直接使用pip進(jìn)行(需要主要好自身Python版本,Python2使用pip命令,Python3使用pip3命令)。不過,由于Python本身不像Anaconda直接帶有CUDA與OpenCV庫,所以只能安裝CPU版本的[5]。我的電腦是MacbookPro15’2016款,由于macOS不支持Nvidia型號的顯卡,因此只能安裝CPU版本。而在另一臺Linux電腦系統(tǒng)上安裝了CUDA10版本的GPU版Faiss庫。使用Docker構(gòu)建如今,除了寫代碼之外,還需要更多的東西來發(fā)展。在各個(gè)生命周期的各個(gè)時(shí)期,不同的編程語言、架構(gòu)、架構(gòu)和斷開的界面都會導(dǎo)致非常復(fù)雜的問題。Docker讓你在為每一個(gè)專案中的工具、應(yīng)用程式和部署環(huán)境中自由地挑選創(chuàng)意,從而簡化和加快你的工作過程。因此,我也本著“能Docker,絕不install”的態(tài)度搜索了一下DockerHub,果然找到了想要的Dockerimage(鏡像文件),名為“illagrenan/faiss-python”,下載即可使用,也為后面在服務(wù)器上進(jìn)行一鍵化部署打下了基礎(chǔ)。服務(wù)器環(huán)境搭建圖2.4Dockerfile文件在服務(wù)器中,使用源碼編譯或者conda安裝都顯得比較累贅,因此選擇Docker進(jìn)行安裝是最方便的形式[6]。我選擇了網(wǎng)上已有的Dockerimage為plippe/faiss-web-service作為基礎(chǔ)鏡像,其中我所需要的環(huán)境Faiss、Flask都已經(jīng)安裝好了,如圖2.4所示,還加入了OpenCV3.2用于特征提取,這樣就可以直接在Docker內(nèi)訓(xùn)練Faiss索引了。Faiss算法庫Faiss簡介Faiss是什么Faiss是一種有效的相似度檢索和向量聚集的圖書館。該方法包括一個(gè)可以查找任何尺寸的矢量,即使是不適用于RAM的矢量[7]。還包含了評價(jià)和參數(shù)調(diào)節(jié)的支撐編碼。使用C++和Python的全部封裝(第2版和第3版)。一些最有用的算法在GPU上實(shí)現(xiàn)。Faiss中的最近鄰搜索算法給定維數(shù)為d的向量xi的集合,F(xiàn)aiss用它在RAM中建立一個(gè)數(shù)據(jù)結(jié)構(gòu)。構(gòu)造結(jié)構(gòu)后,在給定維度d的新向量x時(shí),它將有效地執(zhí)行以下操作:i=argmin如果用Faiss來表達(dá),那么這個(gè)資料結(jié)構(gòu)就是帶有添加矢量的add方式的一個(gè)指數(shù)。請記住,假定是不變的。argmin的運(yùn)算是在檢索中進(jìn)行的[8]。這是Faiss所有的目的。也可以:(1)不但可以傳回最近的鄰近,也可以傳回最近的鄰近的一個(gè);(2)代替逐個(gè)地進(jìn)行檢索(批次),一次對多個(gè)矢量進(jìn)行檢索。這將大大加快很多的指數(shù)類型的查找速度;(3)準(zhǔn)確率,以速率計(jì),例如采用快10倍、慢10倍記憶量的方式,或10%的誤差值;(4)執(zhí)行最大的內(nèi)積搜索argmaxi(5)在指定的半徑中(區(qū)域檢索)中,將查詢點(diǎn)中的全部要素(區(qū)域檢索);(6)在硬盤上而非在運(yùn)行記憶體中保存該指數(shù)。簡單測試Faiss所Faiss的整體應(yīng)用程序可以分成三個(gè)步驟:1.構(gòu)造(表示為矩陣)的培訓(xùn)數(shù)據(jù);2.選擇適當(dāng)?shù)腎ndex(Faiss的內(nèi)核組件),在Index中添加培訓(xùn)數(shù)據(jù);3.搜尋,即搜尋,得出最終的答案[9]。構(gòu)建訓(xùn)練數(shù)據(jù)圖3.1構(gòu)建訓(xùn)練數(shù)據(jù)上面的代碼中,生成了訓(xùn)練數(shù)據(jù)矩陣xb和查詢數(shù)據(jù)矩陣xq。如圖3.1所示,為了增加隨機(jī)性,我在xd和xq中的數(shù)據(jù)里,分別在他們的第一個(gè)維度中添加了一個(gè)小的偏移量,并且這個(gè)偏移量會隨著數(shù)據(jù)規(guī)模的擴(kuò)大而增大。創(chuàng)建索引對象圖3.2創(chuàng)建Index對象Faiss是圍繞Index對象構(gòu)建的。Faiss也提供了許多種類的Index,這里簡單起見,使用IndexFlatL2(一個(gè)暴力L2歐式距離搜索的索引)。如圖3.2所示,所有的指標(biāo)都必須了解其建立的時(shí)間,以及其執(zhí)行的矢量維度(在我的示例中為d)。大部分的指數(shù)都會要求一個(gè)培訓(xùn)期來對矢量的分配進(jìn)行研究??梢院雎訧ndexFlatL2的這個(gè)動作[10]。相似矩陣搜索圖3.3搜索為該指數(shù)進(jìn)行的一個(gè)最基礎(chǔ)的檢索運(yùn)算是k近鄰檢索[13],也就是說,針對每一個(gè)問矢量,它可以在一個(gè)資料庫中找到它的k(topK)近鄰。因此,得到的集合是一個(gè)矩陣nq*k[11]。上面的代碼執(zhí)行了兩個(gè)搜尋,見圖3.3。第一個(gè)查詢的時(shí)候,采用的是前面五個(gè)字的訓(xùn)練資料,以便于對比。I和D,表示“Id”和“Distance”,即“距離”和“鄰居”。研究的結(jié)論是:圖3.4第一次搜索結(jié)果如圖3.4所示,在第一次搜索結(jié)果中,第一個(gè)I直接顯示了與輸入向量最近的4個(gè)鄰居的ID,第二個(gè)D顯示了與輸入向量之間的距離。圖3.5第二次搜索結(jié)果如圖3.5所示,在第二次搜索結(jié)果中,第一個(gè)I表示與輸入向量距離最遠(yuǎn)的4個(gè)鄰居的ID,而第二個(gè)D顯示了這些最遠(yuǎn)的鄰居與輸入向量之間的距離。優(yōu)化使用Faiss由于圖像多、維度高,所以提高搜索速度是必要的操作。提高檢索速度為了加快搜索速度,我們可以根據(jù)特定規(guī)則或順序?qū)?shù)據(jù)集進(jìn)行細(xì)分,劃分出n個(gè)小段。我們可以在d維度上,將Voronoi單元作為一個(gè)單元,而每一個(gè)資料庫矢量都是一個(gè)單元。當(dāng)進(jìn)行搜索時(shí),你可以通過對向量x進(jìn)行運(yùn)算來判斷它將要落入的那個(gè)單位。我們可以簡單地將這個(gè)存儲空間和它的鄰近的一些單位中的向量x進(jìn)行對比。(以下是HashMap的實(shí)施原則的對比。培訓(xùn)就是產(chǎn)生哈希圖,而getByKey則是一個(gè)處理。)上面的工作是由IndexIVFlat來實(shí)現(xiàn)的。此類指標(biāo)要求進(jìn)行培訓(xùn),能夠?qū)λ信c資料庫矢量分布完全一致的矢量組進(jìn)行。這里,我們只會用到資料庫矢量。IndexIVFlat也要求其他Index,即為Voronoi的單位指定矢量。各單位格由質(zhì)心確定。要想知道一個(gè)矢量歸屬于哪一個(gè)Voronoi的工作就是要在這個(gè)矢量的中心處尋找它的鄰近點(diǎn)。這是另外一項(xiàng)工作,它一般被設(shè)定為IndexFlatL2[12]。這里的搜尋方式包含兩個(gè)參數(shù):nlist,nprobe(每次搜尋時(shí)能存取的單位數(shù)目,缺省1)。搜索時(shí)間隨nprobe的值和一些量化常數(shù)而呈現(xiàn)出線性增加的趨勢。圖3.6提高檢索速度的代碼實(shí)驗(yàn)如圖3.6所示,寫了一段簡單測試搜索速度的實(shí)驗(yàn)代碼。在第4行中,我設(shè)置了METRIC_L2選項(xiàng),默認(rèn)它執(zhí)行了inner-product搜索[13]。圖3.7提高檢索速度的實(shí)驗(yàn)結(jié)果如圖3.7左所示,如果nprobe=1,則輸出與粗略查找相似,但是并不完全一致(參見圖3.4),原因在于在Voronoi的不同的單元中會產(chǎn)生不一樣的效果。所以,更多的存取單位是可以改進(jìn)的。從圖3.7右邊可以看出,在nprobe的數(shù)值達(dá)到10以后,其效果也是一樣的。在這個(gè)例子中,得到同樣的效果,只是由于使用了x軸上的強(qiáng)大的資料處理軟件,并且使得其易于操作。Nprobe參數(shù)值可以平衡搜索結(jié)果的速度和準(zhǔn)確度,從而使得檢索系統(tǒng)的精確性和效率均有所保證。如果想要極致的精確度,可以設(shè)置nprobe=nlist值,這會得出和暴力搜索完全相同的結(jié)果,不過速度也會和暴力搜索一樣慢。因此,在真正的工業(yè)用途中,依舊需要在這兩者之間取得一個(gè)平衡[14]。減少內(nèi)存占用由于圖像多、維度高,所以減少內(nèi)存占用是必要的操作。在搜索過程中,會伴隨有大量的I/O操作即讀取大規(guī)模圖像的特征向量數(shù)據(jù),因此,無損壓縮甚至是一定程度的有損壓縮在這里也是可以接受的。IndexFlatL2和IndexIVFlat都將保存全部矢量。為擴(kuò)大到大量的資料,F(xiàn)aiss還提供了幾種不同的形式,這些變量按照產(chǎn)品質(zhì)量計(jì)算法對所儲存的向量進(jìn)行壓縮,并進(jìn)行有損性的壓縮。矢量仍然保存在Voronoi單位內(nèi),但是其尺寸減少到可以設(shè)置的字節(jié)m(d的乘積為m)。壓縮是以產(chǎn)品量化器為基礎(chǔ)的,它可以被看作是對矢量進(jìn)行編碼的一個(gè)額外層次。這樣,當(dāng)向量不能被完整地保存時(shí),所用的回程也就是一個(gè)逼近。圖3.8減少內(nèi)存占用的代碼實(shí)驗(yàn)如圖3.8所示,我寫了一段簡單測試內(nèi)存占用的實(shí)驗(yàn)代碼。圖3.9減少內(nèi)存占用的實(shí)驗(yàn)結(jié)果如圖3.9所示,我們可以看到,我已經(jīng)準(zhǔn)確地發(fā)現(xiàn)了附近的一個(gè)(這就是矢量ID),不過這個(gè)矢量和自己的估算值并不等于0,雖然這個(gè)值比周圍的相鄰值要小得多。這是因?yàn)橛袚p性的壓力。在此,我把64個(gè)32比特的浮點(diǎn)數(shù)據(jù)縮減到8個(gè)比特,因此壓縮系數(shù)為32。圖3.10減少內(nèi)存占用試驗(yàn)結(jié)果的真實(shí)值而在進(jìn)行真實(shí)查詢搜索時(shí),結(jié)果如圖3.10所示。與圖3.4的IVFFlat結(jié)果進(jìn)行比較后可以發(fā)現(xiàn),大多數(shù)結(jié)果都是不正確的,但是結(jié)果都落在正確的空間區(qū)域內(nèi),基本都是10000左右的ID。后來,又針對大規(guī)模數(shù)據(jù)集(百萬級別規(guī)模的圖像集)做了一個(gè)測試,實(shí)驗(yàn)結(jié)果很樂觀,基本和預(yù)想效果一致。我猜想有這兩點(diǎn)原因:第一點(diǎn)是,統(tǒng)一數(shù)據(jù)很難索引,因?yàn)闆]有可用于聚類或者降低維度的規(guī)律可循;第二點(diǎn)是,在自然資料中,與無關(guān)緊要的結(jié)論相比,語義關(guān)系的鄰近關(guān)系往往離我們所期望的更近[15]。因?yàn)榫幾g指數(shù)會很麻煩,所以有一個(gè)工廠功能來構(gòu)造一個(gè)指定的字串。圖3.11簡化索引構(gòu)建流程上述索引可以簡寫如圖3.11所示。如果將“PQ8”替換為“Flat”,那么可以得到一個(gè)IndexFlat。如果需要預(yù)處理(PCA,PrincipalComponentAnalysis)輸入向量,這個(gè)方法顯得尤為方便:例如需要將PCA投影矢量降維至16D的預(yù)處理過程中,工廠字符串應(yīng)該是“PCA16,IVF100,Flat”。挑選恰當(dāng)索引Faiss提供了很多Index,那么如何根據(jù)實(shí)際情況選擇Index顯得尤為重要。我通過閱讀Faiss文檔和編寫測試程序,總結(jié)出以下幾點(diǎn)挑選合適Index的規(guī)律。請記住以下規(guī)則中的Index是用一個(gè)工廠的字串來代表的,而且當(dāng)你想要設(shè)定其他的參數(shù)時(shí),你必須設(shè)定相應(yīng)的屬性空間的參數(shù)。當(dāng)你想要得到準(zhǔn)確的結(jié)果時(shí),可以選擇“Flat”,因?yàn)橹挥蠭ndexFlatL2才能確保準(zhǔn)確的搜索,而IndexFlatL2則是其它指標(biāo)的參照。該方法既不會對矢量進(jìn)行壓縮,也不會增加附加的開銷。但是,“Flat”選項(xiàng)并不支持隨機(jī)添加ID的操作(add_with_ids),只可以順序添加即只能往后面按照ID值的自增加入更多數(shù)據(jù),所以,在要求在需要的時(shí)候,可以隨意地增加ID,請用“IDMap,Flat”。由于Faiss的所有指標(biāo)都儲存在RAM中,所以當(dāng)沒有足夠準(zhǔn)確的存儲器時(shí),那么可以在內(nèi)存的限制下,優(yōu)化精準(zhǔn)度-速度比(precision-speedtradeoff)。(1)完全不需要關(guān)心內(nèi)存使用問題:“HNSWx”是最好的選項(xiàng),因?yàn)槟銚碛泻芏鄡?nèi)存,或者是一個(gè)很短的數(shù)據(jù)集合。x的作用域?yàn)閇4,64],代表各矢量的連接數(shù)目,愈大愈準(zhǔn)確,所占用的記憶體就愈多,而對于各矢量而言,則為(d*4+x*2*4)。HNSW僅支援序列加入,因此,若有必要,請?jiān)诖藢DMap用作前綴。然而,HNSW并不要求進(jìn)行培訓(xùn),并且不能從索引中移除向量。(2)對內(nèi)存的利用有些擔(dān)憂:選擇“…,Flat”?!啊贝硪粋€(gè)群組的方式,它需要預(yù)先進(jìn)行(6.4.3部分將更多地說明)。在群集后面,“Flat”僅僅把矢量分成幾個(gè)桶,這樣就不用對其進(jìn)行壓縮了,而且儲存的尺寸和原來的資料集合一樣。在速率與準(zhǔn)確性間進(jìn)行折衷,由nprobe參數(shù)設(shè)定。(3)對內(nèi)存的占用進(jìn)行了更多的考慮:選擇“PCARx,…,SQ8”。若要儲存全部的特性向量記憶體,則首先使用大小為x的PCA法,將各向量的標(biāo)量壓縮到一個(gè)字節(jié),使各特征向量的記憶空間為x個(gè)字節(jié)。(4)對內(nèi)存的占用感到很擔(dān)憂;“OPQx_y,…,PQx”可以選擇。PQx表示一個(gè)矢量經(jīng)過了x個(gè)字節(jié)的加壓,x通常是64以下;OPQ時(shí)矢量的直線轉(zhuǎn)換使得它在轉(zhuǎn)換后更易于被壓縮,y是一個(gè)空間,需要y的倍率是x的整數(shù)倍,而x的大小最好是4,而y的尺寸要比輸入矢量的尺寸要小,所以O(shè)PQ的處理對系統(tǒng)的性能要求很低。該問題被用來選取群集(6.4.3-2節(jié)中的”…“)。在進(jìn)行檢索時(shí),數(shù)據(jù)集合集中在bucket中,僅對bucket(nprobeblock)進(jìn)行訪問。在典型的資料集向量的典型樣例上進(jìn)行群組,一般為資料集中的取樣。我們指定了這個(gè)樣品的最優(yōu)尺寸。(1)向量數(shù)量低于1M:“…,IVFx,…”當(dāng)數(shù)據(jù)集的數(shù)量為N時(shí),那么x的范圍應(yīng)該在[4N(2)向量數(shù)量在1M到10M之間:“…,IMI2x10,…”IMI在訓(xùn)練向量上執(zhí)行具有2^10個(gè)質(zhì)心的k-means,但它在向量的前半部分和后半部分獨(dú)立地執(zhí)行,這將簇的數(shù)量增加到22×10個(gè),將需要大約64(3)向量數(shù)量在10M到100M之間:“…,IMI2x12,…”同理,將10替換為12即可;(4)向量數(shù)量在100M到1G之間:“…,IMI2x14,…”同理,將12替換為14即可。預(yù)處理后處理前、后處理的方法是:向量ID的再映射,把轉(zhuǎn)換用于資料,再利用更好的指數(shù)來排序。根據(jù)預(yù)設(shè),F(xiàn)aiss將序列id指定給被加入到該索引中的矢量。這個(gè)頁面描述了怎樣把它修改成一個(gè)隨意的ID。有些Index類通過向量和64比特矢量id來執(zhí)行add_with_ids方式。當(dāng)搜尋時(shí),類別會傳回儲存的id,而非最初的矢量。在IndexIDMap中,這個(gè)索引會將另外一個(gè)索引包起來,當(dāng)增加或搜尋時(shí),這個(gè)索引會對ID進(jìn)行變換。首先,IndexIVF的子類總是保存向量ID。由于IndexIVF自身也會提供add_with_ids,所以IndexIDMap的額外表格就會占用大量的內(nèi)存。在建立索引以前,對資料進(jìn)行變換是很有幫助的。變換類別將會繼承矢量傳輸。VectorTransform對一個(gè)輸入矢量(d_in)施加轉(zhuǎn)換,并且向量的矢量具有d_out的尺寸。從表格3.1中可以看出,可以通過一套向量來進(jìn)行轉(zhuǎn)換,只要有必要,就可以用train進(jìn)行轉(zhuǎn)換。他們可以在一套向量上應(yīng)用??梢詫⒃撝笖?shù)封裝到IndexPreTransform中,這樣就可以實(shí)現(xiàn)映射的透明化,而train則與indextrain相結(jié)合。表3.1索引前的幾種數(shù)據(jù)轉(zhuǎn)換方法轉(zhuǎn)換類型類名使用方法隨機(jī)回轉(zhuǎn)RandomRotationMatrix在IndexPQ或IndexLSH中建立索引之前重新平衡向量的組件很有用重新映射維度RemapDimensionsTransform減少或增加向量的大小,因?yàn)樗饕哂惺走x維度,或者在維度上應(yīng)用隨機(jī)排列PCAPCAMatrix減少維數(shù)OPQrotationOPQMatrixOPQ對輸入向量應(yīng)用旋轉(zhuǎn),使其更適合PQ編碼。在查詢矢量時(shí),利用IndexRefineFlat,可以利用真實(shí)的距離來調(diào)整搜索的結(jié)果。IndexPQ對索引進(jìn)行了試驗(yàn),并對其進(jìn)行了排序,并對其進(jìn)行了計(jì)算。該算法會從IndexPQ中獲得k*n的相鄰關(guān)系,并根據(jù)其實(shí)際的距離進(jìn)行運(yùn)算,并保存n個(gè)最優(yōu)解。但是IndexRefineFlat需要保存整個(gè)矢量,所以不能節(jié)省內(nèi)存。如果一個(gè)資料集遍歷多個(gè)指標(biāo),你可以利用這些指標(biāo)來安排一個(gè)查詢,然后再把它和IndexShards一起使用。這對于在多GPU上分散的索引和能夠平行處理的查詢來說是很有用的。索引I/O優(yōu)化Faiss指數(shù)經(jīng)常是一個(gè)復(fù)雜的指數(shù),它不能很好地處理單個(gè)的指數(shù)。另外,他們擁有很多的參數(shù),在一個(gè)特定的用案例中,要找出一個(gè)優(yōu)化的架構(gòu)是非常困難的。Faiss為大量地處理指數(shù)和自動地探究參數(shù)的空間,提供了一個(gè)先進(jìn)的界面。I/O函數(shù)有一個(gè)write_index(),它可以作為一個(gè)指定的索引來寫一個(gè)文檔。clone_index()功能可以在不考慮物體歸屬的情況下,可以進(jìn)行深復(fù)制的索引,并將能夠在GPU中執(zhí)行的指標(biāo)復(fù)制到GPU中,加快計(jì)算速度;index_factory對該字串進(jìn)行解讀,從而產(chǎn)生一個(gè)合成錯(cuò)誤指數(shù)。這個(gè)字串由一個(gè)由三個(gè)部分組成的逗點(diǎn)隔開:預(yù)處理部分、反轉(zhuǎn)檔和精煉部分。在向量前處理方面,index_factory支持:PCA:“PCA64”指的是由PCA(PCAMatrix)把大小縮小到64D,“PCAR64”代表PCA的完成,然后是無規(guī)則的轉(zhuǎn)動。跟蹤Flat指數(shù)是非常有用的;OPQ:“OPQ16”相當(dāng)于在OPQMatrix中為PQ或IVFPQ到16個(gè)字節(jié)的編碼而做好OPQMatrix,在跟蹤PQ但是在較慢的情況下,這是非常有效的。在反轉(zhuǎn)的檔案中,該軟件提供了以下功能:平面指標(biāo)“IVF4096”表示:利用扁平的粗粒度發(fā)生器IndexFlatL2來創(chuàng)建一個(gè)4096的反轉(zhuǎn)的檔案;而逆向多指標(biāo)“IMI2x8”是指利用2x8比特的逆向多指標(biāo)量化器(利用MultiIndexQuantizer)創(chuàng)建一個(gè)2^(2×8)的逆向多指標(biāo)(利用MultiIndexQuantizer);在不想要逆向的檔案而想要添加add_with_ids時(shí),可以設(shè)定“IDMap”來產(chǎn)生一個(gè)已被包裝好的IndexIDMap。在精煉運(yùn)算中,該方法提供了:將整個(gè)矢量與“Flat”一起保存。使用“PQ16”,用16個(gè)字節(jié)的PQ精煉編碼。利用IndexPQ或IndexIVFPQ來實(shí)施;只在逆向的檔案選擇后面工作,利用IndexIVFPQR來完成8個(gè)字節(jié)和16個(gè)字節(jié)的精煉。自動調(diào)整參數(shù)指標(biāo)的參數(shù)可以分成:建立時(shí)需要設(shè)定的版本時(shí)的參數(shù),以及在進(jìn)行搜尋前可以進(jìn)行調(diào)節(jié)的運(yùn)行時(shí)的參數(shù)。表3.2運(yùn)行時(shí)可自動調(diào)整的參數(shù)Key索引名稱運(yùn)行時(shí)參數(shù)使用方法IVF,IMI2xIndexIVF*nprobe調(diào)整速度-精度權(quán)衡的主要參數(shù)IMI2x*IndexIVFmax_codes對于IMI很有用,它通常具有不平衡的反向列表PQ*IndexIVFPQ,IndexPQht多義的HammingthresholdPQ+IndexIVFPQRk_factor確定驗(yàn)證了多少結(jié)果向量對運(yùn)行時(shí)參數(shù)執(zhí)行自動調(diào)整,調(diào)整的參數(shù)如表6.2所示,自動調(diào)整探索速度精度空間并使程序保持最佳狀態(tài)。有3個(gè)因素會對自動調(diào)節(jié)的可靠性產(chǎn)生影響:(1)靈敏度及查詢集合的準(zhǔn)則;(2)數(shù)據(jù)集合必須具有充分的查找點(diǎn),最好為1000,并且充分地對參數(shù)設(shè)定非常靈敏;(3)可靠的時(shí)效性。計(jì)算的是CPU的時(shí)間。對于非使用GPU或者CPU的一個(gè)線程來說,這是最安全的,而且在多個(gè)執(zhí)行緒中也不那么穩(wěn)定。數(shù)據(jù)集合的時(shí)間長度愈短,其穩(wěn)定性愈差。多線程測試在1s以下。多線程同異步由于對性能的特殊要求,因此多線程運(yùn)行和異步調(diào)用函數(shù)也是需要的。就內(nèi)部的線程和線程的安全性而言,F(xiàn)aissCPU的指數(shù)是用索引功能,要求執(zhí)行互斥性。FaissGPU索引甚至是只讀功能都沒有被執(zhí)行過。這是由于GPU測試的標(biāo)準(zhǔn)Gpu資源不具有線程安全性。對于活躍地執(zhí)行GPU錯(cuò)誤指數(shù)的所有執(zhí)行緒,您都需要建立標(biāo)準(zhǔn)Gpu資源物件。多GPU的指標(biāo)被一一個(gè)標(biāo)準(zhǔn)GpuResources(事實(shí)上,這是由于他們能夠利用同一個(gè)GPU暫時(shí)存儲區(qū))。單一Gpu資源物件可以支援多臺裝置,但是僅支援單一呼叫ex_cpu_to_gpu_multiple)得到,從多個(gè)線程中執(zhí)行GPU的指標(biāo)。Faiss自身擁有若干個(gè)不同的內(nèi)線。三個(gè)基礎(chǔ)的(培訓(xùn)、增加、行緒。該方法由OpenMP和多線程BLAS來實(shí)現(xiàn)。失敗沒有設(shè)定線程的數(shù)目。呼叫方可以在任何時(shí)候調(diào)用omp_set_Python中的faiss實(shí)現(xiàn)的。在添加和搜索功能中,線程是向量。這表示一個(gè)單一矢量的查詢或增加并不是多執(zhí)行緒。就搜索效能而言,通過大量的查詢來實(shí)現(xiàn)QPS的最優(yōu)表現(xiàn)。如果一個(gè)一個(gè)地進(jìn)行了一個(gè)請求,就會在一個(gè)呼叫的線程中運(yùn)行(當(dāng)前的所有的指數(shù)都是這樣)。所以,一個(gè)多個(gè)執(zhí)行緒來訪問一個(gè)單一的請求也比較有效率。然而,從多個(gè)執(zhí)行緒中調(diào)用大量的查詢效率很低,會導(dǎo)致超過內(nèi)核從內(nèi)部的線程表現(xiàn)來看,不一定會有多少個(gè)OpenMP的線程被選中。存在著比內(nèi)核數(shù)量更多的配置,因此可以顯著地改善運(yùn)行的有效性。比如,在IntelE5-2680v2中,可以使用20個(gè)線程來代替缺省40。當(dāng)您在在非同步檢索中,通過與其它計(jì)算同時(shí)進(jìn)行的檢索運(yùn)算,如:單程運(yùn)算,I/O等待,GPU計(jì)算,使程序能夠平行地進(jìn)行。與FaissCPU進(jìn)行平行處理,比如其它的多線程運(yùn)算,比如其它的查詢,這樣做會導(dǎo)致大量的線程,從而導(dǎo)致總體的表現(xiàn)下降;應(yīng)該將來自可能不同的用戶線程的多個(gè)傳入搜索排隊(duì)并由用戶聚合/批處理。在多個(gè)GPU上并行運(yùn)行操作當(dāng)然是可行且有用的,其中每個(gè)CPU線程專用于在不同GPU上的內(nèi)核啟動,這就是IndexProxy和IndexShards的實(shí)現(xiàn)方式。如果想要生成多并發(fā)的搜索線程,可以在C++中,使用pthread_create+pthread_join;也可以在Python中,thread.start_new_thread和一個(gè)鎖共同使用,或者使用multiprocessing.dummy.Pool。search、add、train函數(shù)都會釋放GIL(GlobalInterpreterLock)。其他優(yōu)化操作有一些可以對索引所進(jìn)行的操作,并不適用于所有Index??梢詮乃饕兄匦聵?gòu)建向量:方法reconstruct和reconstruct_n從給定其ID的索引重建一個(gè)或多個(gè)向量。支持IndexFlat,IndexIVFFlat(需要先調(diào)用make_direct_map),IndexIVFPQ,IndexPreTransform(需要底層的支持)??梢詮乃饕幸瞥粋€(gè)項(xiàng)目:remove_ids方法將索引中的所有的元素都移到一個(gè)量子組上。IDSelectorBatch將對該目錄進(jìn)行該操作。Python界面是這種方式的重要組成部分。請記住,因?yàn)檫@個(gè)函數(shù)會傳送到全部的資料庫,所以僅當(dāng)您想要移除了許多矢量時(shí),這是正確的。提供IndexIVFPQ、IDMap方式??梢栽谔囟ǖ膮^(qū)域中進(jìn)行檢索:range_search(除了k的最靠近的矢量),它將會傳回在查找點(diǎn)附近的所有矢量。因?yàn)槊恳淮卧儐柖加幸粋€(gè)不一樣的結(jié)果清單,所以需要專門地進(jìn)行:(1)C++中,其將結(jié)果以預(yù)定的RangeSearchResult形式形式傳回;(2)在Python中,將結(jié)果作為一個(gè)元組,列、D、I組成的一維陣列。支援:IndexFlat,IndexIVFlat(只支援CPU操作).可以將其分解為與合并的指標(biāo):(1)merge_from在執(zhí)行階段將其他的指標(biāo)拷貝到這里,然后釋放它??梢栽陬A(yù)先轉(zhuǎn)化中使用ivflib::merge_into。(2)copy_subset_to將該代碼的一部分拷貝至其他的下標(biāo)。由于它們大多是在大的指數(shù)中使用的,所以只在IndexIVF的子類中執(zhí)行??偨Y(jié)Faiss通過第3節(jié)對于Faiss各種情況的不斷了解,現(xiàn)在對Faiss已經(jīng)有了一個(gè)更深層次的理解。而理解的最好方式就是類比自己已經(jīng)熟悉的事物,F(xiàn)aiss就可以類比為一個(gè)可以設(shè)置索引的數(shù)據(jù)庫。索引的作用是更快的讀取,數(shù)據(jù)庫的作用是完成增刪改查的操作并存儲許多條記錄,而對于Faiss來說存儲的就是非常大規(guī)模的向量。唯一的區(qū)別就是Faiss沒有數(shù)據(jù)庫存儲介質(zhì)的概念,全部都以Index作為存儲媒介。Faiss中的Index就像是數(shù)據(jù)庫中的索引一樣,為了更快地查找數(shù)據(jù),一般用唯一ID作為主鍵,也可以像查字典一樣用首字母作為索引標(biāo)準(zhǔn)進(jìn)行建立,還可以像早期的搜索引擎一樣使用倒排索引(invertedindex)。不同的索引方式,都有不同的優(yōu)劣勢,而我在第3.3小節(jié)已經(jīng)詳細(xì)敘述過了,只需要通過各自使用場景特點(diǎn)選擇合適的索引類型即可。設(shè)計(jì)海量圖像檢索系統(tǒng)總體框架圖4.1海量圖像檢索系統(tǒng)的基本流程在海量圖像檢索系統(tǒng)中,從最開始的輸入查詢圖像開始,到最后的輸出檢索見過的整個(gè)過程中,主要有提取圖像特征、建立存儲索引、定義相似矩陣這三大步驟。提取圖像特征圖像的特征抽取就是對圖像的描述進(jìn)行了界定。在這個(gè)步驟中,我們必須確定哪個(gè)部位應(yīng)該被描繪。在一幅圖片中,有許多可被描繪的特點(diǎn),包括形狀,顏色,紋理,色塊等等;而形狀又可分為規(guī)則的凹凸多邊形、圓,和不規(guī)則的各式各樣的形狀;顏色又可分為顏色直方圖、顏色矩陣等很多種;紋理也可分為表面紋理和深層紋理等等……在這一階段,我們需要選定需要提取的特征,而根據(jù)不同的應(yīng)用,選取的特征可以是一種,也可以是許多種。建立存儲索引建立存儲索引即是索引化數(shù)據(jù)集的過程?,F(xiàn)在已經(jīng)有了圖像描述符,接下來就是需要將這個(gè)統(tǒng)一的圖像描述符標(biāo)準(zhǔn)應(yīng)用于數(shù)據(jù)集中的每一幅圖像,即計(jì)算出每一幅圖像的特征值,然后再將其有效地存儲起來(如SQL、Redis數(shù)據(jù)庫),以便于后續(xù)更好地用于比較。定義相似矩陣定義相似矩陣即是定義相似性度量標(biāo)準(zhǔn)的過程?,F(xiàn)在既有數(shù)據(jù)集中每一幅圖像的特征向量,又計(jì)算出了輸入圖像的特征向量,但如何比較這些特征向量的相似性呢?目前比較常用的相似性度量方法有以下幾種:歐幾里得距離(ED,EuclideanDistance)、余弦相似性比較(Cosinesimilarity)、卡方距離(Chi-squaremeasure)、巴氏距離(BD,BhattacharyyaDistance)、閔氏距離(Minkowskidistance)、距離相關(guān)系數(shù)(Distancecorrelation)等。在實(shí)際操作中,如何選擇合適的度量方法主要取決于數(shù)據(jù)集和提取的特征類型。具體設(shè)計(jì)大體架構(gòu)是一個(gè)客戶端-服務(wù)器端(CS,Client&Server)架構(gòu)的海量圖像檢索系統(tǒng)。服務(wù)器端(1)嘗試離線處理小數(shù)據(jù)庫(千級數(shù)據(jù)庫),提取出特征向量并通過索引的方式存儲在硬盤中;(2)嘗試實(shí)現(xiàn)大規(guī)模數(shù)據(jù)庫(百萬級數(shù)據(jù)庫)的離線處理;(3)嘗試實(shí)現(xiàn)在線處理數(shù)據(jù)庫,即可以在線更新數(shù)據(jù)庫,適應(yīng)不斷更新的數(shù)據(jù)規(guī)模;(4)嘗試接入組內(nèi)的PythonSpider爬蟲接口,做到數(shù)據(jù)最大化重復(fù)利用;(5)嘗試搭建微服務(wù)架構(gòu),用Docker甚至是K8S(Kubernetes)進(jìn)行一鍵化部署和統(tǒng)一管理??蛻舳耍?)嘗試?yán)肞ythonWeb框架,搭建可在線查詢圖片的Web應(yīng)用;(2)嘗試使用Flask構(gòu)建更人性化UI界面。構(gòu)建Index圖4.2構(gòu)建Index核心代碼在簡單的測試中,如圖4.2所示,我選取的是最基礎(chǔ)的Index類型“IDMap,Flat”,這是暴力搜索的類型。在正式生產(chǎn)環(huán)境中,因?yàn)閳D片數(shù)據(jù)庫較大,可以達(dá)到千萬級別甚至上億,而且是自己算的特征向量,因此可以選用“OPQx_y,RMI2x12,PQx”索引類型加速構(gòu)建Index。當(dāng)然,這是需要預(yù)訓(xùn)練的Index類型,需要先訓(xùn)練好再將向量進(jìn)行添加,最后將Index以及index_dict保存為文件存儲在服務(wù)器硬盤中。構(gòu)建查詢服務(wù)通過PythonFlask接口提供了查詢接口,由于一般都是查詢一組圖片數(shù)據(jù),因此就沒有做圖形化UI界面,而是直接使用命令行操作,也便于后期其他使用者寫腳本進(jìn)行批量查詢。圖4.3命令行使用查詢服務(wù)我在本地開啟了9859端口作為查詢服務(wù)的測試端口。第1行:為用于檢測服務(wù)是否正常運(yùn)行,如果獲取到了正常的HealthCheck(心跳檢測),就證明服務(wù)正常運(yùn)行中,可以進(jìn)行查詢服務(wù)。第2-4行:分別是通過輸入查詢ID、輸入查詢圖片和輸入向量進(jìn)行查詢,k=5代表了查詢前5個(gè)最近鄰居結(jié)果。部署海量圖像檢索系統(tǒng)服務(wù)目前,海量圖像檢索系統(tǒng)已經(jīng)準(zhǔn)備就緒,直接在服務(wù)器上通過Docker安裝并開啟服務(wù)后就可以使用。圖4.4服務(wù)器部署海量圖像檢索服務(wù)如圖4.4所示,至此檢索服務(wù)已經(jīng)開啟,通過第7.4小節(jié)的查詢命令即可得到結(jié)果。當(dāng)然,這只是用了第7.3小節(jié)提到的最簡單的索引類型,如果有其他的需求可以還有其他選項(xiàng)可供選擇。在真實(shí)場景中,經(jīng)常需要構(gòu)建預(yù)訓(xùn)練的索引,運(yùn)行src/train_index/目錄下的train_index_with_pre_train.py即可;其次,如果需要輸出更高維度的特征向量,可以使用詞袋模型進(jìn)行訓(xùn)練,運(yùn)行src/train_index/目錄下的train_index_bow.py即可;有一些是基于JavaCV提取出的特征向量,運(yùn)行src/train_index/目錄下的train_index_from_java.py即可。目前,該系統(tǒng)已在小組內(nèi)部投入使用,也開始在部門內(nèi)部進(jìn)行小范圍推廣使用,在千萬級別的圖像數(shù)據(jù)庫中的搜索時(shí)間也在毫秒級別,使用反饋良好,基本完成了既定目標(biāo),實(shí)現(xiàn)了圖
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 中學(xué)網(wǎng)絡(luò)與信息安全管理制度
- 企業(yè)員工培訓(xùn)與職業(yè)規(guī)劃制度
- 企業(yè)安全生產(chǎn)管理制度
- 2026年食品營養(yǎng)學(xué)基礎(chǔ)食品安全與營養(yǎng)搭配知識競賽試題
- 2026年建筑工程師專業(yè)試題庫及答案全解
- 2026年公共政策專業(yè)題目政策制定與評估方法論
- 《JBT 14704-2024 汽車轉(zhuǎn)向盤骨架壓鑄模專題研究報(bào)告》
- 傳聲港新媒體營銷白皮書:文旅行業(yè)品牌推廣與獲客轉(zhuǎn)化全鏈路解決方案
- 季度政務(wù)信息采編報(bào)送發(fā)布工作總結(jié)
- 廣東省珠海市金灣區(qū)2025-2026學(xué)年度第一學(xué)期義務(wù)教育階段質(zhì)量監(jiān)測八年級英語試題(含答案)
- 健康小鎮(zhèn)建設(shè)方案
- dbj41河南省城市地下綜合管廊施工與驗(yàn)收標(biāo)準(zhǔn)
- 2026屆新高考語文三輪沖刺復(fù)習(xí):二元思辨作文審題構(gòu)思寫作
- 行業(yè)背景分析報(bào)告
- 2025中國農(nóng)業(yè)大學(xué)管理服務(wù)崗位(非事業(yè)編)招聘1人筆試備考試題附答案解析
- 2025福建省融資擔(dān)保有限責(zé)任公司招聘4人筆試試題附答案解析
- 2025年青海公務(wù)員《行政職業(yè)能力測驗(yàn)》試題及答案
- 工程管理費(fèi)合同協(xié)議
- 協(xié)助審計(jì)協(xié)議書范本
- 學(xué)堂在線 雨課堂 學(xué)堂云 生活英語聽說 期末復(fù)習(xí)題答案
- 30以內(nèi)加法運(yùn)算有進(jìn)位1000題1
評論
0/150
提交評論