pltobing commited on
Commit
6c8db5a
·
1 Parent(s): 91df59b

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.

.gitattributes CHANGED
@@ -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
qwen3-tts_onnx/codec_decoder_model_dynamic_chunks.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c928257877ac48d058bae7a90357f09ca59fa0445822aec70e92f3906fd9c66d
3
+ size 456883759
src/inference/qwen3_tts_inferencer_onnx.py CHANGED
@@ -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.85,
412
- top_p: float = 0.8,
413
  top_k: int = 50,
414
- repetition_penalty: float = 1.9,
415
- repetition_window: int = 50,
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
- # Non-graphed utility sessions
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
- len_pad_right = self.chunk_frames - chunk_tokens.shape[-1]
2018
- chunk_tokens = np.concatenate(
2019
- (
2020
- chunk_tokens,
2021
- np.zeros((chunk_tokens.shape[0], chunk_tokens.shape[1], len_pad_right)).astype(np.int64),
2022
- ),
2023
- axis=-1,
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 + self.chunk_frames, dtype=np.int64)
2033
  cos_rope = self._cos_rope_codec[:, pos].copy()
2034
  sin_rope = self._sin_rope_codec[:, pos].copy()
2035
- if self._codec_step_idx + self.chunk_frames < self._speech_tokenizer_sliding_window:
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 + self.chunk_frames)
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[:, :, -self.chunk_frames :, :] # [1,1,q_len,72]
2051
  attn_mask = np.where(causal_rows, 0.0, -np.inf).astype(np.float32) # [1, 1, q_len, 72]
2052
 
2053
- # Run the wired graph
2054
- # chunk_tokens need to be .copy(), otherwise it messed up if we bind input and/or use CUDA graph
2055
- wav = self._run_codec_decoder(chunk_tokens.copy(), attn_mask, cos_rope, sin_rope).copy()
2056
- # new memory address, so that output wav not only the last repeated
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 += self.chunk_frames
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:
test_qwen3-tts-streaming_onnx.py CHANGED
@@ -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,