在官方的使用demo中,我跑了下demo結果一樣,但是這個表示的結果是什麼意思呢?
faiss.IndexFlatL2(d)
官方解釋是暴力搜索L2距離方法,add後即建立索引了,無需index.train(xb),我對比了,有沒有這一步的結果是一樣的
得到的D是距離,I是索引,
>>> k=4
>>> D,I=index.search(xb[:5],k)
>>> I
array([[ 0, 393, 363, 78],
[ 1, 555, 277, 364],
[ 2, 304, 101, 13],
[ 3, 173, 18, 182],
[ 4, 288, 370, 531]])
>>> D
array([[0. , 7.1751733, 7.207629 , 7.2511625],
[0. , 6.3235645, 6.684581 , 6.7999454],
[0. , 5.7964087, 6.391736 , 7.2815123],
[0. , 7.2779055, 7.5279865, 7.6628466],
[0. , 6.7638035, 7.2951202, 7.3688145]], dtype=float32)
這是合理性檢測,因爲
xb[:, 0] += np.arange(nb) / 1000.
這一步將每條數據的第一個元素全都加上了該元素的index,由於產生的數據是np.random.random即[0.0, 1.0)
那麼在top1必然是該條數據本身,而距離本身就是倒排,從小到大的距離,也就是相似度從大到小。
下面看另外一個函數faiss.IndexFlatIP,餘弦相似度還是餘弦距離啊??這個sklearn可以作爲對比。
【餘弦距離=1-餘弦相似度,餘弦距離越小越好,此時餘弦相似度越大】
1-創建index和加載數據集時間用的短,query時用的時間長,在沒有用快速方法時,在1千萬數據集中查1萬個top4需要100s,這個時間太長了。d=64
2-驗證中發現faiss.IndexFlatL2計算的是歐式距離的平方,將官方例子中得到的I挨個驗證如下:k=6
L2 distances
[[0. 7.1751733 7.207629 7.2511625 7.321895 7.351989 ]
[0. 6.3235645 6.684581 6.7999454 6.8844795 6.919898 ]
[0. 5.7964087 6.391736 7.2815123 7.640502 7.7231803]
[0. 7.2779055 7.5279865 7.6628466 7.7859573 7.790914 ]
[0. 6.7638035 7.2951202 7.3688145 7.3900466 7.46482 ]]
index
[[ 0 393 363 78 924 364]
[ 1 555 277 364 617 175]
[ 2 304 101 13 801 134]
[ 3 173 18 182 484 64]
[ 4 288 370 531 178 381]]
0.0,7.175172963007071,7.207629517529313,7.251163094237256,7.32189456020302,7.351988795840555,
0.0,6.323564681684957,6.684580949409394,6.7999456742750795,6.884479284324755,6.919898182110273,
0.0,5.796407676635283,6.391735719267899,7.281511928833652,7.640502286348237,7.723179155793559,
0.0,7.277905725671246,7.527987963394992,7.662846322185942,7.785958432863538,7.790914131558168,
0.0,6.763803673639131,7.295120098456721,7.368814161903231,7.3900459631258855,7.464819925508493,
3-faiss.IndexFlatIP求出來的D根本不是餘弦方面的東西,既不是餘弦距離也不是餘弦相似度,你看看數值就知道了,完全超出了這倆數的最大範圍2。(只是將上面的函數替換【L2——>IP】)
cosin distances ????
[[1937.2388 1936.8904 1936.407 1936.4034 1936.3837 1936.2039 ]
[3854.9084 3853.9912 3853.5012 3853.4224 3853.3848 3853.3577 ]
[ 775.8727 775.72815 775.4991 775.3009 775.2481 775.1989 ]
[1764.4421 1764.3489 1764.1312 1764.116 1764.0082 1763.9166 ]
[1894.5415 1894.508 1893.7448 1893.7166 1893.6948 1893.63 ]]
index
[[9996145 9999103 9998705 9999520 9996659 9999163]
[9999930 9999529 9999160 9999743 9996855 9999219]
[9986256 9990562 9997819 9999103 9990206 9993650]
[9994808 9998483 9999930 9999520 9999895 9998792]
[9999930 9994808 9995033 9999520 9996145 9996287]]
這是什麼鬼??完全與L2得到的結果不同,難道說IP需要分nlist或者nprobe??官方加速例子中有train
所以我覺得這並不是餘弦方面的東西,等待官方回覆吧。
我猜想官方肯定會說需要設置一些參數,有些確實不同,
官方回覆說,只有第一種方法得到的是準確的方法,其他方法均是近似方法。但第一種方法慢,想快又準,你在開玩笑,肯定是折中問題,trade-off,速度越快,Recall越小,這是顯然的。
5-計算時間的比較,仍舊從1千萬查詢1萬,但用top100,我估計需要設置的參數可能有很大影響
一是創建index時間,二是查詢時間,仍舊用4中的可能不適合的腳本對比,後面再用1G的腳本
訓練數據後創建index,再查找,所用的查找時間短,第一種方法是暴力搜索,沒有訓練數據,直接查找肯定慢。
但如果訓練時間長也不符合線上實時應用。第2/3種方法均是訓練時間長(10分鐘內),這也是不行的
目前發現第4/6種速度較快[最後一個創建index2.56s,查詢不到1s-0.8s,多GPU就是厲害],
第5種結果有點奇怪。index出現-1的情況,如下所示:查詢時間雖然短,0.01s,但是結果有點可怕
[ 767 1228 230 1196 706 1365 256 1488 562 940 718 346 658 43
1431 1232 761 837 1108 593 1674 633 1363 152 477 1139 171 1198
938 672 190 1328 472 525 885 855 977 704 694 86 1150 321
486 1128 659 1019 881 354 850 742 412 1203 957 1179 496 905
229 1119 464 1798 1118 402 1186 360 1200 629 985 1519 1483 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1]]
官方說Consider 增加 nprobe
(or 減少 nlist
).但是這樣真的好嗎?我還要嘗試??是不是其他幾種方法也可能出現這個情況啊
這次只是偶然沒有出現,這就蛋疼了啊,有沒有自適應或者一勞永逸的方法??按照這個數據量的話我推薦第6種,速度最快,且又相對正確。
【這個方法如果沒有這種情況的話,速度是最快的,0.05s左右,創建index時間8s】
6-1G數據量的腳本,待後續吧
7-如果創建和查詢時間都是10ms左右則無需保存index,然而大多數情況下不是的,而且保存的話不需要引入數據重新訓練了
因而這裏介紹怎麼保存index,如何加載index,可能會與nmslib比較像
但是我大意了,並不是這樣的啊,見我的issue,待續
For Video Recommendation in Deep learning QQ Group 277356808
For Speech, Image, Video in deep learning QQ Group 868373192
I'm here waiting for you.