Mason commited on
Commit
d305c24
·
1 Parent(s): 3bfb4b1

Add Jetson fp16 model serving assets

Browse files
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 open(hyper_yaml_path, 'r') as f:
38
- configs = load_hyperpyyaml(f)
 
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 open(hyper_yaml_path, 'r') as f:
150
- configs = load_hyperpyyaml(f, overrides={'qwen_pretrain_path': os.path.join(model_dir, 'CosyVoice-BlankEN')})
 
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 open(hyper_yaml_path, 'r') as f:
200
- configs = load_hyperpyyaml(f, overrides={'qwen_pretrain_path': os.path.join(model_dir, 'CosyVoice-BlankEN')})
 
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
- self.llm.load_state_dict(torch.load(llm_model, map_location=self.device, weights_only=True), strict=True)
67
- self.llm.to(self.device).eval()
68
- self.flow.load_state_dict(torch.load(flow_model, map_location=self.device, weights_only=True), strict=True)
69
- self.flow.to(self.device).eval()
 
 
 
70
  # in case hift_model is a hifigan model
71
- hift_state_dict = {k.replace('generator.', ''): v for k, v in torch.load(hift_model, map_location=self.device, weights_only=True).items()}
72
- self.hift.load_state_dict(hift_state_dict, strict=True)
73
- self.hift.to(self.device).eval()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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,