REST API на PyTorch (CNN) для распознавания эмоции по голосовой записи — 8 категорий в реальном времени. Применимо для аналитики колл-центров, мониторинга эмоционального состояния и адаптивных UX-систем.
Колл-центрам, платформам ментального здоровья и HR-инструментам нужно понимать эмоциональное состояние говорящего в реальном времени — ручная разметка тысяч звонков в день слишком дорога и непоследовательна. Автоматическое распознавание эмоций в речи даёт триггеры эскалации (злой/испуганный клиент), аналитику тональности после звонка и мониторинг терапевтических сессий — без ручной проверки в масштабе.
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
| Метрика | Значение |
|---|---|
| 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 клипах без предобученных весов.
- Источник: 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-...→ код06→fearful, при обучении приводится к 0-индексации) - Разбиение: 80/20 random split,
manual_seed(42)
- Загрузка данных — через
kagglehub;RAVDESSDatasetобходит папкиActor_XX/, парсит код эмоции из имени файла (parts[2]), переводит в 0-индексированный класс - Предобработка — стерео→моно (
mean(dim=0)), ресемплинг до 48kHz,MelSpectrogram(sample_rate=48000, n_mels=128)→AmplitudeToDB, паддинг/обрезка доmax_len=500 - Модель — 3-блочный CNN с
BatchNorm2d+Dropout2d(0.25)на каждом блоке,AdaptiveAvgPool2d((4,4)),Dropout(0.5)в классификаторе - Обучение — 300 эпох,
Adam(lr=0.001, weight_decay=1e-4),CrossEntropyLoss,batch_size=32 - Inference API —
preprocess()вmain.pyиспользует ту же логику: приведение к моно, ресемплинг до 48kHz, паддинг спектрограммы до[128, 500], применяетemotion_mapсо сдвигом индексов ({k-1: v}), т.к. исходные метки хранятся как 1–8
Метки эмоций в файле пронумерованы с 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) перед
конвертацией в тензор, иначе усреднение каналов "стерео→моно"
применялось бы не к той оси.
| 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) |
# 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- Автоматическое определение эмоции по голосу без участия оператора — 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