zipvoice: add k2-fsa ZipVoice community TTS with zh/en frontend - #599
davidxifeng wants to merge 4 commits into
Conversation
|
@davidxifeng Thank you for contirbuting a new model! Serveral comments:
A better approach is to follow Kokoro’s g2p_multilingual.cpp: implement the required Jieba DAG segmentation and four-state HMM locally within the ZipVoice model. Keep the implementation model-local, include only the required logic, preserve the appropriate license attribution, and embed the dictionaries in the GGUF as model resources.
Please add performance mertics. The target RTF is < 1 for community models. |
add097f to
ca27ab7
Compare
c396f97 to
4a66f08
Compare
|
@0xShug0 Thank you for the detailed review! 😄 I’ve addressed the comments: removed vendored cppjieba I’ve also added performance metrics. On Apple M3 with Metal, the two tested cases achieved Tested ZipVoice-Distill on Apple M3 / Metal, Release build, 8 CPU threads
Parameters: Please take another look when you have a chance. Thanks! |
4a66f08 to
dc43ef2
Compare
Zero-shot voice cloning on a TTSZipformer flow-matching backbone with a Vocos mel-24kHz vocoder; supports the distilled 8-step variant (guidance-scale embedding) and the base model (batched CFG). - TTSZipformer ggml graphs: text encoder with duration-ratio conditioning, U-Net flow-matching decoder (relative-position attention, non-linear attention, downsampling stacks) in the physical [C,T,B] convention, built through the framework module wrappers (Linear/Softmax/ DepthwiseConv1d/Embedding/BiasNorm/...) with raw strided views and the batch-broadcast mul_mat fallback where no wrapper exists - GPU-first runtime: ZipVoiceComputeDevice resolves BestAvailable to Metal/CUDA with CPU fallback for the whole stack (text encoder, flow-matching decoder, Vocos backbone); extend the ggml Metal F32 tiled matmul kernel to short contractions (32 <= K < 64, M >= 64, N >= 32, explicit GGML_PREC_F32) via a dedicated F32-operand pipeline plus a padded-row guard, so ZipVoice's 32-dim QK products leave the matrix-vector path and Distill reaches RTF < 1 on Apple M3 - Vocos vocoder through the shared framework ConvNeXt/iSTFT backbone; single self-contained GGUF packaging: model.* + vocos.* namespaces with the tokens/config and the zh frontend sidecars embedded, so the hosted package is one file (davidxifeng/zipvoice-gguf, huggingface_snapshot download); the model spec is GGUF-only and the naming follows the repo convention (<name>-<precision>.gguf inside a <Name>-GGUF directory) - Chinese/English text frontend (tokenizer=emilia) reproducing the upstream EmiliaTokenizer: framework Chinese normalization, punctuation mapping, jieba segmentation via a model-local JiebaSegmenter (PreFilter separator pass, maximum-probability DAG over jieba.dict.utf8, four-state BMES HMM from hmm_model.utf8; equivalent to cppjieba::MixSegment, with MIT attribution to cppjieba (c) 2013 Yanyi Wu and jieba (c) 2012 Sun Junyi), pypinyin readings from baked zh_chars/zh_phrases/zh_syllables sidecars, per-word tone sandhi, espeak-ng for English runs; tokenizer=espeak|simple kept as alternatives. The segmenter dictionaries are model resources embedded in the GGUF (zh_jieba_dict.txt / zh_hmm_model.txt); export_zipvoice_zh_dict.py documents the pinned download source (URL/SHA-256 unchanged) - Session-owned runtime: weights, Vocos vocoder and bounded runtime::CacheSlots for the text-encoder and flow-decoder graphs live on the per-device ZipVoiceRuntimeState, so zipvoice_clear_runtime releases their memory and no process-global cache exists (RAII ZipVoiceGraphResources frees graph contexts, backend buffer and gallocr); long text is chunked with runtime::chunk_text_request and per-chunk audio merged via runtime::append_audio_buffer; reference audio is mixed to mono and resampled via convert_interleaved_audio_to_mono_torchaudio_sinc_hann_resampled with ref_channels on the synthesis request; the session loads the spec-resolved resource bundle so embedded sidecars materialize and resolve from the downloaded file alone, while direct API callers (parity harnesses) fall back to loose files next to the checkpoint - Conversion tools: convert_zipvoice.py (torch -> safetensors -> GGUF, staging the frontend sidecars into the converter root) and export_zipvoice_zh_dict.py - Verification: full-stage parity against the reference PyTorch implementation (encoder taps, text conditioning, sampled features, single+batched velocity, fbank, vocoder audio), token-for-token frontend parity against the upstream tokenizer, byte-identical segmentation against cppjieba::MixSegment over 349,011 dictionary entries plus 20,000 synthetic mixed cases, CPU/Metal parity (cosine 1.0 across all taps), and end-to-end zh/en/mixed synthesis ASR-verified from the hosted package - Docs: docs/community_models/zipvoice.md, catalog and README rows
dc43ef2 to
7432a42
Compare
|
Next, I'd like to work on:
|
|
@davidxifeng Thanks for the update! The code is in much better shape now. Could you exclude the ggml changes from this PR? ggml changes need to be submitted in separate PRs and should be additive in nature (if not should provide regression tests for affected models). I think the current performance is already good enough (my RTF < 1 is for CUDA :) ). Usually Metal is much slower than CUDA. Can’t test it right now, but I’ll do so as soon as I can. |
|
@davidxifeng The broader model changes are substantially improved. Only three minor issues to fix before merge: (1) Remove ggml changes. (2) The spec defines only zipvoice_distill_gguf pointing to the F32 file.
(3) ZipVoice loads every model tensor through load_f32_tensor(), and Vocos does the same. Therefore Q8 weights are expanded to F32 during loading. Please keep the changes scoped to the three comments so I can just review the delta. The other changes can be follow-up PRs. |
Load ZipVoice linear and embedding weights and Vocos linear weights with Native storage. Keep convolution, normalization and bias tensors in F32 for their operators. Validated the F32 parity harness, Q8_0 CPU and Metal synthesis, and loaded tensor types for ZipVoice and all Vocos linear layers.
|
@0xShug0 Thanks for your reviewing! Updated the PR to address all three comments:
F32 parity and Q8 CPU/Metal synthesis checks passed. |
Zero-shot voice cloning on a TTSZipformer flow-matching backbone with a Vocos mel-24kHz vocoder; supports the distilled 8-step variant (guidance-scale embedding) and the base model (batched CFG).