Сегментация вместо диаризации для оценки количества говорящих

Я использую диаризацию pyannote, чтобы определить количество динамиков в аудио, где количество динамиков не может быть определено заранее. Вот код для определения количества говорящих путем диаризации:

      from pyannote.audio import Pipeline
MY_TOKEN = ""  # huggingface_auth_token
audio_file = "my_audio.wav"
pipeline = Pipeline.from_pretrained("pyannote/speaker-diarization@2.1", use_auth_token=MY_TOKEN)
output = pipeline(audio_file, min_speakers=2, max_speakers=10)
results = []
for turn, _, speaker in list(output.itertracks(yield_label=True)):
    results.append(speaker)
num_speakers = len(set(results))
print(num_speakers)

Использование диаризации для оценки количества говорящих кажется излишним и медленным. Поэтому я пытался сегментировать звук на куски, встроить аудиосегменты и выполнить некоторую кластеризацию встраивания, чтобы определить идеальное количество кластеров в качестве возможного количества динамиков. В серверной части pyannote также может делать что-то подобное для оценки количества говорящих. Вот что я пробовал в коде:

      from sklearn.cluster import SpectralClustering, KMeans, AgglomerativeClustering
from sklearn.metrics import silhouette_score
from spectralcluster import SpectralClusterer
from resemblyzer import VoiceEncoder, preprocess_wav
from pyannote.audio.pipelines.speaker_verification import PretrainedSpeakerEmbedding
from pyannote.audio import Model
from pyannote.audio import Audio
from pyannote.core import Segment
from pyannote.audio.pipelines import VoiceActivityDetection
import numpy as np


audio_file = "my_audio.wav"
MY_TOKEN = ""  # huggingface_token
embedding_model = PretrainedSpeakerEmbedding("speechbrain/spkrec-ecapa-voxceleb")
encoder = VoiceEncoder()
model = Model.from_pretrained("pyannote/segmentation", 
                              use_auth_token=MY_TOKEN)
pipeline = VoiceActivityDetection(segmentation=model)
HYPER_PARAMETERS = {
  # onset/offset activation thresholds
  "onset": 0.5, "offset": 0.5,
  # remove speech regions shorter than that many seconds.
  "min_duration_on": 0.0,
  # fill non-speech regions shorter than that many seconds.
  "min_duration_off": 0.0
}
pipeline.instantiate(HYPER_PARAMETERS)
vad = pipeline(audio_file)
audio_model = Audio()

segments = list(vad.itertracks(yield_label=True))
embeddings = np.zeros(shape=(len(segments), 192))
#embeddings = np.zeros(shape=(len(segments), 256))

for i, diaz in enumerate(segments):
    print(i, diaz)
    waveform, sample_rate = audio_model.crop(audio_file, diaz[0])
    embed = embedding_model(waveform[None])
    #wav = preprocess_wav(waveform[None].flatten().numpy())
    #embed = encoder.embed_utterance(wav)
    embeddings[i] = embed
embeddings = np.nan_to_num(embeddings)

max_clusters = 10
silhouette_scores = []
# clustering = SpectralClusterer(min_clusters=2, max_clusters=max_clusters, custom_dist="cosine")
# labels = clustering.predict(embeddings)
# print(labels)

for n_clusters in range(2, max_clusters+1):
    # clustering = SpectralClustering(n_clusters=n_clusters, affinity='nearest_neighbors').fit(embeddings)
    # clustering = KMeans(n_clusters=n_clusters).fit(embeddings)
    clustering = AgglomerativeClustering(n_clusters).fit(embeddings)
    labels = clustering.labels_
    score = silhouette_score(embeddings, labels)
    print(n_clusters, score)
    silhouette_scores.append(score)

# Choose the number of clusters that maximizes the silhouette score
number_of_speakers = np.argmax(silhouette_scores) + 2  # add 2 to account for starting at n_clusters=2
print(number_of_speakers)

Но проблема в том, что я не получаю тех же результатов, что и результаты диаризации Pyannote, особенно когда количество говорящих больше 2. Кажется, что диаризация Pyannote возвращает более реалистичное число. Как получить те же результаты, что и диаризация в пианноте, но используя какой-то более быстрый процесс, например сегментацию?

1 ответ

Неудивительно, что два метода дают разные результаты. Диаризизация говорящих и группировка говорящих — это два разных подхода к одной и той же проблеме подсчета говорящих, и они делают разные предположения относительно данных и проблемы.

Диаризация говорящих основана на таких методах, как обнаружение смены говорящих и встраивание говорящих, чтобы сегментировать звук на регионы, соответствующие разным говорящим, а затем присваивать каждому сегменту уникальную метку говорящего. Этот подход устойчив к различным источникам изменений звука, таким как наложение речи, фоновый шум и характеристики динамиков, но он может быть дорогостоящим в вычислительном отношении.

С другой стороны, кластеризация динамиков предполагает, что звук можно разделить на фиксированное количество непересекающихся сегментов, и пытается сгруппировать их в кластеры, соответствующие разным динамикам, на основе некоторой метрики сходства. Этот подход быстрее, чем диаризация, но может быть не таким точным, особенно когда количество говорящих заранее неизвестно.

Чтобы повысить точность вашего подхода к кластеризации говорящих, вы можете рассмотреть возможность включения некоторых методов, используемых при диаризации, таких как обнаружение голосовой активности и встраивание говорящих. Например, вы можете использовать алгоритм VAD для сегментации звука на речевые и неречевые области, а затем применить кластеризацию только к речевым областям. Вы также можете использовать предварительно обученную модель внедрения говорящего, чтобы извлечь функции из речевых регионов и использовать их в качестве входных данных для вашего алгоритма кластеризации.

В целом, маловероятно, что вы сможете достичь того же уровня точности, что и диаризация, используя только кластеризацию, но вы можете приблизиться к этому, объединив два подхода.

Другие вопросы по тегам