目次
1 プロジェクトの背景
写真の文字検索は、文字による説明を入力して写真を検索するクロスモーダル検索技術であり、補助的な検索や情報検索だけでなく、文字で正確に説明することが難しい場面でも活躍します。キーワードを使用すると、情報を効率的に検索することができます。この技術には幅広い応用シナリオと価値があり、補助情報検索、アート、広告などの分野で重要な応用価値があり、よりパーソナライズされた検索体験をユーザーに提供します。文字付きの画像を検索する際の技術的なポイントは次のとおりです。
- テキストデータをベクトルエンコードする方法
- 大量の画像データをベクトル化して保存する方法
- テキスト ベクトルと画像ベクトルの間の関係をマッピングする方法
- 大量のベクター データを迅速に取得する方法
Milvus ベクトル データベースと組み合わせた OpenAI の Clip 事前トレーニング モデルに基づいて、このプロジェクトは果物データセットにテキストから画像への検索システムを実装します。読者はデータセットを他の分野に拡張し、テキストから画像への検索システムを構築できます。自らのビジネスニーズを満たします。
2つのキーテクノロジー
2.1 クリップモデル
CLIP の正式名称は Constrative Language-Image Pre-training で、対照学習を使用して OpenAI によって開始されたテキスト画像事前トレーニング モデルです。CLIP の驚くべき点は、アーキテクチャが非常にシンプルであり、その効果が信じられないほど優れていることです。ゼロショット テキスト画像の取得、ゼロショット画像の分類、テキストから画像への生成タスク ガイダンス、オープンドメインの検出とセグメンテーション、パフォーマンス。
CLIP の革新的な点は、画像とテキストを共有ベクトル空間にマッピングできることで、これによりモデルが画像とテキストの間の意味論的な関係を理解できるようになります。この共有ベクトル空間により、CLIP は画像とテキストの間の教師なし共同学習を実現でき、さまざまな視覚タスクや言語タスクに使用できます。
CLIP の設計は、教師ありトレーニングだけでなく自己監視を通じてモデルに画像とテキストの関係を理解させるというシンプルなアイデアからインスピレーションを受けました。CLIP は、モデルがベクトル空間内で互いに近くに対応する画像とテキストを埋め込むように、多数の画像とテキストのペアを使用してトレーニングされます。
CLIPモデルの特徴
- 統合ベクトル空間: CLIP の重要な革新は、画像とテキストの両方を同じベクトル空間にマッピングすることです。これにより、追加の中間表現を使用せずに、モデルがベクトル空間内の画像とテキスト間の類似性を直接計算できるようになります。
- 対照学習: CLIP は事前トレーニングに対照学習を使用します。モデルは、同じサンプルからの画像とテキストの埋め込みを近くの場所にマッピングし、別のサンプルからの埋め込みを離れた場所にマッピングするように求められます。これにより、モデルは画像とテキストの間の共通の特徴を学習できるようになります。
- 多言語サポート: CLIP の事前トレーニング済みモデルは多言語対応です。つまり、複数の言語でテキストを処理し、共有ベクトル空間に埋め込むことができます。
- 教師なし学習: CLIP の事前トレーニングは教師なしです。つまり、トレーニングをガイドするために大量のラベル付きデータを必要としません。インターネット上のテキストや画像データから学習し、さまざまなドメインのタスクを適切に実行できるようにします。
Clip モデルの詳細な紹介: Clip モデルの詳細な説明
2.2 Milvus ベクター データベース
Milvus は、高可用性、高性能、簡単な拡張を備えたクラウドネイティブのベクトル データベースであり、大量のベクトル データをリアルタイムに呼び出すために使用されます。
Milvus は FAISS、Annoy、HNSW およびその他のベクトル検索ライブラリに基づいて構築されており、その中心は高密度ベクトル類似性検索の問題を解決することです。ベクトル検索ライブラリに基づいて、Milvus はデータ分割、データ永続化、増分データ取り込み、スカラー ベクトル ハイブリッド クエリ、タイム トラベルなどの機能をサポートし、ベクトル検索シナリオのアプリケーション要件を満たすためにベクトル検索のパフォーマンスを大幅に最適化します。 。一般に、最高の可用性と回復力を得るために、Kubernetes を使用して Milvus をデプロイすることをお勧めします。
Milvus は共有ストレージ アーキテクチャを採用しており、ストレージとコンピューティングは完全に分離されており、コンピューティング ノードは水平方向の拡張をサポートしています。アーキテクチャの観点から見ると、Milvus はデータ フローと制御フローの分離に従い、全体としてアクセス層、コーディネーター サービス、ワーカー ノード、ストレージ層の 4 つの層に分かれています。各レベルは互いに独立しており、独立した拡張と災害復旧が行われます。
Milvus ベクトル データベースは、ユーザーが大量の非構造化データ (画像/ビデオ/音声/テキスト) の検索を簡単に処理できるようにします。シングルノードの Milvus は数秒以内に 10 億レベルのベクトル検索を完了でき、分散アーキテクチャはユーザーの水平拡張要件にも対応できます。
milvusの特徴をまとめると以下のようになります。
- 高性能: 高性能で、大規模なデータセットに対してベクトル類似性検索を実行できます。
- 高可用性と信頼性: Milvus はクラウド上での拡張をサポートしており、その災害復旧機能により高いサービス可用性を確保できます。
- ハイブリッド クエリ: Milvus は、ハイブリッド クエリを実現するために、ベクトル類似性検索中のスカラー フィールド フィルタリングをサポートします。
- 開発者に優しい: 多言語とマルチツールをサポートする Milvus エコシステム。
ミルブスの詳細:ミルブスの詳細
3 システムコードの実装
3.1 動作環境の構築
conda 環境の準備については、annoconda を参照してください。
git clone https://gitcode.net/ai-medical/text_image_search.git
cd text_image_search
pip install -r requirements.txt
pip install git+https://ghproxy.com/https://github.com/openai/CLIP.git
3.2 データセットのダウンロード
ダウンロードリンク:
最初のパケット: package01
2 番目のパッケージ: package01
次の図に示すように、データセット ディレクトリの下には 10 個のフォルダーがあり、フォルダー名は果物の種類であり、各フォルダーにはこの種類の果物の数百から数千の写真が含まれています。
例として apple フォルダーを取り上げます。内容は次のとおりです。
ダウンロード後、解凍してD:/dataset/fruitディレクトリに保存すると以下のように表示されます
# ll fruit/
总用量 508
drwxr-xr-x 2 root root 36864 8月 2 16:35 apple
drwxr-xr-x 2 root root 24576 8月 2 16:36 apricot
drwxr-xr-x 2 root root 40960 8月 2 16:36 banana
drwxr-xr-x 2 root root 20480 8月 2 16:36 blueberry
drwxr-xr-x 2 root root 45056 8月 2 16:37 cherry
drwxr-xr-x 2 root root 12288 8月 2 16:37 citrus
drwxr-xr-x 2 root root 49152 8月 2 16:38 grape
drwxr-xr-x 2 root root 16384 8月 2 16:38 lemon
drwxr-xr-x 2 root root 36864 8月 2 16:39 litchi
drwxr-xr-x 2 root root 49152 8月 2 16:39 mango
3.3 事前トレーニングモデルのダウンロード
事前トレーニング モデルには 5 つの resnet と 4 つの VIT が含まれており、そのうち ViT-L/14@336px が最もよく機能します。
"RN50": "https://openaipublic.azureedge.net/clip/models/afeb0e10f9e5a86da6080e35cf09123aca3b358a0c3e3b6c78a7b63bc04b6762/RN50.pt",
"RN101": "https://openaipublic.azureedge.net/clip/models/8fa8567bab74a42d41c5915025a8e4538c3bdbe8804a470a72f30b0d94fab599/RN101.pt",
"RN50x4": "https://openaipublic.azureedge.net/clip/models/7e526bd135e493cef0776de27d5f42653e6b4c8bf9e0f653bb11773263205fdd/RN50x4.pt",
"RN50x16": "https://openaipublic.azureedge.net/clip/models/52378b407f34354e150460fe41077663dd5b39c54cd0bfd2b27167a4a06ec9aa/RN50x16.pt",
"RN50x64": "https://openaipublic.azureedge.net/clip/models/be1cfb55d75a9666199fb2206c106743da0f6468c9d327f3e0d0a543a9919d9c/RN50x64.pt",
"ViT-B/32": "https://openaipublic.azureedge.net/clip/models/40d365715913c9da98579312b702a82c18be219cc2a73407c4526f58eba950af/ViT-B-32.pt",
"ViT-B/16": "https://openaipublic.azureedge.net/clip/models/5806e77cd80f8b59890b7e101eabd078d9fb84e6937f9e85e4ecb61988df416f/ViT-B-16.pt",
"ViT-L/14": "https://openaipublic.azureedge.net/clip/models/b8cca3fd41ae0c99ba7e8951adf17d267cdb84cd88be6f7c2e0eca1737a03836/ViT-L-14.pt",
"ViT-L/14@336px": "https://openaipublic.azureedge.net/clip/models/3035c92b350959924f9f00213499208652fc7ea050643e8b385c2dac08641f02/ViT-L-14-336px.pt",
ViT-L/14@336px: ViT-L-14-336px.ptの事前トレーニング モデルをダウンロードし、D:/models ディレクトリに保存します。
3.4 コードの実装
3.4.1 ベクトルテーブルとインデックスの作成
from pymilvus import connections, db
conn = connections.connect(host="192.168.1.156", port=19530)
database = db.create_database("text_image_db")
db.using_database("text_image_db")
print(db.list_database())
コレクションを作成する
from pymilvus import CollectionSchema, FieldSchema, DataType
from pymilvus import Collection, db, connections
conn = connections.connect(host="192.168.1.156", port=19530)
db.using_database("text_image_db")
m_id = FieldSchema(name="m_id", dtype=DataType.INT64, is_primary=True,)
embeding = FieldSchema(name="embeding", dtype=DataType.FLOAT_VECTOR, dim=768,)
path = FieldSchema(name="path", dtype=DataType.VARCHAR, max_length=256,)
schema = CollectionSchema(
fields=[m_id, embeding, path],
description="text to image embeding search",
enable_dynamic_field=True
)
collection_name = "text_image_vector"
collection = Collection(name=collection_name, schema=schema, using='default', shards_num=2)
インデックスを作成する
from pymilvus import Collection, utility, connections, db
conn = connections.connect(host="192.168.1.156", port=19530)
db.using_database("text_image_db")
index_params = {
"metric_type": "IP",
"index_type": "IVF_FLAT",
"params": {"nlist": 1024}
}
collection = Collection("text_image_vector")
collection.create_index(
field_name="embeding",
index_params=index_params
)
utility.index_building_progress("text_image_vector")
3.4.2 ベクトルエンコーディングモデルの構築
事前トレーニングされたモデルをロードし、Clip モデルを通じて画像をエンコードし、エンコード後に 768 の特徴次元を出力します。
from torchvision.models import resnet50
import torch
from torchvision import transforms
from torch import nn
class RestnetEmbeding:
pretrained_model = 'D:/models/resnet50-0676ba61.pth'
def __init__(self):
self.model = resnet50()
self.model.load_state_dict(torch.load(self.pretrained_model))
# delete fc layer
self.model.fc = nn.Sequential()
self.transform = transforms.Compose([transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.48145466, 0.4578275, 0.40821073],
std=[0.26862954, 0.26130258, 0.27577711])])
def embeding(self, image):
trans_image = self.transform(image)
trans_image = trans_image.unsqueeze_(0)
return self.model(trans_image)
restnet_embeding = RestnetEmbeding()
3.4.3 データのベクトル化とロード
from clip_embeding import clip_embeding
from milvus_operator import text_image_vector, MilvusOperator
from PIL import Image
import os
def update_image_vector(data_path, operator: MilvusOperator):
idxs, embedings, paths = [], [], []
total_count = 0
for dir_name in os.listdir(data_path):
sub_dir = os.path.join(data_path, dir_name)
for file in os.listdir(sub_dir):
image = Image.open(os.path.join(sub_dir, file)).convert('RGB')
embeding = clip_embeding.embeding_image(image)
idxs.append(total_count)
embedings.append(embeding[0].detach().numpy().tolist())
paths.append(os.path.join(sub_dir, file))
total_count += 1
if total_count % 50 == 0:
data = [idxs, embedings, paths]
operator.insert_data(data)
print(f'success insert {operator.coll_name} items:{len(idxs)}')
idxs, embedings, paths = [], [], []
if len(idxs):
data = [idxs, embedings, paths]
operator.insert_data(data)
print(f'success insert {operator.coll_name} items:{len(idxs)}')
print(f'finish update {operator.coll_name} items: {total_count}')
if __name__ == '__main__':
data_dir = 'D:/dataset/fruit'
update_image_vector(data_dir, text_image_vector)
3.4.4 検索ウェブの構築
import gradio as gr
import torch
import argparse
from net_helper import net_helper
from PIL import Image
from clip_embeding import clip_embeding
from milvus_operator import text_image_vector
def image_search(text):
if text is None:
return None
# clip编码
imput_embeding = clip_embeding.embeding_text(text)
imput_embeding = imput_embeding[0].detach().cpu().numpy()
results = text_image_vector.search_data(imput_embeding)
pil_images = [Image.open(result['path']) for result in results]
return pil_images
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--share", action="store_true",
default=False, help="share gradio app")
args = parser.parse_args()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
app = gr.Blocks(theme='default', title="image",
css=".gradio-container, .gradio-container button {background-color: #009FCC} "
"footer {visibility: hidden}")
with app:
with gr.Tabs():
with gr.TabItem("image search"):
with gr.Row():
with gr.Column():
text = gr.TextArea(label="Text",
placeholder="description",
value="",)
btn = gr.Button(label="search")
with gr.Column():
with gr.Row():
output_images = [gr.outputs.Image(type="pil", label=None) for _ in range(16)]
btn.click(image_search, inputs=[text], outputs=output_images, show_progress=True)
ip_addr = net_helper.get_host_ip()
app.queue(concurrency_count=3).launch(show_api=False, share=True, server_name=ip_addr, server_port=9099)
4 まとめ
OpenAI の Clip 事前トレーニング モデルと milvus ベクトル データベースの 2 つの主要なテクノロジに基づいて、このプロジェクトは、テキストによって画像を検索するためのクロスモーダル検索システムを構築します。Clip モデルによってエンコードされた後の各画像の出力ベクトル次元は、 768、これは milvus ベクトル データベースに保存されます。画像検索の効率を確保するために、スクリプトを通じて milvus ベクトル データベースにベクトル インデックスが構築されます。このプロジェクトは、同様の情報検索プロジェクトを実際に開発する際の参考として使用できます。
プロジェクトの完全なコード アドレス: code