Skip to content

Commit 2644f3a

Browse files
committed
Separate RL configurations into a dedicated config class
1 parent 82a8e56 commit 2644f3a

44 files changed

Lines changed: 629 additions & 295 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

codecov.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,3 @@ coverage:
6565
threshold: 10% # fail on 10+ percent degradation
6666
flags:
6767
- regular
68-

src/maxtext/common/metric_logger.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def _log_training_metrics(self, metrics, step):
218218
moe_lb_loss = scalars.get("learning/moe_lb_loss", 0.0)
219219
log_parts.append(f"moe_lb_loss: {moe_lb_loss:.3f}")
220220

221-
if self.config.mtp_num_layers > 0:
221+
if getattr(self.config, "mtp_num_layers", 0) > 0:
222222
mtp_loss = scalars.get("learning/mtp_loss", 0.0)
223223
log_parts.append(f"main_model_loss: {loss - mtp_loss:.3f}")
224224
log_parts.append(f"mtp_loss: {mtp_loss:.3f}")
@@ -237,7 +237,7 @@ def _log_eval_metrics(self, metrics, step):
237237
]
238238
if self.config.num_experts > 1:
239239
log_parts.append(f"avg_moe_lb_loss={scalars['eval/avg_moe_lb_loss']:.3f}")
240-
if self.config.mtp_num_layers > 0:
240+
if getattr(self.config, "mtp_num_layers", 0) > 0:
241241
log_parts.extend(
242242
[
243243
f"avg_mtp_loss={scalars['eval/avg_mtp_loss']:.3f}",
@@ -258,7 +258,7 @@ def _log_running_eval_metrics(self, metrics, step):
258258
f"running perplexity={scalars['eval/avg_perplexity']:.3f}",
259259
f"running total_weights={scalars['eval/total_weights']}",
260260
]
261-
if self.config.mtp_num_layers > 0:
261+
if getattr(self.config, "mtp_num_layers", 0) > 0:
262262
log_parts.extend(
263263
[
264264
f"running mtp_loss={scalars['eval/avg_mtp_loss']:.3f}",

src/maxtext/configs/base.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ run_name: ""
2323
model_name: "default" # override config settings to match a specific model. other than the override, nothing should use this!
2424
override_model_config: false # When set to true allows overriding model parameters via CLI (or kwargs or env vars) for the purpose of debugging/testing.
2525
override_logical_axis_rules: false # When set overrides logical axis rules instead of merging them.
26-
debug:
27-
rl: false # RL-specific debugging
2826

2927
normalization_layer_epsilon: 1.e-05 # epsilon value for rmsnorm, layernorm.
3028

src/maxtext/configs/inference/vllm.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
base_config: "base.yml"
1615
attention: "vllm_rpa"
1716
model_call_mode: "inference"
1817

@@ -27,6 +26,11 @@ weight_dtype: bfloat16
2726
# Allow model config to be overridden by CLI kwargs
2827
override_model_config: true
2928

29+
# vLLM Adapter Configurations
30+
vllm_hf_config_path: ""
31+
vllm_hf_overrides: {}
32+
vllm_additional_config: {}
33+
3034

3135
# -------------- Logical Axis Rules --------------
3236
mesh_axes: ['data', 'attn_dp', 'model', 'expert', 'attn_dp_expert']

src/maxtext/configs/post_train/rl.yml

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
# RL Configuration
1616
# This config consolidates common parameters for RL training across different model sizes
1717

18-
base_config: "../base.yml"
19-
2018
# ====== Hardware =====
2119
trainer_devices_fraction: 0.5
2220
sampler_devices_fraction: 0.5
@@ -72,7 +70,6 @@ rl:
7270
# If null, the entire model is resharded at once.
7371
reshard_chunk_size: null
7472

75-
7673
# ====== Models ======
7774
# for MaxText
7875
# Model and Tokenizer Configuration
@@ -95,15 +92,16 @@ decoder_layer_input: 'offload'
9592
query_proj: 'offload'
9693
key_proj: 'offload'
9794
value_proj: 'offload'
98-
checkpoint_storage_use_ocdbt: false # For Pathways
99-
checkpoint_storage_use_zarr3: false # For Pathways
10095
use_pathways: true
10196
log_period: 20
97+
98+
# ====== Checkpointing configs ======
99+
checkpoint_storage_use_ocdbt: false # For Pathways
100+
checkpoint_storage_use_zarr3: false # For Pathways
102101
convert_checkpoint_if_possible: true
103102

104103
# ====== Debugging ======
105-
debug:
106-
rl: true
104+
debug: false
107105
# If true, Tunix-managed metrics measurement will be enabled. The metrics will be
108106
# uploaded to tensorboard.
109107
enable_tunix_perf_metrics: false
@@ -190,7 +188,6 @@ checkpoint_period: 50
190188
max_num_checkpoints_to_keep: 10
191189

192190
# ====== Reward ======
193-
194191
reward_exact_answer: 1.0
195192
reward_white_space_format_match: 1.0
196193
reward_exact_format_match: 0.1
@@ -199,6 +196,13 @@ reward_ratio_guess_to_answer_high: 0.0
199196
reward_ratio_guess_to_answer_low: 0.0
200197
penalty_incorrect_format: 0.0
201198
penalty_incorrect_answer: 0.0
199+
# Optional: path to a user-provided Python file with custom reward functions,
200+
# AND a comma-separated list of function names to import from that file.
201+
# Each function signature: fn(prompts, completions, tmvp_config, **kwargs) -> list[float].
202+
# When both are set, the built-in [match_format_exactly, match_format_approximately,
203+
# check_numbers] reward list is REPLACED entirely.
204+
reward_functions_path: ''
205+
reward_functions: ''
202206

203207
# ====== Configuration for math_verify Pool ======
204208
# Global timeout (seconds) for math_verify calls across all examples in a batch
@@ -235,19 +239,80 @@ eval_dataset_name: 'openai/gsm8k'
235239
# tmvp_config, x) -> dict with keys {prompts, question, answer}. When empty
236240
# (default), the built-in utils_rl.process_data is used.
237241
dataset_processor_path: ''
238-
# Optional: path to a user-provided Python file with custom reward functions,
239-
# AND a comma-separated list of function names to import from that file.
240-
# Each function signature: fn(prompts, completions, tmvp_config, **kwargs) -> list[float].
241-
# When both are set, the built-in [match_format_exactly, match_format_approximately,
242-
# check_numbers] reward list is REPLACED entirely.
243-
reward_functions_path: ''
244-
reward_functions: ''
245242
train_split: 'train'
246243
eval_split: 'test'
247-
hf_name: 'main' # subset of Hugging Face dataset
248-
tokenizer_type: 'huggingface'
244+
hf_subset: 'main' # subset of Hugging Face dataset
249245

250246
##### MaxText to VLLM Converter validation parameters
251247
vllm_load_format: dummy # Format to load the model for conversion. Options are "auto", "dummy"
252248
debug_converter: false # If true, run key coverage check, weight stats, and GCS upload then exit without generation.
253249
gcs_debug_path: "" # If set and debug_converter=true, upload converted layer-0 and global tensors as .npy to this GCS prefix.
250+
251+
# Logical Axis Rules
252+
logical_axis_rules: [
253+
['circular_repeats', []],
254+
255+
# Vocabulary Embedding
256+
['activation_embed_and_logits_batch', ['data', 'stage', 'fsdp', 'fsdp_transpose', 'expert']],
257+
['activation_embed_and_logits_batch_sequence', ['data', 'stage', 'fsdp', 'fsdp_transpose', 'context', 'expert']],
258+
['activation_vocab', ['tensor', 'tensor_sequence']],
259+
['activation_vocab', ['tensor']],
260+
['activation_vocab', 'tensor_sequence'],
261+
['vocab', ['tensor', 'tensor_sequence', 'autoregressive']],
262+
['embed_vocab', ['fsdp', 'fsdp_transpose', 'context', 'expert']],
263+
264+
# Attention
265+
['activation_batch_attn', ['data', 'fsdp', 'fsdp_transpose', 'expert']],
266+
['activation_heads', ['tensor', 'tensor_sequence', 'autoregressive']],
267+
['activation_kv_heads', ['tensor', 'tensor_sequence']],
268+
['activation_length_attn', ['context']],
269+
['activation_q_length', ['context']],
270+
['activation_kv_length', []],
271+
['activation_embed_attn', ['tensor']],
272+
['activation_kv', ['tensor', 'tensor_sequence']],
273+
['activation_kv_batch', ['data', 'fsdp', 'fsdp_transpose', 'expert']],
274+
['activation_kv_head_dim', ['tensor', 'tensor_sequence']],
275+
['heads', ['tensor', 'tensor_sequence', 'autoregressive']],
276+
['q_heads', ['tensor', 'tensor_sequence', 'autoregressive']],
277+
['kv_heads', ['tensor', 'tensor_sequence', 'autoregressive']],
278+
['qkv', []],
279+
['kv', []],
280+
['kv_head_dim', []],
281+
['q_lora', ['fsdp', 'fsdp_transpose', 'context', 'expert']],
282+
['q_lora', ['fsdp', 'context', 'expert']],
283+
["q_lora_up_proj", []],
284+
['kv_lora', ['fsdp', 'fsdp_transpose', 'context', 'expert']],
285+
['kv_lora', ['fsdp', 'context', 'expert']],
286+
["kv_lora_up_proj", []],
287+
288+
# Mixture of Experts (MoE)
289+
['activation_batch_moe', ['data', 'fsdp', 'fsdp_transpose', 'expert']],
290+
['activation_length_moe', ['context']],
291+
['activation_norm_length_moe', ['tensor_sequence', 'context']],
292+
['activation_embed_moe', ['tensor']],
293+
['activation_mlp_moe', ['tensor', 'tensor_sequence']],
294+
['activation_exp', ['expert']],
295+
['exp', 'expert'],
296+
['mlp_moe', ['fsdp_transpose', 'tensor', 'tensor_sequence', 'autoregressive']],
297+
['embed_moe', ['fsdp', 'fsdp_transpose', 'context']],
298+
['embed_moe', ['fsdp', 'context']],
299+
300+
# Standard MLP / Dense Layers / Model Structure
301+
['activation_mlp', ['tensor', 'tensor_sequence']],
302+
['activation_batch', ['data', 'fsdp', 'fsdp_transpose', 'expert']],
303+
['activation_length', ['context']],
304+
['activation_norm_length', ['tensor_sequence', 'context']],
305+
['activation_embed', ['tensor']],
306+
['activation_stage', 'stage'],
307+
['mlp', ['fsdp_transpose', 'tensor', 'tensor_sequence', 'autoregressive']],
308+
['gdn_head', ['fsdp_transpose', 'tensor', 'tensor_sequence', 'autoregressive']],
309+
['embed', ['fsdp', 'fsdp_transpose', 'context', 'expert']],
310+
['embed', ['fsdp', 'context', 'expert']],
311+
['norm', ['tensor']],
312+
['layers', 'stage'],
313+
['diloco', 'diloco'],
314+
['engram_dim', ['tensor']],
315+
['dense_layers', []],
316+
['moe_layers', []],
317+
['mhc', []],
318+
]

src/maxtext/configs/pyconfig.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
from maxtext.utils.globals import MAXTEXT_CONFIGS_DIR, MAXTEXT_ASSETS_ROOT, HF_IDS, MAXTEXT_PKG_DIR
3434
from maxtext.common.common_types import DecoderBlockType, ShardMode
3535
from maxtext.configs import types
36-
from maxtext.configs.types import MaxTextConfig
3736
from maxtext.inference.inference_utils import str2bool
3837
from maxtext.utils import max_utils
3938
from maxtext.utils import max_logging
@@ -238,13 +237,29 @@ def _coerce_to_list(value: Any) -> list[str] | Any:
238237
return value
239238

240239

241-
def _prepare_for_pydantic(raw_keys: dict[str, Any]) -> dict[str, Any]:
240+
def _check_for_invalid_keys(key: str, valid_fields: set[str]) -> bool:
241+
"""Recursively checks if the key is valid according to the Pydantic model hierarchy."""
242+
if key in valid_fields:
243+
return True
244+
245+
# Check inside nested Pydantic models
246+
for field_info in valid_fields.values():
247+
annotation = getattr(field_info, "annotation", None)
248+
if hasattr(annotation, "model_fields"):
249+
if _check_for_invalid_keys(key, annotation.model_fields):
250+
return True
251+
252+
return False
253+
254+
255+
def _prepare_for_pydantic(raw_keys: dict[str, Any], config_class: type[Any] = types.MaxTextConfig) -> dict[str, Any]:
242256
"""Prepares the raw dictionary for Pydantic model instantiation."""
243257
pydantic_kwargs = {}
244-
valid_fields = types.MaxTextConfig.model_fields.keys()
258+
valid_fields = config_class.model_fields
245259

246260
for key, value in raw_keys.items():
247-
if key not in valid_fields:
261+
check_flag = _check_for_invalid_keys(key, valid_fields)
262+
if not check_flag:
248263
logger.warning("Ignoring invalid/unsupported field from YAML/CLI: %s", repr(key))
249264
raise ValueError(f"{key!r} not in {', '.join(map(repr, valid_fields))}.")
250265

@@ -318,7 +333,6 @@ def __init__(self, pydantic_config: types.MaxTextConfig):
318333
final_dict["mu_dtype"] = (
319334
final_dict["weight_dtype"] if not final_dict["mu_dtype"] else jnp.dtype(final_dict["mu_dtype"])
320335
)
321-
322336
final_dict["logical_axis_rules"] = _lists_to_tuples(final_dict["logical_axis_rules"])
323337
final_dict["data_sharding"] = _lists_to_tuples(final_dict["data_sharding"])
324338

@@ -379,10 +393,10 @@ def _handle_config_exception(e: Exception):
379393
raise e
380394

381395

382-
def initialize(argv: list[str] | None = None, **kwargs) -> HyperParameters:
396+
def initialize(argv: list[str] | None = None, config_class: type[Any] = types.MaxTextConfig, **kwargs) -> HyperParameters:
383397
"""Initializes the configuration by loading YAML files, and applying CLI, env, and kwarg overrides."""
384398
try:
385-
pydantic_config = _initialize_pydantic(argv, **kwargs)
399+
pydantic_config = _initialize_pydantic(argv, config_class=config_class, **kwargs)
386400
config = HyperParameters(pydantic_config)
387401
return config
388402
except Exception as e: # pylint: disable=broad-exception-caught
@@ -392,23 +406,23 @@ def initialize(argv: list[str] | None = None, **kwargs) -> HyperParameters:
392406
raise e
393407

394408

395-
def initialize_pydantic(argv: list[str] | None = None, **kwargs) -> MaxTextConfig:
409+
def initialize_pydantic(argv: list[str] | None = None, config_class: type[Any] = types.MaxTextConfig, **kwargs) -> Any:
396410
"""Initializes the configuration by loading YAML files, and applying CLI, env, and overrides.
397411
398-
Returns the pydantic MaxTextConfig class.
412+
Returns the pydantic config class.
399413
"""
400414
try:
401-
return _initialize_pydantic(argv, **kwargs)
415+
return _initialize_pydantic(argv, config_class=config_class, **kwargs)
402416
except Exception as e: # pylint: disable=broad-exception-caught
403417
if isinstance(e, (SystemExit, KeyboardInterrupt)):
404418
raise e
405419
_handle_config_exception(e)
406420
raise e
407421

408422

409-
def _initialize_pydantic(argv: list[str] | None = None, **kwargs) -> MaxTextConfig:
423+
def _initialize_pydantic(argv: list[str] | None = None, config_class: type[Any] = types.MaxTextConfig, **kwargs) -> Any:
410424
"""Initializes the configuration by loading YAML files, and applying CLI, env, and kwarg overrides.
411-
Returns pydantic MaxTextConfig class whereas `initialize` returns the og `HyperParameters`
425+
Returns pydantic config class whereas `initialize` returns the og `HyperParameters`
412426
"""
413427
# 1. Load base and inherited configs from file(s)
414428
config_path, cli_args = _resolve_or_infer_config(argv, **kwargs)
@@ -531,7 +545,7 @@ def _initialize_pydantic(argv: list[str] | None = None, **kwargs) -> MaxTextConf
531545
except (ValueError, KeyError) as e:
532546
raise ValueError(f"Couldn't parse value from ENV '{new_proposal}' for key '{k}'") from e
533547

534-
pydantic_kwargs = _prepare_for_pydantic(raw_keys_dict)
548+
pydantic_kwargs = _prepare_for_pydantic(raw_keys_dict, config_class=config_class)
535549

536550
if pydantic_kwargs.get("use_tokamax_splash") and pydantic_kwargs.get("use_jax_splash"):
537551
raise ValueError("At most one of `use_tokamax_splash` and `use_jax_splash` can be set to True.")
@@ -552,8 +566,8 @@ def _initialize_pydantic(argv: list[str] | None = None, **kwargs) -> MaxTextConf
552566

553567
compilation_cache.set_cache_dir(os.path.expanduser(pydantic_kwargs["jax_cache_dir"]))
554568

555-
pydantic_config = types.MaxTextConfig(**pydantic_kwargs)
556-
explicit_keys = set((cli_keys | kwargs_keys | env_keys) & frozenset(types.MaxTextConfig.model_fields.keys()))
569+
pydantic_config = config_class(**pydantic_kwargs)
570+
explicit_keys = set((cli_keys | kwargs_keys | env_keys) & frozenset(config_class.model_fields.keys()))
557571
object.__setattr__(pydantic_config, "__pydantic_fields_set__", explicit_keys)
558572
config = HyperParameters(pydantic_config)
559573

0 commit comments

Comments
 (0)