Как увидеть близость двух высказываний в библиотеке Python?
Требуется Ваша помощь по одному вопросу в коде: сделал, а теперь сомневаюсь. Подход модуля Resemblyzer
Итак, у нас есть в отдельных папках по нескольку высказываний каждого спикера: папка spk1 - несколько его высказываний, spk2 - несколько его высказываний и т.д.
Выполняя работу, я ориентировался на код примера, где сравнивались просто по 2 первых эмбединга (высказывания) говорящего вне перебора всех возможных вариаций. Я же перебирал циклом все сочетания внутри папки всякого спикера: ( высказывание 1 , высказывание 2 ), (высказывание 1 , высказывание 3 ) и т.д. по всем спикерам.
В коде примера есть длинная и короткая версии перемножения эмбедингов. Поначалу я решил, что именно эти векторы, полученные двумя версиями, мы должны сравнить. Но сейчас, внимательно проанализировав сии векторы, заметил, что на деле имеем по паре векторов, которые фактически всегда идентичны (различаются последними цифрами: в одном случае - с округлением):
Матрица_1 [[0.6333688]]
Матрица_2 [[0.63336879]]
Далее я перешел к расчету метрики accuracy, но сейчас мне кажется, что поторопился.
Первоначально я отбросил продолжение кода примера, но теперь мне кажется, что оно может быть важно (хотя не могу понять его смысл):
## Сходство между двумя эмбедингами говорящего
# Разделим высказывания каждого говорящего на группы одинакового размера
# и представим каждую группу в качестве эмбединга спикера
spk_embeds_a = np.array([encoder.embed_speaker(wavs[:len(wavs) // 2]) \
for wavs in speaker_wavs.values()])
spk_embeds_b = np.array([encoder.embed_speaker(wavs[len(wavs) // 2:]) \
for wavs in speaker_wavs.values()])
spk_sim_matrix = np.inner(spk_embeds_a, spk_embeds_b)
Может ли (и каким образом) строка spk_sim_matrix = np.inner(spk_embeds_a, spk_embeds_b) играть роль при определении сходства двух эмбедингов? Ведь по сути там просто вектор: array([[0.7750825]], dtype=float32)
Как вариант, думается, он задает порог: скажем, до 0,5 - сходства нет, больше 0,5 - спикер верифицируется как один и тот же. Тогда почему в коде примера мы явно не видим задания порога???
Мой код:
# сравниваем в рамках папок одного спикера (комбинации своих голосов)
!pip install resemblyzer
!pip install umap
from resemblyzer import preprocess_wav, VoiceEncoder
from itertools import groupby
from pathlib import Path
from tqdm import tqdm
import numpy as np
from itertools import combinations
num_true=0
num_total=0
# ради сравнения перебираем значения словаря (т.е. эмбединги записей спикеров) и создаем список всех возможных комбинаций:
# (спикер 1 запись 1 - спикер 1 запись 2), (спикер 1 запись 1 - спикер 1 запись 3) и т.д.
for elems in speaker_wavs.values():
tuples = list(combinations(elems, 2)) # получаем перебор всех комбинаций
for single in tuples: # идем по каждому кортежу в списке
# функция .embed_utterance() создает эмбединги голосов внутри каждой папки
embeds = (np.array( [encoder.embed_utterance(single[0]) ] ), np.array([encoder.embed_utterance(single[1]) ] ) )
num_total+=1
# Вычислим матрицу подобия. Сходство двух эмбедингов - это просто их точечное произведение,
# потому что метрикой сходства является косинусное сходство, а эмбединги уже нормированы по L2.
# Короткая версия:
utt_sim_matrix = np.inner(embeds[0], embeds[1]) # Внутреннее произведение двух массивов.
# Длинная, подробная версия:
utt_sim_matrix2 = np.zeros( (len(embeds[0]), len(embeds[1]) ) )
for i in range(len(embeds[0])):
for j in range(len(embeds[1])):
# Обозначение @ эквивалентно np.dot(embedds_a[i], embedds_b[i])
utt_sim_matrix2[i, j] = embeds[0][i] @ embeds[1][j]
# np.allclose() возвращает True, если два массива равны по элементам в пределах допуска
if np.allclose(utt_sim_matrix, utt_sim_matrix2):
num_true+=1
# считаем метрику accuracy:
if num_total !=0:
accuracy = num_true/num_total
print('accuracy: ', accuracy)
else:
print('На ноль делить нельзя')