KuangWei Chen commited on
Commit
fed8398
·
1 Parent(s): 5c74984

Update MOSS Audio Tokenizer v2 weight dtype loading methods

Browse files
README.md CHANGED
@@ -82,13 +82,30 @@ For production use with `trust_remote_code=True`, pin `revision` to a reviewed c
82
 
83
  `config.attention_implementation` controls whether transformer layers prefer `sdpa` or `flash_attention_2`.
84
  `config.compute_dtype` controls the non-quantizer autocast dtype and supports `fp32`, `bf16`.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
  ```python
87
  model.set_attention_implementation("flash_attention_2")
88
  model.set_compute_dtype("bf16")
 
89
  ```
90
 
91
- The quantizer always runs in fp32.
92
 
93
  ### Streaming
94
 
 
82
 
83
  `config.attention_implementation` controls whether transformer layers prefer `sdpa` or `flash_attention_2`.
84
  `config.compute_dtype` controls the non-quantizer autocast dtype and supports `fp32`, `bf16`.
85
+ `config.codec_weight_dtype` controls encoder/decoder parameter dtype and defaults to `fp32`.
86
+ The quantizer is always kept in fp32.
87
+
88
+ GPU bf16 loading:
89
+
90
+ ```python
91
+ import torch
92
+ from transformers import AutoModel
93
+
94
+ repo_id = "OpenMOSS-Team/MOSS-Audio-Tokenizer-v2"
95
+ device = "cuda" if torch.cuda.is_available() else "cpu"
96
+ model = AutoModel.from_pretrained(repo_id, trust_remote_code=True, low_cpu_mem_usage=True, codec_weight_dtype="bf16").eval().to(device)
97
+ ```
98
+ Passing codec_weight_dtype="bf16" at load time avoids first materializing encoder/decoder weights as fp32 on GPU and then converting them to bf16, which would increase peak GPU memory.
99
+
100
+ You can also switch an already loaded model:
101
 
102
  ```python
103
  model.set_attention_implementation("flash_attention_2")
104
  model.set_compute_dtype("bf16")
105
+ model.set_codec_weight_dtype("bf16") # encoder/decoder bf16, quantizer fp32
106
  ```
107
 
108
+ Avoid calling plain `model.to(torch.bfloat16)` on the whole codec; that also casts quantizer weights and can cause dtype mismatches or serious precision loss.
109
 
110
  ### Streaming
111
 
configuration_moss_audio_tokenizer.py CHANGED
@@ -59,6 +59,9 @@ class MossAudioTokenizerConfig(PreTrainedConfig):
59
  `"flash_attention_2"`.
60
  compute_dtype (`str`, *optional*, defaults to `"fp32"`):
61
  Inference compute dtype for non-quantizer modules. Supported values are `"fp32"`, `"bf16"`.
 
 
 
62
  quantizer_type (`str`, *optional*, defaults to `"rlfq"`):
63
  Quantizer type. Options include `"rvq"`, `"spec_rvq"`, `"rlfq"`, `"random_prefix_rlfq"`.
64
  quantizer_kwargs (`dict`, *optional*):
@@ -95,6 +98,7 @@ class MossAudioTokenizerConfig(PreTrainedConfig):
95
  enable_channel_interleave: bool
96
  attention_implementation: str
97
  compute_dtype: str
 
98
  quantizer_type: str
99
  quantizer_kwargs: dict[str, Any]
100
 
@@ -110,6 +114,7 @@ class MossAudioTokenizerConfig(PreTrainedConfig):
110
  enable_channel_interleave: bool = True,
111
  attention_implementation: str = "sdpa",
112
  compute_dtype: str = "fp32",
 
113
  quantizer_type: str = "rlfq",
114
  quantizer_kwargs: dict[str, Any] | None = None,
115
  **kwargs,
@@ -125,6 +130,8 @@ class MossAudioTokenizerConfig(PreTrainedConfig):
125
  attention_implementation = kwargs.pop("attention_backend")
126
  if "codec_compute_dtype" in kwargs and compute_dtype == "fp32":
127
  compute_dtype = kwargs.pop("codec_compute_dtype")
 
 
128
  reversed_decoder_kwargs = kwargs.pop("reversed_decoder_kwargs", None)
129
 
130
  # `version` is accepted for compatibility but not used in modeling.
@@ -136,6 +143,7 @@ class MossAudioTokenizerConfig(PreTrainedConfig):
136
  self.enable_channel_interleave = enable_channel_interleave
137
  self.attention_implementation = attention_implementation
138
  self.compute_dtype = compute_dtype
 
139
  # Default encoder configuration
140
  if encoder_kwargs is None:
141
  encoder_kwargs = [
 
59
  `"flash_attention_2"`.
60
  compute_dtype (`str`, *optional*, defaults to `"fp32"`):
61
  Inference compute dtype for non-quantizer modules. Supported values are `"fp32"`, `"bf16"`.
62
+ codec_weight_dtype (`str`, *optional*, defaults to `"fp32"`):
63
+ Parameter dtype for encoder and decoder modules. The quantizer remains fp32 because it explicitly disables
64
+ autocast and performs numerically sensitive codebook operations in fp32.
65
  quantizer_type (`str`, *optional*, defaults to `"rlfq"`):
66
  Quantizer type. Options include `"rvq"`, `"spec_rvq"`, `"rlfq"`, `"random_prefix_rlfq"`.
67
  quantizer_kwargs (`dict`, *optional*):
 
98
  enable_channel_interleave: bool
99
  attention_implementation: str
100
  compute_dtype: str
101
+ codec_weight_dtype: str
102
  quantizer_type: str
103
  quantizer_kwargs: dict[str, Any]
104
 
 
114
  enable_channel_interleave: bool = True,
115
  attention_implementation: str = "sdpa",
116
  compute_dtype: str = "fp32",
117
+ codec_weight_dtype: str = "fp32",
118
  quantizer_type: str = "rlfq",
119
  quantizer_kwargs: dict[str, Any] | None = None,
120
  **kwargs,
 
130
  attention_implementation = kwargs.pop("attention_backend")
131
  if "codec_compute_dtype" in kwargs and compute_dtype == "fp32":
132
  compute_dtype = kwargs.pop("codec_compute_dtype")
133
+ if "codec_load_dtype" in kwargs and codec_weight_dtype == "fp32":
134
+ codec_weight_dtype = kwargs.pop("codec_load_dtype")
135
  reversed_decoder_kwargs = kwargs.pop("reversed_decoder_kwargs", None)
136
 
137
  # `version` is accepted for compatibility but not used in modeling.
 
143
  self.enable_channel_interleave = enable_channel_interleave
144
  self.attention_implementation = attention_implementation
145
  self.compute_dtype = compute_dtype
146
+ self.codec_weight_dtype = codec_weight_dtype
147
  # Default encoder configuration
148
  if encoder_kwargs is None:
149
  encoder_kwargs = [
modeling_moss_audio_tokenizer.py CHANGED
@@ -62,6 +62,18 @@ except ImportError:
62
 
63
  SUPPORTED_ATTENTION_IMPLEMENTATIONS = {"sdpa", "flash_attention_2"}
64
  SUPPORTED_COMPUTE_DTYPES = {"fp32": None, "bf16": torch.bfloat16}
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
 
67
  def resolve_compute_dtype(compute_dtype: str) -> torch.dtype | None:
@@ -72,6 +84,26 @@ def resolve_compute_dtype(compute_dtype: str) -> torch.dtype | None:
72
  return SUPPORTED_COMPUTE_DTYPES[compute_dtype]
73
 
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  @contextmanager
76
  def disable_cuda_autocast():
77
  with torch.autocast(device_type="cuda", enabled=False):
@@ -715,7 +747,7 @@ class MossAudioTokenizerMultiheadAttention(StreamingModule):
715
  )
716
 
717
  def _supports_flash_attention(self, device: torch.device, dtype: torch.dtype) -> bool:
718
- return HAS_FLASH_ATTN and device.type == "cuda" and dtype in {torch.float16, torch.bfloat16}
719
 
720
  def _get_backend_check_dtype(self, x: torch.Tensor) -> torch.dtype:
721
  if x.device.type != "cuda":
@@ -1778,6 +1810,9 @@ class MossAudioTokenizerModel(MossAudioTokenizerPreTrainedModel):
1778
  self.attention_implementation = config.attention_implementation
1779
  self.compute_dtype_name = config.compute_dtype
1780
  self.compute_dtype = resolve_compute_dtype(config.compute_dtype)
 
 
 
1781
 
1782
  encoder_context_durations = [
1783
  float(module_kwargs.get("context_duration", config.causal_transformer_context_duration))
@@ -1848,6 +1883,21 @@ class MossAudioTokenizerModel(MossAudioTokenizerPreTrainedModel):
1848
 
1849
  self.post_init()
1850
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1851
  def _start_streaming(self, batch_size: int):
1852
  """Start streaming mode for all modules."""
1853
 
@@ -1936,6 +1986,9 @@ class MossAudioTokenizerModel(MossAudioTokenizerPreTrainedModel):
1936
  if device.type == "cuda" and self.compute_dtype is not None:
1937
  with torch.autocast(device_type="cuda", dtype=self.compute_dtype):
1938
  yield
 
 
 
1939
  else:
1940
  yield
1941
 
@@ -1948,6 +2001,37 @@ class MossAudioTokenizerModel(MossAudioTokenizerPreTrainedModel):
1948
  def set_compute_dtype(self, compute_dtype: str) -> None:
1949
  self.compute_dtype_name = compute_dtype
1950
  self.compute_dtype = resolve_compute_dtype(compute_dtype)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1951
 
1952
  def _prepare_waveform_batch(
1953
  self,
@@ -2117,6 +2201,9 @@ class MossAudioTokenizerModel(MossAudioTokenizerPreTrainedModel):
2117
 
2118
  quantizer = cast(MossAudioTokenizerResidualVQ | MossAudioTokenizerResidualLFQ, self.quantizer)
2119
  _, audio_codes, audio_codes_lengths = quantizer(encoder_hidden_states.float(), encoder_hidden_lengths, n_quantizers)
 
 
 
2120
 
2121
  return MossAudioTokenizerEncoderOutput(
2122
  audio_codes=audio_codes,
 
62
 
63
  SUPPORTED_ATTENTION_IMPLEMENTATIONS = {"sdpa", "flash_attention_2"}
64
  SUPPORTED_COMPUTE_DTYPES = {"fp32": None, "bf16": torch.bfloat16}
65
+ SUPPORTED_CODEC_WEIGHT_DTYPES = {
66
+ "fp32": torch.float32,
67
+ "float32": torch.float32,
68
+ "bf16": torch.bfloat16,
69
+ "bfloat16": torch.bfloat16,
70
+ }
71
+ CANONICAL_CODEC_WEIGHT_DTYPES = {
72
+ "fp32": "fp32",
73
+ "float32": "fp32",
74
+ "bf16": "bf16",
75
+ "bfloat16": "bf16",
76
+ }
77
 
78
 
79
  def resolve_compute_dtype(compute_dtype: str) -> torch.dtype | None:
 
84
  return SUPPORTED_COMPUTE_DTYPES[compute_dtype]
85
 
86
 
87
+ def canonicalize_codec_weight_dtype(codec_weight_dtype: str) -> str:
88
+ key = str(codec_weight_dtype).lower()
89
+ if key not in CANONICAL_CODEC_WEIGHT_DTYPES:
90
+ raise ValueError(
91
+ "Unsupported codec_weight_dtype="
92
+ f"{codec_weight_dtype!r}. Expected one of {sorted(CANONICAL_CODEC_WEIGHT_DTYPES)}."
93
+ )
94
+ return CANONICAL_CODEC_WEIGHT_DTYPES[key]
95
+
96
+
97
+ def resolve_codec_weight_dtype(codec_weight_dtype: str) -> torch.dtype:
98
+ key = str(codec_weight_dtype).lower()
99
+ if key not in SUPPORTED_CODEC_WEIGHT_DTYPES:
100
+ raise ValueError(
101
+ "Unsupported codec_weight_dtype="
102
+ f"{codec_weight_dtype!r}. Expected one of {sorted(SUPPORTED_CODEC_WEIGHT_DTYPES)}."
103
+ )
104
+ return SUPPORTED_CODEC_WEIGHT_DTYPES[key]
105
+
106
+
107
  @contextmanager
108
  def disable_cuda_autocast():
109
  with torch.autocast(device_type="cuda", enabled=False):
 
747
  )
748
 
749
  def _supports_flash_attention(self, device: torch.device, dtype: torch.dtype) -> bool:
750
+ return HAS_FLASH_ATTN and device.type == "cuda" and dtype == torch.bfloat16
751
 
752
  def _get_backend_check_dtype(self, x: torch.Tensor) -> torch.dtype:
753
  if x.device.type != "cuda":
 
1810
  self.attention_implementation = config.attention_implementation
1811
  self.compute_dtype_name = config.compute_dtype
1812
  self.compute_dtype = resolve_compute_dtype(config.compute_dtype)
1813
+ self.codec_weight_dtype_name = canonicalize_codec_weight_dtype(
1814
+ getattr(config, "codec_weight_dtype", "fp32")
1815
+ )
1816
 
1817
  encoder_context_durations = [
1818
  float(module_kwargs.get("context_duration", config.causal_transformer_context_duration))
 
1883
 
1884
  self.post_init()
1885
 
1886
+ @classmethod
1887
+ def from_pretrained(cls, pretrained_model_name_or_path, *model_args, **kwargs):
1888
+ codec_weight_dtype = kwargs.pop("codec_weight_dtype", None)
1889
+ explicit_torch_dtype = kwargs.get("torch_dtype", None)
1890
+ model = super().from_pretrained(pretrained_model_name_or_path, *model_args, **kwargs)
1891
+ if codec_weight_dtype is None:
1892
+ codec_weight_dtype = getattr(model.config, "codec_weight_dtype", "fp32")
1893
+ if explicit_torch_dtype is not None and canonicalize_codec_weight_dtype(codec_weight_dtype) != "fp32":
1894
+ logger.warning(
1895
+ "`torch_dtype` was passed while `codec_weight_dtype` is enabled. "
1896
+ "Prefer leaving codec `torch_dtype` unset so the fp32 quantizer weights are loaded without precision loss."
1897
+ )
1898
+ model.set_codec_weight_dtype(codec_weight_dtype)
1899
+ return model
1900
+
1901
  def _start_streaming(self, batch_size: int):
1902
  """Start streaming mode for all modules."""
1903
 
 
1986
  if device.type == "cuda" and self.compute_dtype is not None:
1987
  with torch.autocast(device_type="cuda", dtype=self.compute_dtype):
1988
  yield
1989
+ elif device.type == "cpu" and self.compute_dtype is torch.bfloat16:
1990
+ with torch.autocast(device_type="cpu", dtype=self.compute_dtype):
1991
+ yield
1992
  else:
1993
  yield
1994
 
 
2001
  def set_compute_dtype(self, compute_dtype: str) -> None:
2002
  self.compute_dtype_name = compute_dtype
2003
  self.compute_dtype = resolve_compute_dtype(compute_dtype)
2004
+ self.config.compute_dtype = compute_dtype
2005
+
2006
+ def set_codec_weight_dtype(self, codec_weight_dtype: str) -> None:
2007
+ codec_weight_dtype = canonicalize_codec_weight_dtype(codec_weight_dtype)
2008
+ weight_dtype = resolve_codec_weight_dtype(codec_weight_dtype)
2009
+
2010
+ self.encoder.to(dtype=weight_dtype)
2011
+ self.decoder.to(dtype=weight_dtype)
2012
+
2013
+ # Quantizer decode/encode intentionally disables autocast and builds fp32 intermediates.
2014
+ # Keeping it fp32 avoids fp32-input/bf16-bias mismatches and preserves codebook numerics.
2015
+ self.quantizer.to(dtype=torch.float32)
2016
+
2017
+ self.codec_weight_dtype_name = codec_weight_dtype
2018
+ self.config.codec_weight_dtype = codec_weight_dtype
2019
+ if codec_weight_dtype != "fp32" and self.compute_dtype is None:
2020
+ self.set_compute_dtype(codec_weight_dtype)
2021
+
2022
+ def get_codec_dtype_summary(self) -> dict[str, str]:
2023
+ def _first_param_dtype(module: nn.Module) -> str:
2024
+ for param in module.parameters():
2025
+ return str(param.dtype)
2026
+ return "no_params"
2027
+
2028
+ return {
2029
+ "encoder": _first_param_dtype(self.encoder),
2030
+ "decoder": _first_param_dtype(self.decoder),
2031
+ "quantizer": _first_param_dtype(self.quantizer),
2032
+ "compute_dtype": self.compute_dtype_name,
2033
+ "codec_weight_dtype": self.codec_weight_dtype_name,
2034
+ }
2035
 
2036
  def _prepare_waveform_batch(
2037
  self,
 
2201
 
2202
  quantizer = cast(MossAudioTokenizerResidualVQ | MossAudioTokenizerResidualLFQ, self.quantizer)
2203
  _, audio_codes, audio_codes_lengths = quantizer(encoder_hidden_states.float(), encoder_hidden_lengths, n_quantizers)
2204
+ max_valid_length = int(audio_codes_lengths.max().item()) if audio_codes_lengths.numel() > 0 else 0
2205
+ audio_codes = audio_codes[:, :, :max_valid_length]
2206
+ encoder_hidden_states = encoder_hidden_states[:, :, :max_valid_length]
2207
 
2208
  return MossAudioTokenizerEncoderOutput(
2209
  audio_codes=audio_codes,