|
Download README.md from AXERA-TECH/FS-EEND.AXERA: direct link, hf CLI and curl.
- Browser
- Download file 8.37 kB
-
https://huggingface.co/AXERA-TECH/FS-EEND.AXERA/resolve/main/README.md
- Command line
-
hf download hf://AXERA-TECH/FS-EEND.AXERA/README.md
-
curl -L -o README.md https://huggingface.co/AXERA-TECH/FS-EEND.AXERA/resolve/main/README.md
8.37 kB
| license: apache-2.0 | |
| library_name: axera | |
| pipeline_tag: audio-classification | |
| tags: | |
| - speaker-diarization | |
| - ls-eend | |
| - fs-eend | |
| - end-to-end-neural-diarization | |
| - rttm | |
| - speech | |
| - axera | |
| - ax650n | |
| # FS-EEND.AXERA | |
| LS-EEND(FS-EEND 的在线版本)说话人日志模型 Axera AX650N 推理 demo: | |
| 输入音频,输出 RTTM 说话人时序标签。 | |
| - [x] Python 推理(axengine,`python/example.py`) | |
| - [x] C++ 可执行文件(`bin/ls_eend_ax650`) | |
| - [x] 一键运行脚本(`run_ax650.sh`) | |
| 源码(模型转换 + C++ 源码)见 GitHub: | |
| [FS-EEND.AXERA](https://github.com/ZY-2012/FS-EEND.AXERA) | |
| 上游模型:[Audio-WestlakeU/FS-EEND](https://github.com/Audio-WestlakeU/FS-EEND) | |
| ## 支持模型 | |
| 上游为每个数据集单独训练了模型,`max_speakers` 不同导致输出通道数不同。本仓提供 | |
| 两个量化变体: | |
| | 变体 | 来源 checkpoint | 适用场景 | max_speakers | 输出通道 | axmodel | | |
| |---|---|---|---|---|---| | |
| | `models/simu/` | `ls_eend_1-8spk_16_25_avg_model` | 通用 / 电话带宽 | 8 | 10 | 12.5 MB | | |
| | `models/ami/` | `ls_eend_ami_allspk_model` | 会议室(AMI 域) | 4 | 6 | 12.5 MB | | |
| 接口:`feat [1,1,345]` + 10 路状态 → `pred [1,1,C]` + 11 路状态,U16 激活 / S8 权重。 | |
| 8 kHz 输入,每帧 0.1 s;通道布局为 ch0 静音、ch1..C-2 说话人、ch(C-1) 非说话人。 | |
| 两个 SDK 都在加载时从模型读取通道数,切换变体不用改代码。 | |
| CALLHOME(7→9 通道)与 DIHARD2/3(10→12 通道)未提供量化产物,可用 GitHub 仓的 | |
| `model_convert/` 自行量化(`LS_EEND_CONF` 切换配置)。 | |
| ## 精度与速度 | |
| 测试录音 `samples/mix_0000176.wav`(192.02 s / 1921 帧 / 4 人), | |
| 参考 `samples/ground_truth_4spk_mix176.rttm`,DER 用 `collar=0.25`。 | |
| | 路径 | vs 原生 cosine | DER(±0.25 s,上游口径) | DER(±0.125 s) | ms/帧 | RTF | | |
| |---|---|---|---|---|---| | |
| | 原生 PyTorch 逐帧 | — | **0.4411%** | 1.2156% | — | — | | |
| | FP32 ONNX 流式循环 | **1.0000000** | 0.8672% | 1.6489% | — | — | | |
| | **AX650N Python** | **0.9985337** | **1.1214%** | 1.9512% | 7.29 | 0.073 | | |
| | **AX650N C++** | 0.9985337 | **1.1214%** | 1.9512% | **2.79** | **0.0279** | | |
| 上游 `metrics.py` 用 `DiarizationErrorRate(collar=50)`,其 `Segment` 单位是 10 ms 帧 | |
| (注释写明 "250ms tolerance"),等效 pyannote 的 `collar=0.5`(±0.25 s,NIST 惯例)。 | |
| 两条路径 confusion 均为 0%,说话人指派完全正确,DER 完全相同。C++ 比 Python 快约 2.6 倍 | |
| (主机端 FP32 状态累加在 numpy 里开销较大);55 段里仅 1 段边界差一帧,来自前端 | |
| 2.3e-05 的浮点残差翻转了一个接近阈值的帧,在 collar 内。 | |
| 真实会议数据(AMI Eval,用上游 AMI finetune checkpoint 另行量化):4 场加权 | |
| 原生 26.50% → 板端 30.18%,板端 2.2 ms/帧。 | |
| ## 目录结构 | |
| ``` | |
| FS-EEND.AXERA/ | |
| ├── models/ | |
| │ ├── simu/ # 仿真数据模型(10 通道,默认) | |
| │ │ ├── streaming_step.axmodel | |
| │ │ └── model_meta.json | |
| │ └── ami/ # AMI finetune 模型(6 通道) | |
| │ ├── streaming_step.axmodel | |
| │ └── model_meta.json | |
| ├── python/ | |
| │ ├── example.py # 推理入口 | |
| │ └── ls_eend_sdk/ # 前端 / 流式循环 / 后处理 | |
| ├── bin/ls_eend_ax650 # 预编译 C++ 可执行文件(aarch64) | |
| ├── samples/ # 演示音频 + 参考 RTTM | |
| ├── run_ax650.sh # 一键运行 | |
| └── requirements.txt | |
| ``` | |
| ## 运行(AX650N 板端) | |
| ```bash | |
| # C++(默认,最快),仿真模型 | |
| bash run_ax650.sh | |
| bash run_ax650.sh cpp your.wav | |
| # Python | |
| bash run_ax650.sh python your.wav | |
| # 会议室场景用 AMI finetune 模型(第三个参数选变体) | |
| bash run_ax650.sh cpp your_meeting.wav ami | |
| ``` | |
| 手动调用: | |
| ```bash | |
| export LD_LIBRARY_PATH=/soc/lib:$LD_LIBRARY_PATH | |
| ./bin/ls_eend_ax650 --model models/simu/streaming_step.axmodel \ | |
| --wav samples/mix_0000176.wav \ | |
| --rttm out.rttm --max-speakers 4 | |
| python3 python/example.py --model models/ami/streaming_step.axmodel \ | |
| --wav your_meeting.wav \ | |
| --rttm out.rttm --max-speakers 4 --median 1 | |
| ``` | |
| 参数:`--max-speakers`(保留 8 个说话人通道中的前 N 个)、`--threshold`(默认 0.5)、 | |
| `--median`(中值滤波帧数,默认 11,与上游一致)。 | |
| C++ 源码与编译方式见 GitHub 仓库的 `cpp/`。 | |
| ## 作为库调用 | |
| ```python | |
| import sys; sys.path.insert(0, 'python') | |
| from ls_eend_sdk import diarize | |
| result = diarize('meeting.wav', 'models/ami/streaming_step.axmodel', max_speakers=4) | |
| print(result['rttm'], result['speakers'], result['rtf']) | |
| for start, end, spk in result['segments']: | |
| print(f'{start:.2f}-{end:.2f} speaker_{spk}') | |
| ``` | |
| 逐帧流式(真实实时场景): | |
| ```python | |
| from ls_eend_sdk import StreamingDiarizer, extract_features, load_audio | |
| runner = StreamingDiarizer('models/simu/streaming_step.axmodel') | |
| audio, _ = load_audio('meeting.wav') | |
| for frame in extract_features(audio): | |
| logits = runner.step(frame) # 前 9 帧返回 None(卷积 warmup) | |
| if logits is not None: | |
| ... # (10,) logits | |
| ``` | |
| ## 模型接口 | |
| 单帧图,14 输入 / 12 输出,全 FP32 边界(量化只在图内部)。 | |
| **输入** | |
| | 名称 | shape | 说明 | | |
| |---|---|---| | |
| | `feat` | `1×1×345` | 8 kHz `logmel23_cummn`,23 mel × ±7 帧拼接,10 倍下采样 | | |
| | `inv_count` | `1×4×1×1` | `1/t`,encoder retention 均值混合系数,由调用方给 | | |
| | `dec_inv_count` | `1×4×1×1` | `1/t_dec`,decoder 同上 | | |
| | `conv_cache` | `1×256×18` | 输出端因果 CNN 的 cache(kernel 19) | | |
| | `enc{0..3}_kv` | `1×4×64×64` | encoder 各层 retention 运行均值 | | |
| | `enc{0..3}_conv` | `1×256×15` | encoder Conformer 卷积 cache | | |
| | `dec{0..1}_kv` | `10×4×64×64` | decoder 各层 retention 运行均值 | | |
| **输出** | |
| | 名称 | shape | 说明 | | |
| |---|---|---| | |
| | `pred` | `1×1×10` | 10 通道 logit | | |
| | `enc{0..3}_inc` | `1×4×64×64` | 本帧增量 `k_t·v_t`(**不是**更新后的状态) | | |
| | `enc{0..3}_conv_out` | `1×256×15` | 卷积 cache 更新 | | |
| | `conv_cache_out` | `1×256×18` | 输出卷积 cache 更新 | | |
| | `dec{0..1}_inc` | `10×4×64×64` | decoder 本帧增量 | | |
| **调用方必须实现两件事**(`python/ls_eend_sdk/session.py` 已实现,自行改写不能省): | |
| 1. **FP32 主机端累加**——图只返回有界的单帧增量,主机侧用 FP32 维护 | |
| `mean += (inc - mean)/t`。把量化后的状态直接喂回会让误差沿递推累积 | |
| (DER 1.95% → 7.4%)。 | |
| 2. **Warmup 门控**——上游 `StreamingConv1d` 前 9 帧不输出,原生循环此时完全不调用 | |
| decoder。前 9 帧要喂真实特征让 encoder 状态前进,但丢弃 `pred` 且保持 decoder | |
| 状态不变(漏掉这步 DER 会到 71.8%)。 | |
| 后处理:`sigmoid` → 阈值 0.5 → 11 帧中值滤波 → 段合并 → RTTM。 | |
| ## 已知限制 | |
| - **尾部 0.9 s 不输出。** 原生 flush 把零 *embedding* 直接推进输出卷积、绕过 encoder, | |
| 融合的单帧图表达不了。 | |
| - **前端有状态。** `logmel23_cummn` 用累积均值归一化,跨调用不是无状态的。 | |
| - **模型是 8 kHz 的**(上游配置 `sample_rate: 8000`,`feature.py` 里 `sr = 8000` 硬编码)。 | |
| 其他采样率的音频会被自动带限重采样到 8 kHz(Python 用 librosa `kaiser_best`,C++ 用 | |
| 同参数的 Kaiser 窗 sinc)。上游 AMI / DIHARD2 / DIHARD3 也是先降到 8 kHz 再训练和评测的。 | |
| - `max_speakers` 上限 8。 | |
| - **量化退化随录音长度增长**,几乎全落在 confusion(说话人指派):14~17 min 录音上 | |
| Δconfusion 仅 +0.5~0.8 pp,36 min 会议上可达 +1.4~5.9 pp。原因是 `inv_count = 1/t` | |
| 在 2 万帧时降到 5e-5、跌出校准范围。长会议场景请用同等长度录音重做校准 | |
| (见 GitHub 仓 `model_convert/`)。 | |
| - 量化时把 retention 状态改成了有界的运行均值形式,前提是本 checkpoint | |
| `decay == 1`。换成 per-head decay < 1 的权重需要重新导出。 | |
| ## License | |
| Apache-2.0。上游 FS-EEND 与 LS-EEND 权重的许可以其原仓库为准。 | |