Show HN: SpectroMood 用决策模型做语音情感识别
Show HN: SpectroMood, speech emotion detection with a decision model
SpectroMood 是一个开源实验,把语音转成标注图表和相对说话人自身平静基线的声学测量值,再交给 Cloudflare 的 clef-flash 决策模型判断愤怒、恐惧、开心、悲伤或中性。
使用决策模型进行语音情感检测。 将声音转化为带标签的图表和通俗易懂的测量数据,然后让 Cloudflare Clef 判断说话者的情绪。
仪表盘通过虚拟麦克风播放基准音频片段;结果是 clef-flash 的真实回答。
SpectroMood 是一个开放实验:一个从未在音频上训练过的通用决策模型,如果我们向它展示正确的证据,它能否识别语音中的情感?Clef 读取一段简短的状态描述、最多四张图片和一个文字问题,并为每个允许的答案返回一个概率。我们给它一张声音的图片、说话者声音相对于其自身平静基线的测量值,以及一份关于情绪如何发声的简短指南,然后问:愤怒、恐惧、快乐、悲伤还是中性?
结果
clef-flash 采用推荐的 plots+features+guide 设置,每种语言 50 个片段
(每种情绪 10 个:愤怒、恐惧、快乐、悲伤、中性)。随机概率为 20%。
| 语言 | 数据集 | 说话者基线 | 准确率 | 宏平均 F1 | 唤醒度 AUC | 😠 愤怒 | 😨 恐惧 | 😄 快乐 | 😢 悲伤 | 😐 中性 |
|---|---|---|---|---|---|---|---|---|---|---|
| 英语 | RAVDESS | 按说话者 | 48% | 0.39 | 0.93 | 90% | 0% | 50% | 0% | 100% |
| 俄语 | RESD | 语料库平均 | 40% | 0.31 | 0.83 | 50% | 0% | 100% | 0% | 50% |
| 西班牙语 | MESD | 语料库平均 | 26% | 0.16 | 0.66 | 0% | 0% | 50% | 0% | 80% |
每种设置发送给 Clef 的内容(准确率):
| 设置 | 图像 | 文本 | 英语 | 俄语 | 西班牙语 |
|---|---|---|---|---|---|
spectrogram |
对数梅尔频谱图 | – | 20% | 20% | 20% |
plots |
频谱图 + 音高 + 响度图 | – | 20% | 20% | 20% |
features |
– | 声音测量值 vs 基线 | 40% | 38% | 20% |
plots+features+guide |
图表 | 测量值 + 线索指南 | 48% | 40% | 26% |
唤醒度 AUC 衡量唤醒度分数将高能量语音(愤怒、恐惧、 快乐)与低能量语音(悲伤、中性)区分开来的程度:0.5 为随机,1.0 为完美。每种语言 50 个 片段时,准确率的 95% 区间约为 ±14 个百分点。完整表格:reports/results.md。
混淆矩阵
工作原理
- 门控。 Silero VAD 检查每个窗口是否有人声。只有噪声、音乐或打字声的窗口 永远不会发送给 Clef,因此不产生任何费用。
- 测量。 一个 4 秒的窗口被重采样为 16 kHz。测量 pYIN 音高跟踪、响度、频谱 倾斜、谐噪比、音高不稳定性、语速和停顿。
- 展示。 该窗口被绘制为三个堆叠的带标签面板(频谱图、音高轮廓和 响度包络),因为通用视觉模型读取明确的坐标轴远比读取裸热图要好得多。
- 比较。 每个测量值都相对于同一说话者的平静声音重新表述("音高 +12 个半音,响度 +20 dB")。绝对值在不同声音之间差异太大,单独来看没有意义。
- 解释。 答案选项描述了每种情绪通常如何改变声音 (Banse & Scherer 1996; Juslin & Laukka 2003)。
- 决策。 Clef 为每种情绪返回一个概率和一个唤醒度分数,大约需要半秒钟。
快速开始
你需要 Docker 和一个 Cloudflare 账户。创建一个具有 Workers AI 权限的 API 令牌 (仪表盘 → My Profile → API Tokens → "Workers AI" 模板)。
git clone https://github.com/ketul93/spectromood.git && cd spectromood cp .env.example .env # set CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN docker compose up -d --build
- 点击 🧘 Calibrate my voice 并平静地说话 6 秒钟。这就是你的基线。它保留在你的 浏览器中,并随每个请求一起发送。
- 点击 🎙️ Start microphone 并说话。每隔几秒分析一个窗口,结果会在 大约一秒后出现。
- 或者点击 📁 Analyse a file 将录音通过相同的流程运行。
浏览器只允许在 localhost 或通过 HTTPS 使用麦克风。要从另一台设备使用它,请将容器置于 HTTPS 之后(例如 Cloudflare Tunnel);文件分析可通过普通 HTTP 进行。
复现基准测试
一切都在 tools 容器中运行;无需在本地安装任何东西。
docker compose run --rm tools python scripts/prepare_data.py --lang en,it,ru,es docker compose run --rm tools python scripts/evaluate.py --lang en,it,ru,es docker compose run --rm tools pytest
data/<lang>/ 中的片段列表已提交,因此每次运行评估的都是相同的录音。每个 Clef 答案都缓存在精确请求的哈希下,因此重新运行只需为新的请求付费。结果保存在 reports/results.md 中,图表保存在 docs/images/ 中。
意大利语(--lang it)也以同样的方式准备。评估全部四种语言会进行 800 次 Clef 调用(四种设置 × 各 50 个片段),远在 Workers 免费额度的一天之内。
我们学到了什么
- 仅靠图片行不通。 只有频谱图,甚至加上标注的音高和响度图,clef-flash 对每种语言的每个片段都回答“中性”(完全等同于随机)。Clef 确实会读取图像,这一点通过检查面板标题得到了证实;它只是无法将其转化为情感判断。
- 相对于说话者的测量值是关键。 将特征与说话者自己的平静声音进行对比陈述(“音高 +12 st,响度 +20 dB”)带来了最大的提升:英语从 20% 提高到 40%。在数据集不标识说话者的情况下(俄语、西班牙语),平均语料库基线是一个较弱的替代方案。
- 唤醒度容易;恐惧和悲伤很难。 Clef 能可靠地区分激动和平静的语音(唤醒度 AUC 0.83–0.93),并能正确识别愤怒和中性,但它会把恐惧和悲伤称为“愤怒”或“快乐”:在表演性语音中,这三种情绪都会提高音高和响度。
- 在这里,更大并不更好。 27B 的
clef模型得分低于 9B 的clef-flash(它几乎把任何提高的声音都标记为“愤怒”),而clef-flash更快、更便宜,因此它是唯一使用的模型。 - 在我们的实验中,以下做法没有帮助:带标签示例的少样本表格、用五个是/否问题代替一个选择、一份将各种情绪相互对比的指南,以及将 37 个 eGeMAPS 风格的特征筛选到最具区分度的那些。对相同测量值进行逻辑回归可达到 52–66%,因此信息是存在的。同时权衡许多数字的决策模型才是瓶颈。
- 从不使用文字。 该流程只看到声学信息,因此设计上就与语言无关。西班牙语的下降更多反映的是该数据集(单个口语单词,部分由儿童录制,没有说话者 ID),而非语言本身。
后续步骤
- 意大利语(Emozionalmente,431 位非专业说话者):片段列表已提交,音频随
prepare_data.py --lang it下载,但尚未评估。运行evaluate.py --lang it(200 次 Clef 调用)并提交包含数字的 PR。 - 印地语和古吉拉特语计划通过 AI4Bharat 的 Rasa(CC BY 4.0,受限访问,每种语言 2 位配音艺术家)进行。你自己的带标签录音也可以:添加
data/<lang>/manifest.csv和baselines.csv(列file,emotion,speaker和file,speaker),将 WAV 文件放入data/<lang>/clips/,并在scripts/evaluate.py中注册该语言。 - 一种混合方案,其中一个小型训练分类器提供一个概率,Clef 将其与图表一起权衡,并使用真实(非表演性)语音。
成本与限制
- 一个包含一张图片的请求大约有 1,800 个输入 token。图片本身大约 660 个 token。
clef-flash按发布价格每百万输入 token 收费 $0.09,大约每次请求 $0.0002,或连续使用麦克风每小时约 $0.20(每 3 秒一次请求)。- 在 Workers Free 计划中,每日配额(10,000 neurons)大约可支持 2,300 次请求,约两小时的实时使用。它在 UTC 00:00 重置。当配额用尽时,仪表盘会显示明确的错误(HTTP 429),而不是静默失败。
项目结构
src/spectromood/ audio prep, features, plots, Clef client, prompts, FastAPI dashboard
scripts/ prepare_data.py (download clips), evaluate.py (benchmark + figures)
data/<lang>/ committed clip lists: manifest.csv, baselines.csv
worker/ optional Cloudflare Worker that proxies Clef via the Workers AI binding
reports/ benchmark results
数据集与许可
代码采用 Apache-2.0 许可。音频不重新分发;prepare_data.py 从原始来源下载,这些来源保留各自的许可:
| 语言 | 数据集 | 许可 | 说话人 |
|---|---|---|---|
| 英语 | RAVDESS(Livingstone & Russo, 2018) | CC BY-NC-SA 4.0 | 24 名演员 |
| 意大利语 | Emozionalmente,经由 CAMEO | CC BY 4.0 | 众多,非专业 |
| 俄语 | RESD,经由 CAMEO | MIT | 未标注(语料库基线) |
| 西班牙语 | MESD,经由 CAMEO | CC BY 4.0 | 未标注(语料库基线) |
docs/images/ 中的示例图像源自这些录音,并遵循相同条款。
致谢
感谢 Cloudflare 提供 Clef 和 Workers AI;感谢 RAVDESS、Emozionalmente、RESD、MESD 和 Rasa 的作者;感谢 CAMEO 合集将众多情感语音语料库汇集于一处。
许可
来源:Hacker News · github.com





