Metadata-Version: 2.5
Name: fireredtts3-mnn
Version: 0.2.2
Summary: FireRedTTS3 zero-shot TTS on MNN (CPU, torch-free, mixed fp16/w8)
License: Apache-2.0
Requires-Python: >=3.10
Requires-Dist: huggingface-hub
Requires-Dist: mnn
Requires-Dist: numpy
Requires-Dist: tokenizers
Description-Content-Type: text/markdown

# fireredtts3-mnn

FireRedTTS3（零样本语音克隆 / 多语言 TTS）的 MNN 部署：ONNX → MNN 分段转换 + 混合精度（编码器/解码器/DiT/embed 用 fp16 近无损，backbone 用 w8 权重量化），纯 CPU、无 torch 依赖。

## 一键运行（uvx）

```sh
uvx fireredtts3-mnn
```

首次运行自动从 Hugging Face 下载 tokenizer（~11MB）与 MNN 混合精度产物（~5.3GB），然后启动 HTTP TTS 服务：

```
POST /tts
{
  "text": "今天天气很好，我们一起去公园散步吧。",
  "prompt_text": "参考音频对应的文本",
  "prompt_audio_b64": "<参考音频 wav 的 base64>",
  "prompt_audio_sr": 16000,
  "language": "Chinese"        # 可选，默认 Chinese
}
-> {"audio_b64": "<合成 wav base64>", "sample_rate": 24000}

GET /health
```

单次合成（不启动服务）：

```sh
uvx fireredtts3-mnn --text "你好世界" --prompt-wav ref.wav --prompt-text "参考文本" --out gen.wav
```

## 模型目录

默认缓存到 `~/.cache/fireredtts3-mnn`：
- `weights/` 文本 tokenizer（来自 `FireRedTeam/FireRedTTS3`，运行时为纯 numpy，无需原始权重）
- `mnn/` 转换产物（19 个分段 MNN：campp / redae 编解码 / patch_encoder / dit / 线性头 / embed / norm / prefill_seg1-4 / step_seg1-4，backbone 8.5GB 拆 8 段解决 MNNConvert 无法读 ONNX external data 与 protobuf 2GB 上限）

产物仓库默认 `yunfengwang/fireredtts3-mnn`（fp16 + w8 混合精度版），可用环境变量覆盖：

```sh
export FIREREDTTS3_MNN_REPO="your-hf-account/fireredtts3-mnn"
```

`HF_ENDPOINT` 环境变量可走 HF 镜像（hf-mirror.com）。

## 转换流程（复现）

```sh
# 1) PyTorch -> ONNX 分段导出（export_split.py：手写层 _LayerCore + dynamo，opset 18）
# 2) inline 合并（inline_onnx.py，<2GB 内联单文件）
# 3) ONNX -> MNN（convert_mnn.py：小模型 --fp16，backbone 分段 --weight-quant-bits 8）
```

注：本机环境 mnnquant（全 int8 激活+权重）C++ 崩溃不可用；纯 w8 权重量化对编码器/解码器/DiT
误差过大（prompt latents 最大偏差 1.7），故这些组件发布 fp16（实测偏差 ≤0.08，端到端与
torch 同种子轨迹一致），backbone 分段保持 w8（已验证 stop 轨迹 40 步内与 torch 一致）。

## 精度对比（各组件输出 vs torch fp32 的最大绝对误差）

| 组件 | w8(int8 权重） | fp16 | fp32 |
|---|---|---|---|
| redae_encoder（prompt latents） | 1.69 | 0.059 | 2.8e-4 |
| campp（spk_emb） | 0.61 | 0.080 | 1.9e-3 |
| redae_decoder（feats） | 0.27 | — | 3.1e-5 |
| dit（v） | 0.093 | 0.014 | 1.0e-5 |
| backbone 分段 | stop 轨迹与 torch 一致 | — | 一致 |

分块 int8（--weightQuantBlock 64）实测与逐通道 int8 误差几乎相同，无法改善。

## 性能实测

4 线程 Intel Xeon Platinum（AVX-512，无 VNNI/fp16 硬件），纯生成耗时（不含模型加载）：

| 版本 | RTF（越小越好） |
|---|---|
| torch fp32 原版 | 86.6 |
| MNN fp16+w8（本包） | 112 |
| ONNX fp32（fireredtts3-onnx） | 117 |

结论：
- 无 VNNI / fp16 硬件的 CPU 上 int8/fp16 不提速（仅省体积），转换版比 torch/MKL 慢约 30%
- w8 backbone 的加速在 VNNI(x86) / i8mm(ARM) 机器上才会体现；w8 同时把 backbone 从 11.3GB 压到 2.8GB
- mnnquant 全 int8（激活+权重）在当前 MNN 构建上崩溃（std::length_error）不可用，且 Qwen3 激活
  离群值高达 ~5e4，激活 int8 本身也会严重损伤音质
