Sentence Transformers 2.2 : 画像検索 – 画像 & テキストの結合埋め込み

Sentence Transformers 2.2 : ノートブック : 画像検索 – 画像 & テキストの結合埋め込み (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 11/29/2022 (v2.2.2)

* 本ページは、UKPLab/sentence-transformers の以下のドキュメントを翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

クラスキャット 人工知能 研究開発支援サービス

クラスキャット は人工知能・テレワークに関する各種サービスを提供しています。お気軽にご相談ください :

◆ 人工知能とビジネスをテーマに WEB セミナーを定期的に開催しています。スケジュール
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

  • 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
  • sales-info@classcat.com  ;  Web: www.classcat.com  ;   ClassCatJP

 

 

Sentence Transformers 2.2 : ノートブック : 画像検索 – 画像 & テキストの結合埋め込み

このサンプルは SentenceTransformer が画像とテキストを同じベクトル空間にマップするためにどのように使用できるかを示します。

モデルとしては OpenAI CLIP モデル を使用します、これは画像と画像の alt テキストの大規模なセットで訓練されました。

写真のソースとしては、Unsplash Dataset Lite を使用します、これは約 25k 画像を含みます。Unsplash 画像については ライセンス をご覧ください。

Note : 25k 画像は非常に少ないです。実際に特定の用語を検索した場合、そのような写真がコレクションに存在しない可能性は高いです。

from sentence_transformers import SentenceTransformer, util
from PIL import Image
import glob
import torch
import pickle
import zipfile
from IPython.display import display
from IPython.display import Image as IPImage
import os
from tqdm.autonotebook import tqdm
torch.set_num_threads(4)



# 最初に、個別の CLIP モデルをロードします。
model = SentenceTransformer('clip-ViT-B-32')
# 次に Unsplash から約 25k 画像を取得します。
img_folder = 'photos/'
if not os.path.exists(img_folder) or len(os.listdir(img_folder)) == 0:
    os.makedirs(img_folder, exist_ok=True)
    
    photo_filename = 'unsplash-25k-photos.zip'
    if not os.path.exists(photo_filename):   #Download dataset if does not exist
        util.http_get('http://sbert.net/datasets/'+photo_filename, photo_filename)
        
    #Extract all images
    with zipfile.ZipFile(photo_filename, 'r') as zf:
        for member in tqdm(zf.infolist(), desc='Extracting'):
            zf.extract(member, img_folder)
# 今は、埋め込みを計算する必要があります。
# 早めるために、事前計算された埋め込みを分配します。
# そうでないなら画像を貴方自身でエンコードすることもできます。
# 画像をエンコードするには、以下のコードを使用できます :
# from PIL import Image
# img_emb = model.encode(Image.open(filepath))

use_precomputed_embeddings = True

if use_precomputed_embeddings: 
    emb_filename = 'unsplash-25k-photos-embeddings.pkl'
    if not os.path.exists(emb_filename):   #Download dataset if does not exist
        util.http_get('http://sbert.net/datasets/'+emb_filename, emb_filename)
        
    with open(emb_filename, 'rb') as fIn:
        img_names, img_emb = pickle.load(fIn)  
    print("Images:", len(img_names))
else:
    img_names = list(glob.glob('unsplash/photos/*.jpg'))
    print("Images:", len(img_names))
    img_emb = model.encode([Image.open(filepath) for filepath in img_names], batch_size=128, convert_to_tensor=True, show_progress_bar=True)
Images: 24996
# 次に、search 関数を定義します。
def search(query, k=3):
    # 最初に、クエリーを埋め込みます (それは画像かテキスト文字列のいずれかです)。
    query_emb = model.encode([query], convert_to_tensor=True, show_progress_bar=False)
    
    # そして、util.semantic_search 関数を使用します、
    # これはクエリー埋め込みとすべての画像埋め込みの間のコサイン類以度を計算します。
    # そしてそれは top_k の最も高いランクされた画像を返し、私たちはそれを出力します :
    hits = util.semantic_search(query_emb, img_emb, top_k=k)[0]
    
    print("Query:")
    display(query)
    for hit in hits:
        print(img_names[hit['corpus_id']])
        display(IPImage(os.path.join(img_folder, img_names[hit['corpus_id']]), width=200))
search("Two dogs playing in the snow")
Query:
'Two dogs playing in the snow'
FAcSe7SjDUU.jpg


lyStEjlKNSw.jpg


Hb6nGDgWztE.jpg

search("A sunset on the beach")
Query:
'A sunset on the beach'
nfQ2QGhdQNc.jpg


JC5U3Eyiyr4.jpg


vlukOqxOA8o.jpg

search("London")
Query:
'London'
UnGcRvTyJOo.jpg


S3G8qX4Ft5s.jpg


t05kfHeygbE.jpg

search("A dog in a park")
Query:
'A dog in a park'
IVyZrLp41D0.jpg


0O9A0F_d1qA.jpg


KVeogBZzl4M.jpg

search("A beach with palm trees")
Query:
'A beach with palm trees'
7rrgPPljqYU.jpg


kmihWgpbDEg.jpg


ZyfOq52b0cs.jpg

 

画像-to-画像検索

このメソッドを画像-to-画像検索にも使用できます。

これを実現するためには、Image.open(‘path/to/image.jpg’) を search メソッドに渡します。

するとそれは類似の画像を返します。

search(Image.open(os.path.join(img_folder, 'lyStEjlKNSw.jpg')), k=5)
Query:


lyStEjlKNSw.jpg


8rmYDezMIE4.jpg


mMj5ykKvwAk.jpg


nJW1RzBXZcI.jpg


Xmo004TUzrI.jpg

 

以上