birdsong-recognizer · 音视频鸟鸣种类识别
通过康奈尔实验室的 BirdNET v2.4 声学模型,从音频或视频中识别鸟叫声对应的鸟种。
💰 省 token 提示(给执行 Agent):识别本身(神经网络推理)在本地脚本完成、零 token。 token 主要花在 Agent 读取长输出并二次加工。默认请加
--report参数,让脚本直接 输出成品结论,Agent 几乎只需转述,单次成本可降一个数量级。仅当用户要求深度分析 (逐段明细、调试)时才用非 report 模式。
⚠️ 首次使用必读(给执行 Agent 的强制前置) 本技能需要一个独立 Python 环境 + 联网下载约 50MB 模型,不是开箱即用的纯脚本技能。 在第一次运行 infer.py / spectro.py 之前,Agent 必须先完成下方「Setup」一次性安装; 安装通常需 1–3 分钟(装 tensorflow 等依赖)。请直接执行,不要询问用户是否安装。 后续调用若检测到 venv 已存在则跳过安装。
When to use
- 用户给出音频/视频文件并问"这是什么鸟 / 识别鸟叫 / 音视频鸟鸣识别 / what bird is this"。
- 通常会附带地点(如"北京昌平"),用于地理校正。
Setup(首次,任意机器,一次性)
本技能依赖一个独立 Python 环境。Agent 首次调用前自动执行,无需征求用户同意。
先判断 venv 是否已就绪(幂等):
SKILL_DIR="$(dirname "$(realpath SKILL.md)")" # 或技能实际所在目录
VENV="$SKILL_DIR/.venv"
if [ -x "$VENV/bin/python" ] && "$VENV/bin/python" -c "import birdnet, soundfile, imageio_ffmpeg" 2>/dev/null; then
echo "环境已就绪,跳过安装"
else
bash "$SKILL_DIR/scripts/setup.sh" # 自动创建 venv 并装好依赖(1–3 分钟)
fi
手动等价方式:
python3 -m venv .venv
.venv/bin/pip install -r scripts/requirements.txt
依赖:birdnet(含 tensorflow/scipy/soundfile/pandas)、imageio-ffmpeg(自带静态 ffmpeg,无需系统安装)、matplotlib、requests(v1.4.1 起 calibrate_weights.py / xc_download.py 需要,已加入 requirements.txt 显式声明,此前只是 tensorflow 间接依赖带进来的,未来 tensorflow 版本变化可能导致其消失,故显式声明)。
网络要求:首次运行 infer.py 会从网络下载 BirdNET 模型(约 50MB)到 BIRDNET_APP_DATA 目录。离线环境请提前准备好该目录。识别/批量推理本身(infer.py / batch.py)全程零网络依赖;calibrate_weights.py(GBIF 校准)与 xc_download.py(Xeno-canto 下载)是独立的离线辅助工具,仅在主动调用时才联网,不影响识别流程的离线特性。
Steps
-
确定 Python 解释器:使用上面 setup 出的 venv,例如
VENV=.venv,解释器$VENV/bin/python。 -
设定数据目录(避免某些系统对默认目录无写权限):
export BIRDNET_APP_DATA="$PWD/birdnet_data"首次运行 infer.py 会自动把模型下载到这里(约 50MB),含
acoustic-models/v2.4/tf/model-fp32.tflite与中文标签labels/zh.txt(格式学名_中文名,6522 种)。 -
直接对音频或视频运行识别(脚本自动抽音轨、无硬编码路径):
$VENV/bin/python scripts/infer.py INPUT.mp4 --region cn --lang zh --keep-audio out.wav- 支持 mp4/mov/mkv/avi/webm 等视频与 wav/mp3/m4a/flac 等音频。
--region cn启用中国地理/物候动态权重表(scripts/data/region_weights.csv)做地理校正;--region none关闭过滤。v1.4.0 起不再是硬性白名单——每个属有一个 [0,1] 权重, 未登记的属给低权重压制(而非直接剔除),保留极小概率真实迷鸟被看到的机会。--month 1-12:传入录制月份可触发候鸟季节性权重折扣(如夏候鸟在冬季出现会被打折)。 建议尽量传入,能进一步压制候鸟在非活跃季节的误判。--bandpass none(或300,9000):识别夜鹰/鸮/鸠鸽等低频鸟时关闭/放宽带通。--rhythm:开启节律/颤音检测(见下,补 BirdNET 盲区)。--silence-rms:静音过滤阈值,默认自适应(取各段 RMS 中位数 ×0.35)。--report:省 token 首选。脚本内部完成属级归并+置信度分级+节律提示, 直接输出一段成品结论(自动隐含开启地理过滤与节律检测)。Agent 拿到即终稿, 无需读长输出二次加工,token 消耗最低。日常识别/批量强烈建议加此参数。- 不加 --report 时输出:全量 Top-N、加权后 Top-N、逐段明细(供深度分析用,较耗 token)。
省 token 标准用法(推荐默认这样跑):
$VENV/bin/python scripts/infer.py INPUT.m4a --region cn --bandpass none --report -
生成语谱图核验:
$VENV/bin/python scripts/spectro.py INPUT.mp4 spectrogram.png读图核对鸣声的频段与音节结构是否与模型猜测一致(鸟鸣多在 2–8kHz)。
-
节律/颤音检测(BirdNET 盲区补充):对夜行性/连续发声的鸟,加
--rhythm:$VENV/bin/python scripts/infer.py INPUT.m4a --region cn --bandpass none --rhythm它用「带通→希尔伯特包络→自相关」找持续稳定的脉冲节律,输出疑似时间段
- 脉冲率 + 候选类群提示。定位明确:专攻 BirdNET 对连续发声的盲区 (夜鹰 churring、啄木鸟敲击、部分鸮的连续鸣叫),仅给线索不定种,须人工复核。 它无法做声源分离,重叠声源时可能受前景强声(如鹰鹃纯音)干扰。
-
地理校正:BirdNET 训练数据偏向常见/南方种。把 Top 物种与该地点/季节实际分布交叉核对;属级置信通常很高,种级给"最可能"判断并指明本地常见种。
-
呈现结论:用 present_files 展示 spectrogram.png 与音频,结论用 show_widget 或文字给出。
-
批量场景(一个文件夹几十~上千条录音,如声纹监测设备连续采样数据):不要循环调用 infer.py——每次调用都要重新加载 TensorFlow + 模型(约1.3-2秒固定开销/次),文件数一多耗时会线性放大。改用
scripts/batch.py,只加载一次模型,逐文件复用同一个 Interpreter:$VENV/bin/python scripts/batch.py <文件夹> --region cn --month 4 --out results.csv --summary- 实测 47 秒音频约 0.5-0.6 秒/条(1008 条 4GB 数据约 9-10 分钟跑完)。
- 自动按文件名解析时间(识别
..._YYYYMMDD_HHMMSS...模式,如声纹监测设备的标准命名)。 - v1.4.0 起输出标准化预筛报告格式:CSV 新增
priority_tier字段(high/medium/rhythm_only/low/corrupted),可直接对接人工标注任务分发——不用再让标注员盲选文件, 按这个字段排队即可(high优先建库确认,rhythm_only提示标注员优先用耳听而非只信模型分数,low可降低优先级,corrupted直接反馈给采集方不进队列)。 --summary:额外输出<out>.summary.csv,按小时聚合各优先级占比,一眼看出"哪几个小时段 值得优先人工标注"(如晨昏鸣叫高峰 vs 夜间大概率环境噪声)。geo_mismatch_flag:全量最高分≥0.5 但加权后最高分<0.15 且该物种所属属为低权重, 即"模型给高分但地理不合理"信号,值得整体复核该时段/该模式的录音。--pattern默认*.WAV(大小写敏感),文件名后缀不同(如.wav/.mp3)需显式传入。- 若一批文件跨多个月份采集,
--month建议按月分批调用,而非传入单一月份笼统处理。 - v1.4.1 起 CSV 新增
noise_confusable_flag字段与needs_spectro_review优先级分级: 命中data/noise_confusable_species.csv里登记的物种时,即使加权后置信度≥0.5,也不会 直接标high,而是标needs_spectro_review——这类结果必须先看语谱图人工确认是离散音节 还是无差别环境噪声,确认后才能升级为可信建库记录。
-
权重表校准(用真实分布数据核对 region_weights.csv 是否准确):权重表最初是凭经验手写的, 建议定期用
scripts/calibrate_weights.py核对:$VENV/bin/python scripts/calibrate_weights.py --out calibration_report.md会用 GBIF 免费公开 API(无需 Key,10万次/天额度)查询每个属在中国的真实分布记录数与月份 分布,生成对比报告标出"权重值明显不合理"的条目,供人工审核后手动更新 CSV(不会自动改写)。 务必用全国范围跑(不传
--province)——权重表是region=cn全国尺度的配置,用某个省的 数据去校准会把"该省无分布"错误地当成"全国权重该调低"。若要核对具体监测点位周边的物种更 贴近实际,可加--province Guangdong单独看一份省级参考报告,但不要拿它去改 CSV。 这一步是纯离线校准工具,不会让 infer.py/batch.py 的推理流程产生任何网络依赖。
噪声易混淆物种清单(data/noise_confusable_species.csv)
和地理权重表是两个独立机制,职责不同,不要混用:
- 地理权重表回答"这个物种在这个地区/季节是否合理",权重值必须基于真实分布数据(GBIF等), 不能因为"模型容易在噪声上误报这个名字"而压低。
- 噪声易混淆清单回答"这个 label 历史上是否被观测到把环境噪声误判成高置信度",不改变任何
分数,只在
--report结论里追加强制人工复核警告。 - 格式:
species(学名_中文名,须与 BirdNET 标签格式完全一致)+reason(说明触发场景与证据)。 - 目前登记的案例:
Porzana porzana_斑胸秧雞——SZYG03 红树林点位实测,宽频环境噪声在无地理 过滤时被判定为该种,置信度可达0.9+;该种中国确有分布,不应靠压低地理权重掩盖,只能靠这份 清单提示人工核验语谱图。 - 清单缺失时该功能静默跳过,不影响主流程。
Pitfalls
- 绝不使用高层
model.predict():它的多进程 producer 在受限/沙箱环境会卡死或 fork 风暴(模块级代码被子进程重复执行)。本技能用tf.lite.Interpreter直接推理(见 scripts/infer.py)。 - birdnet 后端名是
tf(不是tflite);版本是2.4(不带 v)。 - 默认数据目录在
~/Library/Application Support(macOS)等位置,部分环境无写权限 → 务必设置BIRDNET_APP_DATA到可写目录。 - BirdNET 输入 = 恰好 144000 个 float32 采样(3s @ 48kHz),shape (1,144000);输出是 6522 类 logits,需做 sigmoid。
- 剪映/CapCut 等剪辑过的视频经过重编码,置信度常偏低(<0.4)。用重叠窗口 + 聚焦高能量段提高收敛。
- 置信度低 ≠ 无结果:若多段 Top 命中集中在同一属,应报告该属。
- matplotlib 在受限环境对
~/.matplotlib可能无写权限 → spectro.py 已自动设MPLCONFIGDIR到临时目录;如仍报错可手动export MPLCONFIGDIR=/tmp/mplcache。 - infer.py 的逐段明细列表元素是
(idx, prob)元组,取标签时务必解包为labels[i](曾因直接用元组索引报 TypeError)。 - 低频鸟类(夜鹰 churring、鸮、鸠鸽、秧鸡等):默认带通 1500-9000Hz 会削弱其关键低频,且 BirdNET 对夜鹰这类「连续颤音/churring」本就识别弱(训练偏向离散音节)。识别这类鸟时用
--bandpass 300,9000或--bandpass none。注意:即便如此夜鹰仍可能识别不出,属模型固有短板,需结合语谱图人工判断。 - 弱信号/静音段误报:BirdNET 会在近乎静音的底噪上给出高分(如把夜间噪声判成「苍鹭」等)。技能已内置自适应静音过滤(
--silence-rms默认负数=自适应),静音段在输出里标 ⚠ 且不计入 Top 榜;仍须结合录制场景人工把关。 - 节律检测的定位:
--rhythm只补「连续发声」盲区(夜鹰churring/啄木鸟敲击/部分鸮),给类群线索而非种级定名;它无法做声源分离,重叠声源(如夜鹰叠在鹰鹃上)时脉冲率会被前景纯音干扰,须结合语谱图与现场聆听确认。脉冲率参考:20-50Hz≈夜鹰churring,3-10Hz≈啄木鸟敲击。 - rhythm/keras 缓存目录:tensorflow/keras 首次运行会写
~/.keras、~/.matplotlib,受限环境可能被拦截但不影响识别结果;如需消除可设KERAS_HOME/MPLCONFIGDIR到临时目录。 - 批量处理性能:infer.py 单次调用固定开销约1.3-2秒(主要是 TensorFlow import + 模型加载),逐文件循环调用会让总耗时随文件数线性放大且大部分是重复开销。文件数>10 时改用
scripts/batch.py,一次加载模型复用,实测提速可达数倍。 - 地理过滤是刚需,不是可选项:实测过一批7天/1008条的真实点位监测数据,
--region none时约28.6%的文件会给出"高置信度但地理不合理"的物种(如把宽频环境噪声/潮汐风声误判成欧洲/古北界物种,置信度可达0.9+),且这类误判高度集中在夜间低信息量时段。批量识别自动入库场景务必开--region cn(或对应地区权重表),否则会产生系统性的"幽灵物种"记录污染数据。 - v1.4.0 动态权重表 vs 旧版硬白名单:
scripts/data/region_weights.csv定义每个(地区,属)的权重, 推理时用权重去调制原始置信度(乘法),而非硬性剔除不在名单里的候选。若data/region_weights.csv缺失(如复制技能目录时遗漏),会自动回退到 infer.py 里REGION_GENERA的旧版二元白名单, 不影响可移植性。 - 【重要教训】地理权重 ≠ 声学混淆黑名单,两者不能共用一个数值:v1.4.0 早期曾把
Porzana(斑胸秧鸡所在属)压到 0.15 权重,理由写的是"该属欧洲种常被模型误判为噪声"——这是把"地理是否 合理"和"声学上是否容易被误判"两件不同的事,混进了同一个数值里。用 GBIF 校准 (scripts/calibrate_weights.py)核实后发现:斑胸秧鸡在中国全国有 1854 条真实分布记录(不是 "境外种"),压低地理权重的做法本身没有依据。修复后权重已改回 1.0,但这样一来"模型确实会把 环境噪声误判成这个物种"的真实问题又失去了压制手段——因此拆分出一个独立的scripts/data/noise_confusable_species.csv:只登记"哪些 label 历史上出现过噪声误判", 不改变任何分数(保持地理权重的诚实性),而是在--report结论里追加一条强制人工复核警告 (见下方"噪声易混淆物种清单"小节)。以后新增权重表条目时,判断依据必须是"这个物种在这个 地区/季节是否真的可能出现",不能因为"模型容易在噪声上误报这个名字"而压低地理权重—— 这两个问题要用两个不同的机制分别解决。 - 属级过滤的固有局限(权重表未解决):权重按"属"而非"种"设置,同属的跨大陆种无法被区分——
例如中国的四声杜鹃与马达加斯加的
Cuculus rochii同属Cuculus,权重表会同等对待,跨大陆种 可能被误判为高分且不受权重压制。这是属级过滤的天花板,下一步升级方向是种级过滤(需要更精细 的地区物种分布数据,如中国观鸟记录中心的分布清单),本次未实现。 - 权重表的月份折扣是粗粒度的:
--month触发的季节性折扣是"活跃月份内 1.0,月份外 ×0.3"的 简单规则,不是连续的物候曲线,对候鸟迁徙前后的过渡期不够精确,够用但不精细。 - GBIF 校准工具(
scripts/calibrate_weights.py)的查询方式选型踩坑记录:初版用species/match解析属名拿 taxonKey 再查询,属名跨界撞名严重(Pica/Troglodytes/Passer等鸟类属名恰好和其他生物学名词根撞车),模糊匹配退化到门/界级别导致查询全部落空;改用species/search限定 GBIF Backbone Taxonomy 数据集后属名能解析,但发现属级taxonKey/genusKey在部分属上无法自动展开匹配到下属物种的真实记录(如Cettia fortipes已被重新 分类到Horornis属,taxonKey 查询对不上);最终改用q=<属名>全文检索,不依赖 taxonKey 匹配是否命中分类树,抽样验证过检索结果的genus字段 100% 精确匹配。这不是随便选的实现 细节——如果只信任 taxonKey 查询返回的"0条记录",会把大量真实分布的物种误判为"境外种", 这正是本次修复前的错误根源。 - 校准报告的地区尺度必须和权重表的适用范围匹配:曾经用广东省范围的 GBIF 数据去校准
region=cn(全国尺度)的权重表,导致像Nucifraga(星鸦,广东确实无分布但全国有 3905+ 条 记录)这类物种被错误地建议压低权重——省级数据只能验证"该省是否有分布",不能反过来证明 "全国范围权重该调低"。校准全国权重表时必须用全国范围数据(不传--province),省级数据 只用于核对具体监测点位的合理性,不应用来改全国配置。
Verification
- 语谱图在 2–8kHz 显示清晰的鸟鸣音节。
- 多段 Top 物种一致(同种或同属)。
- 报告的物种对所述地点与季节合理。
分发与许可
本技能可对外分发,详见 README.md 与 LICENSE(MIT)。模型权重归 BirdNET / 康奈尔鸟类学实验室所有,按其授权使用。
Scan to join WeChat group