Instructions to use jiaaom/CosyVoice3-TalkingFlowerZH with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- CosyVoice
How to use jiaaom/CosyVoice3-TalkingFlowerZH with CosyVoice:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Mason commited on
Commit ·
d305c24
1
Parent(s): 3bfb4b1
Add Jetson fp16 model serving assets
Browse files- cosyvoice/cli/cosyvoice.py +23 -6
- cosyvoice/cli/model.py +47 -7
- flow.fp16.pt +3 -0
- hift.fp16.pt +3 -0
- inference.py +1 -1
- llm.fp16.pt +3 -0
- scripts/convert_checkpoints_to_fp16.py +52 -0
- web-app/app.py +1 -1
cosyvoice/cli/cosyvoice.py
CHANGED
|
@@ -11,6 +11,7 @@
|
|
| 11 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
# See the License for the specific language governing permissions and
|
| 13 |
# limitations under the License.
|
|
|
|
| 14 |
import os
|
| 15 |
import time
|
| 16 |
from typing import Generator
|
|
@@ -24,6 +25,19 @@ from cosyvoice.utils.file_utils import logging
|
|
| 24 |
from cosyvoice.utils.class_utils import get_model_type
|
| 25 |
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
class CosyVoice:
|
| 28 |
|
| 29 |
def __init__(self, model_dir, load_jit=False, load_trt=False, fp16=False, trt_concurrent=1):
|
|
@@ -34,8 +48,9 @@ class CosyVoice:
|
|
| 34 |
hyper_yaml_path = '{}/cosyvoice.yaml'.format(model_dir)
|
| 35 |
if not os.path.exists(hyper_yaml_path):
|
| 36 |
raise ValueError('{} not found!'.format(hyper_yaml_path))
|
| 37 |
-
with
|
| 38 |
-
|
|
|
|
| 39 |
assert get_model_type(configs) == CosyVoiceModel, 'do not use {} for CosyVoice initialization!'.format(model_dir)
|
| 40 |
self.frontend = CosyVoiceFrontEnd(configs['get_tokenizer'],
|
| 41 |
configs['feat_extractor'],
|
|
@@ -146,8 +161,9 @@ class CosyVoice2(CosyVoice):
|
|
| 146 |
hyper_yaml_path = '{}/cosyvoice2.yaml'.format(model_dir)
|
| 147 |
if not os.path.exists(hyper_yaml_path):
|
| 148 |
raise ValueError('{} not found!'.format(hyper_yaml_path))
|
| 149 |
-
with
|
| 150 |
-
|
|
|
|
| 151 |
assert get_model_type(configs) == CosyVoice2Model, 'do not use {} for CosyVoice2 initialization!'.format(model_dir)
|
| 152 |
self.frontend = CosyVoiceFrontEnd(configs['get_tokenizer'],
|
| 153 |
configs['feat_extractor'],
|
|
@@ -196,8 +212,9 @@ class CosyVoice3(CosyVoice2):
|
|
| 196 |
hyper_yaml_path = '{}/cosyvoice3.yaml'.format(model_dir)
|
| 197 |
if not os.path.exists(hyper_yaml_path):
|
| 198 |
raise ValueError('{} not found!'.format(hyper_yaml_path))
|
| 199 |
-
with
|
| 200 |
-
|
|
|
|
| 201 |
assert get_model_type(configs) == CosyVoice3Model, 'do not use {} for CosyVoice3 initialization!'.format(model_dir)
|
| 202 |
self.frontend = CosyVoiceFrontEnd(configs['get_tokenizer'],
|
| 203 |
configs['feat_extractor'],
|
|
|
|
| 11 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
# See the License for the specific language governing permissions and
|
| 13 |
# limitations under the License.
|
| 14 |
+
from contextlib import contextmanager
|
| 15 |
import os
|
| 16 |
import time
|
| 17 |
from typing import Generator
|
|
|
|
| 25 |
from cosyvoice.utils.class_utils import get_model_type
|
| 26 |
|
| 27 |
|
| 28 |
+
@contextmanager
|
| 29 |
+
def _fp16_default_dtype(enabled):
|
| 30 |
+
if not enabled:
|
| 31 |
+
yield
|
| 32 |
+
return
|
| 33 |
+
previous_dtype = torch.get_default_dtype()
|
| 34 |
+
torch.set_default_dtype(torch.float16)
|
| 35 |
+
try:
|
| 36 |
+
yield
|
| 37 |
+
finally:
|
| 38 |
+
torch.set_default_dtype(previous_dtype)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
class CosyVoice:
|
| 42 |
|
| 43 |
def __init__(self, model_dir, load_jit=False, load_trt=False, fp16=False, trt_concurrent=1):
|
|
|
|
| 48 |
hyper_yaml_path = '{}/cosyvoice.yaml'.format(model_dir)
|
| 49 |
if not os.path.exists(hyper_yaml_path):
|
| 50 |
raise ValueError('{} not found!'.format(hyper_yaml_path))
|
| 51 |
+
with _fp16_default_dtype(fp16 and torch.cuda.is_available()):
|
| 52 |
+
with open(hyper_yaml_path, 'r') as f:
|
| 53 |
+
configs = load_hyperpyyaml(f)
|
| 54 |
assert get_model_type(configs) == CosyVoiceModel, 'do not use {} for CosyVoice initialization!'.format(model_dir)
|
| 55 |
self.frontend = CosyVoiceFrontEnd(configs['get_tokenizer'],
|
| 56 |
configs['feat_extractor'],
|
|
|
|
| 161 |
hyper_yaml_path = '{}/cosyvoice2.yaml'.format(model_dir)
|
| 162 |
if not os.path.exists(hyper_yaml_path):
|
| 163 |
raise ValueError('{} not found!'.format(hyper_yaml_path))
|
| 164 |
+
with _fp16_default_dtype(fp16 and torch.cuda.is_available()):
|
| 165 |
+
with open(hyper_yaml_path, 'r') as f:
|
| 166 |
+
configs = load_hyperpyyaml(f, overrides={'qwen_pretrain_path': os.path.join(model_dir, 'CosyVoice-BlankEN')})
|
| 167 |
assert get_model_type(configs) == CosyVoice2Model, 'do not use {} for CosyVoice2 initialization!'.format(model_dir)
|
| 168 |
self.frontend = CosyVoiceFrontEnd(configs['get_tokenizer'],
|
| 169 |
configs['feat_extractor'],
|
|
|
|
| 212 |
hyper_yaml_path = '{}/cosyvoice3.yaml'.format(model_dir)
|
| 213 |
if not os.path.exists(hyper_yaml_path):
|
| 214 |
raise ValueError('{} not found!'.format(hyper_yaml_path))
|
| 215 |
+
with _fp16_default_dtype(fp16 and torch.cuda.is_available()):
|
| 216 |
+
with open(hyper_yaml_path, 'r') as f:
|
| 217 |
+
configs = load_hyperpyyaml(f, overrides={'qwen_pretrain_path': os.path.join(model_dir, 'CosyVoice-BlankEN')})
|
| 218 |
assert get_model_type(configs) == CosyVoice3Model, 'do not use {} for CosyVoice3 initialization!'.format(model_dir)
|
| 219 |
self.frontend = CosyVoiceFrontEnd(configs['get_tokenizer'],
|
| 220 |
configs['feat_extractor'],
|
cosyvoice/cli/model.py
CHANGED
|
@@ -63,14 +63,54 @@ class CosyVoiceModel:
|
|
| 63 |
self.silent_tokens = []
|
| 64 |
|
| 65 |
def load(self, llm_model, flow_model, hift_model):
|
| 66 |
-
|
| 67 |
-
self.
|
| 68 |
-
|
| 69 |
-
|
|
|
|
|
|
|
|
|
|
| 70 |
# in case hift_model is a hifigan model
|
| 71 |
-
hift_state_dict =
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
def load_jit(self, llm_text_encoder_model, llm_llm_model, flow_encoder_model):
|
| 76 |
llm_text_encoder = torch.jit.load(llm_text_encoder_model, map_location=self.device)
|
|
|
|
| 63 |
self.silent_tokens = []
|
| 64 |
|
| 65 |
def load(self, llm_model, flow_model, hift_model):
|
| 66 |
+
llm_model = self._select_checkpoint_path(llm_model)
|
| 67 |
+
flow_model = self._select_checkpoint_path(flow_model)
|
| 68 |
+
hift_model = self._select_checkpoint_path(hift_model)
|
| 69 |
+
|
| 70 |
+
self._load_module_checkpoint(self.llm, llm_model)
|
| 71 |
+
self._load_module_checkpoint(self.flow, flow_model)
|
| 72 |
+
|
| 73 |
# in case hift_model is a hifigan model
|
| 74 |
+
hift_state_dict = torch.load(hift_model, map_location='cpu', weights_only=True, mmap=True)
|
| 75 |
+
hift_state_dict = {
|
| 76 |
+
k.replace('generator.', ''): v
|
| 77 |
+
for k, v in hift_state_dict.items()
|
| 78 |
+
}
|
| 79 |
+
self._assign_state_dict(self.hift, hift_state_dict)
|
| 80 |
+
|
| 81 |
+
def _select_checkpoint_path(self, checkpoint_path: str) -> str:
|
| 82 |
+
if not self.fp16:
|
| 83 |
+
return checkpoint_path
|
| 84 |
+
base, ext = os.path.splitext(checkpoint_path)
|
| 85 |
+
fp16_path = f'{base}.fp16{ext}'
|
| 86 |
+
return fp16_path if os.path.exists(fp16_path) else checkpoint_path
|
| 87 |
+
|
| 88 |
+
def _assign_state_dict(self, module: torch.nn.Module, state_dict: dict):
|
| 89 |
+
module.load_state_dict(state_dict, strict=True, assign=True)
|
| 90 |
+
del state_dict
|
| 91 |
+
self._move_module_tensors(module)
|
| 92 |
+
module.eval()
|
| 93 |
+
|
| 94 |
+
def _load_module_checkpoint(self, module: torch.nn.Module, checkpoint_path: str):
|
| 95 |
+
state_dict = torch.load(checkpoint_path, map_location='cpu', weights_only=True, mmap=True)
|
| 96 |
+
self._assign_state_dict(module, state_dict)
|
| 97 |
+
|
| 98 |
+
def _move_module_tensors(self, module: torch.nn.Module):
|
| 99 |
+
target_dtype = torch.float16 if self.fp16 else torch.float32
|
| 100 |
+
for child in module.children():
|
| 101 |
+
self._move_module_tensors(child)
|
| 102 |
+
for name, param in list(module._parameters.items()):
|
| 103 |
+
if param is None:
|
| 104 |
+
continue
|
| 105 |
+
moved = param.to(device=self.device, dtype=target_dtype if param.is_floating_point() else None)
|
| 106 |
+
module._parameters[name] = torch.nn.Parameter(moved, requires_grad=param.requires_grad)
|
| 107 |
+
for name, buf in list(module._buffers.items()):
|
| 108 |
+
if buf is None:
|
| 109 |
+
continue
|
| 110 |
+
if buf.is_floating_point():
|
| 111 |
+
module._buffers[name] = buf.to(device=self.device, dtype=target_dtype)
|
| 112 |
+
else:
|
| 113 |
+
module._buffers[name] = buf.to(device=self.device)
|
| 114 |
|
| 115 |
def load_jit(self, llm_text_encoder_model, llm_llm_model, flow_encoder_model):
|
| 116 |
llm_text_encoder = torch.jit.load(llm_text_encoder_model, map_location=self.device)
|
flow.fp16.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:50df4fe9f2e0a9a54dd2efd48f98ddcd4c4a3672f5e56212c672ac590b280b41
|
| 3 |
+
size 664624971
|
hift.fp16.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2b199a89141c2561e36e3311e96da32a0cdcdfd7bbdc80094a333f06b602c884
|
| 3 |
+
size 41665547
|
inference.py
CHANGED
|
@@ -167,7 +167,7 @@ def remove_tail_click(audio, sr, search_s=0.20, burst_thresh=0.05,
|
|
| 167 |
|
| 168 |
|
| 169 |
def synthesize(text, out_path):
|
| 170 |
-
model = CosyVoice3(MODEL_DIR)
|
| 171 |
for output in model.inference_sft(
|
| 172 |
INSTRUCT + text,
|
| 173 |
spk_id=SPK_ID,
|
|
|
|
| 167 |
|
| 168 |
|
| 169 |
def synthesize(text, out_path):
|
| 170 |
+
model = CosyVoice3(MODEL_DIR, fp16=True)
|
| 171 |
for output in model.inference_sft(
|
| 172 |
INSTRUCT + text,
|
| 173 |
spk_id=SPK_ID,
|
llm.fp16.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6b4849441034fcfc4ab39821a7ae96fa59b53b0ade8eff60768c7f0b455041cb
|
| 3 |
+
size 1284662368
|
scripts/convert_checkpoints_to_fp16.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import argparse
|
| 3 |
+
import os
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def convert_state_dict_to_fp16(state_dict):
|
| 10 |
+
converted = {}
|
| 11 |
+
for key, value in state_dict.items():
|
| 12 |
+
if isinstance(value, torch.Tensor) and value.is_floating_point():
|
| 13 |
+
converted[key] = value.half()
|
| 14 |
+
else:
|
| 15 |
+
converted[key] = value
|
| 16 |
+
return converted
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def convert_checkpoint(src_path: Path, dst_path: Path):
|
| 20 |
+
state_dict = torch.load(src_path, map_location="cpu", weights_only=True)
|
| 21 |
+
converted = convert_state_dict_to_fp16(state_dict)
|
| 22 |
+
torch.save(converted, dst_path)
|
| 23 |
+
src_size = os.path.getsize(src_path)
|
| 24 |
+
dst_size = os.path.getsize(dst_path)
|
| 25 |
+
print(
|
| 26 |
+
f"{src_path.name} -> {dst_path.name} | "
|
| 27 |
+
f"{src_size / 1024**2:.2f} MiB -> {dst_size / 1024**2:.2f} MiB"
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def main():
|
| 32 |
+
parser = argparse.ArgumentParser(description="Create fp16 checkpoint copies alongside the original fp32 files.")
|
| 33 |
+
parser.add_argument(
|
| 34 |
+
"--files",
|
| 35 |
+
nargs="*",
|
| 36 |
+
default=["llm.pt", "flow.pt", "hift.pt"],
|
| 37 |
+
help="Checkpoint files to convert.",
|
| 38 |
+
)
|
| 39 |
+
args = parser.parse_args()
|
| 40 |
+
|
| 41 |
+
for rel_path in args.files:
|
| 42 |
+
src_path = Path(rel_path)
|
| 43 |
+
if not src_path.exists():
|
| 44 |
+
raise FileNotFoundError(f"Missing checkpoint: {src_path}")
|
| 45 |
+
if src_path.suffix != ".pt":
|
| 46 |
+
raise ValueError(f"Expected a .pt checkpoint, got: {src_path}")
|
| 47 |
+
dst_path = src_path.with_suffix(f".fp16{src_path.suffix}")
|
| 48 |
+
convert_checkpoint(src_path, dst_path)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
if __name__ == "__main__":
|
| 52 |
+
main()
|
web-app/app.py
CHANGED
|
@@ -76,7 +76,7 @@ def load_model():
|
|
| 76 |
global model
|
| 77 |
if model is None:
|
| 78 |
print(f"Loading model from {MODEL_DIR}...")
|
| 79 |
-
model = CosyVoice3(MODEL_DIR)
|
| 80 |
return model
|
| 81 |
|
| 82 |
def remove_tail_click(audio, sr, search_s=0.20, burst_thresh=0.05,
|
|
|
|
| 76 |
global model
|
| 77 |
if model is None:
|
| 78 |
print(f"Loading model from {MODEL_DIR}...")
|
| 79 |
+
model = CosyVoice3(MODEL_DIR, fp16=True)
|
| 80 |
return model
|
| 81 |
|
| 82 |
def remove_tail_click(audio, sr, search_s=0.20, burst_thresh=0.05,
|