feat: improve the last chunk with dynamic codec
Browse files- Previously, the chunk_frames length for the
last chunk of each rounds follow the fixed 4 (320 ms.).
This caused requirement to flush the codec cache
after every round of text due to zero pad right,
which in turns caused annoying pulses between
round of text.
- Now, it has been fixed with a separate onnx session
of codec decoder with dynamic axis on the chunk frames
length, which is without CUDA graph. This allows the
cache to be continuous over all rounds, as all of
the caches of the codec decoder are ring buffer type.
- Now, the generated speech sounds smooth with real-time
streaming processing within each round of text and
across rounds of texts.
- Final polishing will be to slightly put cross-fade
just in case the amplitude jumps too sharp between
rounds.
|
@@ -63,3 +63,4 @@ audio_synth/output_1776738826.4899054.wav filter=lfs diff=lfs merge=lfs -text
|
|
| 63 |
audio_synth/output_1776994773.978851.wav filter=lfs diff=lfs merge=lfs -text
|
| 64 |
audio_synth/output_1777092578.4959543.wav filter=lfs diff=lfs merge=lfs -text
|
| 65 |
audio_synth/output_1777159335.3181114.wav filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 63 |
audio_synth/output_1776994773.978851.wav filter=lfs diff=lfs merge=lfs -text
|
| 64 |
audio_synth/output_1777092578.4959543.wav filter=lfs diff=lfs merge=lfs -text
|
| 65 |
audio_synth/output_1777159335.3181114.wav filter=lfs diff=lfs merge=lfs -text
|
| 66 |
+
qwen3-tts_onnx/codec_decoder_model_dynamic_chunks.onnx filter=lfs diff=lfs merge=lfs -text
|
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c928257877ac48d058bae7a90357f09ca59fa0445822aec70e92f3906fd9c66d
|
| 3 |
+
size 456883759
|
|
@@ -366,6 +366,7 @@ class Qwen3TTSInferencerONNX:
|
|
| 366 |
talker_local_lm_head_model_path : str
|
| 367 |
Path to ``talker_local_lm_head.onnx`` (batched lm_head for all 15 codebook groups).
|
| 368 |
codec_decoder_model_path : str
|
|
|
|
| 369 |
speaker_encoder_model_path : str
|
| 370 |
talker_codec_embed_model_path : str
|
| 371 |
text_embed_proj_model_path : str
|
|
@@ -395,6 +396,7 @@ class Qwen3TTSInferencerONNX:
|
|
| 395 |
talker_local_model_step_path: str,
|
| 396 |
talker_local_lm_head_model_path: str,
|
| 397 |
codec_decoder_model_path: str,
|
|
|
|
| 398 |
speaker_encoder_model_path: str,
|
| 399 |
talker_codec_embed_model_path: str,
|
| 400 |
text_embed_proj_model_path: str,
|
|
@@ -408,11 +410,11 @@ class Qwen3TTSInferencerONNX:
|
|
| 408 |
enable_cuda_graph: bool = True,
|
| 409 |
chunk_frames: int = 4,
|
| 410 |
num_threads: int = 4,
|
| 411 |
-
temperature: float = 0.
|
| 412 |
-
top_p: float = 0.
|
| 413 |
top_k: int = 50,
|
| 414 |
-
repetition_penalty: float =
|
| 415 |
-
repetition_window: int =
|
| 416 |
) -> None:
|
| 417 |
|
| 418 |
self._use_cuda = use_cuda
|
|
@@ -449,9 +451,13 @@ class Qwen3TTSInferencerONNX:
|
|
| 449 |
log.info(f" local lm_head <- {talker_local_lm_head_model_path}")
|
| 450 |
_local_lm_head_sess = _sess(talker_local_lm_head_model_path, graph=self._enable_cuda_graph)
|
| 451 |
|
| 452 |
-
#
|
| 453 |
log.info(f" codec decoder <- {codec_decoder_model_path}")
|
| 454 |
self._codec_decoder_sess = _sess(codec_decoder_model_path, graph=self._enable_cuda_graph)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 455 |
log.info(f" speaker encoder <- {speaker_encoder_model_path}")
|
| 456 |
self._speaker_encoder = _sess(speaker_encoder_model_path, graph=False)
|
| 457 |
log.info(f" codec embed <- {talker_codec_embed_model_path}")
|
|
@@ -625,10 +631,6 @@ class Qwen3TTSInferencerONNX:
|
|
| 625 |
_causal_tril_local = np.tril(np.ones((self._num_code_groups, self._num_code_groups), dtype=bool))
|
| 626 |
self._causal_tril_local = _causal_tril_local.reshape(1, 1, self._num_code_groups, self._num_code_groups)
|
| 627 |
|
| 628 |
-
# Define cache_write mask for each position in the Local prefill and steps, used to update KV-cache
|
| 629 |
-
# self._local_cache_write_mask_list = self._make_local_cache_write_mask(batch_size=1) # 15 cache write masks
|
| 630 |
-
# For each, [B, H, 16, D], with varying 1/0 depending on the position
|
| 631 |
-
|
| 632 |
# Define cos and sin table for Local RoPE embedding
|
| 633 |
self._cos_rope_local, self._sin_rope_local = self._build_rope_tables_numpy(
|
| 634 |
rope_dim=self._code_predictor_config.head_dim,
|
|
@@ -975,6 +977,15 @@ class Qwen3TTSInferencerONNX:
|
|
| 975 |
for ov in self._kv_local_ov:
|
| 976 |
_copy_numpy_to_ortvalue(z, ov)
|
| 977 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 978 |
def _zero_codec_kv(self) -> None:
|
| 979 |
"""Zero out all Codec Decoder device buffers and reset the step counter."""
|
| 980 |
zero_wav = np.zeros(
|
|
@@ -1865,6 +1876,78 @@ class Qwen3TTSInferencerONNX:
|
|
| 1865 |
avg_exec_time = exec_time_tot / len(times["codec_decoder"]) * 1000
|
| 1866 |
log.info(f"\t{n_iter} iter. run codec_decoder in {exec_time_tot:.2f} s. --> {avg_exec_time:.2f} ms. per run.")
|
| 1867 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1868 |
# Summary log
|
| 1869 |
log.info("Warmup latency summary:")
|
| 1870 |
for k, v in times.items():
|
|
@@ -2011,31 +2094,24 @@ class Qwen3TTSInferencerONNX:
|
|
| 2011 |
def _process_frames_to_audio(self, num_frames: int) -> NDArrayFloat:
|
| 2012 |
"""Run Codec Decoder via IOBinding + CUDA graph."""
|
| 2013 |
chunk_tokens = self._consume_frames(num_frames)
|
| 2014 |
-
len_pad_right = 0
|
| 2015 |
-
log.info(f"codec-idx-{self._codec_step_idx} chunk_tokens {chunk_tokens} {chunk_tokens.shape}")
|
| 2016 |
if chunk_tokens.shape[-1] < self.chunk_frames:
|
| 2017 |
-
|
| 2018 |
-
|
| 2019 |
-
|
| 2020 |
-
|
| 2021 |
-
|
| 2022 |
-
|
| 2023 |
-
|
| 2024 |
-
)
|
| 2025 |
-
log.info(
|
| 2026 |
-
f"codec-idx-{self._codec_step_idx} len_pad_right {len_pad_right} "
|
| 2027 |
-
f"chunk_tokens {chunk_tokens} {chunk_tokens.shape}"
|
| 2028 |
-
)
|
| 2029 |
|
| 2030 |
# cache_position for the decoder transformer
|
| 2031 |
# It starts from 0 and grows. The model handles the sliding window internally.
|
| 2032 |
-
pos = np.arange(self._codec_step_idx, self._codec_step_idx +
|
| 2033 |
cos_rope = self._cos_rope_codec[:, pos].copy()
|
| 2034 |
sin_rope = self._sin_rope_codec[:, pos].copy()
|
| 2035 |
-
if self._codec_step_idx +
|
| 2036 |
# attention mask goes from the right to the left
|
| 2037 |
# we pad left False if the current + chunks still less than sliding window left
|
| 2038 |
-
pad_len = self._speech_tokenizer_sliding_window - (self._codec_step_idx +
|
| 2039 |
# here, basically, we need to pad left because we start from the right
|
| 2040 |
# and there still remaining amounts before it attends full sliding window length
|
| 2041 |
# so we must not attend to those previous remaining amounts, which is less than pos. 0
|
|
@@ -2047,24 +2123,57 @@ class Qwen3TTSInferencerONNX:
|
|
| 2047 |
# this case where the current + chunks is exactly sliding window length
|
| 2048 |
# or more than sliding window length
|
| 2049 |
# simply take the last chunks from the causal tril
|
| 2050 |
-
causal_rows = self._causal_tril_codec[:, :, -
|
| 2051 |
attn_mask = np.where(causal_rows, 0.0, -np.inf).astype(np.float32) # [1, 1, q_len, 72]
|
| 2052 |
|
| 2053 |
-
|
| 2054 |
-
|
| 2055 |
-
|
| 2056 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2057 |
|
| 2058 |
-
# The decoder output already discards the upsampled left-context frames (25 frames)
|
| 2059 |
-
# Just crop the right-pad region from the waveform if chunk_tokens padded
|
| 2060 |
-
if len_pad_right > 0:
|
| 2061 |
-
wav = wav[..., : -(len_pad_right * self._speech_tokenizer_decoder_total_upsample)]
|
| 2062 |
log.info(
|
| 2063 |
f"codec-idx-{self._codec_step_idx} wav {wav} "
|
| 2064 |
f"{np.min(wav)} {np.mean(wav)} {np.std(wav)} {np.max(wav)} {wav.shape}"
|
| 2065 |
)
|
| 2066 |
|
| 2067 |
-
self._codec_step_idx +=
|
| 2068 |
if self._ref_wav_history_list is not None:
|
| 2069 |
self._ref_wav_history_list.append(wav.copy())
|
| 2070 |
else:
|
|
|
|
| 366 |
talker_local_lm_head_model_path : str
|
| 367 |
Path to ``talker_local_lm_head.onnx`` (batched lm_head for all 15 codebook groups).
|
| 368 |
codec_decoder_model_path : str
|
| 369 |
+
codec_decoder_model_dynamic_chunks_path : str
|
| 370 |
speaker_encoder_model_path : str
|
| 371 |
talker_codec_embed_model_path : str
|
| 372 |
text_embed_proj_model_path : str
|
|
|
|
| 396 |
talker_local_model_step_path: str,
|
| 397 |
talker_local_lm_head_model_path: str,
|
| 398 |
codec_decoder_model_path: str,
|
| 399 |
+
codec_decoder_model_dynamic_chunks_path: str,
|
| 400 |
speaker_encoder_model_path: str,
|
| 401 |
talker_codec_embed_model_path: str,
|
| 402 |
text_embed_proj_model_path: str,
|
|
|
|
| 410 |
enable_cuda_graph: bool = True,
|
| 411 |
chunk_frames: int = 4,
|
| 412 |
num_threads: int = 4,
|
| 413 |
+
temperature: float = 0.75,
|
| 414 |
+
top_p: float = 0.85,
|
| 415 |
top_k: int = 50,
|
| 416 |
+
repetition_penalty: float = 9.5,
|
| 417 |
+
repetition_window: int = 75,
|
| 418 |
) -> None:
|
| 419 |
|
| 420 |
self._use_cuda = use_cuda
|
|
|
|
| 451 |
log.info(f" local lm_head <- {talker_local_lm_head_model_path}")
|
| 452 |
_local_lm_head_sess = _sess(talker_local_lm_head_model_path, graph=self._enable_cuda_graph)
|
| 453 |
|
| 454 |
+
# Codec decoder session: IOBinding + CUDA graph (chunk_frames fixed to 4 [320 ms.])
|
| 455 |
log.info(f" codec decoder <- {codec_decoder_model_path}")
|
| 456 |
self._codec_decoder_sess = _sess(codec_decoder_model_path, graph=self._enable_cuda_graph)
|
| 457 |
+
|
| 458 |
+
# Non-graphed utility sessions
|
| 459 |
+
log.info(f" codec decoder dynamic chunks <- {codec_decoder_model_dynamic_chunks_path}")
|
| 460 |
+
self._codec_decoder_dynamic_chunks = _sess(codec_decoder_model_dynamic_chunks_path, graph=False)
|
| 461 |
log.info(f" speaker encoder <- {speaker_encoder_model_path}")
|
| 462 |
self._speaker_encoder = _sess(speaker_encoder_model_path, graph=False)
|
| 463 |
log.info(f" codec embed <- {talker_codec_embed_model_path}")
|
|
|
|
| 631 |
_causal_tril_local = np.tril(np.ones((self._num_code_groups, self._num_code_groups), dtype=bool))
|
| 632 |
self._causal_tril_local = _causal_tril_local.reshape(1, 1, self._num_code_groups, self._num_code_groups)
|
| 633 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 634 |
# Define cos and sin table for Local RoPE embedding
|
| 635 |
self._cos_rope_local, self._sin_rope_local = self._build_rope_tables_numpy(
|
| 636 |
rope_dim=self._code_predictor_config.head_dim,
|
|
|
|
| 977 |
for ov in self._kv_local_ov:
|
| 978 |
_copy_numpy_to_ortvalue(z, ov)
|
| 979 |
|
| 980 |
+
def _snapshot_codec_kv(self) -> List[np.ndarray]:
|
| 981 |
+
"""Copy all Codec KV device OrtValues to CPU NumPy arrays."""
|
| 982 |
+
return [ov.numpy().copy() for ov in self._codec_kv_ovs]
|
| 983 |
+
|
| 984 |
+
def _restore_codec_kv(self, snapshot: List[np.ndarray]) -> None:
|
| 985 |
+
"""Copy a CPU snapshot back into the Codec KV device OrtValues."""
|
| 986 |
+
for ov, arr in zip(self._codec_kv_ovs, snapshot):
|
| 987 |
+
_copy_numpy_to_ortvalue(arr, ov)
|
| 988 |
+
|
| 989 |
def _zero_codec_kv(self) -> None:
|
| 990 |
"""Zero out all Codec Decoder device buffers and reset the step counter."""
|
| 991 |
zero_wav = np.zeros(
|
|
|
|
| 1876 |
avg_exec_time = exec_time_tot / len(times["codec_decoder"]) * 1000
|
| 1877 |
log.info(f"\t{n_iter} iter. run codec_decoder in {exec_time_tot:.2f} s. --> {avg_exec_time:.2f} ms. per run.")
|
| 1878 |
|
| 1879 |
+
# Codec decoder with dynamic chunk frames
|
| 1880 |
+
n_chunk_frames = 2
|
| 1881 |
+
log.info(f"Warming-up codec decoder with dynamic chunk frames (n={n_chunk_frames})...")
|
| 1882 |
+
self._zero_codec_kv()
|
| 1883 |
+
chunk_tokens = np.random.randint(0, self._local_vocab_size, size=(1, self._num_code_groups, n_chunk_frames))
|
| 1884 |
+
n_iter = n_iter // n_chunk_frames
|
| 1885 |
+
codec_step_idx = 0
|
| 1886 |
+
for n in range(n_iter):
|
| 1887 |
+
pos = np.arange(codec_step_idx, codec_step_idx + n_chunk_frames, dtype=np.int64)
|
| 1888 |
+
cos_rope = self._cos_rope_codec[:, pos].copy()
|
| 1889 |
+
sin_rope = self._sin_rope_codec[:, pos].copy()
|
| 1890 |
+
if codec_step_idx + n_chunk_frames < self._speech_tokenizer_sliding_window:
|
| 1891 |
+
# attention mask goes from the right to the left
|
| 1892 |
+
# we pad left False if the current + chunks still less than sliding window left
|
| 1893 |
+
pad_len = self._speech_tokenizer_sliding_window - (codec_step_idx + n_chunk_frames)
|
| 1894 |
+
# here, basically, we need to pad left because we start from the right
|
| 1895 |
+
# and there still remaining amounts before it attends full sliding window length
|
| 1896 |
+
# so we must not attend to those previous remaining amounts, which is less than pos. 0
|
| 1897 |
+
causal_rows_right = self._causal_tril_codec[:, :, pos, :-pad_len] # [1,1,q_len,72-accum_len]
|
| 1898 |
+
causal_rows = np.pad(
|
| 1899 |
+
causal_rows_right, ((0, 0), (0, 0), (0, 0), (pad_len, 0)), mode="constant", constant_values=False
|
| 1900 |
+
)
|
| 1901 |
+
else:
|
| 1902 |
+
# this case where the current + chunks is exactly sliding window length
|
| 1903 |
+
# or more than sliding window length
|
| 1904 |
+
# simply take the last chunks from the causal tril
|
| 1905 |
+
causal_rows = self._causal_tril_codec[:, :, -n_chunk_frames:, :] # [1,1,q_len,72]
|
| 1906 |
+
attn_mask = np.where(causal_rows, 0.0, -np.inf).astype(np.float32) # [1, 1, q_len, 72]
|
| 1907 |
+
# use session with dynamic axes as this is the last chunk of this round
|
| 1908 |
+
# and it is less than the default chunk frames 4
|
| 1909 |
+
# copy cache from ortvalue of the cuda-graph static session
|
| 1910 |
+
hidden_state_cache = self._codec_hidden_cache_ov.numpy()
|
| 1911 |
+
pre_conv_hidden_state_cache = self._codec_pre_conv_cache_ov.numpy()
|
| 1912 |
+
kv_cache = self._snapshot_codec_kv()
|
| 1913 |
+
# set with the input names
|
| 1914 |
+
feed = {
|
| 1915 |
+
"codes": chunk_tokens,
|
| 1916 |
+
"hidden_state_cache": hidden_state_cache,
|
| 1917 |
+
"pre_conv_hidden_state_cache": pre_conv_hidden_state_cache,
|
| 1918 |
+
"attention_mask": attn_mask,
|
| 1919 |
+
"cos_rope": cos_rope,
|
| 1920 |
+
"sin_rope": sin_rope,
|
| 1921 |
+
}
|
| 1922 |
+
for i in range(self._speech_tokenizer_num_hidden_layers):
|
| 1923 |
+
feed[f"past_key_{i}"] = kv_cache[2 * i]
|
| 1924 |
+
feed[f"past_value_{i}"] = kv_cache[2 * i + 1]
|
| 1925 |
+
# set output names
|
| 1926 |
+
output_names = ["wav", "current_hidden_state_cache", "current_pre_conv_hidden_state_cache"]
|
| 1927 |
+
for i in range(self._speech_tokenizer_num_hidden_layers):
|
| 1928 |
+
output_names.extend([f"present_key_{i}", f"present_value_{i}"])
|
| 1929 |
+
# run the session with dynamic axes on the chunk frame
|
| 1930 |
+
t0 = time.perf_counter()
|
| 1931 |
+
outputs = self._codec_decoder_dynamic_chunks.run(output_names, feed)
|
| 1932 |
+
times["codec_decoder_dynamic"].append((time.perf_counter() - t0) * 1000) # ms
|
| 1933 |
+
# get the output
|
| 1934 |
+
hidden_state_cache, pre_conv_hidden_state_cache, past_key_values = (
|
| 1935 |
+
outputs[1],
|
| 1936 |
+
outputs[2],
|
| 1937 |
+
outputs[3:],
|
| 1938 |
+
)
|
| 1939 |
+
# update the bound ort cache for the cuda-graph static session
|
| 1940 |
+
_copy_numpy_to_ortvalue(hidden_state_cache, self._codec_hidden_cache_ov)
|
| 1941 |
+
_copy_numpy_to_ortvalue(pre_conv_hidden_state_cache, self._codec_pre_conv_cache_ov)
|
| 1942 |
+
self._restore_codec_kv(past_key_values)
|
| 1943 |
+
codec_step_idx += n_chunk_frames
|
| 1944 |
+
exec_time_tot = sum(times["codec_decoder_dynamic"]) / 1000
|
| 1945 |
+
avg_exec_time = exec_time_tot / len(times["codec_decoder_dynamic"]) * 1000
|
| 1946 |
+
log.info(
|
| 1947 |
+
f"\t{n_iter} iter. run codec_decoder_dynamic in {exec_time_tot:.2f} s. "
|
| 1948 |
+
f"--> {avg_exec_time:.2f} ms. per run."
|
| 1949 |
+
)
|
| 1950 |
+
|
| 1951 |
# Summary log
|
| 1952 |
log.info("Warmup latency summary:")
|
| 1953 |
for k, v in times.items():
|
|
|
|
| 2094 |
def _process_frames_to_audio(self, num_frames: int) -> NDArrayFloat:
|
| 2095 |
"""Run Codec Decoder via IOBinding + CUDA graph."""
|
| 2096 |
chunk_tokens = self._consume_frames(num_frames)
|
|
|
|
|
|
|
| 2097 |
if chunk_tokens.shape[-1] < self.chunk_frames:
|
| 2098 |
+
n_chunk_frames = chunk_tokens.shape[-1]
|
| 2099 |
+
else:
|
| 2100 |
+
n_chunk_frames = self.chunk_frames
|
| 2101 |
+
log.info(
|
| 2102 |
+
f"codec-idx-{self._codec_step_idx} chunk_tokens {chunk_tokens} {chunk_tokens.shape} "
|
| 2103 |
+
f"n_chunk_frames {n_chunk_frames}"
|
| 2104 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2105 |
|
| 2106 |
# cache_position for the decoder transformer
|
| 2107 |
# It starts from 0 and grows. The model handles the sliding window internally.
|
| 2108 |
+
pos = np.arange(self._codec_step_idx, self._codec_step_idx + n_chunk_frames, dtype=np.int64)
|
| 2109 |
cos_rope = self._cos_rope_codec[:, pos].copy()
|
| 2110 |
sin_rope = self._sin_rope_codec[:, pos].copy()
|
| 2111 |
+
if self._codec_step_idx + n_chunk_frames < self._speech_tokenizer_sliding_window:
|
| 2112 |
# attention mask goes from the right to the left
|
| 2113 |
# we pad left False if the current + chunks still less than sliding window left
|
| 2114 |
+
pad_len = self._speech_tokenizer_sliding_window - (self._codec_step_idx + n_chunk_frames)
|
| 2115 |
# here, basically, we need to pad left because we start from the right
|
| 2116 |
# and there still remaining amounts before it attends full sliding window length
|
| 2117 |
# so we must not attend to those previous remaining amounts, which is less than pos. 0
|
|
|
|
| 2123 |
# this case where the current + chunks is exactly sliding window length
|
| 2124 |
# or more than sliding window length
|
| 2125 |
# simply take the last chunks from the causal tril
|
| 2126 |
+
causal_rows = self._causal_tril_codec[:, :, -n_chunk_frames:, :] # [1,1,q_len,72]
|
| 2127 |
attn_mask = np.where(causal_rows, 0.0, -np.inf).astype(np.float32) # [1, 1, q_len, 72]
|
| 2128 |
|
| 2129 |
+
if n_chunk_frames == self.chunk_frames:
|
| 2130 |
+
# Run the wired graph
|
| 2131 |
+
# chunk_tokens need to be .copy(), otherwise it messed up if we bind input and/or use CUDA graph
|
| 2132 |
+
wav = self._run_codec_decoder(chunk_tokens.copy(), attn_mask, cos_rope, sin_rope).copy()
|
| 2133 |
+
# new memory address, so that output wav not only the last repeated
|
| 2134 |
+
else:
|
| 2135 |
+
# use session with dynamic axes as this is the last chunk of this round
|
| 2136 |
+
# and it is less than the default chunk frames 4
|
| 2137 |
+
# copy cache from ortvalue of the cuda-graph static session
|
| 2138 |
+
hidden_state_cache = self._codec_hidden_cache_ov.numpy()
|
| 2139 |
+
pre_conv_hidden_state_cache = self._codec_pre_conv_cache_ov.numpy()
|
| 2140 |
+
kv_cache = self._snapshot_codec_kv()
|
| 2141 |
+
# set with the input names
|
| 2142 |
+
feed = {
|
| 2143 |
+
"codes": chunk_tokens,
|
| 2144 |
+
"hidden_state_cache": hidden_state_cache,
|
| 2145 |
+
"pre_conv_hidden_state_cache": pre_conv_hidden_state_cache,
|
| 2146 |
+
"attention_mask": attn_mask,
|
| 2147 |
+
"cos_rope": cos_rope,
|
| 2148 |
+
"sin_rope": sin_rope,
|
| 2149 |
+
}
|
| 2150 |
+
for i in range(self._speech_tokenizer_num_hidden_layers):
|
| 2151 |
+
feed[f"past_key_{i}"] = kv_cache[2 * i]
|
| 2152 |
+
feed[f"past_value_{i}"] = kv_cache[2 * i + 1]
|
| 2153 |
+
# set output names
|
| 2154 |
+
output_names = ["wav", "current_hidden_state_cache", "current_pre_conv_hidden_state_cache"]
|
| 2155 |
+
for i in range(self._speech_tokenizer_num_hidden_layers):
|
| 2156 |
+
output_names.extend([f"present_key_{i}", f"present_value_{i}"])
|
| 2157 |
+
# run the session with dynamic axes on the chunk frame
|
| 2158 |
+
outputs = self._codec_decoder_dynamic_chunks.run(output_names, feed)
|
| 2159 |
+
# get the output
|
| 2160 |
+
wav, hidden_state_cache, pre_conv_hidden_state_cache, past_key_values = (
|
| 2161 |
+
outputs[0],
|
| 2162 |
+
outputs[1],
|
| 2163 |
+
outputs[2],
|
| 2164 |
+
outputs[3:],
|
| 2165 |
+
)
|
| 2166 |
+
# update the bound ort cache for the cuda-graph static session
|
| 2167 |
+
_copy_numpy_to_ortvalue(hidden_state_cache, self._codec_hidden_cache_ov)
|
| 2168 |
+
_copy_numpy_to_ortvalue(pre_conv_hidden_state_cache, self._codec_pre_conv_cache_ov)
|
| 2169 |
+
self._restore_codec_kv(past_key_values)
|
| 2170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2171 |
log.info(
|
| 2172 |
f"codec-idx-{self._codec_step_idx} wav {wav} "
|
| 2173 |
f"{np.min(wav)} {np.mean(wav)} {np.std(wav)} {np.max(wav)} {wav.shape}"
|
| 2174 |
)
|
| 2175 |
|
| 2176 |
+
self._codec_step_idx += n_chunk_frames
|
| 2177 |
if self._ref_wav_history_list is not None:
|
| 2178 |
self._ref_wav_history_list.append(wav.copy())
|
| 2179 |
else:
|
|
@@ -319,6 +319,7 @@ def main() -> None:
|
|
| 319 |
|
| 320 |
# Other model paths
|
| 321 |
codec_decoder_path = _onnx_path(args.onnx_dir, f"codec_decoder_model{suffix}")
|
|
|
|
| 322 |
speaker_encoder_path = _onnx_path(args.onnx_dir, f"speaker_encoder_model{suffix}")
|
| 323 |
talker_codec_embed_path = _onnx_path(args.onnx_dir, f"talker_codec_embed_model{suffix}")
|
| 324 |
text_embed_proj_path = _onnx_path(args.onnx_dir, f"text_embed_proj_model{suffix}")
|
|
@@ -331,6 +332,7 @@ def main() -> None:
|
|
| 331 |
talker_local_step_path,
|
| 332 |
talker_local_lm_head_path,
|
| 333 |
codec_decoder_path,
|
|
|
|
| 334 |
speaker_encoder_path,
|
| 335 |
talker_codec_embed_path,
|
| 336 |
text_embed_proj_path,
|
|
@@ -351,6 +353,7 @@ def main() -> None:
|
|
| 351 |
talker_local_model_step_path=talker_local_step_path,
|
| 352 |
talker_local_lm_head_model_path=talker_local_lm_head_path,
|
| 353 |
codec_decoder_model_path=codec_decoder_path,
|
|
|
|
| 354 |
speaker_encoder_model_path=speaker_encoder_path,
|
| 355 |
talker_codec_embed_model_path=talker_codec_embed_path,
|
| 356 |
text_embed_proj_model_path=text_embed_proj_path,
|
|
|
|
| 319 |
|
| 320 |
# Other model paths
|
| 321 |
codec_decoder_path = _onnx_path(args.onnx_dir, f"codec_decoder_model{suffix}")
|
| 322 |
+
codec_decoder_dynamic_chunks_path = _onnx_path(args.onnx_dir, f"codec_decoder_model_dynamic_chunks{suffix}")
|
| 323 |
speaker_encoder_path = _onnx_path(args.onnx_dir, f"speaker_encoder_model{suffix}")
|
| 324 |
talker_codec_embed_path = _onnx_path(args.onnx_dir, f"talker_codec_embed_model{suffix}")
|
| 325 |
text_embed_proj_path = _onnx_path(args.onnx_dir, f"text_embed_proj_model{suffix}")
|
|
|
|
| 332 |
talker_local_step_path,
|
| 333 |
talker_local_lm_head_path,
|
| 334 |
codec_decoder_path,
|
| 335 |
+
codec_decoder_dynamic_chunks_path,
|
| 336 |
speaker_encoder_path,
|
| 337 |
talker_codec_embed_path,
|
| 338 |
text_embed_proj_path,
|
|
|
|
| 353 |
talker_local_model_step_path=talker_local_step_path,
|
| 354 |
talker_local_lm_head_model_path=talker_local_lm_head_path,
|
| 355 |
codec_decoder_model_path=codec_decoder_path,
|
| 356 |
+
codec_decoder_model_dynamic_chunks_path=codec_decoder_dynamic_chunks_path,
|
| 357 |
speaker_encoder_model_path=speaker_encoder_path,
|
| 358 |
talker_codec_embed_model_path=talker_codec_embed_path,
|
| 359 |
text_embed_proj_model_path=text_embed_proj_path,
|