はじめに
2024年5月31日(Fri)20:00 ~ 2024年6月7日(Fri)22:00
#生成AI オンラインハッカソン4 by #protopedia
https://protopedia.net/event/102
このイベントで作った作品の解説をします。
ネタ作品ですが、Embeddingとベクター検索は生成AI関連でもよく使う技術となりますので、何かの役にたつと幸いです。
概要
- 以前どこかで会って名刺交換したのだが、名前を思い出せないという時に使用
- Raspberry Pi4 カメラで撮影した画像をベクター検索して、可能性の高い人を教えてくれるシステム
仕様
使い方
-
パーティなどで名刺交換したあと、写真を撮影。
-
家に帰ったら忘れないうちにEmbeddingし、MacのローカルベクターDBに登録しておく。
-
人と会う機会にこのデバイスを持っていき、うっかり名前を思い出せない時に、「ちょっと失礼します!」と勢いよく鞄から人形を取り出し、目をあわせてもらう
-
MacからRaspberry Piに有線などで接続
-
Raspberry Pi カメラで撮影
-
ベクター化 → 類似検索
-
可能性のある人物が提示される
コード
以下は 「2. 家に帰ったら忘れないうちにEmbeddingし、MacのローカルのベクターDBに登録しておく」
の部分のコードとなります。
tensorflowのライブラリに含まれるResNet50を使っています。
# 画像からembeddingを抽出するモデルの設定
model = ResNet50(weights='imagenet', include_top=False, pooling='avg')
def get_image_embedding(img_path):
"""
指定されたパスの画像からembeddingを取得します。
"""
# 画像の読み込みと前処理
img = image.load_img(img_path, target_size=(224, 224))
img_array = image.img_to_array(img)
img_array = np.expand_dims(img_array, axis=0)
img_array = preprocess_input(img_array)
# 画像からembeddingを取得
embedding = model.predict(img_array)
return embedding
def load_images_and_embeddings(directory):
"""
指定されたディレクトリ内の全ての画像を読み込み、それぞれのembeddingを取得します。
"""
image_paths = [os.path.join(directory, f) for f in os.listdir(directory) if f.endswith(('.jpg', '.jpeg', '.png'))]
embeddings = []
for img_path in image_paths:
embedding = get_image_embedding(img_path)
embeddings.append(embedding)
return image_paths, np.vstack(embeddings)
def create_faiss_index(embeddings):
"""
embeddingをFAISSインデックスに追加します。
"""
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(embeddings)
return index
Raspberry Piのカメラを叩いて撮影し、ローカル上の/content/target-image/target.jpeg
に保存するコードは割愛します。
次は、「6. ベクター化 → 類似検索」の部分のコードです。
# クエリ画像のパス
query_image_path = '/content/target-image/target.jpeg'
# 類似画像を検索
similar_images = search_similar_images(query_image_path, image_paths, index, top_k=5)
# 結果を表示
print("Query image:", query_image_path)
print("Similar images:")
for img_path in similar_images:
print(img_path)
結果
自分の顔と芸能人3人の方の写真を、1人3枚づつ集めてこのシステムで判定したところ、残念ながら正確には判定できませんでした。
1位 ロバート秋山さん
2位 自分
3位 ファーストサマーウイカさん
4位 ロバート秋山さん
5位 自分
選外
ビートたけしさん
うる星やつらの「ラムちゃん」さん
(著作権の都合上、顔写真を出す事は控えます)
結果その2
結果が納得いかないので、他のモデルを試そうと思い、ResNet50 -> VGG16に変えて試したところ、信頼性が落ちてしまいました。
1位 ファーストサマーウイカさん
2位 自分
3位 ロバート秋山さん
4位 自分
5位 うる星やつらの「ラムちゃん」さん
選外
ビートたけしさん
Tips
VGG16はResNet50より古く、ベクターの次元数も少ないので、多少重かったとしてもResNet50を使った方が良さそうです。
名前 | 特徴 | ベクトルの次元数 |
---|---|---|
VGG16 | 深さが 16 層の畳み込みニューラル ネットワーク | 512次元 |
ResNet50 | 深さが 50 層の畳み込みニューラル ネットワーク | 2048次元 |
振り返り
様々なハードルがあり、実用には適しておりませんでした。
とくに「勢いよく人形を取り出し、目をあわせてもらう」運用は無理でした。残念。
ですが将来的に「Ray-Ban Meta」のような民間のwearable デバイスがネット越しにAIと繋がり、このような機能を持つ事は容易に想像できます。
その時を楽しみに待ちたいと思います。
以上となります。