画像の類似度を算出して検索を行う
からのつづき
#Elasticsearchに連携する
「Vector Scoring」系のプラグインの説明にしたがってインデックスするだけ。
「Vector Scoring」系のプラグインはたくさんあるのでどれか入れておけば問題ない。
Elasticsearchバージョンをシビアにチェックしているのでpom.xmlを書き換えてパッケージにすればOK。
(書き換えても物によって入ったり入らなかったりするので、このへんはよくわかりません。)
##試してみる
結果として使い物にならない。
画像を1000枚、5000、10000と増やしていくと明らかに遅くなる。15000で2分以上かかってしまった。
マシンスペックは4コアCPUとSSD、メモリー16G。
目標の100万画像だとしたら・・・133分かかるの??
このスピードでは話にならない。プラグインのソースをみても、類似度を算出しているだけなのでいじりようがない。
O(n)を真面目に計算しているみたいなので、プラグインというかElasticsearch仕様でドキュメント毎にとりだして真面目に実行しているのではないかと想像する。
Elasticsearchを改造か?と思った。
そもそもElasticsearchがコサイン類似度の塊みたいなものなんじゃ??
#解決策
困った時のGPU。CPUバウンドだから解決できるはずなので・・またCUDACか・・・
未来が見えないので、Pythonとcupyでサクッと書いてみる。
15000画像が4秒でおわる・・・・CPUバウンド以前の問題な気がする。
Elasticsearchはインデックスできる前提で頑張れる子ですね。
Elasticsearchは忘れて・・・
適当に作ったので、最適化してみたら70000画像で3秒になった。
cupyで書くよりnumpyじゃないか?と思いnumpyにサクッと書き直して実行
貧弱なGPUだからか?cupy:numpyの速度に変化なし
ちょっとcuypがはやいかなぁ?くらい。
cupyのコツがあるのか?GPUのLOADも大したことない。
Elasticsearchに比べて、70000画像*4096次元の計算するのに3秒なのでとてつもなく早くなった。
サービス化するなら、さらに100倍早くしないと。。。
Pythonはシングルコアなので、複数プロセス立ち上げればマルチコア分くらいは早くなる?
以下に全画像のコサイン類似度を算出するコード(これが最速コードかどうかわかりません・・・)
検索される一つのクエリ対、全画像のコサイン類似度を算出する
#データの準備
#これはクエリ画像
A=numpy.array([[0.1345,0.5781・・・4096個]])
#これは検索される画像(事前に読み込んでおく)
vectors=numpy.array([[0.45345,0.22781・・・4096個],[0.17878345,0.1345781・・・4096個]・・・画像の数])
#コサイン類似度
X = (A * vectors).sum(axis=1, keepdims=True) /
(numpy.sqrt(numpy.square(A).sum(axis=1, keepdims=True)) * numpy.sqrt(numpy.square(vectors).sum(axis=1, keepdims=True)))
#結果を一次元に変換
NX=X.flatten()
#ソート
index=np.argsort(NX,axis=0)
#indexを逆向きに取り出せば、スコア順にとれる
文章みたいに軸が変化しないから超簡単!
numpy.arrayをdtype=np.float32にすれば指定なしの倍くらい早くなる。
(計算精度は低くても問題ないと思っている)
dtype=np.float16は逆に遅かった。
さらに「(cp.sqrt(cp.square(A).sum(axis=1, keepdims=True))」の部分は、検索毎に計算しなくてもよいので事前に計算しておくことでさらに早くなる。
pythonのtornadoを使ってhttp(rest)で検索できるようにする。
問題点は・・・
大量データなので起動時間が遅い(我慢できる)。
1スレッドだけしか動かない(今後の課題)。
##WEBサービス化で見えてきたこと
画像から画像にジャンプしていくような有効グラフ的な感じで使えるようにしてみた。
かなり面白い。
データ・ダイブの一つだと思う。
今後~
画像検索エンジンは強化しないと話にならない。
特徴量なので何かの区切り(サイト、お店、建物)で混ぜて、区切り特徴量でブラウズしたり・・・実験してみたい
商品のおすすめに、画像軸が追加できたり・・・(ECでも実店舗でも)
この記事に書いたことを使ってファッション検索サービスファンネルを作りました。