3월에 출시된 gemini-embedding-2-preview는 텍스트·이미지·동영상·음성을 인풋(Input)으로 받아들여, 동일한 포맷의 임베딩 (Embedding)을 출력할 수 있습니다.
이를 통해 이론상 이미지 간의 유사도 비교나, 이미지와 텍스트의 유사도 비교 등 매우 많은 용도가 생겨날 것으로 생각됩니다.
이번에는 위의 용도에 대해 가볍게 검증해 보고자 합니다.
face1.jpg부터 face5.jpg까지는 Pexels에서 다운로드한 모두 다른 인물의 표정 이미지(테스트를 위해 각각 어떤 표정인지는 명시하지 않습니다).
face16.jpg는 한 사람의 표정이 4x4로 분할된 이미지이며, face16.py를 사용하여 개별 이미지로 분할합니다.
※ 보충: 이미지 소스는 Pexels에서 입수했으므로 저작권 문제는 없습니다.
face1.jpg ~ face5.jpg (5명의 서로 다른 표정)를 사용 - 각 이미지를 「분노(怒)」, 「슬픔(哀)」, 「즐거움(楽)」 텍스트와 각각 코사인 유사도 (Cosine Similarity)로 비교 (「기쁨(喜)」은 「즐거움(楽)」과 거의 같으므로 생략)
face16.jpg를 face16.py로 4×4 분할한 16장을 사용 (동일 인물의 서로 다른 표정) - 각 이미지를 「분노(怒)」, 「슬픔(哀)」, 「즐거움(楽)」 텍스트와 각각 코사인 유사도 (Cosine Similarity)로 비교 (「기쁨(喜)」은 「즐거움(楽)」과 거의 같으므로 생략)
face1.jpg ~ face5.jpg 5장 + face16.jpg에서 분할한 것 중 5장, 총 10장을 사용 - 10장 간의 모든 쌍에 대해 코사인 유사도 (Cosine Similarity)를 비교 (10×10 유사도 행렬)
- 서로 다른 인물 vs 동일 인물 (
face16 분할)의 스코어 차이를 통해, 모델의 얼굴 식별 능력을 검증
def embed_image(
client: genai.Client,
image_path: str | os.PathLike,
...
def embed_text(
client: genai.Client,
text: str,
...
def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
denom = float(np.linalg.norm(a) * np.linalg.norm(b))
if denom == 0.0:
...
먼저, 이것이 검증에 사용한 샘플 이미지입니다.
face16.jpg (이것을 face_01부터 face_16까지 분할)
일본어 텍스트와의 유사도는 그리 좋지 않은 결과였습니다.
영어 (Angry, Sad, Happy 등)를 사용하여 다시 한번 분석해 본 결과, 일본어보다 조금 좋아졌습니다. 이 정도라면 어느 정도 쓸 수 있는 수준이라고 생각합니다.
동일 인물이라면 생김새에 따른 변수 (노이즈)가 없어지므로, 더욱 정확하게 측정할 수 있을 것이라 생각합니다.
결과적으로 정밀도가 좋아졌다고 느껴집니다.
애초에 왜 「분노(怒)」·「슬픔(哀)」·「즐거움(楽)」의 스코어 차이가 이토록 작은지에 대해 생각해 보았습니다.
하나의 이미지에서 추출되는 임베딩 (Embedding)에는 매우 많은 정보가 포함되어 있으며, 「인간」, 「얼굴」, 「표정」 등도 그 일부입니다. 「분노(怒)」·「슬픔(哀)」·「즐거움(楽)」은 표정으로서는 각각 다르지만, 모두 「표정」이라는 틀의 서브셋 (Subset)에 불과하기 때문에, 전체 임베딩 내에서 비교하면 그렇게 큰 차이가 나지 않는 것도 합리적이라고 할 수 있습니다.
분명히 동일 인물끼리는 유사도가 높아진다는 것을 확인할 수 있었습니다.
이상의 검증은 멀티모달 (Multimodal) 임베딩 모델의 아주 일부 용도에 불과하므로, 앞으로 또 다른 용도에 대해서도 검증해 나가고 싶습니다.