Skip to content

Latest commit

 

History

History
199 lines (160 loc) · 8.96 KB

File metadata and controls

199 lines (160 loc) · 8.96 KB

Speech Emotion Recognition API

REST API на PyTorch (CNN) для распознавания эмоции по голосовой записи — 8 категорий в реальном времени. Применимо для аналитики колл-центров, мониторинга эмоционального состояния и адаптивных UX-систем.

Python PyTorch torchaudio FastAPI Test Accuracy License: MIT


Business Problem

Колл-центрам, платформам ментального здоровья и HR-инструментам нужно понимать эмоциональное состояние говорящего в реальном времени — ручная разметка тысяч звонков в день слишком дорога и непоследовательна. Автоматическое распознавание эмоций в речи даёт триггеры эскалации (злой/испуганный клиент), аналитику тональности после звонка и мониторинг терапевтических сессий — без ручной проверки в масштабе.


Demo

curl -X POST "http://127.0.0.1:8000/predict" \
  -H "accept: application/json" \
  -F "file=@angry_speech.wav"

Response:

{
  "index": 4,
  "emotion": "angry"
}

Классы эмоций (8): neutral · calm · happy · sad · angry · fearful · disgust · surprised


Results

Метрика Значение
Test Accuracy 67.71%
Классов 8
Эпох обучения 300

Модель: CheckAudioEmotion (3-блочный CNN: log-Mel спектрограмма → Conv2d(1→32→64→128) + BatchNorm2d + Dropout2d(0.25) на каждом блоке → AdaptiveAvgPool2d((4,4))Linear(2048→256) + Dropout(0.5)Linear(256→8)).

67.71% на 8-классовой задаче различения эмоций (baseline случайного классификатора — 12.5%) — приемлемый результат для CNN, обученного с нуля на всего 1 440 клипах без предобученных весов.


Dataset

  • Источник: RAVDESS (Kaggle: uwrfkaggler/ravdess-emotional-speech-audio)
  • Размер: 1 440 WAV-клипов, 24 актёра (12 муж / 12 жен), каждый начитывает фразы с 8 эмоциями
  • Признаки: 48kHz WAV → стерео→моно → Mel-спектрограмма (128 mel bins, n_fft=1024, hop_length=512) → AmplitudeToDB; эмоция зашита в имени файла на позиции 3 (03-01-06-... → код 06fearful, при обучении приводится к 0-индексации)
  • Разбиение: 80/20 random split, manual_seed(42)

Approach

  1. Загрузка данных — через kagglehub; RAVDESSDataset обходит папки Actor_XX/, парсит код эмоции из имени файла (parts[2]), переводит в 0-индексированный класс
  2. Предобработка — стерео→моно (mean(dim=0)), ресемплинг до 48kHz, MelSpectrogram(sample_rate=48000, n_mels=128)AmplitudeToDB, паддинг/обрезка до max_len=500
  3. Модель — 3-блочный CNN с BatchNorm2d + Dropout2d(0.25) на каждом блоке, AdaptiveAvgPool2d((4,4)), Dropout(0.5) в классификаторе
  4. Обучение — 300 эпох, Adam(lr=0.001, weight_decay=1e-4), CrossEntropyLoss, batch_size=32
  5. Inference APIpreprocess() в main.py использует ту же логику: приведение к моно, ресемплинг до 48kHz, паддинг спектрограммы до [128, 500], применяет emotion_map со сдвигом индексов ({k-1: v}), т.к. исходные метки хранятся как 1–8

Key Challenges & Solutions

Метки эмоций в файле пронумерованы с 1, модель обучена на 0-индексации labels_RAVDESS_EmotionalSpeechAudio.pth хранит эмоции как {1: ..., 8: ...} (как в оригинальном RAVDESS), а модель обучена предсказывать классы 0..7 → в main.py при загрузке словарь пересобирается ({k - 1: v for k, v in _raw_labels.items()}), иначе предсказание модели 0 (neutral) маппилось бы на реальную метку 1 из словаря — рассинхрон на один класс по всей выдаче.

Переобучение на маленьком датасете (1 440 клипов) При 180 клипах на класс CNN без регуляризации быстро запоминает train-выборку → BatchNorm2d после каждого conv-блока, Dropout2d(0.25) для пространственного дропаута карт признаков, Dropout(0.5) в классификаторе — три уровня регуляризации вместо одного, чтобы сдержать разрыв train/test.

Разный формат тензора между soundfile и torchaudio soundfile.read() отдаёт numpy (samples, channels), а torchaudio.load()(channels, samples)preprocess() в main.py явно транспонирует numpy-вход (waveform.T) перед конвертацией в тензор, иначе усреднение каналов "стерео→моно" применялось бы не к той оси.


Tech Stack

Category Tools
Язык Python 3.11
ML PyTorch 2.6.0, torchaudio
Аудио soundfile, torchaudio.transforms
Регуляризация BatchNorm2d, Dropout2d, Dropout, AdaptiveAvgPool2d
API FastAPI, Uvicorn
Обучение Google Colab (T4 GPU)

How to Run

# 1. Клонировать и установить зависимости
git clone https://github.com/your-username/speech-emotion-recognition
cd RAVDESS_EmotionalSpeechAudio
pip install -r requirements.txt
# 2. Обучение — Google Colab (RAVDESS_EmotionalSpeechAudio.ipynb)
# сохраняет model_RAVDESS_EmotionalSpeechAudio.pth
# и labels_RAVDESS_EmotionalSpeechAudio.pth
# 3. Запуск API
python main.py
# или: uvicorn main:app --host 127.0.0.1 --port 8000
# Docs: http://127.0.0.1:8000/docs

Business Impact

  • Автоматическое определение эмоции по голосу без участия оператора — 8 категорий в реальном времени
  • REST API принимает любой формат через soundfile — интегрируется с системами записи VoIP, экспортами видеозвонков, мобильными приложениями для интервью
  • Инференс без облачной зависимости — важно для здравоохранения и финансового сектора со строгими требованиями к приватности данных

Структура проекта:

ml_RAVDESS_EmotionalSpeechAudio/
├── .gitignore
├── readme.md
├── requirements.txt
└── RAVDESS_EmotionalSpeechAudio/
    ├── RAVDESS_EmotionalSpeechAudio.ipynb
    ├── main.py
    ├── model_RAVDESS_EmotionalSpeechAudio.pth
    ├── labels_RAVDESS_EmotionalSpeechAudio.pth
    └── tests/
        ├── 03-01-01-01-01-01-01.wav
        ├── 03-01-01-01-02-02-05.wav
        ├── 03-01-02-02-02-02-09.wav
        ├── 03-01-03-01-02-02-06.wav
        ├── 03-01-03-02-01-01-04.wav
        ├── 03-01-03-02-01-02-24.wav
        ├── 03-01-03-02-02-02-21.wav
        ├── 03-01-04-02-01-01-03.wav
        ├── 03-01-04-02-02-02-02.wav
        └── 03-01-05-01-01-01-18.wav