S3 Vectorsを利用してマルチモーダル検索をするための調査
S3 Vectorsの気になる点
- 2025年10月現在プレビュー版
- 東京リージョンは提供されていない
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-vectors-regions-quotas.html
- シドニー(ap-southeast-2)かUS East (N. Virginia, us-east-1)の利用を検討する
- 将来的には日本以外のユーザー数の増加も考慮に入れる
公式ドキュメント
マルチモーダル検索
埋め込みモデル
- Amazon Titan Multimodal Embeddings G1 モデルが利用できそう
-
マルチモーダル埋め込み G1 モデルは、テキストによる画像検索、類似画像による画像検索、またはテキストと画像の組み合わせによる画像の検索などのユースケースに使用されます。
- https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/titan-multiemb-models.html
-
- 対応言語: 英語のみ
- 日本語で検索する場合の考慮が必要
- コスト
- https://aws.amazon.com/jp/bedrock/pricing/
- バージニア北部の場合
- シドニーリージョンではサポートされていない
参考資料
マルチモーダル検索をやってみる
- リージョンはバージニア北部を利用
- モデルはAmazon Titan Multimodal Embeddings G1
概要
- Amazon S3 Vectorsの作成
- ベクトル埋め込みをベクトルインデックスに挿入
- テキスト検索
- 類似画像の検索
S3 Vectorsの作成
ベクトルバケットをコンソールから作成
インデックスの作成
ディメンションは、Amazon Titan Multimodal Embeddings G1が以下となっているのでため、1024
を指定(256 や 384 次元に落とすことも可能)
Output vector size – 1,024 (default), 384, 256
https://docs.aws.amazon.com/bedrock/latest/userguide/titan-multiemb-models.html
距離メトリックはコサインを指定
追加設定のメタデータはなし
ベクトル埋め込みをベクトルインデックスに挿入
import base64
import glob
import json
import boto3
from dotenv import load_dotenv
load_dotenv()
bedrock= boto3.client("bedrock-runtime", region_name="us-east-1")
s3vectors = boto3.client("s3vectors", region_name="us-east-1")
file_paths = glob.glob("image/*")
embeddings=[]
for path in file_paths:
image_bytes = open(path, "rb").read()
body = json.dumps({
"inputImage": base64.b64encode(image_bytes).decode("utf-8"),
})
response = bedrock.invoke_model(
modelId='amazon.titan-embed-image-v1',
body=body
)
response_body = json.loads(response['body'].read())
embeddings.append( {
"key": path,
"data": {"float32": response_body["embedding"]},
})
res = s3vectors.put_vectors(
vectorBucketName="vector-20251003", indexName="vector-20251003-index", vectors=embeddings
)
用意した画像
5つの猫の画像を利用する
テキスト検索
日本語で「白い猫」「黒い猫」と入力された場合を想定し、white cat
とblack cat
で検索。
import base64
import json
import boto3
bedrock= boto3.client("bedrock-runtime", region_name="us-east-1")
s3vectors = boto3.client("s3vectors", region_name="us-east-1")
input_text = "white cat"
body = json.dumps({
"inputText": input_text,
})
response = bedrock.invoke_model(
modelId="amazon.titan-embed-image-v1",
body=body
)
response_body = json.loads(response["body"].read())
embedding = response_body["embedding"]
query = s3vectors.query_vectors(
vectorBucketName="vector-20251003",
indexName="vector-20251003-index",
queryVector={"float32":embedding},
topK=3,
returnDistance=True,
returnMetadata=True
)
results = query["vectors"]
print(results)
結果
検索ワードに近い画像が取得できている
-
white cat
の結果の画像
-
black cat
の結果の画像
類似画像の検索
import base64
import json
import boto3
bedrock= boto3.client("bedrock-runtime", region_name="us-east-1")
s3vectors = boto3.client("s3vectors", region_name="us-east-1")
image_bytes = open("image/5b73a923-a894-4c55-abe9-c2a2279d89e4.webp", "rb").read()
body = json.dumps({
"inputImage": base64.b64encode(image_bytes).decode("utf-8"),
})
response = bedrock.invoke_model(
modelId="amazon.titan-embed-image-v1",
body=body
)
response_body = json.loads(response["body"].read())
embedding = response_body["embedding"]
query = s3vectors.query_vectors(
vectorBucketName="vector-20251003",
indexName="vector-20251003-index",
queryVector={"float32":embedding},
topK=3,
returnDistance=True,
returnMetadata=True
)
results = query["vectors"]
print(results)
検索結果
[
{'key': 'image/5b73a923-a894-4c55-abe9-c2a2279d89e4.webp', 'metadata': {}, 'distance': 0.0004391670227050781},
{'key': 'image/0ab0c123-0562-4ee9-9f89-d7c544a14fd2.webp', 'metadata': {}, 'distance': 0.2183462381362915}
]
-
検索用の画像
-
検索結果
検索に利用した画像と同じもの、同じポーズをしている猫の画像が検索された
日本語による検索
Cohere Embed v4が使用可能になった(2025年10月2日)
やってみる
モデルアクセスのリクエスト
ベクトルインデックスの作成
ベクトル埋め込みをベクトルインデックスに挿入
日本語によるテキスト検索
類似画像の検索
モデルアクセスをリクエスト
AWSコンソール Amazon Bedrock > モデルアクセスから「Embed v4」のアクセスをリクエスト
数秒程度でアクセス可能になった
ベクトルインデックスの作成
ディメンションはデフォルトの1536
を設定
ベクトル埋め込みをベクトルインデックスに挿入
def get_base64_image_uri(image_file_path: str, image_mime_type: str):
with open(image_file_path, "rb") as f:
image_bytes = f.read()
base64_image = base64.b64encode(image_bytes).decode("utf-8")
return f"data:{image_mime_type};base64,{base64_image}"
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
model_id = "cohere.embed-v4:0"
input_type = "search_document"
embedding_types = ["float"]
accept = '*/*'
content_type = 'application/json'
embeddings = []
file_paths = glob.glob("../image/*")
for path in file_paths:
image_base64_uri = get_base64_image_uri(path, image_mime_type)
body = json.dumps({
"input_type": input_type,
"images": [image_base64_uri],
"embedding_types": embedding_types
})
response = bedrock.invoke_model(
modelId=model_id,
body=body,
accept=accept,
contentType=content_type
)
response_body = json.loads(response['body'].read())
embedding_vector = response_body["embeddings"]["float"][0]
embeddings.append({
"key": path,
"data": {"float32": embedding_vector},
})
s3vectors = boto3.client("s3vectors", region_name="us-east-1")
res = s3vectors.put_vectors(
vectorBucketName="vector-20251003",
indexName="vector-20251004-cohere-v4-index",
vectors=embeddings
)
AWS CLIで登録されていることを確認
aws s3vectors list-vectors \
--vector-bucket-name "vector-20251003" \
--index-name "vector-20251004-cohere-v4-index"
日本語によるテキスト検索
日本語で「白い猫」「黒い猫」「寝ている猫」を検索
結果
- 「白い猫」の結果
[ {'key': '../image/7717955d-f83e-4466-b9f5-201c232ffd14.webp', 'metadata': {}, 'distance': 0.6253760457038879}, {'key': '../image/b301e8c3-71fb-4db4-ade3-34693311980a.webp', 'metadata': {}, 'distance': 0.6433943510055542}, {'key': '../image/fb7f3a0e-fccd-45ee-a3f0-17c7138a6a8a.webp', 'metadata': {}, 'distance': 0.6550061702728271} ]
- 「黒い猫」の結果
[
{'key': '../image/5b73a923-a894-4c55-abe9-c2a2279d89e4.webp', 'metadata': {}, 'distance': 0.6397557258605957},
{'key': '../image/7717955d-f83e-4466-b9f5-201c232ffd14.webp', 'metadata': {}, 'distance': 0.6870872974395752},
{'key': '../image/0ab0c123-0562-4ee9-9f89-d7c544a14fd2.webp', 'metadata': {}, 'distance': 0.7297742366790771}
]
- 「寝ている猫」の結果
[
{'key': '../image/7717955d-f83e-4466-b9f5-201c232ffd14.webp', 'metadata': {}, 'distance': 0.5258817672729492},
{'key': '../image/b301e8c3-71fb-4db4-ade3-34693311980a.webp', 'metadata': {}, 'distance': 0.6387431621551514},
{'key': '../image/0ab0c123-0562-4ee9-9f89-d7c544a14fd2.webp', 'metadata': {}, 'distance': 0.6802964210510254}
]
類似画像の検索
def get_base64_image_uri(image_file_path: str, image_mime_type: str):
with open(image_file_path, "rb") as f:
image_bytes = f.read()
base64_image = base64.b64encode(image_bytes).decode("utf-8")
return f"data:{image_mime_type};base64,{base64_image}"
bedrock= boto3.client("bedrock-runtime", region_name="us-east-1")
model_id = "cohere.embed-v4:0"
input_type = "search_document"
embedding_types = ["float"]
accept = '*/*'
content_type = 'application/json'
image_mime_type = "image/webp"
image_base64_uri = get_base64_image_uri("../image/5b73a923-a894-4c55-abe9-c2a2279d89e4.webp", image_mime_type)
body = json.dumps({
"input_type": input_type,
"images": [image_base64_uri],
"embedding_types": embedding_types
})
response = bedrock.invoke_model(
modelId=model_id,
body=body,
accept=accept,
contentType=content_type
)
response_body = json.loads(response["body"].read())
embedding = response_body["embeddings"]["float"][0]
s3vectors = boto3.client("s3vectors", region_name="us-east-1")
query = s3vectors.query_vectors(
vectorBucketName="vector-20251003",
indexName="vector-20251004-cohere-v4-index",
queryVector={"float32":embedding},
topK=3,
returnDistance=True,
returnMetadata=True
)
results = query["vectors"]
print(results)
[
{'key': '../image/5b73a923-a894-4c55-abe9-c2a2279d89e4.webp', 'metadata': {}, 'distance': 0.0004458427429199219},
{'key': '../image/0ab0c123-0562-4ee9-9f89-d7c544a14fd2.webp', 'metadata': {}, 'distance': 0.4271997809410095},
{'key': '../image/7717955d-f83e-4466-b9f5-201c232ffd14.webp', 'metadata': {}, 'distance': 0.45190203189849854}
]
最小限のサンプルコードを下記リポジトリに追加