環境
- Python 3.10
やりたいこと
すでに分類されている話者の複数wave形式の音声ファイルを学習し、未知の音声ファイルを渡したときにどれが一番近いかを推論してほしい。
いわゆる話者分類ってやつ。
ライブラリインストール
このプロジェクトでは、音声ファイルの話者を識別するためにpyannote.audio
、scikit-learn
、librosa
といったライブラリを使用する。これらのライブラリは以下のコマンドでインストールできる。
pip install pyannote.audio==3.3.1 scikit-learn==1.5.1 librosa==0.10.2.post1
コード
train.py
import os import pickle import librosa from pyannote.audio import Inference, Model from sklearn.preprocessing import LabelEncoder from sklearn.svm import SVC # pyannote/embeddingモデルを読み込む model = Model.from_pretrained("pyannote/embedding", use_auth_token="YOUR_ACCESS_TOKEN") inference = Inference(model, window="whole") # 話者の音声ファイルが格納されているディレクトリ voices_dir = "./voices" embeddings = [] labels = [] # 各話者のディレクトリをループ for speaker in os.listdir(voices_dir): speaker_dir = os.path.join(voices_dir, speaker) if os.path.isdir(speaker_dir): # 各音声ファイルをループ for file in os.listdir(speaker_dir): if file.endswith(".wav"): file_path = os.path.join(speaker_dir, file) print(file_path) duration = librosa.get_duration(path=file_path) # 一定秒数未満の音声ファイルはスキップ threshold_seconds = 2 if duration < threshold_seconds: print( f"Skipping {file_path}: Duration is less than {threshold_seconds} seconds ({duration:.2f}s)" ) continue # 音声ファイルから埋め込みベクトルを抽出 embedding = inference(file_path) embeddings.append(embedding.squeeze()) labels.append(speaker) # ラベルをエンコード le = LabelEncoder() encoded_labels = le.fit_transform(labels) # SVMモデルを訓練 svm = SVC(kernel="rbf", probability=True) svm.fit(embeddings, encoded_labels) # モデルと関連情報を保存 with open("voices.pkl", "wb") as f: pickle.dump({"svm": svm, "label_encoder": le}, f) print("saved as voices.pkl")
predict.py
import pickle import sys from pyannote.audio import Inference, Model # コマンドライン引数をチェック if len(sys.argv) != 2: print("使用方法: python predict.py <音声ファイルのパス>") sys.exit(1) # 音声ファイルのパスを取得 audio_file = sys.argv[1] # pyannote/embeddingモデルを読み込む model = Model.from_pretrained("pyannote/embedding", use_auth_token="YOUR_ACCESS_TOKEN") inference = Inference(model, window="whole") # 保存されたモデルを読み込む with open("voices.pkl", "rb") as f: data = pickle.load(f) svm = data["svm"] le = data["label_encoder"] # 新しい音声ファイルから埋め込みベクトルを抽出 embedding = inference(audio_file) # embeddingを2D配列にリシェイプ (1 サンプル × N 特徴量) embedding_reshaped = embedding.reshape(1, -1) # 予測を行う prediction = svm.predict(embedding_reshaped) probabilities = svm.predict_proba(embedding_reshaped) # 予測結果を人間が読める形式に変換 predicted_speaker = le.inverse_transform(prediction)[0] confidence = probabilities[0][prediction[0]] print(f"予測された話者: {predicted_speaker}") print(f"信頼度: {confidence:.2f}")
実行
学習
以下のようにディレクトリを配置し、それぞれwaveファイルを置く
├── voices │ ├── taro │ ├── 1.wav │ ├── 2.wav (以下略) │ ├── hanako │ ├── mike (以下略)
で学習開始
python train.py
すると voices.pkl が作成される。
予測
あとは未知のファイルのパスを引数で渡すと
python predict.py unknown.wav
予測された話者: hanako 信頼度: 0.69
のように自動判別してくれる。やったね
使ったモデル、手法の解説
このプロジェクトでは、話者の音声ファイルから特徴を抽出し、それを元に話者を識別するモデルを訓練する。
具体的には、pyannote.audio
のembedding
モデルを使用して音声ファイルから埋め込みベクトルを抽出し、その埋め込みベクトルを元にSVM(Support Vector Machine)モデルを訓練する。
pyannote.audio
のembedding
モデルは、音声ファイルから話者の特徴を捉える埋め込みベクトルを抽出するためのモデルである。このモデルは大量の音声データを元に訓練されており、様々な話者の音声特徴を捉えることができる。
SVMは、高次元空間上での分類問題を解くためのアルゴリズムである。このプロジェクトでは、pyannote.audio
のembedding
モデルで抽出した埋め込みベクトルを元に、話者を識別するSVMモデルを訓練する。SVMモデルは、各話者の埋め込みベクトルが形成する分布を学習し、未知の音声ファイルがどの話者の分布に最も近いかを推論する。
このようにして、未知の音声ファイルの話者を識別する。この手法は、話者の数が多く、各話者の音声データが少ない場合でも高い性能を発揮する。また、新たな話者が追加された場合でも、その話者の音声データを元にモデルを追加訓練することで対応可能である。このような特性から、この手法は「話者分類」と呼ばれる。