初めに
以下でも音声ファイルの感情判定を行っていますが、こちらとは違うモデルを使って判定を行っていきます
開発環境
環境構築
以下で必要なライブラリをインストールします
uv pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
uv pip install transformers huggingface_hub librosa soundfile
感情の判定
以下のコードをファイルを指定して実行します
import argparse import os import torch import torchaudio import librosa import numpy as import torch.nn.functional as F from transformers import AutoModelForAudioClassification, AutoFeatureExtractor from huggingface_hub import HfFolder import warnings warnings.filterwarnings("ignore") def analyze_anime_emotion(audio_file_path: str): """ litagin/anime_speech_emotion_classificationモデルを使用して音声ファイルの感情を分析する。 (librosaによる音声読込強化版) """ audio_file_path = os.path.abspath(audio_file_path) if not os.path.exists(audio_file_path): print(f"エラー: 指定されたファイルが見つかりません。") print(f"パスを確認してください: {audio_file_path}") return print("--- 環境・モデル情報 ---") print(f"ライブラリ: transformers (手動制御)") model_id = "litagin/anime_speech_emotion_classification" print(f"モデル: {model_id}") try: device = "cuda:0" if torch.cuda.is_available() else "cpu" print(f"使用デバイス: {device}") hf_token = HfFolder.get_token() if hf_token is None: print("\nエラー: Hugging Faceの認証トークンが見つかりません。`huggingface-cli login` を実行してください。") return print("モデルをロードしています...") feature_extractor = AutoFeatureExtractor.from_pretrained(model_id, token=hf_token, trust_remote_code=True) model = AutoModelForAudioClassification.from_pretrained(model_id, token=hf_token, trust_remote_code=True).to(device) model.eval() print("モデルのロードが完了しました。") except Exception as e: print(f"モデルのロード中にエラーが発生しました: {e}") return print(f"\n音声ファイル '{audio_file_path}' を読み込んでいます...") try: waveform_np, original_sample_rate = librosa.load(audio_file_path, sr=None, mono=False) # NumPy配列をPyTorchテンソルに変換 waveform = torch.from_numpy(waveform_np) # librosaがモノラルで1次元配列を返した場合、2次元に変換 if waveform.ndim == 1: waveform = waveform.unsqueeze(0) # チャンネルが複数ある場合、モノラルに変換 if waveform.shape[0] > 1: waveform = torch.mean(waveform, dim=0, keepdim=True) # モデルが要求するサンプリングレート(16kHz)に変換 target_sample_rate = 16000 if original_sample_rate != target_sample_rate: # librosaはNumPy配列を扱うため、一度テンソルに変換してからリサンプル resampler = torchaudio.transforms.Resample(orig_freq=original_sample_rate, new_freq=target_sample_rate) waveform = resampler(waveform) except Exception as e: print(f"音声ファイルの読み込みまたは処理中にエラーが発生しました: {e}") return # 推論の実行 print("音声の感情を判定しています...") try: inputs = feature_extractor( waveform.squeeze(0).numpy(), sampling_rate=target_sample_rate, return_tensors="pt" ).to(device) with torch.no_grad(): outputs = model(**inputs) logits = outputs.logits probabilities = F.softmax(logits, dim=1)[0] print("\n" + "="*40) print(" 感情判定結果") print("="*40) sorted_probs, sorted_ids = torch.sort(probabilities, descending=True) top_prediction_id = sorted_ids[0].item() top_label = model.config.id2label[top_prediction_id] top_score = sorted_probs[0].item() print(f" ファイル: {os.path.basename(audio_file_path)}") print(f" 最も可能性の高い感情: {top_label} ({top_score:.2%})") print("\n --- 各感情の確率 ---") for i in range(len(sorted_probs)): label_id = sorted_ids[i].item() label_name = model.config.id2label[label_id] score = sorted_probs[i].item() print(f" - {label_name:<12}: {score:.2%}") print("="*40) except Exception as e: print(f"\n推論中に予期せぬエラーが発生しました: {e}") if __name__ == '__main__': parser = argparse.ArgumentParser( description="アニメ風音声の感情認識モデルを使用して、感情を分析します。" ) parser.add_argument( "audio_file", type=str, help="分析したい音声ファイルのパス。" ) args = parser.parse_args() analyze_anime_emotion(args.audio_file)
以下のように実行します
python .\anime_emotion_recognition.py '.\Kanjyou Ikari96.wav'
結果は以下のようになります
======================================== 感情判定結果 ======================================== ファイル: Kanjyou Ikari96.wav 最も可能性の高い感情: Angry (38.79%) --- 各感情の確率 --- - Angry : 38.79% - Happy : 28.14% - Sexual1 : 8.57% - Surprised : 8.50% - Embarrassed : 7.67% - Sad : 3.16% - Neutral : 3.14% - Disgusted : 1.43% - Fearful : 0.57% - Sexual2 : 0.02% ========================================