Configuration
Configuration dataclasses for SkyRL training.
Top-Level Config
The root configuration object and helpers.
class SkyRLTrainConfig
SkyRLTrainConfig(data: DataConfig = DataConfig(), trainer: TrainerConfig = TrainerConfig(), generator: GeneratorConfig = GeneratorConfig(), environment: EnvironmentConfig = EnvironmentConfig()) -> NoneBases: BaseConfig
Root configuration object for SkyRL training with the fsdp and megatron backends.
Every field is overridable from the CLI in key.path=value form (see
from_cli_overrides): trainer.policy.model.path=... sets
SkyRLTrainConfig.trainer.policy.model.path.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
from_cli_overrides | Construct a SkyRLTrainConfig from CLI arguments or a dict of overrides. |
Attributes:
| Name | Type | Description |
|---|---|---|
data | DataConfig | |
trainer | TrainerConfig | |
generator | GeneratorConfig | |
environment | EnvironmentConfig |
Source code in skyrl/train/config/config.py:1715-1891
@dataclass
class SkyRLTrainConfig(BaseConfig):
"""Root configuration object for SkyRL training with the ``fsdp`` and ``megatron`` backends.
Every field is overridable from the CLI in ``key.path=value`` form (see
``from_cli_overrides``): ``trainer.policy.model.path=...`` sets
``SkyRLTrainConfig.trainer.policy.model.path``.
"""
data: DataConfig = field(default_factory=DataConfig)
trainer: TrainerConfig = field(default_factory=TrainerConfig)
generator: GeneratorConfig = field(default_factory=GeneratorConfig)
environment: EnvironmentConfig = field(default_factory=EnvironmentConfig)
def __post_init__(self):
# generator.max_input_length defaults to trainer.max_prompt_length
if self.generator.max_input_length is None:
self.generator.max_input_length = self.trainer.max_prompt_length
# Copy temperature from generator sampling params to algorithm config
# so workers can access it without needing the generator config
if self.trainer.algorithm.temperature is None:
self.trainer.algorithm.temperature = self.generator.sampling_params.temperature
if self.data.dataloader.num_workers is None:
self.data.dataloader.num_workers = 8
if self.data.dataloader.persistent_workers and self.data.dataloader.num_workers == 0:
raise ValueError(
"data.dataloader.persistent_workers requires num_workers > 0, but it was set explicitly to 0."
)
# TODO(devpatel): Bandaid solution, replace this once we have a better
# solution for LoRA performance degradation on the vLLM side
from skyrl.backends.skyrl_train.inference_servers.utils import (
_uses_lora_weight_sync,
)
ie_cfg = self.generator.inference_engine
if _uses_lora_weight_sync(self) and ie_cfg.enforce_eager and ie_cfg.backend == "vllm":
import warnings
warnings.warn(
"LoRA is enabled but inference_engine.enforce_eager=true. "
"This combination causes significant performance degradation (2-3x slower generation). "
"Automatically setting enforce_eager=false for better performance. "
)
ie_cfg.enforce_eager = False
@classmethod
def from_cli_overrides(cls, args: Union[List[str], dict]) -> "SkyRLTrainConfig":
"""Construct a SkyRLTrainConfig from CLI arguments or a dict of overrides.
Parses CLI arguments and builds a typed config. Dataclass field defaults
are used for any values not specified on the command line.
Args:
args: Either a list of CLI arguments in 'key.path=value' format, or a dict
mapping dot-notation keys to values.
Example list: ['trainer.policy.model.path=Qwen/Qwen2.5-1.5B-Instruct', 'trainer.seed=123']
Example dict: {'trainer.policy.model.path': 'Qwen/Qwen2.5-1.5B-Instruct', 'trainer.seed': 123}
Dict values are serialized as JSON, so ``None``, bools, strings,
lists and nested dicts keep their types.
Returns:
A fully constructed SkyRLTrainConfig with CLI overrides applied.
Raises:
ValueError: If an argument uses the unsupported '+' prefix.
"""
if isinstance(args, dict):
args = overrides_dict_to_dotlist(args)
# Check for unsupported '+' prefix
for arg in args:
if arg.startswith("+"):
raise ValueError(
f"The '+' prefix for adding new config fields is not supported: '{arg}'. "
"To add custom config fields, subclass the relevant config dataclass."
)
overrides = OmegaConf.from_cli(args)
unsupported_rope_paths = (
"trainer.rope_scaling",
"trainer.rope_theta",
"trainer.rope_parameters",
"generator.rope_scaling",
"generator.rope_theta",
"generator.rope_parameters",
"generator.inference_engine.rope_scaling",
"generator.inference_engine.rope_theta",
"generator.inference_engine.rope_parameters",
"generator.inference_engine.engine_init_kwargs.rope_scaling",
"generator.inference_engine.engine_init_kwargs.rope_theta",
"generator.inference_engine.engine_init_kwargs.rope_parameters",
"generator.inference_engine.engine_init_kwargs.hf_overrides.rope_scaling",
"generator.inference_engine.engine_init_kwargs.hf_overrides.rope_theta",
)
if any(_has_nested_key(overrides, path) for path in unsupported_rope_paths):
raise ValueError(
"`rope_scaling`, `rope_theta`, and `rope_parameters` are no longer supported as native "
"config overrides, use `generator.inference_engine.engine_init_kwargs.hf_overrides.rope_parameters` "
"and `trainer.policy.model_config_kwargs.rope_parameters` or "
"`trainer.policy.megatron_config.transformer_config_kwargs.rope_parameters` instead"
)
inference_rope_parameters = _get_nested_value(
overrides, "generator.inference_engine.engine_init_kwargs.hf_overrides.rope_parameters"
)
if inference_rope_parameters is not _MISSING:
trainer_strategy = _get_nested_value(overrides, "trainer.strategy")
trainer_strategy = "fsdp" if trainer_strategy is _MISSING else trainer_strategy
trainer_rope_parameters_path = (
"trainer.policy.megatron_config.transformer_config_kwargs.rope_parameters"
if trainer_strategy == "megatron"
else "trainer.policy.model_config_kwargs.rope_parameters"
)
trainer_rope_parameters = _get_nested_value(overrides, trainer_rope_parameters_path)
if inference_rope_parameters != trainer_rope_parameters:
raise ValueError(
"`generator.inference_engine.engine_init_kwargs.hf_overrides.rope_parameters` must match "
f"the trainer-side override at `{trainer_rope_parameters_path}`"
)
async_engine_path = "generator.inference_engine.async_engine"
async_engine = _get_nested_value(overrides, async_engine_path)
if async_engine is not _MISSING:
if async_engine is True or (isinstance(async_engine, str) and async_engine.lower() == "true"):
_delete_nested_key(overrides, async_engine_path)
elif async_engine is False or (isinstance(async_engine, str) and async_engine.lower() == "false"):
raise ValueError(
"`async_engine=False` is no longer supported; SkyRL always uses the async "
"HTTP/vLLM inference path. Remove the override."
)
else:
raise ValueError("`async_engine` is no longer supported as a config field. Remove the override.")
removed_inference_engine_overrides = {
"generator.inference_engine.enable_http_endpoint": (
"`enable_http_endpoint` is no longer supported; SkyRL always uses the HTTP/vLLM inference path. "
"Remove the override."
),
"generator.inference_engine.override_existing_update_group": (
"`override_existing_update_group` is no longer supported; update-group handling is managed "
"automatically by the vLLM-native inference path. Remove the override."
),
}
for path, message in removed_inference_engine_overrides.items():
if _has_nested_key(overrides, path):
raise ValueError(message)
if (
"generator" in overrides
and "inference_engine" in overrides.generator
and "remote_urls" in overrides.generator.inference_engine
):
raise ValueError(
"`remote_urls` is no longer supported, external inference servers can be used with "
"`external_proxy_url` and `external_server_urls` instead"
)
# Accept the deprecated ``trainer.use_sample_packing`` key as an alias
# for ``trainer.remove_microbatch_padding``. Remap it before
# construction so the strict key validation does not reject the old
# name.
if "trainer" in overrides and "use_sample_packing" in overrides.trainer:
if "remove_microbatch_padding" in overrides.trainer:
raise ValueError(
"Specify only one of trainer.use_sample_packing (deprecated) and "
"trainer.remove_microbatch_padding, not both."
)
import warnings
warnings.warn(
"trainer.use_sample_packing has been renamed to "
"trainer.remove_microbatch_padding; use "
"trainer.remove_microbatch_padding instead.",
DeprecationWarning,
stacklevel=2,
)
overrides.trainer["remove_microbatch_padding"] = overrides.trainer["use_sample_packing"]
del overrides.trainer["use_sample_packing"]
return cls.from_dict_config(overrides)from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr data
data: DataConfig = field(default_factory=DataConfig)attr trainer
trainer: TrainerConfig = field(default_factory=TrainerConfig)attr generator
generator: GeneratorConfig = field(default_factory=GeneratorConfig)attr environment
environment: EnvironmentConfig = field(default_factory=EnvironmentConfig)method classmethod from_cli_overrides
from_cli_overrides(args: Union[List[str], dict]) -> SkyRLTrainConfigConstruct a SkyRLTrainConfig from CLI arguments or a dict of overrides.
Parses CLI arguments and builds a typed config. Dataclass field defaults are used for any values not specified on the command line.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
args | Union[List[str], dict] | Either a list of CLI arguments in 'key.path=value' format, or a dict mapping dot-notation keys to values. Example list: ['trainer.policy.model.path=Qwen/Qwen2.5-1.5B-Instruct', 'trainer.seed=123'] Example dict: {'trainer.policy.model.path': 'Qwen/Qwen2.5-1.5B-Instruct', 'trainer.seed': 123} Dict values are serialized as JSON, so None, bools, strings, lists and nested dicts keep their types. | required |
Returns:
| Type | Description |
|---|---|
| SkyRLTrainConfig | A fully constructed SkyRLTrainConfig with CLI overrides applied. |
Raises:
| Type | Description |
|---|---|
| ValueError | If an argument uses the unsupported '+' prefix. |
Source code in skyrl/train/config/config.py:1764-1891
@classmethod
def from_cli_overrides(cls, args: Union[List[str], dict]) -> "SkyRLTrainConfig":
"""Construct a SkyRLTrainConfig from CLI arguments or a dict of overrides.
Parses CLI arguments and builds a typed config. Dataclass field defaults
are used for any values not specified on the command line.
Args:
args: Either a list of CLI arguments in 'key.path=value' format, or a dict
mapping dot-notation keys to values.
Example list: ['trainer.policy.model.path=Qwen/Qwen2.5-1.5B-Instruct', 'trainer.seed=123']
Example dict: {'trainer.policy.model.path': 'Qwen/Qwen2.5-1.5B-Instruct', 'trainer.seed': 123}
Dict values are serialized as JSON, so ``None``, bools, strings,
lists and nested dicts keep their types.
Returns:
A fully constructed SkyRLTrainConfig with CLI overrides applied.
Raises:
ValueError: If an argument uses the unsupported '+' prefix.
"""
if isinstance(args, dict):
args = overrides_dict_to_dotlist(args)
# Check for unsupported '+' prefix
for arg in args:
if arg.startswith("+"):
raise ValueError(
f"The '+' prefix for adding new config fields is not supported: '{arg}'. "
"To add custom config fields, subclass the relevant config dataclass."
)
overrides = OmegaConf.from_cli(args)
unsupported_rope_paths = (
"trainer.rope_scaling",
"trainer.rope_theta",
"trainer.rope_parameters",
"generator.rope_scaling",
"generator.rope_theta",
"generator.rope_parameters",
"generator.inference_engine.rope_scaling",
"generator.inference_engine.rope_theta",
"generator.inference_engine.rope_parameters",
"generator.inference_engine.engine_init_kwargs.rope_scaling",
"generator.inference_engine.engine_init_kwargs.rope_theta",
"generator.inference_engine.engine_init_kwargs.rope_parameters",
"generator.inference_engine.engine_init_kwargs.hf_overrides.rope_scaling",
"generator.inference_engine.engine_init_kwargs.hf_overrides.rope_theta",
)
if any(_has_nested_key(overrides, path) for path in unsupported_rope_paths):
raise ValueError(
"`rope_scaling`, `rope_theta`, and `rope_parameters` are no longer supported as native "
"config overrides, use `generator.inference_engine.engine_init_kwargs.hf_overrides.rope_parameters` "
"and `trainer.policy.model_config_kwargs.rope_parameters` or "
"`trainer.policy.megatron_config.transformer_config_kwargs.rope_parameters` instead"
)
inference_rope_parameters = _get_nested_value(
overrides, "generator.inference_engine.engine_init_kwargs.hf_overrides.rope_parameters"
)
if inference_rope_parameters is not _MISSING:
trainer_strategy = _get_nested_value(overrides, "trainer.strategy")
trainer_strategy = "fsdp" if trainer_strategy is _MISSING else trainer_strategy
trainer_rope_parameters_path = (
"trainer.policy.megatron_config.transformer_config_kwargs.rope_parameters"
if trainer_strategy == "megatron"
else "trainer.policy.model_config_kwargs.rope_parameters"
)
trainer_rope_parameters = _get_nested_value(overrides, trainer_rope_parameters_path)
if inference_rope_parameters != trainer_rope_parameters:
raise ValueError(
"`generator.inference_engine.engine_init_kwargs.hf_overrides.rope_parameters` must match "
f"the trainer-side override at `{trainer_rope_parameters_path}`"
)
async_engine_path = "generator.inference_engine.async_engine"
async_engine = _get_nested_value(overrides, async_engine_path)
if async_engine is not _MISSING:
if async_engine is True or (isinstance(async_engine, str) and async_engine.lower() == "true"):
_delete_nested_key(overrides, async_engine_path)
elif async_engine is False or (isinstance(async_engine, str) and async_engine.lower() == "false"):
raise ValueError(
"`async_engine=False` is no longer supported; SkyRL always uses the async "
"HTTP/vLLM inference path. Remove the override."
)
else:
raise ValueError("`async_engine` is no longer supported as a config field. Remove the override.")
removed_inference_engine_overrides = {
"generator.inference_engine.enable_http_endpoint": (
"`enable_http_endpoint` is no longer supported; SkyRL always uses the HTTP/vLLM inference path. "
"Remove the override."
),
"generator.inference_engine.override_existing_update_group": (
"`override_existing_update_group` is no longer supported; update-group handling is managed "
"automatically by the vLLM-native inference path. Remove the override."
),
}
for path, message in removed_inference_engine_overrides.items():
if _has_nested_key(overrides, path):
raise ValueError(message)
if (
"generator" in overrides
and "inference_engine" in overrides.generator
and "remote_urls" in overrides.generator.inference_engine
):
raise ValueError(
"`remote_urls` is no longer supported, external inference servers can be used with "
"`external_proxy_url` and `external_server_urls` instead"
)
# Accept the deprecated ``trainer.use_sample_packing`` key as an alias
# for ``trainer.remove_microbatch_padding``. Remap it before
# construction so the strict key validation does not reject the old
# name.
if "trainer" in overrides and "use_sample_packing" in overrides.trainer:
if "remove_microbatch_padding" in overrides.trainer:
raise ValueError(
"Specify only one of trainer.use_sample_packing (deprecated) and "
"trainer.remove_microbatch_padding, not both."
)
import warnings
warnings.warn(
"trainer.use_sample_packing has been renamed to "
"trainer.remove_microbatch_padding; use "
"trainer.remove_microbatch_padding instead.",
DeprecationWarning,
stacklevel=2,
)
overrides.trainer["remove_microbatch_padding"] = overrides.trainer["use_sample_packing"]
del overrides.trainer["use_sample_packing"]
return cls.from_dict_config(overrides)method make_config
make_config(algorithm_cls: Optional[Type[AlgorithmConfig]] = None, trainer_cls: Optional[Type[TrainerConfig]] = None, generator_cls: Optional[Type[GeneratorConfig]] = None) -> Type[SkyRLTrainConfig]Create a SkyRLTrainConfig subclass with custom nested config classes.
Convenience helper to avoid boilerplate when extending configs for custom algorithms or generators. For full IDE autocomplete on custom fields, use explicit subclassing instead (see examples/algorithms/dapo/main_dapo.py).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
algorithm_cls | Optional[Type[AlgorithmConfig]] | Custom AlgorithmConfig subclass. If provided without trainer_cls, a TrainerConfig subclass is automatically created. | None |
trainer_cls | Optional[Type[TrainerConfig]] | Custom TrainerConfig subclass. Takes precedence over algorithm_cls for the trainer config. | None |
generator_cls | Optional[Type[GeneratorConfig]] | Custom GeneratorConfig subclass. | None |
Returns:
| Type | Description |
|---|---|
| Type[SkyRLTrainConfig] | A SkyRLTrainConfig subclass wired up with the custom config classes. |
Example::
@dataclass class MyAlgorithmConfig(AlgorithmConfig): my_param: int = 42
MyConfig = make_config(algorithm_cls=MyAlgorithmConfig) cfg = MyConfig.from_cli_overrides(sys.argv[1:])
method get_config_as_dict
get_config_as_dict(cfg: Union[dict, BaseConfig]) -> dictmethod get_config_as_yaml_str
get_config_as_yaml_str(cfg: BaseConfig) -> strData & Model
class DataConfig
DataConfig(train_data: List[str] = (lambda: [os.path.expanduser('~/data/gsm8k/train.parquet')])(), val_data: List[str] = (lambda: [os.path.expanduser('~/data/gsm8k/validation.parquet')])(), dataloader: DataLoaderConfig = DataLoaderConfig()) -> NoneBases: BaseConfig
Training and validation dataset configuration.
NOTE: datasets are currently loaded entirely into memory, so the maximum usable dataset size is bounded by the CPU memory available on a worker node.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
train_data | List[str] | Files for the training dataset. |
val_data | List[str] | Files for the evaluation dataset, in the same formats accepted by train_data. |
dataloader | DataLoaderConfig |
Source code in skyrl/train/config/config.py:68-84
@dataclass
class DataConfig(BaseConfig):
"""Training and validation dataset configuration.
NOTE: datasets are currently loaded entirely into memory, so the maximum usable dataset
size is bounded by the CPU memory available on a worker node.
"""
train_data: List[str] = field(default_factory=lambda: [os.path.expanduser("~/data/gsm8k/train.parquet")])
"""Files for the training dataset.
Each entry is a path to a parquet or json file, or the name of a HuggingFace dataset."""
val_data: List[str] = field(default_factory=lambda: [os.path.expanduser("~/data/gsm8k/validation.parquet")])
"""Files for the evaluation dataset, in the same formats accepted by ``train_data``.
When more than one is given, evaluation runs over all of them: both per-dataset metrics
(keyed by each sample's ``data_source``) and aggregated ``eval/all/*`` metrics are logged,
and ``trainer.dump_eval_results`` dumps the per-dataset and aggregated results."""
dataloader: DataLoaderConfig = field(default_factory=DataLoaderConfig)from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr train_data
train_data: List[str] = field(default_factory=(lambda: [os.path.expanduser('~/data/gsm8k/train.parquet')]))Files for the training dataset. Each entry is a path to a parquet or json file, or the name of a HuggingFace dataset.
attr val_data
val_data: List[str] = field(default_factory=(lambda: [os.path.expanduser('~/data/gsm8k/validation.parquet')]))Files for the evaluation dataset, in the same formats accepted by train_data.
When more than one is given, evaluation runs over all of them: both per-dataset metrics
(keyed by each sample's data_source) and aggregated eval/all/* metrics are logged,
and trainer.dump_eval_results dumps the per-dataset and aggregated results.
attr dataloader
dataloader: DataLoaderConfig = field(default_factory=DataLoaderConfig)class DataLoaderConfig
DataLoaderConfig(num_workers: Optional[int] = None, persistent_workers: bool = False) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
num_workers | Optional[int] | |
persistent_workers | bool |
Source code in skyrl/train/config/config.py:42-65
@dataclass
class DataLoaderConfig(BaseConfig):
num_workers: Optional[int] = field(
default=None,
metadata={
"help": (
"Prompt DataLoader worker processes. Default of None auto-derives to 8. "
"Set 0 for in-process loading that never respawns workers at epoch boundaries."
)
},
)
persistent_workers: bool = field(
default=False,
metadata={
"help": (
"Keep DataLoader workers alive across epochs instead of respawning them at "
"every epoch boundary. Setting this requires `num_workers > 0`"
)
},
)
def __post_init__(self) -> None:
if self.num_workers is not None and self.num_workers < 0:
raise ValueError(f"data.dataloader.num_workers must be None or >= 0, got {self.num_workers}.")from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr num_workers
num_workers: Optional[int] = field(default=None, metadata={'help': 'Prompt DataLoader worker processes. Default of None auto-derives to 8. Set 0 for in-process loading that never respawns workers at epoch boundaries.'})attr persistent_workers
persistent_workers: bool = field(default=False, metadata={'help': 'Keep DataLoader workers alive across epochs instead of respawning them at every epoch boundary. Setting this requires `num_workers > 0`'})class ModelConfig
ModelConfig(path: Optional[str] = None, lora: SkyRLLoraConfig = SkyRLLoraConfig(), fake_int4_qat: FakeInt4QatConfig = FakeInt4QatConfig()) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
path | Optional[str] | HuggingFace model path (or local directory) for this model. |
lora | SkyRLLoraConfig | |
fake_int4_qat | FakeInt4QatConfig |
Source code in skyrl/train/config/config.py:165-178
@dataclass
class ModelConfig(BaseConfig):
path: Optional[str] = None
"""HuggingFace model path (or local directory) for this model."""
lora: SkyRLLoraConfig = field(default_factory=SkyRLLoraConfig)
fake_int4_qat: FakeInt4QatConfig = field(default_factory=FakeInt4QatConfig)
def __post_init__(self) -> None:
if self.fake_int4_qat.enabled:
assert self.lora.rank > 0, (
"`trainer.policy.model.fake_int4_qat.enabled=True` currently requires LoRA "
"(`trainer.policy.model.lora.rank > 0`) because full-weight sync exports "
"dense expert weights."
)from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr path
path: Optional[str] = NoneHuggingFace model path (or local directory) for this model.
attr lora
lora: SkyRLLoraConfig = field(default_factory=SkyRLLoraConfig)attr fake_int4_qat
fake_int4_qat: FakeInt4QatConfig = field(default_factory=FakeInt4QatConfig)class SkyRLLoraConfig
SkyRLLoraConfig(rank: int = 0, alpha: int = 16, dropout: float = 0.0, lora_sync_path: str = '/tmp/skyrl_lora_sync', target_modules: str = 'all-linear', exclude_modules: Optional[str] = None, init_method: str = 'kaiming', max_loras: int = 1, max_cpu_loras: Optional[int] = None) -> NoneBases: BaseConfig
LoRA configuration for parameter-efficient fine-tuning.
Trains a small number of additional low-rank matrices instead of the full model weights.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
rank | int | Rank of the low-rank decomposition. |
alpha | int | Scaling factor for LoRA updates. |
dropout | float | Dropout probability applied to LoRA layers, to help prevent overfitting. |
lora_sync_path | str | Directory where LoRA adapter weights are saved and synchronized between the training and inference processes. |
target_modules | str | Modules to apply LoRA to. |
exclude_modules | Optional[str] | Modules to exclude from LoRA. |
init_method | str | For FSDP, corresponds to init_lora_weights in PEFT. |
max_loras | int | Maximum number of LoRA adapters that can be active concurrently in a |
max_cpu_loras | Optional[int] | Total LoRA adapter capacity in vLLM's CPU LRU cache. Maps to vLLM's |
Source code in skyrl/train/config/config.py:93-128
@dataclass
class SkyRLLoraConfig(BaseConfig):
"""LoRA configuration for parameter-efficient fine-tuning.
Trains a small number of additional low-rank matrices instead of the full model weights.
"""
rank: int = 0
"""Rank of the low-rank decomposition.
``0`` disables LoRA. Higher values increase capacity but also memory usage; 8, 16, 32, and 64 are common choices."""
alpha: int = 16
"""Scaling factor for LoRA updates."""
dropout: float = 0.0
"""Dropout probability applied to LoRA layers, to help prevent overfitting."""
lora_sync_path: str = "/tmp/skyrl_lora_sync"
"""Directory where LoRA adapter weights are saved and synchronized between the training and inference processes.
Must be accessible to all workers in distributed setups."""
target_modules: str = "all-linear"
"""Modules to apply LoRA to.
``"all-linear"`` targets every linear layer for FSDP/PEFT, and is remapped to a fixed module list
on Megatron. A list of specific module names can be given instead."""
exclude_modules: Optional[str] = None
"""Modules to exclude from LoRA."""
init_method: str = "kaiming"
"""For FSDP, corresponds to ``init_lora_weights`` in PEFT.
For Megatron, used for ``lora_A_init_method``; supports "xavier", "normal", "kaiming", "zero"."""
max_loras: int = 1
"""Maximum number of LoRA adapters that can be active concurrently in a
single GPU batch. Maps to vLLM's ``max_loras``. Increase past 1 to enable
multi-tenant LoRA serving via ``RemoteInferenceClient.load_lora_adapter``."""
max_cpu_loras: Optional[int] = None
"""Total LoRA adapter capacity in vLLM's CPU LRU cache. Maps to vLLM's
``max_cpu_loras``; when None, vLLM defaults it to ``max_loras``. Must be
>= ``max_loras`` if explicitly set."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr rank
rank: int = 0Rank of the low-rank decomposition.
0 disables LoRA. Higher values increase capacity but also memory usage; 8, 16, 32, and 64 are common choices.
attr alpha
alpha: int = 16Scaling factor for LoRA updates.
attr dropout
dropout: float = 0.0Dropout probability applied to LoRA layers, to help prevent overfitting.
attr lora_sync_path
lora_sync_path: str = '/tmp/skyrl_lora_sync'Directory where LoRA adapter weights are saved and synchronized between the training and inference processes. Must be accessible to all workers in distributed setups.
attr target_modules
target_modules: str = 'all-linear'Modules to apply LoRA to.
"all-linear" targets every linear layer for FSDP/PEFT, and is remapped to a fixed module list
on Megatron. A list of specific module names can be given instead.
attr exclude_modules
exclude_modules: Optional[str] = NoneModules to exclude from LoRA.
attr init_method
init_method: str = 'kaiming'For FSDP, corresponds to init_lora_weights in PEFT.
For Megatron, used for lora_A_init_method; supports "xavier", "normal", "kaiming", "zero".
attr max_loras
max_loras: int = 1Maximum number of LoRA adapters that can be active concurrently in a
single GPU batch. Maps to vLLM's max_loras. Increase past 1 to enable
multi-tenant LoRA serving via RemoteInferenceClient.load_lora_adapter.
attr max_cpu_loras
max_cpu_loras: Optional[int] = NoneTotal LoRA adapter capacity in vLLM's CPU LRU cache. Maps to vLLM's
max_cpu_loras; when None, vLLM defaults it to max_loras. Must be
=
max_lorasif explicitly set.
Training
class TrainerConfig
TrainerConfig(placement: PlacementConfig = PlacementConfig(), use_expandable_segments: bool = True, sequence_parallel_backend: str = 'ulysses', strategy: str = 'fsdp', policy: PolicyConfig = PolicyConfig(), ref: RefConfig = RefConfig(), critic: CriticConfig = CriticConfig(), algorithm: AlgorithmConfig = AlgorithmConfig(), mtp: MTPConfig = MTPConfig(), fully_async: FullyAsyncConfig = FullyAsyncConfig(), gradient_checkpointing: bool = True, gradient_checkpointing_use_reentrant: bool = False, seed: int = 42, resume_mode: Optional[str] = 'latest', resume_path: Optional[str] = None, log_path: str = '/tmp/skyrl-logs', ckpt_path: str = (lambda: os.path.expanduser('~/ckpts/'))(), max_ckpts_to_keep: int = -1, ckpt_interval: int = 10, hf_save_interval: int = -1, export_path: str = (lambda: os.path.expanduser('~/exports/'))(), bf16: bool = True, epochs: int = 1, max_training_steps: Optional[int] = None, update_epochs_per_batch: int = 1, train_batch_size: int = 1024, policy_mini_batch_size: int = 256, critic_mini_batch_size: int = 256, micro_train_batch_size_per_gpu: int = 1, micro_forward_batch_size_per_gpu: int = 1, max_tokens_per_microbatch: int = -1, recompute_old_logprobs_per_minibatch: bool = True, update_ref_every_epoch: bool = False, remove_microbatch_padding: bool = True, eval_batch_size: int = 1024, eval_before_train: bool = True, eval_interval: int = 5, max_prompt_length: int = 512, flash_attn: bool = True, disable_fast_tokenizer: bool = False, project_name: str = 'skyrl', run_name: str = 'test_run', logger: str = 'wandb', enable_ray_gpu_monitor: bool = True, tags: Optional[List[str]] = None, dump_data_batch: bool = False, dump_eval_results: bool = True, print_example_interval: int = 1, num_logger_eval_samples: int = -1, num_logger_train_samples: int = -1, log_example_interval: int = -1, logprobs_chunk_size: Optional[int] = 1024, vocab_entropy_chunk_size: Optional[int] = 0, vocab_entropy_chunk_memory_mb: int = 512, fused_lm_head_logprob: bool = False, fused_lm_head_logprob_backend: str = 'torch') -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
placement | PlacementConfig | |
use_expandable_segments | bool | Enable PyTorch's CUDA expandable_segments allocator on the training workers. |
sequence_parallel_backend | str | |
strategy | str | Training backend: either "fsdp" or "megatron". |
policy | PolicyConfig | |
ref | RefConfig | |
critic | CriticConfig | |
algorithm | AlgorithmConfig | |
mtp | MTPConfig | |
fully_async | FullyAsyncConfig | |
gradient_checkpointing | bool | Use gradient checkpointing (activation recomputation) to trade compute for memory. |
gradient_checkpointing_use_reentrant | bool | |
seed | int | Random seed for training. |
resume_mode | Optional[str] | None/"none", "latest", or "from_path". |
resume_path | Optional[str] | Checkpoint directory to resume from. Only used when resume_mode="from_path". |
log_path | str | Path for infrastructure log files. |
ckpt_path | str | Directory for resumable training checkpoints (model state, optimizer state, etc.). |
max_ckpts_to_keep | int | -1 to keep all checkpoints, N to keep only the last N. |
ckpt_interval | int | Save a full training checkpoint every N steps. |
hf_save_interval | int | Save HuggingFace-format model every N steps. -1 to disable. |
export_path | str | Path for exported artifacts (HF models, debug dumps, etc.). |
bf16 | bool | |
epochs | int | Number of epochs (passes over the full dataset). |
max_training_steps | Optional[int] | If set, stop training after this many steps regardless of epochs or dataset size. |
update_epochs_per_batch | int | Number of gradient update passes over each training batch. |
train_batch_size | int | Batch size of prompts used for each dataloader step. |
policy_mini_batch_size | int | Mini batch size for the RL training step; each mini batch is one optimizer step. |
critic_mini_batch_size | int | Like policy_mini_batch_size, but for the critic model. |
micro_train_batch_size_per_gpu | int | Micro batch size during the training step, common to both policy and critic. |
micro_forward_batch_size_per_gpu | int | Micro batch size during the forward pass, i.e. log probability or value computation. |
max_tokens_per_microbatch | int | Maximum number of tokens per microbatch for both forward and training steps. When > 0, microbatches |
recompute_old_logprobs_per_minibatch | bool | When True, recomputes policy/ref model logprobs (and critic values) per mini-batch using |
update_ref_every_epoch | bool | Re-sync the reference model from the policy model at every epoch boundary. |
remove_microbatch_padding | bool | Pack samples into the THD layout and strip intra-microbatch padding (requires flash attention). |
eval_batch_size | int | Batch size for evaluation. |
eval_before_train | bool | Evaluate the model once before training starts. |
eval_interval | int | Evaluate against the validation dataset every N steps. -1 to disable evaluation. |
max_prompt_length | int | Maximum prompt length during training. |
flash_attn | bool | |
disable_fast_tokenizer | bool | |
project_name | str | Project name in WandB and MLflow. |
run_name | str | Run name in WandB and MLflow. |
logger | str | Logger to use: "wandb", "mlflow", "swanlab", "tensorboard", or "console". |
enable_ray_gpu_monitor | bool | Enable background Ray GPU/RAM metrics collection and logging to wandb. |
tags | Optional[List[str]] | Optional list of tags to apply to the W&B run. Has no effect on other backends. |
dump_data_batch | bool | Dump each training data batch to a file for debugging. |
dump_eval_results | bool | Dump full evaluation results to a file. |
print_example_interval | int | Pretty-print an example prompt/response/reward to stdout every N |
num_logger_eval_samples | int | Number of evaluation trajectory (prompt, response, score) tuples to upload to a wandb |
num_logger_train_samples | int | Number of training trajectory (prompt, response, score) tuples to upload to a wandb |
log_example_interval | int | Log an example prompt every N training steps, 0/-1 to disable |
logprobs_chunk_size | Optional[int] | Chunk size along the sequence dimension when computing log-probs from logits. |
vocab_entropy_chunk_size | Optional[int] | Chunk size along the sequence dimension when computing Megatron vocab entropy. |
vocab_entropy_chunk_memory_mb | int | Approximate per-chunk temporary memory budget for auto-sized Megatron vocab entropy chunks. |
fused_lm_head_logprob | bool | Megatron only. Fuse the LM-head projection into log-prob / entropy |
fused_lm_head_logprob_backend | str | Fused LM-head backend: "torch" (default) or "triton". |
Source code in skyrl/train/config/config.py:1329-1561
@dataclass
class TrainerConfig(BaseConfig):
placement: PlacementConfig = field(default_factory=PlacementConfig)
use_expandable_segments: bool = True
"""Enable PyTorch's CUDA ``expandable_segments`` allocator on the training workers.
Reduces GPU memory fragmentation across the offload/backload and forward/backward cycles.
Automatically turned off around CUDA-IPC weight sync, since IPC handles are incompatible with the
VMM addresses expandable segments uses; under ``colocate_all=False`` weight sync uses NCCL
broadcast instead, so it stays on continuously.
``InferenceEngineConfig.use_expandable_segments`` is the independent inference-engine knob (the
trainer and the engine are separate processes with separate allocators). See
https://docs.skyrl.ai/docs/troubleshooting/troubleshooting for the fragmentation symptoms this
addresses."""
sequence_parallel_backend: str = "ulysses"
strategy: str = "fsdp"
"""Training backend: either ``"fsdp"`` or ``"megatron"``.
``"fsdp"`` uses PyTorch's composable ``fully_shard`` API (formerly known as FSDP2)."""
policy: PolicyConfig = field(default_factory=PolicyConfig)
ref: RefConfig = field(default_factory=RefConfig)
critic: CriticConfig = field(default_factory=CriticConfig)
algorithm: AlgorithmConfig = field(default_factory=AlgorithmConfig)
mtp: MTPConfig = field(default_factory=MTPConfig)
fully_async: FullyAsyncConfig = field(default_factory=FullyAsyncConfig)
gradient_checkpointing: bool = True
"""Use gradient checkpointing (activation recomputation) to trade compute for memory."""
gradient_checkpointing_use_reentrant: bool = False
seed: int = 42
"""Random seed for training."""
resume_mode: Optional[str] = "latest"
"""``None``/``"none"``, ``"latest"``, or ``"from_path"``.
See https://docs.skyrl.ai/docs/checkpointing-logging/checkpointing"""
resume_path: Optional[str] = None
"""Checkpoint directory to resume from. Only used when ``resume_mode="from_path"``."""
log_path: str = "/tmp/skyrl-logs"
"""Path for infrastructure log files.
vLLM engine startup, model loading, and worker initialization logs are written to
``{log_path}/infra-YYMMDD_HHMMSS.log``. For multi-node training, use a shared filesystem path to
consolidate logs into a single file. See https://docs.skyrl.ai/docs/checkpointing-logging/logging"""
ckpt_path: str = field(default_factory=lambda: os.path.expanduser("~/ckpts/"))
"""Directory for resumable training checkpoints (model state, optimizer state, etc.).
Accepts a local directory path or a cloud storage path (S3, GCS)."""
max_ckpts_to_keep: int = -1
"""``-1`` to keep all checkpoints, ``N`` to keep only the last N."""
ckpt_interval: int = 10
"""Save a full training checkpoint every N steps."""
hf_save_interval: int = -1
"""Save HuggingFace-format model every N steps. ``-1`` to disable."""
export_path: str = field(default_factory=lambda: os.path.expanduser("~/exports/"))
"""Path for exported artifacts (HF models, debug dumps, etc.).
For sharded multi-node HF exports with ``policy.megatron_config.hf_export_config.distributed_save=True``, this must
be a shared filesystem path visible to all Megatron ranks."""
bf16: bool = True
epochs: int = 1
"""Number of epochs (passes over the full dataset)."""
max_training_steps: Optional[int] = None
"""If set, stop training after this many steps regardless of epochs or dataset size.
Useful for CI smoke tests and quick validation runs."""
update_epochs_per_batch: int = 1
"""Number of gradient update passes over each training batch.
Equivalent to the concept of "PPO epochs", where the same experience is iterated over multiple times."""
train_batch_size: int = 1024
"""Batch size of prompts used for each dataloader step.
See ``utils/utils.py::validate_batch_sizes`` for the constraints relating this to
``policy_mini_batch_size``, ``micro_train_batch_size_per_gpu``, and
``micro_forward_batch_size_per_gpu``."""
policy_mini_batch_size: int = 256
"""Mini batch size for the RL training step; each mini batch is one optimizer step.
For example, with ``train_batch_size=4`` and ``policy_mini_batch_size=2`` there are 2 optimizer steps (model
updates) per training batch. This is the *global* mini batch size, counted in prompts — the
per-worker mini batch is
``policy_mini_batch_size * generator.n_samples_per_prompt / number of DP ranks``."""
critic_mini_batch_size: int = 256
"""Like ``policy_mini_batch_size``, but for the critic model.
The critic generally tolerates off-policy updates better than the policy, so setting this lower than
``policy_mini_batch_size`` (i.e. more critic updates) is usually preferable."""
micro_train_batch_size_per_gpu: int = 1
"""Micro batch size during the training step, common to both policy and critic.
Each mini batch is split into micro batches of this size, and gradients are accumulated over them."""
micro_forward_batch_size_per_gpu: int = 1
"""Micro batch size during the forward pass, i.e. log probability or value computation.
Common to both policy and critic. Each mini batch is split into micro batches of this size."""
max_tokens_per_microbatch: int = -1
"""Maximum number of tokens per microbatch for both forward and training steps. When > 0, microbatches
are formed by bin-packing samples based on their token counts (from attention_mask) instead of using a
fixed sample count, and micro_train_batch_size_per_gpu / micro_forward_batch_size_per_gpu are ignored.
-1 means disabled (use sample-based micro_train_batch_size_per_gpu / micro_forward_batch_size_per_gpu).
Applies to both forward and training micro-batching.
NOTE: this is a *soft* cap. Sequences are never split across microbatches, so a single sequence
longer than ``max_tokens_per_microbatch`` is placed alone in its own microbatch that exceeds the
cap (no error, no truncation). The true peak microbatch size is therefore
``max(max_tokens_per_microbatch, longest_sequence_in_batch)``."""
recompute_old_logprobs_per_minibatch: bool = True
"""When True, recomputes policy/ref model logprobs (and critic values) per mini-batch using
the same mini-batch + DP partition as the training step. When False, a single full-batch forward is run.
This makes the microbatch packing — and therefore the resulting logprobs/values — identical to
what forward_backward recomputes, so the PPO ratio (and critic value clipping) is exact at the
first inner step."""
update_ref_every_epoch: bool = False
"""Re-sync the reference model from the policy model at every epoch boundary."""
remove_microbatch_padding: bool = True
"""Pack samples into the THD layout and strip intra-microbatch padding (requires flash attention).
Common to all models."""
eval_batch_size: int = 1024
"""Batch size for evaluation."""
eval_before_train: bool = True
"""Evaluate the model once before training starts."""
eval_interval: int = 5
"""Evaluate against the validation dataset every N steps. ``-1`` to disable evaluation."""
max_prompt_length: int = 512
"""Maximum prompt length during training.
Prompts longer than this are filtered out of the train/eval datasets at load time, not
truncated."""
flash_attn: bool = True
disable_fast_tokenizer: bool = False
project_name: str = "skyrl"
"""Project name in WandB and MLflow."""
run_name: str = "test_run"
"""Run name in WandB and MLflow."""
logger: str = "wandb"
"""Logger to use: ``"wandb"``, ``"mlflow"``, ``"swanlab"``, ``"tensorboard"``, or ``"console"``.
See https://docs.skyrl.ai/docs/checkpointing-logging/logging"""
enable_ray_gpu_monitor: bool = True
"""Enable background Ray GPU/RAM metrics collection and logging to wandb."""
tags: Optional[List[str]] = None
"""Optional list of tags to apply to the W&B run. Has no effect on other backends."""
dump_data_batch: bool = False
"""Dump each training data batch to a file for debugging.
The batch at global step N is written to
``{export_path}/dumped_data/global_step_{N}_training_input.pkl``."""
dump_eval_results: bool = True
"""Dump full evaluation results to a file.
Results at global step N are written to ``{export_path}/dumped_evals/global_step_{N}_evals``, with both per-dataset
and aggregated results when multiple validation datasets are configured."""
print_example_interval: int = 1
"""Pretty-print an example prompt/response/reward to stdout every N
training steps; ``0``/``-1`` disables. Renamed from ``log_example_interval``."""
num_logger_eval_samples: int = -1
"""Number of evaluation trajectory (prompt, response, score) tuples to upload to a wandb
table on each eval. ``-1`` (default) or ``0`` disables. When positive,
up to this many samples are taken from the start of each eval pass and
logged via :class:`TrajectoryLogger`. Column count is fixed
by the first call, so keep the eval set size and this value stable."""
num_logger_train_samples: int = -1
"""Number of training trajectory (prompt, response, score) tuples to upload to a wandb
table on each training step. ``-1`` (default) or ``0`` disables. When positive,
up to this many samples are taken from the start of each training step and
logged via :class:`TrajectoryLogger`. Column count is fixed
by the first call, so keep the training set size and this value stable."""
log_example_interval: int = -1
"""Log an example prompt every N training steps, ``0``/``-1`` to disable"""
logprobs_chunk_size: Optional[int] = 1024
"""Chunk size along the sequence dimension when computing log-probs from logits.
This lowers peak GPU memory at the cost of ~2x wall-clock time.
``None`` disables chunking (Megatron backend only; FSDP requires a positive int).
See https://github.com/NovaSky-AI/SkyRL/pull/1610 for more details."""
vocab_entropy_chunk_size: Optional[int] = 0
"""Chunk size along the sequence dimension when computing Megatron vocab entropy.
``0`` auto-sizes from the local vocab shard size and ``vocab_entropy_chunk_memory_mb``.
``None`` disables chunking."""
vocab_entropy_chunk_memory_mb: int = 512
"""Approximate per-chunk temporary memory budget for auto-sized Megatron vocab entropy chunks."""
fused_lm_head_logprob: bool = False
"""Megatron only. Fuse the LM-head projection into log-prob / entropy
computation so the full ``[B, S, vocab//TP]`` logits tensor is never
materialized. Uses ``logprobs_chunk_size`` to bound peak memory."""
fused_lm_head_logprob_backend: str = "torch"
"""Fused LM-head backend: ``"torch"`` (default) or ``"triton"``.
The Triton backend requires CUDA + triton and falls back to ``"torch"``
when unavailable. Ignored unless ``fused_lm_head_logprob`` is true."""
def __post_init__(self):
# ref model defaults to the policy model
if self.ref.model.path is None:
self.ref.model.path = self.policy.model.path
if self.log_example_interval > 0:
print(
f"log_example_interval has been renamed, use print_example_interval instead. Setting print_example_interval to {self.log_example_interval}"
)
self.print_example_interval = self.log_example_interval
if self.policy.model.fake_int4_qat.enabled:
assert (
self.strategy == "megatron"
), "`trainer.policy.model.fake_int4_qat.enabled=True` is only supported with `trainer.strategy=megatron`."
assert not self.policy.megatron_config.lora_config.merge_lora, (
"`trainer.policy.model.fake_int4_qat.enabled=True` currently requires "
"`trainer.policy.megatron_config.lora_config.merge_lora=False` so weight "
"sync preserves the inference engine's INT4 base weights."
)
if self.logprobs_chunk_size is not None and (
not isinstance(self.logprobs_chunk_size, int) or self.logprobs_chunk_size <= 0
):
raise ValueError(
f"logprobs_chunk_size must be a positive integer or None, got {self.logprobs_chunk_size!r}."
)
if self.logprobs_chunk_size is None and self.strategy != "megatron":
raise ValueError(
"logprobs_chunk_size=None (no chunking) is only supported with the Megatron backend. "
f"Set a positive integer for strategy={self.strategy!r}."
)
if self.fused_lm_head_logprob and self.strategy != "megatron":
raise ValueError(
"fused_lm_head_logprob=True is only supported with the Megatron backend, "
f"got strategy={self.strategy!r}."
)
if self.fused_lm_head_logprob_backend not in ("torch", "triton"):
raise ValueError(
"fused_lm_head_logprob_backend must be 'torch' or 'triton', "
f"got {self.fused_lm_head_logprob_backend!r}."
)
if self.vocab_entropy_chunk_size is not None and (
isinstance(self.vocab_entropy_chunk_size, bool)
or not isinstance(self.vocab_entropy_chunk_size, int)
or self.vocab_entropy_chunk_size < 0
):
raise ValueError(
"vocab_entropy_chunk_size must be a non-negative integer or None, "
f"got {self.vocab_entropy_chunk_size!r}."
)
if (
isinstance(self.vocab_entropy_chunk_memory_mb, bool)
or not isinstance(self.vocab_entropy_chunk_memory_mb, int)
or self.vocab_entropy_chunk_memory_mb <= 0
):
raise ValueError(
"vocab_entropy_chunk_memory_mb must be a positive integer, "
f"got {self.vocab_entropy_chunk_memory_mb!r}."
)from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr placement
placement: PlacementConfig = field(default_factory=PlacementConfig)attr use_expandable_segments
use_expandable_segments: bool = TrueEnable PyTorch's CUDA expandable_segments allocator on the training workers.
Reduces GPU memory fragmentation across the offload/backload and forward/backward cycles.
Automatically turned off around CUDA-IPC weight sync, since IPC handles are incompatible with the
VMM addresses expandable segments uses; under colocate_all=False weight sync uses NCCL
broadcast instead, so it stays on continuously.
InferenceEngineConfig.use_expandable_segments is the independent inference-engine knob (the
trainer and the engine are separate processes with separate allocators). See
https://docs.skyrl.ai/docs/troubleshooting/troubleshooting for the fragmentation symptoms this
addresses.
attr sequence_parallel_backend
sequence_parallel_backend: str = 'ulysses'attr strategy
strategy: str = 'fsdp'Training backend: either "fsdp" or "megatron".
"fsdp" uses PyTorch's composable fully_shard API (formerly known as FSDP2).
attr policy
policy: PolicyConfig = field(default_factory=PolicyConfig)attr ref
ref: RefConfig = field(default_factory=RefConfig)attr critic
critic: CriticConfig = field(default_factory=CriticConfig)attr algorithm
algorithm: AlgorithmConfig = field(default_factory=AlgorithmConfig)attr mtp
mtp: MTPConfig = field(default_factory=MTPConfig)attr fully_async
fully_async: FullyAsyncConfig = field(default_factory=FullyAsyncConfig)attr gradient_checkpointing
gradient_checkpointing: bool = TrueUse gradient checkpointing (activation recomputation) to trade compute for memory.
attr gradient_checkpointing_use_reentrant
gradient_checkpointing_use_reentrant: bool = Falseattr seed
seed: int = 42Random seed for training.
attr resume_mode
resume_mode: Optional[str] = 'latest'None/"none", "latest", or "from_path".
See https://docs.skyrl.ai/docs/checkpointing-logging/checkpointing
attr resume_path
resume_path: Optional[str] = NoneCheckpoint directory to resume from. Only used when resume_mode="from_path".
attr log_path
log_path: str = '/tmp/skyrl-logs'Path for infrastructure log files.
vLLM engine startup, model loading, and worker initialization logs are written to
{log_path}/infra-YYMMDD_HHMMSS.log. For multi-node training, use a shared filesystem path to
consolidate logs into a single file. See https://docs.skyrl.ai/docs/checkpointing-logging/logging
attr ckpt_path
ckpt_path: str = field(default_factory=(lambda: os.path.expanduser('~/ckpts/')))Directory for resumable training checkpoints (model state, optimizer state, etc.). Accepts a local directory path or a cloud storage path (S3, GCS).
attr max_ckpts_to_keep
max_ckpts_to_keep: int = -1-1 to keep all checkpoints, N to keep only the last N.
attr ckpt_interval
ckpt_interval: int = 10Save a full training checkpoint every N steps.
attr hf_save_interval
hf_save_interval: int = -1Save HuggingFace-format model every N steps. -1 to disable.
attr export_path
export_path: str = field(default_factory=(lambda: os.path.expanduser('~/exports/')))Path for exported artifacts (HF models, debug dumps, etc.).
For sharded multi-node HF exports with policy.megatron_config.hf_export_config.distributed_save=True, this must
be a shared filesystem path visible to all Megatron ranks.
attr bf16
bf16: bool = Trueattr epochs
epochs: int = 1Number of epochs (passes over the full dataset).
attr max_training_steps
max_training_steps: Optional[int] = NoneIf set, stop training after this many steps regardless of epochs or dataset size. Useful for CI smoke tests and quick validation runs.
attr update_epochs_per_batch
update_epochs_per_batch: int = 1Number of gradient update passes over each training batch. Equivalent to the concept of "PPO epochs", where the same experience is iterated over multiple times.
attr train_batch_size
train_batch_size: int = 1024Batch size of prompts used for each dataloader step.
See utils/utils.py::validate_batch_sizes for the constraints relating this to
policy_mini_batch_size, micro_train_batch_size_per_gpu, and
micro_forward_batch_size_per_gpu.
attr policy_mini_batch_size
policy_mini_batch_size: int = 256Mini batch size for the RL training step; each mini batch is one optimizer step.
For example, with train_batch_size=4 and policy_mini_batch_size=2 there are 2 optimizer steps (model
updates) per training batch. This is the global mini batch size, counted in prompts — the
per-worker mini batch is
policy_mini_batch_size * generator.n_samples_per_prompt / number of DP ranks.
attr critic_mini_batch_size
critic_mini_batch_size: int = 256Like policy_mini_batch_size, but for the critic model.
The critic generally tolerates off-policy updates better than the policy, so setting this lower than
policy_mini_batch_size (i.e. more critic updates) is usually preferable.
attr micro_train_batch_size_per_gpu
micro_train_batch_size_per_gpu: int = 1Micro batch size during the training step, common to both policy and critic. Each mini batch is split into micro batches of this size, and gradients are accumulated over them.
attr micro_forward_batch_size_per_gpu
micro_forward_batch_size_per_gpu: int = 1Micro batch size during the forward pass, i.e. log probability or value computation. Common to both policy and critic. Each mini batch is split into micro batches of this size.
attr max_tokens_per_microbatch
max_tokens_per_microbatch: int = -1Maximum number of tokens per microbatch for both forward and training steps. When > 0, microbatches are formed by bin-packing samples based on their token counts (from attention_mask) instead of using a fixed sample count, and micro_train_batch_size_per_gpu / micro_forward_batch_size_per_gpu are ignored. -1 means disabled (use sample-based micro_train_batch_size_per_gpu / micro_forward_batch_size_per_gpu). Applies to both forward and training micro-batching.
NOTE: this is a soft cap. Sequences are never split across microbatches, so a single sequence
longer than max_tokens_per_microbatch is placed alone in its own microbatch that exceeds the
cap (no error, no truncation). The true peak microbatch size is therefore
max(max_tokens_per_microbatch, longest_sequence_in_batch).
attr recompute_old_logprobs_per_minibatch
recompute_old_logprobs_per_minibatch: bool = TrueWhen True, recomputes policy/ref model logprobs (and critic values) per mini-batch using the same mini-batch + DP partition as the training step. When False, a single full-batch forward is run. This makes the microbatch packing — and therefore the resulting logprobs/values — identical to what forward_backward recomputes, so the PPO ratio (and critic value clipping) is exact at the first inner step.
attr update_ref_every_epoch
update_ref_every_epoch: bool = FalseRe-sync the reference model from the policy model at every epoch boundary.
attr remove_microbatch_padding
remove_microbatch_padding: bool = TruePack samples into the THD layout and strip intra-microbatch padding (requires flash attention). Common to all models.
attr eval_batch_size
eval_batch_size: int = 1024Batch size for evaluation.
attr eval_before_train
eval_before_train: bool = TrueEvaluate the model once before training starts.
attr eval_interval
eval_interval: int = 5Evaluate against the validation dataset every N steps. -1 to disable evaluation.
attr max_prompt_length
max_prompt_length: int = 512Maximum prompt length during training. Prompts longer than this are filtered out of the train/eval datasets at load time, not truncated.
attr flash_attn
flash_attn: bool = Trueattr disable_fast_tokenizer
disable_fast_tokenizer: bool = Falseattr project_name
project_name: str = 'skyrl'Project name in WandB and MLflow.
attr run_name
run_name: str = 'test_run'Run name in WandB and MLflow.
attr logger
logger: str = 'wandb'Logger to use: "wandb", "mlflow", "swanlab", "tensorboard", or "console".
See https://docs.skyrl.ai/docs/checkpointing-logging/logging
attr enable_ray_gpu_monitor
enable_ray_gpu_monitor: bool = TrueEnable background Ray GPU/RAM metrics collection and logging to wandb.
attr tags
tags: Optional[List[str]] = NoneOptional list of tags to apply to the W&B run. Has no effect on other backends.
attr dump_data_batch
dump_data_batch: bool = FalseDump each training data batch to a file for debugging.
The batch at global step N is written to
{export_path}/dumped_data/global_step_{N}_training_input.pkl.
attr dump_eval_results
dump_eval_results: bool = TrueDump full evaluation results to a file.
Results at global step N are written to {export_path}/dumped_evals/global_step_{N}_evals, with both per-dataset
and aggregated results when multiple validation datasets are configured.
attr print_example_interval
print_example_interval: int = 1Pretty-print an example prompt/response/reward to stdout every N
training steps; 0/-1 disables. Renamed from log_example_interval.
attr num_logger_eval_samples
num_logger_eval_samples: int = -1Number of evaluation trajectory (prompt, response, score) tuples to upload to a wandb
table on each eval. -1 (default) or 0 disables. When positive,
up to this many samples are taken from the start of each eval pass and
logged via :class:TrajectoryLogger. Column count is fixed
by the first call, so keep the eval set size and this value stable.
attr num_logger_train_samples
num_logger_train_samples: int = -1Number of training trajectory (prompt, response, score) tuples to upload to a wandb
table on each training step. -1 (default) or 0 disables. When positive,
up to this many samples are taken from the start of each training step and
logged via :class:TrajectoryLogger. Column count is fixed
by the first call, so keep the training set size and this value stable.
attr log_example_interval
log_example_interval: int = -1Log an example prompt every N training steps, 0/-1 to disable
attr logprobs_chunk_size
logprobs_chunk_size: Optional[int] = 1024Chunk size along the sequence dimension when computing log-probs from logits.
This lowers peak GPU memory at the cost of ~2x wall-clock time.
None disables chunking (Megatron backend only; FSDP requires a positive int).
See https://github.com/NovaSky-AI/SkyRL/pull/1610 for more details.
attr vocab_entropy_chunk_size
vocab_entropy_chunk_size: Optional[int] = 0Chunk size along the sequence dimension when computing Megatron vocab entropy.
0 auto-sizes from the local vocab shard size and vocab_entropy_chunk_memory_mb.
None disables chunking.
attr vocab_entropy_chunk_memory_mb
vocab_entropy_chunk_memory_mb: int = 512Approximate per-chunk temporary memory budget for auto-sized Megatron vocab entropy chunks.
attr fused_lm_head_logprob
fused_lm_head_logprob: bool = FalseMegatron only. Fuse the LM-head projection into log-prob / entropy
computation so the full [B, S, vocab//TP] logits tensor is never
materialized. Uses logprobs_chunk_size to bound peak memory.
attr fused_lm_head_logprob_backend
fused_lm_head_logprob_backend: str = 'torch'Fused LM-head backend: "torch" (default) or "triton".
The Triton backend requires CUDA + triton and falls back to "torch"
when unavailable. Ignored unless fused_lm_head_logprob is true.
class OptimizerConfig
OptimizerConfig(lr: float = 1e-06, adam_betas: List[float] = (lambda: [0.9, 0.999])(), weight_decay: float = 0.01, max_grad_norm: float = 1.0, offload_after_step: bool = True, num_warmup_steps: int = 0, scheduler: str = 'constant_with_warmup') -> NoneBases: BaseConfig
Optimizer configuration, shared by the policy and critic models.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
lr | float | Learning rate. |
adam_betas | List[float] | Betas for the AdamW optimizer. |
weight_decay | float | L2 regularization strength for AdamW. |
max_grad_norm | float | Gradient clipping. The total L2 norm of the model gradients is scaled to this value. |
offload_after_step | bool | Offload optimizer state to CPU after each full training step. |
num_warmup_steps | int | Number of mini-batch steps to warmup the optimizer. |
scheduler | str | Learning rate scheduler. Intended to align with transformers.SchedulerType: |
Source code in skyrl/train/config/config.py:186-208
@dataclass
class OptimizerConfig(BaseConfig):
"""Optimizer configuration, shared by the policy and critic models."""
lr: float = 1e-6
"""Learning rate."""
adam_betas: List[float] = field(default_factory=lambda: [0.9, 0.999])
"""Betas for the AdamW optimizer."""
weight_decay: float = 1e-2
"""L2 regularization strength for AdamW."""
max_grad_norm: float = 1.0
"""Gradient clipping. The total L2 norm of the model gradients is scaled to this value."""
offload_after_step: bool = True
"""Offload optimizer state to CPU after each full training step.
Applies under colocation (``colocate_all``, or ``colocate_policy_ref`` for policy/ref), and is
inert when ``fsdp_config.cpu_offload=True`` since FSDP2 then offloads natively. Without
colocation it can be preferable to leave optimizer state on GPU, avoiding both the offload cost
and the extra CPU memory usage."""
num_warmup_steps: int = 0
"""Number of mini-batch steps to warmup the optimizer."""
scheduler: str = "constant_with_warmup"
"""Learning rate scheduler. Intended to align with ``transformers.SchedulerType``:
https://huggingface.co/docs/transformers/main/en/main_classes/optimizer_schedules#transformers.SchedulerType"""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr lr
lr: float = 1e-06Learning rate.
attr adam_betas
adam_betas: List[float] = field(default_factory=(lambda: [0.9, 0.999]))Betas for the AdamW optimizer.
attr weight_decay
weight_decay: float = 0.01L2 regularization strength for AdamW.
attr max_grad_norm
max_grad_norm: float = 1.0Gradient clipping. The total L2 norm of the model gradients is scaled to this value.
attr offload_after_step
offload_after_step: bool = TrueOffload optimizer state to CPU after each full training step.
Applies under colocation (colocate_all, or colocate_policy_ref for policy/ref), and is
inert when fsdp_config.cpu_offload=True since FSDP2 then offloads natively. Without
colocation it can be preferable to leave optimizer state on GPU, avoiding both the offload cost
and the extra CPU memory usage.
attr num_warmup_steps
num_warmup_steps: int = 0Number of mini-batch steps to warmup the optimizer.
attr scheduler
scheduler: str = 'constant_with_warmup'Learning rate scheduler. Intended to align with transformers.SchedulerType:
https://huggingface.co/docs/transformers/main/en/main_classes/optimizer_schedules#transformers.SchedulerType
class MixedPrecisionConfig
MixedPrecisionConfig(param_dtype: str = 'bf16', reduce_dtype: str = 'fp32', buffer_dtype: str = 'fp32') -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
param_dtype | str | |
reduce_dtype | str | |
buffer_dtype | str |
Source code in skyrl/train/config/config.py:211-215
@dataclass
class MixedPrecisionConfig(BaseConfig):
param_dtype: str = "bf16"
reduce_dtype: str = "fp32"
buffer_dtype: str = "fp32"from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr param_dtype
param_dtype: str = 'bf16'attr reduce_dtype
reduce_dtype: str = 'fp32'attr buffer_dtype
buffer_dtype: str = 'fp32'class FakeInt4QatConfig
FakeInt4QatConfig(enabled: bool = False, group_size: int = 32, symmetric: bool = True, scale_divisor: float = 7.5, q_min: float = -8.0, bf16_base_path: Optional[str] = None) -> NoneBases: BaseConfig
Fake-INT4 quantization-aware training for MoE experts (Megatron only).
When the inference engine serves the MoE experts as real compressed-tensors
INT4 (e.g. casperhansen/Qwen3.6-35B-A3B-INT4-RTN) but the trainer holds
BF16 masters, enabling this fake-quantizes the frozen expert GEMMs onto the
same INT4 grid in the forward pass (straight-through backward), removing the
train/infer weight mismatch. See
skyrl.backends.skyrl_train.workers.megatron.fake_int4_qat.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
enabled | bool | |
group_size | int | Group size along the input dim; must match the served checkpoint (32). |
symmetric | bool | |
scale_divisor | float | Symmetric-INT4 scale divisor scale = amax / scale_divisor: |
q_min | float | Lower clamp of the INT4 code range: -8 for llm-compressor RTN |
bf16_base_path | Optional[str] | Megatron-Bridge cannot load a compressed-tensors INT4 checkpoint, so when |
Source code in skyrl/train/config/config.py:131-162
@dataclass
class FakeInt4QatConfig(BaseConfig):
"""Fake-INT4 quantization-aware training for MoE experts (Megatron only).
When the inference engine serves the MoE experts as real ``compressed-tensors``
INT4 (e.g. ``casperhansen/Qwen3.6-35B-A3B-INT4-RTN``) but the trainer holds
BF16 masters, enabling this fake-quantizes the frozen expert GEMMs onto the
same INT4 grid in the forward pass (straight-through backward), removing the
train/infer weight mismatch. See
``skyrl.backends.skyrl_train.workers.megatron.fake_int4_qat``.
"""
enabled: bool = False
group_size: int = 32
"""Group size along the input dim; must match the served checkpoint (32)."""
symmetric: bool = True
scale_divisor: float = 7.5
"""Symmetric-INT4 scale divisor ``scale = amax / scale_divisor``:
``7.5`` = llm-compressor / compressed-tensors RTN (``[-8, 7]``; matches
``casperhansen/Qwen3.6-35B-A3B-INT4-RTN``); ``7.0`` = Kimi K2-Thinking / K2.6 /
Miles (``[-7, 7]``). Set ``q_min`` consistently."""
q_min: float = -8.0
"""Lower clamp of the INT4 code range: ``-8`` for llm-compressor RTN
(``scale_divisor=7.5``), ``-7`` for Kimi/Miles (``scale_divisor=7.0``, whose
QAT never emits ``-8``)."""
bf16_base_path: Optional[str] = None
"""Megatron-Bridge cannot load a compressed-tensors INT4 checkpoint, so when
``model.path`` points at the INT4 model the trainer loads its BF16 master
weights from this path instead. The INT4 ``model.path`` remains what the
inference engine serves and the logical name. When None, the trainer loads
weights from ``model.path`` directly (only valid if that path is already a
BF16 checkpoint)."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr enabled
enabled: bool = Falseattr group_size
group_size: int = 32Group size along the input dim; must match the served checkpoint (32).
attr symmetric
symmetric: bool = Trueattr scale_divisor
scale_divisor: float = 7.5Symmetric-INT4 scale divisor scale = amax / scale_divisor:
7.5 = llm-compressor / compressed-tensors RTN ([-8, 7]; matches
casperhansen/Qwen3.6-35B-A3B-INT4-RTN); 7.0 = Kimi K2-Thinking / K2.6 /
Miles ([-7, 7]). Set q_min consistently.
attr q_min
q_min: float = -8.0Lower clamp of the INT4 code range: -8 for llm-compressor RTN
(scale_divisor=7.5), -7 for Kimi/Miles (scale_divisor=7.0, whose
QAT never emits -8).
attr bf16_base_path
bf16_base_path: Optional[str] = NoneMegatron-Bridge cannot load a compressed-tensors INT4 checkpoint, so when
model.path points at the INT4 model the trainer loads its BF16 master
weights from this path instead. The INT4 model.path remains what the
inference engine serves and the logical name. When None, the trainer loads
weights from model.path directly (only valid if that path is already a
BF16 checkpoint).
class MTPConfig
MTPConfig(enabled: bool = False, num_speculative_tokens: int = 1, loss_weight: float = 0.1) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
enabled | bool | Whether to train MTP draft heads and use them for speculative decoding. |
num_speculative_tokens | int | Draft depth vLLM speculates per step, independent of the trained head count. Single-head |
loss_weight | float | Weight w of the draft loss in policy_loss + w * draft_loss. |
Source code in skyrl/train/config/config.py:1312-1321
@dataclass
class MTPConfig(BaseConfig):
enabled: bool = False
"""Whether to train MTP draft heads and use them for speculative decoding."""
num_speculative_tokens: int = 1
"""Draft depth vLLM speculates per step, independent of the trained head count. Single-head
checkpoints (Qwen3.5/Qwen3-Next/DeepSeek-V3) reuse the one head autoregressively at depths > 1;
expect acceptance to decay with depth (the head is trained at depth 1)."""
loss_weight: float = 0.1
"""Weight ``w`` of the draft loss in ``policy_loss + w * draft_loss``."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr enabled
enabled: bool = FalseWhether to train MTP draft heads and use them for speculative decoding.
attr num_speculative_tokens
num_speculative_tokens: int = 1Draft depth vLLM speculates per step, independent of the trained head count. Single-head checkpoints (Qwen3.5/Qwen3-Next/DeepSeek-V3) reuse the one head autoregressively at depths > 1; expect acceptance to decay with depth (the head is trained at depth 1).
attr loss_weight
loss_weight: float = 0.1Weight w of the draft loss in policy_loss + w * draft_loss.
Backend Config
class FSDPConfig
FSDPConfig(cpu_offload: bool = False, reshard_after_forward: Union[bool, int] = True, fsdp_size: int = -1, mixed_precision: Optional[MixedPrecisionConfig] = None, wrap_policy: dict = dict()) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
cpu_offload | bool | Offload params and optimizer state to CPU during the forward pass. |
reshard_after_forward | Union[bool, int] | FSDP2 only. |
fsdp_size | int | Group size within which worker state is sharded, for hybrid sharding in multi-node runs. |
mixed_precision | Optional[MixedPrecisionConfig] | |
wrap_policy | dict |
Source code in skyrl/train/config/config.py:218-240
@dataclass
class FSDPConfig(BaseConfig):
cpu_offload: bool = False
"""Offload params and optimizer state to CPU during the forward pass.
Corresponds to FSDP2's ``offload_policy``:
https://docs.pytorch.org/docs/stable/distributed.fsdp.fully_shard.html
Enabling this replaces SkyRL's manual colocation offload (and makes
``optimizer_config.offload_after_step`` inert) rather than stacking with it; see
https://docs.skyrl.ai/docs/tutorials/placement for the difference."""
reshard_after_forward: Union[bool, int] = True
"""FSDP2 only.
Accepts True, False, or an int between 1 and ``fsdp_size``. See
https://docs.pytorch.org/docs/stable/distributed.fsdp.fully_shard.html. Setting False retains the full model
parameters on each worker (similar to DeepSpeed ZeRO stage 2)."""
fsdp_size: int = -1
"""Group size within which worker state is sharded, for hybrid sharding in multi-node runs.
``-1`` shards across all workers in the group. Example: with 8 workers across 2 nodes (4 each)
and ``fsdp_size=4``, training state is fully sharded across the 4 ranks within each node and
replicated (data-parallel) across nodes."""
mixed_precision: Optional[MixedPrecisionConfig] = None
# specify wrap policy as a dict with `transformer_layer_cls_to_wrap` key for custom module based wrapping
wrap_policy: dict = field(default_factory=dict)from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr cpu_offload
cpu_offload: bool = FalseOffload params and optimizer state to CPU during the forward pass.
Corresponds to FSDP2's offload_policy:
https://docs.pytorch.org/docs/stable/distributed.fsdp.fully_shard.html
Enabling this replaces SkyRL's manual colocation offload (and makes
optimizer_config.offload_after_step inert) rather than stacking with it; see
https://docs.skyrl.ai/docs/tutorials/placement for the difference.
attr reshard_after_forward
reshard_after_forward: Union[bool, int] = TrueFSDP2 only.
Accepts True, False, or an int between 1 and fsdp_size. See
https://docs.pytorch.org/docs/stable/distributed.fsdp.fully_shard.html. Setting False retains the full model
parameters on each worker (similar to DeepSpeed ZeRO stage 2).
attr fsdp_size
fsdp_size: int = -1Group size within which worker state is sharded, for hybrid sharding in multi-node runs.
-1 shards across all workers in the group. Example: with 8 workers across 2 nodes (4 each)
and fsdp_size=4, training state is fully sharded across the 4 ranks within each node and
replicated (data-parallel) across nodes.
attr mixed_precision
mixed_precision: Optional[MixedPrecisionConfig] = Noneattr wrap_policy
wrap_policy: dict = field(default_factory=dict)class MegatronConfig
MegatronConfig(tensor_model_parallel_size: int = 1, pipeline_model_parallel_size: int = 1, context_parallel_size: int = 1, expert_model_parallel_size: int = 1, expert_tensor_parallel_size: Optional[int] = None, moe_token_dispatcher_type: str = 'alltoall', moe_router_load_balancing_type: str = 'none', moe_aux_loss_coeff: float = 0.0, moe_grouped_gemm: bool = True, moe_router_score_function: Optional[str] = None, moe_router_enable_expert_bias: Optional[bool] = None, moe_enable_routing_replay: bool = False, moe_per_layer_logging: bool = False, moe_router_dtype: str = 'fp32', ddp_config: MegatronDDPConfig = MegatronDDPConfig(), hf_export_config: MegatronHFExportConfig = MegatronHFExportConfig(), lora_config: MegatronLoraConfig = MegatronLoraConfig(), optimizer_config_kwargs: Dict[str, Any] = (lambda: copy.deepcopy(DEFAULT_MEGATRON_OPTIMIZER_KWARGS))(), transformer_config_kwargs: Dict[str, Any] = (lambda: copy.deepcopy(DEFAULT_TRANSFORMER_CONFIG_KWARGS))(), empty_cuda_cache: Optional[bool] = True, model_config_kwargs: dict = dict(), dist_ckpt_optim_fully_reshardable: bool = False, freeze_moe_router: bool = False, mtp_num_layers: Optional[int] = None, mtp_loss_weight: float = 0.1, mtp_loss_chunk_size: Optional[int] = 1024, mtp_loss_topk: Optional[int] = None, async_dist_ckpt_save: bool = False, async_dist_ckpt_strategy: str = 'mcore', async_save_prestage_to_cpu: bool = False) -> NoneBases: BaseConfig
Megatron-Core backend configuration, used when trainer.strategy="megatron".
The parallelism sizes must satisfy:
model_size = pipeline_model_parallel_size * tensor_model_parallel_size * context_parallel_sizedp_size = world_size / model_sizeworld_size % (pipeline_model_parallel_size * expert_model_parallel_size * expert_tensor_parallel_size) == 0
The last rule means expert_model_parallel_size * expert_tensor_parallel_size can scale
independently of tensor_model_parallel_size * context_parallel_size, and can span data
parallel ranks. See https://docs.skyrl.ai/docs/examples/megatron for sizing guidance.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
tensor_model_parallel_size | int | Tensor model parallel size, reducing memory for model parameters and activations. |
pipeline_model_parallel_size | int | Pipeline model parallel size, sharding model layers across GPUs. |
context_parallel_size | int | Context parallel size, reducing activation memory along the sequence-length dimension. |
expert_model_parallel_size | int | Expert parallel size, sharding expert modules across GPUs. |
expert_tensor_parallel_size | Optional[int] | Tensor parallel size for each expert module. |
moe_token_dispatcher_type | str | |
moe_router_load_balancing_type | str | Set to "aux_loss", "seq_aux_loss", or "global_aux_loss" to enable aux loss-based load balancing and logging. |
moe_aux_loss_coeff | float | Scaling coefficient for the moe load balancing loss if moe_router_load_balancing_type is not 'none'. Will disable aux loss in megatron-core if set to 0. |
moe_grouped_gemm | bool | |
moe_router_score_function | Optional[str] | |
moe_router_enable_expert_bias | Optional[bool] | |
moe_enable_routing_replay | bool | Enable Megatron router replay. |
moe_per_layer_logging | bool | Enable per-layer logging of MoE metrics (i.e. per layer aux losses). |
moe_router_dtype | str | Pass through to Megatron-Bridge - can be set to 'fp64' for additional numerical stability. |
ddp_config | MegatronDDPConfig | Pass-through config for Megatron's DistributedDataParallelConfig: |
hf_export_config | MegatronHFExportConfig | |
lora_config | MegatronLoraConfig | |
optimizer_config_kwargs | Dict[str, Any] | Pass-through kwargs for Megatron's OptimizerConfig. |
transformer_config_kwargs | Dict[str, Any] | Pass-through kwargs for Megatron's TransformerConfig: |
empty_cuda_cache | Optional[bool] | Manually empty torch's CUDA cache between the forward/backward pass and the optimizer step. |
model_config_kwargs | dict | HF-config overrides read from the nested model_config key only. |
dist_ckpt_optim_fully_reshardable | bool | When True, use the "fully-reshardable" format for the distributed-optimizer checkpoint. |
freeze_moe_router | bool | If True, freeze MoE router parameters so they are not updated during training. No-op on |
mtp_num_layers | Optional[int] | Number of Multi-Token Prediction (MTP) heads to build. None honors the model's HF config |
mtp_loss_weight | float | Weight w of the draft loss in policy_loss + w * draft_loss. The draft loss is fully |
mtp_loss_chunk_size | Optional[int] | Sequence-chunk size for the draft loss, with gradient checkpointing, to bound peak memory at |
mtp_loss_topk | Optional[int] | If set, use a top-k approximation of the soft-CE draft loss: distill only the teacher's top-k |
async_dist_ckpt_save | bool | Write the torch_dist checkpoint from a background process so training resumes |
async_dist_ckpt_strategy | str | Backend for the async write. mcore needs no extra deps; megatron-core's own |
async_save_prestage_to_cpu | bool | Copy shards to host memory on the training rank before handing them to the async |
Source code in skyrl/train/config/config.py:434-570
@dataclass
class MegatronConfig(BaseConfig):
"""Megatron-Core backend configuration, used when ``trainer.strategy="megatron"``.
The parallelism sizes must satisfy:
- ``model_size = pipeline_model_parallel_size * tensor_model_parallel_size * context_parallel_size``
- ``dp_size = world_size / model_size``
- ``world_size % (pipeline_model_parallel_size * expert_model_parallel_size * expert_tensor_parallel_size) == 0``
The last rule means ``expert_model_parallel_size * expert_tensor_parallel_size`` can scale
independently of ``tensor_model_parallel_size * context_parallel_size``, and can span data
parallel ranks. See https://docs.skyrl.ai/docs/examples/megatron for sizing guidance.
"""
tensor_model_parallel_size: int = 1
"""Tensor model parallel size, reducing memory for model parameters and activations.
Megatron sequence parallelism (unrelated to Ulysses ``sequence_parallel_size``) is enabled automatically whenever
this is greater than 1."""
pipeline_model_parallel_size: int = 1
"""Pipeline model parallel size, sharding model layers across GPUs."""
context_parallel_size: int = 1
"""Context parallel size, reducing activation memory along the sequence-length dimension."""
expert_model_parallel_size: int = 1
"""Expert parallel size, sharding expert modules across GPUs."""
expert_tensor_parallel_size: Optional[int] = None
"""Tensor parallel size for each expert module.
``None`` lets Megatron resolve it to ``tensor_model_parallel_size``. Setting this to ``1`` is recommended for best
performance when ``expert_model_parallel_size > 1``."""
# MoE runtime configuration flags
moe_token_dispatcher_type: str = "alltoall"
moe_router_load_balancing_type: str = "none"
"""Set to "aux_loss", "seq_aux_loss", or "global_aux_loss" to enable aux loss-based load balancing and logging."""
moe_aux_loss_coeff: float = 0.0
"""Scaling coefficient for the moe load balancing loss if moe_router_load_balancing_type is not 'none'. Will disable aux loss in megatron-core if set to 0."""
moe_grouped_gemm: bool = True
moe_router_score_function: Optional[str] = None
moe_router_enable_expert_bias: Optional[bool] = None
moe_enable_routing_replay: bool = False
"""Enable Megatron router replay.
Used together with ``generator.inference_engine.enable_return_routed_experts`` to enable R3."""
moe_per_layer_logging: bool = False
"""Enable per-layer logging of MoE metrics (i.e. per layer aux losses)."""
moe_router_dtype: str = "fp32"
"""Pass through to Megatron-Bridge - can be set to 'fp64' for additional numerical stability."""
ddp_config: MegatronDDPConfig = field(default_factory=MegatronDDPConfig)
"""Pass-through config for Megatron's ``DistributedDataParallelConfig``:
https://github.com/NVIDIA/Megatron-LM/blob/core_r0.13.0/megatron/core/distributed/distributed_data_parallel_config.py"""
hf_export_config: MegatronHFExportConfig = field(default_factory=MegatronHFExportConfig)
lora_config: MegatronLoraConfig = field(default_factory=MegatronLoraConfig)
optimizer_config_kwargs: Dict[str, Any] = field(
default_factory=lambda: copy.deepcopy(DEFAULT_MEGATRON_OPTIMIZER_KWARGS)
)
"""Pass-through kwargs for Megatron's ``OptimizerConfig``.
https://github.com/NVIDIA/Megatron-LM/blob/core_r0.13.0/megatron/core/optimizer/optimizer_config.py
Any keys overlapping with what SkyRL resolves from ``optimizer_config`` are overridden by the
values here. ``*_dtype`` keys accept case-insensitive dtype names, coerced by
``distributed.megatron.optimizer_dtype``; see
https://docs.skyrl.ai/docs/examples/megatron for the accepted names and per-field checks.
``use_precision_aware_optimizer=True`` can cause checkpointing to fail
(https://github.com/nvidia/megatron-lm/issues/1820); leaving it ``False`` is recommended."""
transformer_config_kwargs: Dict[str, Any] = field(
default_factory=lambda: copy.deepcopy(DEFAULT_TRANSFORMER_CONFIG_KWARGS)
)
"""Pass-through kwargs for Megatron's ``TransformerConfig``:
https://github.com/NVIDIA/Megatron-LM/blob/core_r0.13.0/megatron/core/transformer/transformer_config.py
Also the place to put HuggingFace config overrides (e.g. ``rope_parameters``) for the Megatron
backend, where FSDP would use ``model_config_kwargs``."""
empty_cuda_cache: Optional[bool] = True
"""Manually empty torch's CUDA cache between the forward/backward pass and the optimizer step.
This frees reserved-but-unallocated memory and can help avoid OOMs in the optimizer."""
model_config_kwargs: dict = field(default_factory=dict)
"""HF-config overrides read from the nested ``model_config`` key only.
Used for bridge and RoPE resolution. Not a general HF-config override -- use
``transformer_config_kwargs`` instead."""
dist_ckpt_optim_fully_reshardable: bool = False
"""When True, use the "fully-reshardable" format for the distributed-optimizer checkpoint.
When False (default), use the "dp-reshardable" format, which is more efficient but only
supports resharding along the data-parallel dimension. See
https://github.com/NVIDIA/Megatron-LM/blob/core_v0.16.0/megatron/core/optimizer/distrib_optimizer.py"""
freeze_moe_router: bool = False
"""If True, freeze MoE router parameters so they are not updated during training. No-op on
non-MoE models."""
mtp_num_layers: Optional[int] = None
"""Number of Multi-Token Prediction (MTP) heads to build. ``None`` honors the model's HF config
(``num_nextn_predict_layers``); an int overrides it (``0`` force-disables MTP). Active heads are
trained with the decoupled draft loss and synced to vLLM for speculative decoding."""
mtp_loss_weight: float = 0.1
"""Weight ``w`` of the draft loss in ``policy_loss + w * draft_loss``. The draft loss is fully
decoupled: trunk, re-embedding, output weight and teacher are all detached, so its gradient
reaches only the ``.mtp.`` head params. Only used when MTP heads are active."""
mtp_loss_chunk_size: Optional[int] = 1024
"""Sequence-chunk size for the draft loss, with gradient checkpointing, to bound peak memory at
large vocab (e.g. Qwen3.5's 248K, where the full-sequence softmax OOMs). Numerically identical to
no chunking. ``None`` disables it; ignored when ``mtp_loss_topk`` is set."""
mtp_loss_topk: Optional[int] = None
"""If set, use a top-k approximation of the soft-CE draft loss: distill only the teacher's top-k
tokens (renormalized), ``O(seq*k)`` memory instead of ``O(seq*vocab)`` -- fits at large vocab
without fragmentation. Reconciled across the TP group, so it scales to any parallel size.
``None`` uses the exact full-vocab loss. Typical: 64-128."""
async_dist_ckpt_save: bool = False
"""Write the torch_dist checkpoint from a background process so training resumes
immediately; the pending write is finalized at the next checkpoint and at shutdown.
The on-disk format is identical to a synchronous save. Only the sharded
model/optimizer state is async -- the rank-0 HF config/tokenizer write stays inline.
Falls back to synchronous for cloud paths."""
async_dist_ckpt_strategy: str = "mcore"
"""Backend for the async write. ``mcore`` needs no extra deps; megatron-core's own
default ``nvrx`` requires nvidia-resiliency-ext. Only used when async saves are on."""
async_save_prestage_to_cpu: bool = False
"""Copy shards to host memory on the training rank before handing them to the async
checkpoint writer, instead of letting the writer pull them over CUDA IPC.
Enable this when using async save on machines with restricted ptrace permissions.
megatron-core hands the writer the *GPU* tensors and copies them in the writer process;
with ``expandable_segments:True`` those handles are file descriptors that the writer
imports via ``pidfd_getfd``, which needs ptrace-attach permission on the rank.
Where that is refused (e.g. ``kernel.yama.ptrace_scope=1``, as on some CI runners)
the writer dies with ``pidfd_getfd: Operation not permitted`` and every rank then
hangs on the preload barrier.
Off by default: prestaging shrinks the rank's blocking
window but delays the background write (per-tensor shared-memory handoff cost).
See ``_stage_async_request_to_host``."""
def __post_init__(self):
# Backfill defaults for any keys the user didn't override so an override dict
# doesn't have to repeat every default just to set one value.
if self.transformer_config_kwargs is None:
self.transformer_config_kwargs = {}
for k, v in DEFAULT_TRANSFORMER_CONFIG_KWARGS.items():
self.transformer_config_kwargs.setdefault(k, copy.deepcopy(v))
if self.optimizer_config_kwargs is None:
self.optimizer_config_kwargs = {}
for k, v in DEFAULT_MEGATRON_OPTIMIZER_KWARGS.items():
self.optimizer_config_kwargs.setdefault(k, copy.deepcopy(v))from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr tensor_model_parallel_size
tensor_model_parallel_size: int = 1Tensor model parallel size, reducing memory for model parameters and activations.
Megatron sequence parallelism (unrelated to Ulysses sequence_parallel_size) is enabled automatically whenever
this is greater than 1.
attr pipeline_model_parallel_size
pipeline_model_parallel_size: int = 1Pipeline model parallel size, sharding model layers across GPUs.
attr context_parallel_size
context_parallel_size: int = 1Context parallel size, reducing activation memory along the sequence-length dimension.
attr expert_model_parallel_size
expert_model_parallel_size: int = 1Expert parallel size, sharding expert modules across GPUs.
attr expert_tensor_parallel_size
expert_tensor_parallel_size: Optional[int] = NoneTensor parallel size for each expert module.
None lets Megatron resolve it to tensor_model_parallel_size. Setting this to 1 is recommended for best
performance when expert_model_parallel_size > 1.
attr moe_token_dispatcher_type
moe_token_dispatcher_type: str = 'alltoall'attr moe_router_load_balancing_type
moe_router_load_balancing_type: str = 'none'Set to "aux_loss", "seq_aux_loss", or "global_aux_loss" to enable aux loss-based load balancing and logging.
attr moe_aux_loss_coeff
moe_aux_loss_coeff: float = 0.0Scaling coefficient for the moe load balancing loss if moe_router_load_balancing_type is not 'none'. Will disable aux loss in megatron-core if set to 0.
attr moe_grouped_gemm
moe_grouped_gemm: bool = Trueattr moe_router_score_function
moe_router_score_function: Optional[str] = Noneattr moe_router_enable_expert_bias
moe_router_enable_expert_bias: Optional[bool] = Noneattr moe_enable_routing_replay
moe_enable_routing_replay: bool = FalseEnable Megatron router replay.
Used together with generator.inference_engine.enable_return_routed_experts to enable R3.
attr moe_per_layer_logging
moe_per_layer_logging: bool = FalseEnable per-layer logging of MoE metrics (i.e. per layer aux losses).
attr moe_router_dtype
moe_router_dtype: str = 'fp32'Pass through to Megatron-Bridge - can be set to 'fp64' for additional numerical stability.
attr ddp_config
ddp_config: MegatronDDPConfig = field(default_factory=MegatronDDPConfig)Pass-through config for Megatron's DistributedDataParallelConfig:
https://github.com/NVIDIA/Megatron-LM/blob/core_r0.13.0/megatron/core/distributed/distributed_data_parallel_config.py
attr hf_export_config
hf_export_config: MegatronHFExportConfig = field(default_factory=MegatronHFExportConfig)attr lora_config
lora_config: MegatronLoraConfig = field(default_factory=MegatronLoraConfig)attr optimizer_config_kwargs
optimizer_config_kwargs: Dict[str, Any] = field(default_factory=(lambda: copy.deepcopy(DEFAULT_MEGATRON_OPTIMIZER_KWARGS)))Pass-through kwargs for Megatron's OptimizerConfig.
https://github.com/NVIDIA/Megatron-LM/blob/core_r0.13.0/megatron/core/optimizer/optimizer_config.py
Any keys overlapping with what SkyRL resolves from optimizer_config are overridden by the
values here. *_dtype keys accept case-insensitive dtype names, coerced by
distributed.megatron.optimizer_dtype; see
https://docs.skyrl.ai/docs/examples/megatron for the accepted names and per-field checks.
use_precision_aware_optimizer=True can cause checkpointing to fail
(https://github.com/nvidia/megatron-lm/issues/1820); leaving it False is recommended.
attr transformer_config_kwargs
transformer_config_kwargs: Dict[str, Any] = field(default_factory=(lambda: copy.deepcopy(DEFAULT_TRANSFORMER_CONFIG_KWARGS)))Pass-through kwargs for Megatron's TransformerConfig:
https://github.com/NVIDIA/Megatron-LM/blob/core_r0.13.0/megatron/core/transformer/transformer_config.py
Also the place to put HuggingFace config overrides (e.g. rope_parameters) for the Megatron
backend, where FSDP would use model_config_kwargs.
attr empty_cuda_cache
empty_cuda_cache: Optional[bool] = TrueManually empty torch's CUDA cache between the forward/backward pass and the optimizer step. This frees reserved-but-unallocated memory and can help avoid OOMs in the optimizer.
attr model_config_kwargs
model_config_kwargs: dict = field(default_factory=dict)HF-config overrides read from the nested model_config key only.
Used for bridge and RoPE resolution. Not a general HF-config override -- use
transformer_config_kwargs instead.
attr dist_ckpt_optim_fully_reshardable
dist_ckpt_optim_fully_reshardable: bool = FalseWhen True, use the "fully-reshardable" format for the distributed-optimizer checkpoint. When False (default), use the "dp-reshardable" format, which is more efficient but only supports resharding along the data-parallel dimension. See https://github.com/NVIDIA/Megatron-LM/blob/core_v0.16.0/megatron/core/optimizer/distrib_optimizer.py
attr freeze_moe_router
freeze_moe_router: bool = FalseIf True, freeze MoE router parameters so they are not updated during training. No-op on non-MoE models.
attr mtp_num_layers
mtp_num_layers: Optional[int] = NoneNumber of Multi-Token Prediction (MTP) heads to build. None honors the model's HF config
(num_nextn_predict_layers); an int overrides it (0 force-disables MTP). Active heads are
trained with the decoupled draft loss and synced to vLLM for speculative decoding.
attr mtp_loss_weight
mtp_loss_weight: float = 0.1Weight w of the draft loss in policy_loss + w * draft_loss. The draft loss is fully
decoupled: trunk, re-embedding, output weight and teacher are all detached, so its gradient
reaches only the .mtp. head params. Only used when MTP heads are active.
attr mtp_loss_chunk_size
mtp_loss_chunk_size: Optional[int] = 1024Sequence-chunk size for the draft loss, with gradient checkpointing, to bound peak memory at
large vocab (e.g. Qwen3.5's 248K, where the full-sequence softmax OOMs). Numerically identical to
no chunking. None disables it; ignored when mtp_loss_topk is set.
attr mtp_loss_topk
mtp_loss_topk: Optional[int] = NoneIf set, use a top-k approximation of the soft-CE draft loss: distill only the teacher's top-k
tokens (renormalized), O(seq*k) memory instead of O(seq*vocab) -- fits at large vocab
without fragmentation. Reconciled across the TP group, so it scales to any parallel size.
None uses the exact full-vocab loss. Typical: 64-128.
attr async_dist_ckpt_save
async_dist_ckpt_save: bool = FalseWrite the torch_dist checkpoint from a background process so training resumes immediately; the pending write is finalized at the next checkpoint and at shutdown. The on-disk format is identical to a synchronous save. Only the sharded model/optimizer state is async -- the rank-0 HF config/tokenizer write stays inline. Falls back to synchronous for cloud paths.
attr async_dist_ckpt_strategy
async_dist_ckpt_strategy: str = 'mcore'Backend for the async write. mcore needs no extra deps; megatron-core's own
default nvrx requires nvidia-resiliency-ext. Only used when async saves are on.
attr async_save_prestage_to_cpu
async_save_prestage_to_cpu: bool = FalseCopy shards to host memory on the training rank before handing them to the async checkpoint writer, instead of letting the writer pull them over CUDA IPC.
Enable this when using async save on machines with restricted ptrace permissions.
megatron-core hands the writer the GPU tensors and copies them in the writer process;
with expandable_segments:True those handles are file descriptors that the writer
imports via pidfd_getfd, which needs ptrace-attach permission on the rank.
Where that is refused (e.g. kernel.yama.ptrace_scope=1, as on some CI runners)
the writer dies with pidfd_getfd: Operation not permitted and every rank then
hangs on the preload barrier.
Off by default: prestaging shrinks the rank's blocking
window but delays the background write (per-tensor shared-memory handoff cost).
See _stage_async_request_to_host.
class MegatronDDPConfig
MegatronDDPConfig(grad_reduce_in_fp32: bool = True, overlap_grad_reduce: bool = False, overlap_param_gather: bool = False, average_in_collective: bool = True) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
grad_reduce_in_fp32 | bool | |
overlap_grad_reduce | bool | |
overlap_param_gather | bool | |
average_in_collective | bool |
Source code in skyrl/train/config/config.py:248-253
@dataclass
class MegatronDDPConfig(BaseConfig):
grad_reduce_in_fp32: bool = True
overlap_grad_reduce: bool = False
overlap_param_gather: bool = False
average_in_collective: bool = Truefrom_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr grad_reduce_in_fp32
grad_reduce_in_fp32: bool = Trueattr overlap_grad_reduce
overlap_grad_reduce: bool = Falseattr overlap_param_gather
overlap_param_gather: bool = Falseattr average_in_collective
average_in_collective: bool = Trueclass MegatronLoraConfig
MegatronLoraConfig(lora_type: str = 'lora', merge_lora: bool = True) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
lora_type | str | "lora" or "canonical_lora". |
merge_lora | bool | Merge LoRA weights into the base weights during weight sync. |
Source code in skyrl/train/config/config.py:409-415
@dataclass
class MegatronLoraConfig(BaseConfig):
lora_type: str = "lora"
"""``"lora"`` or ``"canonical_lora"``.
See https://docs.nvidia.com/nemo/megatron-bridge/0.2.0/apidocs/bridge/bridge.peft.lora.html"""
merge_lora: bool = True
"""Merge LoRA weights into the base weights during weight sync."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr lora_type
lora_type: str = 'lora'"lora" or "canonical_lora".
See https://docs.nvidia.com/nemo/megatron-bridge/0.2.0/apidocs/bridge/bridge.peft.lora.html
attr merge_lora
merge_lora: bool = TrueMerge LoRA weights into the base weights during weight sync.
class MegatronHFExportConfig
MegatronHFExportConfig(distributed_save: bool = False, save_every_n_ranks: int = 1) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
distributed_save | bool | Fan the Megatron->HF safetensors export across ranks instead of writing it all from rank 0. |
save_every_n_ranks | int | In distributed save, only ranks 0, N, 2N, ... write shards (e.g. 8 = one writer per 8-GPU node). |
Source code in skyrl/train/config/config.py:389-406
@dataclass
class MegatronHFExportConfig(BaseConfig):
distributed_save: bool = False
"""Fan the Megatron->HF safetensors export across ranks instead of writing it all from rank 0.
The on-disk result is the standard HF sharded format either way; this only parallelizes the
write. Only affects HF exports from ``hf_save_interval`` or explicit ``save_hf_model`` calls.
Sharded multi-node exports require ``trainer.export_path`` to be a shared filesystem path
visible to every rank; see https://docs.skyrl.ai/docs/checkpointing-logging/checkpointing."""
save_every_n_ranks: int = 1
"""In distributed save, only ranks 0, N, 2N, ... write shards (e.g. 8 = one writer per 8-GPU node).
Must be at least 1. Ignored when ``distributed_save`` is False."""
def __post_init__(self) -> None:
# save_every_n_ranks indexes ranks via modulo/floor-div in the bridge's
# distributed save; < 1 raises ZeroDivisionError there. Fail fast instead.
if self.save_every_n_ranks < 1:
raise ValueError(f"save_every_n_ranks must be >= 1, got {self.save_every_n_ranks}")from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr distributed_save
distributed_save: bool = FalseFan the Megatron->HF safetensors export across ranks instead of writing it all from rank 0.
The on-disk result is the standard HF sharded format either way; this only parallelizes the
write. Only affects HF exports from hf_save_interval or explicit save_hf_model calls.
Sharded multi-node exports require trainer.export_path to be a shared filesystem path
visible to every rank; see https://docs.skyrl.ai/docs/checkpointing-logging/checkpointing.
attr save_every_n_ranks
save_every_n_ranks: int = 1In distributed save, only ranks 0, N, 2N, ... write shards (e.g. 8 = one writer per 8-GPU node).
Must be at least 1. Ignored when distributed_save is False.
class TorchProfilerConfig
TorchProfilerConfig(enable: bool = False, ranks: List[int] = (lambda: [0])(), save_path: Optional[str] = None, skip_first: int = 10, wait: int = 0, warmup: int = 1, active: int = 1, repeat: int = 1, activities: List[str] = (lambda: ['cpu', 'cuda'])(), record_shapes: bool = True, profile_memory: bool = False, with_stack: bool = True, with_flops: bool = False, with_modules: bool = False, export_type: str = 'chrome_trace') -> NoneBases: BaseConfig
torch.profiler config for policy training steps.
Applies to FSDP and Megatron in both RL and SFT. With the default export_type="chrome_trace",
writes one Kineto/HTA-friendly *.pt.trace.json per active window and profiled rank
(https://github.com/facebookresearch/HolisticTraceAnalysis); with export_type="stacks" it
instead writes a per-rank rank{N}_stacks.txt that later windows overwrite.
Scope: policy workers only. Active windows capture policy-worker operations between profiler steps — in RL that includes policy log-prob forwards and policy training; in SFT it includes training and may include eval forwards. Critic/ref workers, the controller, and the generation/inference engines are not profiled.
FSDP restriction: profiling is rejected under colocation without CPU offloading (i.e.
policy.fsdp_config.cpu_offload=False together with placement.colocate_all or
placement.colocate_policy_ref), because that path offloads via torch.utils.swap_tensors
while the profiler holds references to the parameters. See validate.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
validate | Fail fast on invalid or known-incompatible profiler settings. |
Attributes:
| Name | Type | Description |
|---|---|---|
enable | bool | Enable profiling. |
ranks | List[int] | Global ranks to profile, e.g. [0]. |
save_path | Optional[str] | Trace output dir. |
skip_first | int | Steps to skip before scheduling begins. Passed to torch.profiler.schedule: |
wait | int | Steps to wait before warmup in each cycle. Passed to torch.profiler.schedule. |
warmup | int | Warmup steps per cycle. Passed to torch.profiler.schedule. |
active | int | Number of steps recorded per cycle. |
repeat | int | Number of cycles. 0 means forever. |
activities | List[str] | Subset of ["cpu", "cuda"]. |
record_shapes | bool | Passed to torch.profiler.profile. |
profile_memory | bool | Passed to torch.profiler.profile. |
with_stack | bool | Passed to torch.profiler.profile. Required when export_type="stacks". |
with_flops | bool | Passed to torch.profiler.profile. |
with_modules | bool | Passed to torch.profiler.profile. |
export_type | str | Either chrome_trace or stacks. |
Source code in skyrl/train/config/config.py:260-386
@dataclass
class TorchProfilerConfig(BaseConfig):
"""``torch.profiler`` config for policy training steps.
Applies to FSDP and Megatron in both RL and SFT. With the default ``export_type="chrome_trace"``,
writes one Kineto/HTA-friendly ``*.pt.trace.json`` per active window and profiled rank
(https://github.com/facebookresearch/HolisticTraceAnalysis); with ``export_type="stacks"`` it
instead writes a per-rank ``rank{N}_stacks.txt`` that later windows overwrite.
Scope: policy workers only. Active windows capture policy-worker operations between profiler
steps — in RL that includes policy log-prob forwards and policy training; in SFT it includes
training and may include eval forwards. Critic/ref workers, the controller, and the
generation/inference engines are not profiled.
FSDP restriction: profiling is rejected under colocation without CPU offloading (i.e.
``policy.fsdp_config.cpu_offload=False`` together with ``placement.colocate_all`` or
``placement.colocate_policy_ref``), because that path offloads via ``torch.utils.swap_tensors``
while the profiler holds references to the parameters. See ``validate``.
"""
enable: bool = False
"""Enable profiling."""
ranks: List[int] = field(default_factory=lambda: [0])
"""Global ranks to profile, e.g. ``[0]``."""
save_path: Optional[str] = None
"""Trace output dir.
Required when ``enable=True``; must be a local absolute path. Relative paths would land under Ray's
``/tmp/ray/.../working_dir_files``, and cloud URIs are rejected."""
# torch.profiler.schedule
skip_first: int = 10
"""Steps to skip before scheduling begins. Passed to ``torch.profiler.schedule``:
https://docs.pytorch.org/docs/stable/profiler.html#torch.profiler.schedule"""
wait: int = 0
"""Steps to wait before warmup in each cycle. Passed to ``torch.profiler.schedule``."""
warmup: int = 1
"""Warmup steps per cycle. Passed to ``torch.profiler.schedule``."""
active: int = 1
"""Number of steps recorded per cycle."""
repeat: int = 1
"""Number of cycles. 0 means forever."""
# torch.profiler.profile
activities: List[str] = field(default_factory=lambda: ["cpu", "cuda"])
"""Subset of ``["cpu", "cuda"]``."""
record_shapes: bool = True
"""Passed to ``torch.profiler.profile``."""
profile_memory: bool = False
"""Passed to ``torch.profiler.profile``."""
with_stack: bool = True
"""Passed to ``torch.profiler.profile``. Required when ``export_type="stacks"``."""
with_flops: bool = False
"""Passed to ``torch.profiler.profile``."""
with_modules: bool = False
"""Passed to ``torch.profiler.profile``."""
export_type: str = "chrome_trace"
"""Either ``chrome_trace`` or ``stacks``.
``chrome_trace`` writes ``*.pt.trace.json``; ``stacks`` writes self-CUDA-time stacks and
requires ``with_stack=True``."""
def validate(
self,
strategy: Optional[str] = None,
colocate_all: Optional[bool] = None,
colocate_policy_ref: Optional[bool] = None,
fsdp_cpu_offload: Optional[bool] = None,
) -> None:
"""Fail fast on invalid or known-incompatible profiler settings."""
if not self.enable:
return
if not self.ranks:
raise ValueError("`torch_profiler_config.ranks` must be non-empty when profiling is enabled.")
# Avoid implicit relative paths in Ray runtime working dirs.
if not self.save_path:
raise ValueError(
"`torch_profiler_config.save_path` must be set when profiling is enabled. "
"Use an absolute local path -- Ray workers run from a /tmp/ray runtime "
"working dir, so a relative path would write traces there."
)
from skyrl.backends.skyrl_train.utils.io.io import is_cloud_path
if is_cloud_path(self.save_path):
raise ValueError(
f"`torch_profiler_config.save_path` must be a local path; got cloud URI "
f"{self.save_path!r}. torch.profiler cannot write to cloud storage."
)
# Empty activities record nothing.
if not self.activities:
raise ValueError("`torch_profiler_config.activities` must be non-empty when profiling is enabled.")
bad_activities = [a for a in self.activities if a.lower() not in TORCH_PROFILER_ACTIVITIES]
if bad_activities:
raise ValueError(
f"invalid `torch_profiler_config.activities` entries {bad_activities}. "
f"Each must be one of {list(TORCH_PROFILER_ACTIVITIES)}."
)
if self.export_type not in TORCH_PROFILER_EXPORT_TYPES:
raise ValueError(
f"invalid `torch_profiler_config.export_type`: {self.export_type!r}. "
f"Must be one of {list(TORCH_PROFILER_EXPORT_TYPES)}."
)
if self.export_type == "stacks" and not self.with_stack:
raise ValueError(
"`torch_profiler_config.export_type='stacks'` requires `with_stack=true` "
"(torch.profiler.export_stacks needs stack records)."
)
for name in ("skip_first", "wait", "warmup", "repeat"):
value = getattr(self, name)
if value < 0:
raise ValueError(f"`torch_profiler_config.{name}` must be >= 0, got {value}.")
if self.active < 1:
raise ValueError(f"`torch_profiler_config.active` must be >= 1, got {self.active}.")
# FSDP manual CPU offload uses swap_tensors, which conflicts with profiler-held
# parameter refs during colocated runs.
if strategy == "fsdp" and fsdp_cpu_offload is False and (colocate_all or colocate_policy_ref):
raise ValueError(
"`torch_profiler_config.enable=true` is incompatible with this FSDP configuration: "
"with the manual CPU-offload path (`policy.fsdp_config.cpu_offload=false`, the default) "
"under colocation "
f"(`placement.colocate_all={colocate_all}`, `placement.colocate_policy_ref={colocate_policy_ref}`), "
"the trainer offloads models to CPU via `torch.utils.swap_tensors` while the profiler holds "
"references to their parameters, which crashes mid-run with "
"`RuntimeError: _apply(): Couldn't swap <param>`. "
"To profile: set `policy.fsdp_config.cpu_offload=true` (FSDP2-native offload, no swap), or "
"disable colocation (`placement.colocate_all=false` and `placement.colocate_policy_ref=false`), "
"or use the Megatron backend (`trainer.strategy=megatron`)."
)from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr enable
enable: bool = FalseEnable profiling.
attr ranks
ranks: List[int] = field(default_factory=(lambda: [0]))Global ranks to profile, e.g. [0].
attr save_path
save_path: Optional[str] = NoneTrace output dir.
Required when enable=True; must be a local absolute path. Relative paths would land under Ray's
/tmp/ray/.../working_dir_files, and cloud URIs are rejected.
attr skip_first
skip_first: int = 10Steps to skip before scheduling begins. Passed to torch.profiler.schedule:
https://docs.pytorch.org/docs/stable/profiler.html#torch.profiler.schedule
attr wait
wait: int = 0Steps to wait before warmup in each cycle. Passed to torch.profiler.schedule.
attr warmup
warmup: int = 1Warmup steps per cycle. Passed to torch.profiler.schedule.
attr active
active: int = 1Number of steps recorded per cycle.
attr repeat
repeat: int = 1Number of cycles. 0 means forever.
attr activities
activities: List[str] = field(default_factory=(lambda: ['cpu', 'cuda']))Subset of ["cpu", "cuda"].
attr record_shapes
record_shapes: bool = TruePassed to torch.profiler.profile.
attr profile_memory
profile_memory: bool = FalsePassed to torch.profiler.profile.
attr with_stack
with_stack: bool = TruePassed to torch.profiler.profile. Required when export_type="stacks".
attr with_flops
with_flops: bool = FalsePassed to torch.profiler.profile.
attr with_modules
with_modules: bool = FalsePassed to torch.profiler.profile.
attr export_type
export_type: str = 'chrome_trace'Either chrome_trace or stacks.
chrome_trace writes *.pt.trace.json; stacks writes self-CUDA-time stacks and
requires with_stack=True.
method validate
validate(strategy: Optional[str] = None, colocate_all: Optional[bool] = None, colocate_policy_ref: Optional[bool] = None, fsdp_cpu_offload: Optional[bool] = None) -> NoneFail fast on invalid or known-incompatible profiler settings.
Source code in skyrl/train/config/config.py:320-386
def validate(
self,
strategy: Optional[str] = None,
colocate_all: Optional[bool] = None,
colocate_policy_ref: Optional[bool] = None,
fsdp_cpu_offload: Optional[bool] = None,
) -> None:
"""Fail fast on invalid or known-incompatible profiler settings."""
if not self.enable:
return
if not self.ranks:
raise ValueError("`torch_profiler_config.ranks` must be non-empty when profiling is enabled.")
# Avoid implicit relative paths in Ray runtime working dirs.
if not self.save_path:
raise ValueError(
"`torch_profiler_config.save_path` must be set when profiling is enabled. "
"Use an absolute local path -- Ray workers run from a /tmp/ray runtime "
"working dir, so a relative path would write traces there."
)
from skyrl.backends.skyrl_train.utils.io.io import is_cloud_path
if is_cloud_path(self.save_path):
raise ValueError(
f"`torch_profiler_config.save_path` must be a local path; got cloud URI "
f"{self.save_path!r}. torch.profiler cannot write to cloud storage."
)
# Empty activities record nothing.
if not self.activities:
raise ValueError("`torch_profiler_config.activities` must be non-empty when profiling is enabled.")
bad_activities = [a for a in self.activities if a.lower() not in TORCH_PROFILER_ACTIVITIES]
if bad_activities:
raise ValueError(
f"invalid `torch_profiler_config.activities` entries {bad_activities}. "
f"Each must be one of {list(TORCH_PROFILER_ACTIVITIES)}."
)
if self.export_type not in TORCH_PROFILER_EXPORT_TYPES:
raise ValueError(
f"invalid `torch_profiler_config.export_type`: {self.export_type!r}. "
f"Must be one of {list(TORCH_PROFILER_EXPORT_TYPES)}."
)
if self.export_type == "stacks" and not self.with_stack:
raise ValueError(
"`torch_profiler_config.export_type='stacks'` requires `with_stack=true` "
"(torch.profiler.export_stacks needs stack records)."
)
for name in ("skip_first", "wait", "warmup", "repeat"):
value = getattr(self, name)
if value < 0:
raise ValueError(f"`torch_profiler_config.{name}` must be >= 0, got {value}.")
if self.active < 1:
raise ValueError(f"`torch_profiler_config.active` must be >= 1, got {self.active}.")
# FSDP manual CPU offload uses swap_tensors, which conflicts with profiler-held
# parameter refs during colocated runs.
if strategy == "fsdp" and fsdp_cpu_offload is False and (colocate_all or colocate_policy_ref):
raise ValueError(
"`torch_profiler_config.enable=true` is incompatible with this FSDP configuration: "
"with the manual CPU-offload path (`policy.fsdp_config.cpu_offload=false`, the default) "
"under colocation "
f"(`placement.colocate_all={colocate_all}`, `placement.colocate_policy_ref={colocate_policy_ref}`), "
"the trainer offloads models to CPU via `torch.utils.swap_tensors` while the profiler holds "
"references to their parameters, which crashes mid-run with "
"`RuntimeError: _apply(): Couldn't swap <param>`. "
"To profile: set `policy.fsdp_config.cpu_offload=true` (FSDP2-native offload, no swap), or "
"disable colocation (`placement.colocate_all=false` and `placement.colocate_policy_ref=false`), "
"or use the Megatron backend (`trainer.strategy=megatron`)."
)Placement
class PlacementConfig
PlacementConfig(colocate_all: bool = True, colocate_policy_ref: bool = True, policy_num_nodes: int = 1, policy_num_gpus_per_node: int = 1, critic_num_nodes: int = 1, critic_num_gpus_per_node: int = 1, ref_num_nodes: int = 1, ref_num_gpus_per_node: int = 1) -> NoneBases: BaseConfig
GPU placement and colocation for the policy, critic, ref, and inference engines.
See the model placement and colocation guide for an in-depth walkthrough of how the options here interact: https://docs.skyrl.ai/docs/tutorials/placement
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
colocate_all | bool | When True, training and inference share the same GPUs. |
colocate_policy_ref | bool | When colocate_all is False, True (default) still colocates policy and ref |
policy_num_nodes | int | |
policy_num_gpus_per_node | int | |
critic_num_nodes | int | |
critic_num_gpus_per_node | int | |
ref_num_nodes | int | |
ref_num_gpus_per_node | int |
Source code in skyrl/train/config/config.py:578-598
@dataclass
class PlacementConfig(BaseConfig):
"""GPU placement and colocation for the policy, critic, ref, and inference engines.
See the model placement and colocation guide for an in-depth walkthrough of how the
options here interact: https://docs.skyrl.ai/docs/tutorials/placement
"""
colocate_all: bool = True
"""When True, training and inference share the same GPUs."""
colocate_policy_ref: bool = True
"""When colocate_all is False, True (default) still colocates policy and ref
on the same GPUs (one shared placement group). Set this item to False to place
policy and ref on separate GPUs (their own placement groups); needed when
a large model's policy and ref shards can't both fit on one GPU."""
policy_num_nodes: int = 1
policy_num_gpus_per_node: int = 1
critic_num_nodes: int = 1
critic_num_gpus_per_node: int = 1
ref_num_nodes: int = 1
ref_num_gpus_per_node: int = 1from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr colocate_all
colocate_all: bool = TrueWhen True, training and inference share the same GPUs.
attr colocate_policy_ref
colocate_policy_ref: bool = TrueWhen colocate_all is False, True (default) still colocates policy and ref on the same GPUs (one shared placement group). Set this item to False to place policy and ref on separate GPUs (their own placement groups); needed when a large model's policy and ref shards can't both fit on one GPU.
attr policy_num_nodes
policy_num_nodes: int = 1attr policy_num_gpus_per_node
policy_num_gpus_per_node: int = 1attr critic_num_nodes
critic_num_nodes: int = 1attr critic_num_gpus_per_node
critic_num_gpus_per_node: int = 1attr ref_num_nodes
ref_num_nodes: int = 1attr ref_num_gpus_per_node
ref_num_gpus_per_node: int = 1Policy & Algorithm
class PolicyConfig
PolicyConfig(model: ModelConfig = (lambda: copy.deepcopy(ModelConfig(path='Qwen/Qwen2.5-1.5B-Instruct')))(), optimizer_config: OptimizerConfig = OptimizerConfig(), fsdp_config: FSDPConfig = FSDPConfig(), sequence_parallel_size: int = 1, use_torch_compile: bool = False, record_memory: bool = False, torch_profiler_config: TorchProfilerConfig = TorchProfilerConfig(), megatron_config: MegatronConfig = MegatronConfig(), model_config_kwargs: dict = dict(), language_model_only: bool = False, inference_only_init: bool = False) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
model | ModelConfig | |
optimizer_config | OptimizerConfig | Optimizer configuration for the policy model. |
fsdp_config | FSDPConfig | FSDP configuration, applicable when trainer.strategy="fsdp". |
sequence_parallel_size | int | Ulysses sequence parallel size (https://arxiv.org/abs/2309.14509). |
use_torch_compile | bool | Apply torch.compile to logits calculation. |
record_memory | bool | Save memory snapshots to {ckpt_path}/memory_snapshots/. |
torch_profiler_config | TorchProfilerConfig | torch.profiler config for policy training steps. |
megatron_config | MegatronConfig | |
model_config_kwargs | dict | Pass-through kwargs for the HuggingFace model config (FSDP backends). |
language_model_only | bool | When True, skip vision encoder initialization for multimodal models (e.g. Qwen3.5). |
inference_only_init | bool | When True, set up the policy worker for inference-only flows (forward + weight |
Source code in skyrl/train/config/config.py:606-638
@dataclass
class PolicyConfig(BaseConfig):
model: ModelConfig = field(default_factory=lambda: copy.deepcopy(ModelConfig(path="Qwen/Qwen2.5-1.5B-Instruct")))
optimizer_config: OptimizerConfig = field(default_factory=OptimizerConfig)
"""Optimizer configuration for the policy model."""
fsdp_config: FSDPConfig = field(default_factory=FSDPConfig)
"""FSDP configuration, applicable when ``trainer.strategy="fsdp"``."""
sequence_parallel_size: int = 1
"""Ulysses sequence parallel size (https://arxiv.org/abs/2309.14509).
Distinct from the Megatron sequence parallelism implied by ``megatron_config.tensor_model_parallel_size > 1``."""
use_torch_compile: bool = False
"""Apply torch.compile to logits calculation."""
record_memory: bool = False
"""Save memory snapshots to ``{ckpt_path}/memory_snapshots/``.
Visualize by dragging pickle files to https://docs.pytorch.org/memory_viz."""
torch_profiler_config: TorchProfilerConfig = field(default_factory=TorchProfilerConfig)
"""``torch.profiler`` config for policy training steps."""
megatron_config: MegatronConfig = field(default_factory=MegatronConfig)
model_config_kwargs: dict = field(default_factory=dict)
"""Pass-through kwargs for the HuggingFace model config (FSDP backends).
For Megatron, use ``policy.megatron_config.transformer_config_kwargs`` instead."""
language_model_only: bool = False
"""When True, skip vision encoder initialization for multimodal models (e.g. Qwen3.5).
Loads only the language model backbone using AutoModelForCausalLM."""
inference_only_init: bool = False
"""When True, set up the policy worker for inference-only flows (forward + weight
sync, no train_step), skipping the training-only state that would otherwise OOM
memory-constrained nodes (e.g. large MoE on 4xH100). NOT valid for actual training.
Backend-specific behavior:
- FSDP: initialize weights in bf16 instead of fp32 (skipping the fp32 master weights
that mixed-precision training requires) and skip optimizer/LR-scheduler construction.
- Megatron: skip optimizer/LR-scheduler construction (DistributedOptimizer eagerly
materializes fp32 master + AdamW state on GPU)."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr model
model: ModelConfig = field(default_factory=(lambda: copy.deepcopy(ModelConfig(path='Qwen/Qwen2.5-1.5B-Instruct'))))attr optimizer_config
optimizer_config: OptimizerConfig = field(default_factory=OptimizerConfig)Optimizer configuration for the policy model.
attr fsdp_config
fsdp_config: FSDPConfig = field(default_factory=FSDPConfig)FSDP configuration, applicable when trainer.strategy="fsdp".
attr sequence_parallel_size
sequence_parallel_size: int = 1Ulysses sequence parallel size (https://arxiv.org/abs/2309.14509).
Distinct from the Megatron sequence parallelism implied by megatron_config.tensor_model_parallel_size > 1.
attr use_torch_compile
use_torch_compile: bool = FalseApply torch.compile to logits calculation.
attr record_memory
record_memory: bool = FalseSave memory snapshots to {ckpt_path}/memory_snapshots/.
Visualize by dragging pickle files to https://docs.pytorch.org/memory_viz.
attr torch_profiler_config
torch_profiler_config: TorchProfilerConfig = field(default_factory=TorchProfilerConfig)torch.profiler config for policy training steps.
attr megatron_config
megatron_config: MegatronConfig = field(default_factory=MegatronConfig)attr model_config_kwargs
model_config_kwargs: dict = field(default_factory=dict)Pass-through kwargs for the HuggingFace model config (FSDP backends).
For Megatron, use policy.megatron_config.transformer_config_kwargs instead.
attr language_model_only
language_model_only: bool = FalseWhen True, skip vision encoder initialization for multimodal models (e.g. Qwen3.5). Loads only the language model backbone using AutoModelForCausalLM.
attr inference_only_init
inference_only_init: bool = FalseWhen True, set up the policy worker for inference-only flows (forward + weight sync, no train_step), skipping the training-only state that would otherwise OOM memory-constrained nodes (e.g. large MoE on 4xH100). NOT valid for actual training. Backend-specific behavior:
- FSDP: initialize weights in bf16 instead of fp32 (skipping the fp32 master weights that mixed-precision training requires) and skip optimizer/LR-scheduler construction.
- Megatron: skip optimizer/LR-scheduler construction (DistributedOptimizer eagerly materializes fp32 master + AdamW state on GPU).
class CriticConfig
CriticConfig(model: ModelConfig = ModelConfig(), optimizer_config: OptimizerConfig = (lambda: OptimizerConfig(lr=5e-06))(), fsdp_config: FSDPConfig = FSDPConfig(), sequence_parallel_size: int = 1, model_config_kwargs: dict = dict()) -> NoneBases: BaseConfig
Critic model configuration.
Supports a subset of the policy options (model/LoRA, optimizer, FSDP, sequence parallelism).
FSDP only -- a critic is rejected under trainer.strategy="megatron".
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
model | ModelConfig | |
optimizer_config | OptimizerConfig | |
fsdp_config | FSDPConfig | FSDP configuration, applicable when trainer.strategy="fsdp". |
sequence_parallel_size | int | Ulysses sequence parallel size (https://arxiv.org/abs/2309.14509). |
model_config_kwargs | dict | Pass-through kwargs for the HuggingFace model config (e.g. overriding vocab size). |
Source code in skyrl/train/config/config.py:641-656
@dataclass
class CriticConfig(BaseConfig):
"""Critic model configuration.
Supports a subset of the policy options (model/LoRA, optimizer, FSDP, sequence parallelism).
FSDP only -- a critic is rejected under ``trainer.strategy="megatron"``.
"""
model: ModelConfig = field(default_factory=ModelConfig)
optimizer_config: OptimizerConfig = field(default_factory=lambda: OptimizerConfig(lr=5e-6))
fsdp_config: FSDPConfig = field(default_factory=FSDPConfig)
"""FSDP configuration, applicable when ``trainer.strategy="fsdp"``."""
sequence_parallel_size: int = 1
"""Ulysses sequence parallel size (https://arxiv.org/abs/2309.14509)."""
model_config_kwargs: dict = field(default_factory=dict)
"""Pass-through kwargs for the HuggingFace model config (e.g. overriding vocab size)."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr model
model: ModelConfig = field(default_factory=ModelConfig)attr optimizer_config
optimizer_config: OptimizerConfig = field(default_factory=(lambda: OptimizerConfig(lr=5e-06)))attr fsdp_config
fsdp_config: FSDPConfig = field(default_factory=FSDPConfig)FSDP configuration, applicable when trainer.strategy="fsdp".
attr sequence_parallel_size
sequence_parallel_size: int = 1Ulysses sequence parallel size (https://arxiv.org/abs/2309.14509).
attr model_config_kwargs
model_config_kwargs: dict = field(default_factory=dict)Pass-through kwargs for the HuggingFace model config (e.g. overriding vocab size).
class RefConfig
RefConfig(model: ModelConfig = ModelConfig(), sequence_parallel_size: int = 1, fsdp_config: FSDPConfig = FSDPConfig(), megatron_config: MegatronConfig = MegatronConfig(), model_config_kwargs: dict = dict(), language_model_only: bool = False) -> NoneBases: BaseConfig
Reference model configuration.
NOTE: the reference model is only used when base-model log probabilities are needed, either as
part of the training loss or as part of the reward. So trainer.algorithm.use_kl_in_reward or
trainer.algorithm.use_kl_loss must be True for it to be used at all — if both are False the
reference model is never instantiated.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
model | ModelConfig | Reference model. |
sequence_parallel_size | int | Ulysses sequence parallel size (https://arxiv.org/abs/2309.14509). |
fsdp_config | FSDPConfig | FSDP configuration, applicable when trainer.strategy="fsdp". |
megatron_config | MegatronConfig | |
model_config_kwargs | dict | |
language_model_only | bool | When True, skip vision encoder initialization for multimodal models (e.g. Qwen3.5). |
Source code in skyrl/train/config/config.py:660-682
@dataclass
class RefConfig(BaseConfig):
"""Reference model configuration.
NOTE: the reference model is only used when base-model log probabilities are needed, either as
part of the training loss or as part of the reward. So ``trainer.algorithm.use_kl_in_reward`` or
``trainer.algorithm.use_kl_loss`` must be True for it to be used at all — if both are False the
reference model is never instantiated.
"""
model: ModelConfig = field(default_factory=ModelConfig)
"""Reference model.
``model.path`` defaults to ``trainer.policy.model.path``, but can be set separately — e.g. for distillation-style
approaches where the reference differs from the policy."""
sequence_parallel_size: int = 1
"""Ulysses sequence parallel size (https://arxiv.org/abs/2309.14509)."""
fsdp_config: FSDPConfig = field(default_factory=FSDPConfig)
"""FSDP configuration, applicable when ``trainer.strategy="fsdp"``."""
megatron_config: MegatronConfig = field(default_factory=MegatronConfig)
model_config_kwargs: dict = field(default_factory=dict)
language_model_only: bool = False
"""When True, skip vision encoder initialization for multimodal models (e.g. Qwen3.5).
Loads only the language model backbone using AutoModelForCausalLM."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr model
model: ModelConfig = field(default_factory=ModelConfig)Reference model.
model.path defaults to trainer.policy.model.path, but can be set separately — e.g. for distillation-style
approaches where the reference differs from the policy.
attr sequence_parallel_size
sequence_parallel_size: int = 1Ulysses sequence parallel size (https://arxiv.org/abs/2309.14509).
attr fsdp_config
fsdp_config: FSDPConfig = field(default_factory=FSDPConfig)FSDP configuration, applicable when trainer.strategy="fsdp".
attr megatron_config
megatron_config: MegatronConfig = field(default_factory=MegatronConfig)attr model_config_kwargs
model_config_kwargs: dict = field(default_factory=dict)attr language_model_only
language_model_only: bool = FalseWhen True, skip vision encoder initialization for multimodal models (e.g. Qwen3.5). Loads only the language model backbone using AutoModelForCausalLM.
class AlgorithmConfig
AlgorithmConfig(advantage_estimator: str = 'grpo', kl_ctrl: KLCtrlConfig = KLCtrlConfig(), kl_estimator_type: str = 'k3', use_kl_in_reward: bool = False, use_kl_loss: bool = True, kl_loss_coef: float = 0.001, use_entropy_loss: bool = False, entropy_loss_coef: float = 0.01, temperature: Optional[float] = None, advantage_batch_normalize: bool = False, value_head_prefix: str = 'value_head', policy_loss_type: str = 'regular', loss_reduction: str = 'token_mean', grpo_norm_by_std: bool = True, zero_variance_filter: bool = False, zero_variance_filter_tol: float = 1e-06, lambd: float = 1.0, gamma: float = 1.0, eps_clip_low: float = 0.2, eps_clip_high: float = 0.2, clip_ratio_c: float = 3.0, tis_imp_ratio_cap: float = -1.0, use_tis: bool = False, off_policy_correction: OffPolicyCorrectionConfig = OffPolicyCorrectionConfig(), sapo: SAPOConfig = SAPOConfig(), value_clip: float = 0.2, dynamic_sampling: DynamicSamplingConfig = DynamicSamplingConfig(), clip_cov: ClipCovConfig = ClipCovConfig(), kl_cov: KLCovConfig = KLCovConfig(), cispo: CISPOConfig = CISPOConfig(), dppo: DPPOConfig = DPPOConfig(), max_seq_len: Optional[int] = None) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
advantage_estimator | str | "grpo", "gae", "rloo", "reinforce++", or custom via AdvantageEstimatorRegistry. |
kl_ctrl | KLCtrlConfig | Only used when use_kl_in_reward=True (not applied when use_kl_loss=True). |
kl_estimator_type | str | "k1", "k2", "k3", "abs". See http://joschu.net/blog/kl-approx.html. |
use_kl_in_reward | bool | Apply KL penalty to rewards, as rewards - kl * kl_loss_coef. |
use_kl_loss | bool | Apply KL loss in the policy model, as policy_loss + kl * kl_loss_coef. |
kl_loss_coef | float | Coefficient for the KL divergence loss. |
use_entropy_loss | bool | Add an entropy bonus to the policy loss. |
entropy_loss_coef | float | Coefficient for the entropy loss term. Only used when use_entropy_loss=True. |
temperature | Optional[float] | Temperature for scaling logits in policy loss computation. |
advantage_batch_normalize | bool | Normalize advantages by the (global) training-batch mean and standard deviation. |
value_head_prefix | str | Name used to identify the value head in the critic model. |
policy_loss_type | str | Type of policy loss to use, or custom via PolicyLossRegistry: |
loss_reduction | str | Type of loss reduction to use, applied per mini-batch by rescaling advantages: |
grpo_norm_by_std | bool | Normalize advantages by the standard deviation in GRPO. |
zero_variance_filter | bool | Loss-mask prompts with zero-variance rewards. Only applicable when rewards are response-level. |
zero_variance_filter_tol | float | Two rewards within this absolute tolerance count as equal when detecting zero-variance groups. |
lambd | float | Lambda parameter for GAE. |
gamma | float | Gamma (discount) parameter for GAE. |
eps_clip_low | float | Lower bound for PPO clipping. |
eps_clip_high | float | Upper bound for PPO clipping. |
clip_ratio_c | float | Dual-clip parameter. |
tis_imp_ratio_cap | float | Deprecated: use off_policy_correction.tis_ratio_type="token" and token_tis_ratio_clip_high instead. |
use_tis | bool | Deprecated: use off_policy_correction instead. |
off_policy_correction | OffPolicyCorrectionConfig | See https://docs.skyrl.ai/docs/algorithms/off_policy_correction for a full guide. |
sapo | SAPOConfig | Only used when policy_loss_type="sapo". |
value_clip | float | Clip value for the value loss. |
dynamic_sampling | DynamicSamplingConfig | Dynamic sampling configuration. |
clip_cov | ClipCovConfig | Only used when policy_loss_type="clip_cov". |
kl_cov | KLCovConfig | Only used when policy_loss_type="kl_cov". |
cispo | CISPOConfig | Only used when policy_loss_type="cispo". |
dppo | DPPOConfig | Only used when policy_loss_type="dppo". |
max_seq_len | Optional[int] | Sequence-length normalization constant used for seq_mean_token_sum_norm loss reduction. |
Source code in skyrl/train/config/config.py:821-936
@dataclass
class AlgorithmConfig(BaseConfig):
advantage_estimator: str = "grpo"
"""``"grpo"``, ``"gae"``, ``"rloo"``, ``"reinforce++"``, or custom via ``AdvantageEstimatorRegistry``."""
kl_ctrl: KLCtrlConfig = field(default_factory=KLCtrlConfig)
"""Only used when ``use_kl_in_reward=True`` (not applied when ``use_kl_loss=True``).
Uses ``kl_loss_coef`` as the initial KL coefficient."""
kl_estimator_type: str = "k3"
"""``"k1"``, ``"k2"``, ``"k3"``, ``"abs"``. See http://joschu.net/blog/kl-approx.html."""
use_kl_in_reward: bool = False
"""Apply KL penalty to rewards, as ``rewards - kl * kl_loss_coef``.
Mutually exclusive with ``use_kl_loss``."""
use_kl_loss: bool = True
"""Apply KL loss in the policy model, as ``policy_loss + kl * kl_loss_coef``.
Mutually exclusive with ``use_kl_in_reward``."""
kl_loss_coef: float = 0.001
"""Coefficient for the KL divergence loss."""
use_entropy_loss: bool = False
"""Add an entropy bonus to the policy loss.
This encourages exploration by penalizing low-entropy (overly confident) policies."""
entropy_loss_coef: float = 0.01
"""Coefficient for the entropy loss term. Only used when ``use_entropy_loss=True``."""
temperature: Optional[float] = None
"""Temperature for scaling logits in policy loss computation.
If ``None``, will be set to the temperature provided by ``generator.sampling_params.temperature`` during config validation.
NOTE: When using HTTP endpoints directly, make sure to set this value to the temperature used during generation
"""
advantage_batch_normalize: bool = False
"""Normalize advantages by the (global) training-batch mean and standard deviation."""
value_head_prefix: str = "value_head"
"""Name used to identify the value head in the critic model."""
policy_loss_type: str = "regular"
"""Type of policy loss to use, or custom via ``PolicyLossRegistry``:
- ``"regular"``: vanilla PPO loss with token-level importance sampling.
- ``"dual_clip"``: dual-clip PPO loss (https://arxiv.org/pdf/1912.09729).
- ``"gspo"``: Group Sequence Policy Optimization (https://arxiv.org/abs/2507.18071) with
sequence-level importance sampling for improved training stability. Implements the
"GSPO-token" variant from the paper.
- ``"clip_cov"``: combines standard PPO clipping with covariance-based correction masking for
improved stability (https://arxiv.org/abs/2505.22617).
- ``"kl_cov"``: applies KL regularization to tokens selected by covariance value
(https://arxiv.org/abs/2505.22617).
- ``"cispo"``: Clipped Importance Sampling Weight Policy Optimization, from MiniMax-M1
(https://arxiv.org/abs/2506.13585).
- ``"sapo"``: Soft Adaptive Policy Optimization (https://arxiv.org/html/2511.20347v1).
- ``"rollout_is"``: the agentic loss from section 4.1.2 of the GLM-5 tech report
(https://arxiv.org/pdf/2602.15763). Uses rollout logprobs and Icepop-style clipping with an
additional stop gradient for masked tokens.
- ``"cross_entropy"`` and ``"importance_sampling"``: also registered; see ``PolicyLossRegistry``.
- ``"dppo"``: DPPO, from Rethinking the Trust Region in LLM Reinforcement Learning
(https://arxiv.org/pdf/2602.04879). Uses rollout logprobs and absolute probability
divergences rather than probability ratios, improving on PPO clipping behavior.
"""
loss_reduction: str = "token_mean"
"""Type of loss reduction to use, applied per mini-batch by rescaling advantages:
- ``"token_mean"``: average loss over all valid tokens in the batch, as in DAPO
(https://dapo-sia.github.io/).
- ``"sequence_mean"``: per-sequence average token loss, then averaged over the batch.
- ``"seq_mean_token_sum_norm"``: sum of token losses per sequence, normalized by
``max_seq_len``, then averaged over the batch, as in Dr. GRPO
(https://arxiv.org/abs/2503.20783). ``max_seq_len`` must be set explicitly for this mode,
because multi-turn/token budgets are workload-dependent.
- ``"prompt_mean"``: average token loss within each prompt group (all
``generator.n_samples_per_prompt`` responses sampled for a prompt), then averaged over
prompts. Unlike ``"token_mean"``, every prompt contributes equally regardless of how many
tokens its responses contain.
- ``"token_mean_legacy"``: also accepted, retaining the previous ``"token_mean"`` behavior.
"""
grpo_norm_by_std: bool = True
"""Normalize advantages by the standard deviation in GRPO.
Set to False for Dr. GRPO (https://arxiv.org/abs/2503.20783)."""
zero_variance_filter: bool = False
"""Loss-mask prompts with zero-variance rewards. Only applicable when rewards are response-level."""
zero_variance_filter_tol: float = 1e-6
"""Two rewards within this absolute tolerance count as equal when detecting zero-variance groups.
Only used when ``zero_variance_filter=True``. Defaults to 1e-6 so float (LLM-judge) rewards that are
effectively identical are still treated as zero-variance; this is a no-op for integer rewards (e.g.
0/1) where the spread is either 0 or >= 1. Set to 0.0 for exact equality."""
lambd: float = 1.0
"""Lambda parameter for GAE."""
gamma: float = 1.0
"""Gamma (discount) parameter for GAE."""
eps_clip_low: float = 0.2
"""Lower bound for PPO clipping."""
eps_clip_high: float = 0.2
"""Upper bound for PPO clipping."""
clip_ratio_c: float = 3.0
"""Dual-clip parameter."""
tis_imp_ratio_cap: float = -1.0
"""Deprecated: use ``off_policy_correction.tis_ratio_type="token"`` and ``token_tis_ratio_clip_high`` instead."""
use_tis: bool = False
"""Deprecated: use ``off_policy_correction`` instead.
Enabled Truncated Importance Sampling (TIS) as proposed in https://fengyao.notion.site/off-policy-rl."""
off_policy_correction: OffPolicyCorrectionConfig = field(default_factory=OffPolicyCorrectionConfig)
"""See https://docs.skyrl.ai/docs/algorithms/off_policy_correction for a full guide."""
sapo: SAPOConfig = field(default_factory=SAPOConfig)
"""Only used when ``policy_loss_type="sapo"``."""
value_clip: float = 0.2
"""Clip value for the value loss."""
dynamic_sampling: DynamicSamplingConfig = field(default_factory=DynamicSamplingConfig)
"""Dynamic sampling configuration."""
clip_cov: ClipCovConfig = field(default_factory=ClipCovConfig)
"""Only used when ``policy_loss_type="clip_cov"``."""
kl_cov: KLCovConfig = field(default_factory=KLCovConfig)
"""Only used when ``policy_loss_type="kl_cov"``."""
cispo: CISPOConfig = field(default_factory=CISPOConfig)
"""Only used when ``policy_loss_type="cispo"``."""
dppo: DPPOConfig = field(default_factory=DPPOConfig)
"""Only used when ``policy_loss_type="dppo"``."""
max_seq_len: Optional[int] = None
"""Sequence-length normalization constant used for ``seq_mean_token_sum_norm`` loss reduction.
Must be set explicitly for that reduction mode; otherwise can remain ``None``. This often
matches the model context window / vLLM ``max_model_len`` when that is the intended budget."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr advantage_estimator
advantage_estimator: str = 'grpo'"grpo", "gae", "rloo", "reinforce++", or custom via AdvantageEstimatorRegistry.
attr kl_ctrl
kl_ctrl: KLCtrlConfig = field(default_factory=KLCtrlConfig)Only used when use_kl_in_reward=True (not applied when use_kl_loss=True).
Uses kl_loss_coef as the initial KL coefficient.
attr kl_estimator_type
kl_estimator_type: str = 'k3'"k1", "k2", "k3", "abs". See http://joschu.net/blog/kl-approx.html.
attr use_kl_in_reward
use_kl_in_reward: bool = FalseApply KL penalty to rewards, as rewards - kl * kl_loss_coef.
Mutually exclusive with use_kl_loss.
attr use_kl_loss
use_kl_loss: bool = TrueApply KL loss in the policy model, as policy_loss + kl * kl_loss_coef.
Mutually exclusive with use_kl_in_reward.
attr kl_loss_coef
kl_loss_coef: float = 0.001Coefficient for the KL divergence loss.
attr use_entropy_loss
use_entropy_loss: bool = FalseAdd an entropy bonus to the policy loss. This encourages exploration by penalizing low-entropy (overly confident) policies.
attr entropy_loss_coef
entropy_loss_coef: float = 0.01Coefficient for the entropy loss term. Only used when use_entropy_loss=True.
attr temperature
temperature: Optional[float] = NoneTemperature for scaling logits in policy loss computation.
If None, will be set to the temperature provided by generator.sampling_params.temperature during config validation.
NOTE: When using HTTP endpoints directly, make sure to set this value to the temperature used during generation
attr advantage_batch_normalize
advantage_batch_normalize: bool = FalseNormalize advantages by the (global) training-batch mean and standard deviation.
attr value_head_prefix
value_head_prefix: str = 'value_head'Name used to identify the value head in the critic model.
attr policy_loss_type
policy_loss_type: str = 'regular'Type of policy loss to use, or custom via PolicyLossRegistry:
"regular": vanilla PPO loss with token-level importance sampling."dual_clip": dual-clip PPO loss (https://arxiv.org/pdf/1912.09729)."gspo": Group Sequence Policy Optimization (https://arxiv.org/abs/2507.18071) with sequence-level importance sampling for improved training stability. Implements the "GSPO-token" variant from the paper."clip_cov": combines standard PPO clipping with covariance-based correction masking for improved stability (https://arxiv.org/abs/2505.22617)."kl_cov": applies KL regularization to tokens selected by covariance value (https://arxiv.org/abs/2505.22617)."cispo": Clipped Importance Sampling Weight Policy Optimization, from MiniMax-M1 (https://arxiv.org/abs/2506.13585)."sapo": Soft Adaptive Policy Optimization (https://arxiv.org/html/2511.20347v1)."rollout_is": the agentic loss from section 4.1.2 of the GLM-5 tech report (https://arxiv.org/pdf/2602.15763). Uses rollout logprobs and Icepop-style clipping with an additional stop gradient for masked tokens."cross_entropy"and"importance_sampling": also registered; seePolicyLossRegistry."dppo": DPPO, from Rethinking the Trust Region in LLM Reinforcement Learning (https://arxiv.org/pdf/2602.04879). Uses rollout logprobs and absolute probability divergences rather than probability ratios, improving on PPO clipping behavior.
attr loss_reduction
loss_reduction: str = 'token_mean'Type of loss reduction to use, applied per mini-batch by rescaling advantages:
"token_mean": average loss over all valid tokens in the batch, as in DAPO (https://dapo-sia.github.io/)."sequence_mean": per-sequence average token loss, then averaged over the batch."seq_mean_token_sum_norm": sum of token losses per sequence, normalized bymax_seq_len, then averaged over the batch, as in Dr. GRPO (https://arxiv.org/abs/2503.20783).max_seq_lenmust be set explicitly for this mode, because multi-turn/token budgets are workload-dependent."prompt_mean": average token loss within each prompt group (allgenerator.n_samples_per_promptresponses sampled for a prompt), then averaged over prompts. Unlike"token_mean", every prompt contributes equally regardless of how many tokens its responses contain."token_mean_legacy": also accepted, retaining the previous"token_mean"behavior.
attr grpo_norm_by_std
grpo_norm_by_std: bool = TrueNormalize advantages by the standard deviation in GRPO. Set to False for Dr. GRPO (https://arxiv.org/abs/2503.20783).
attr zero_variance_filter
zero_variance_filter: bool = FalseLoss-mask prompts with zero-variance rewards. Only applicable when rewards are response-level.
attr zero_variance_filter_tol
zero_variance_filter_tol: float = 1e-06Two rewards within this absolute tolerance count as equal when detecting zero-variance groups.
Only used when zero_variance_filter=True. Defaults to 1e-6 so float (LLM-judge) rewards that are
effectively identical are still treated as zero-variance; this is a no-op for integer rewards (e.g.
0/1) where the spread is either 0 or >= 1. Set to 0.0 for exact equality.
attr lambd
lambd: float = 1.0Lambda parameter for GAE.
attr gamma
gamma: float = 1.0Gamma (discount) parameter for GAE.
attr eps_clip_low
eps_clip_low: float = 0.2Lower bound for PPO clipping.
attr eps_clip_high
eps_clip_high: float = 0.2Upper bound for PPO clipping.
attr clip_ratio_c
clip_ratio_c: float = 3.0Dual-clip parameter.
attr tis_imp_ratio_cap
tis_imp_ratio_cap: float = -1.0Deprecated: use off_policy_correction.tis_ratio_type="token" and token_tis_ratio_clip_high instead.
attr use_tis
use_tis: bool = FalseDeprecated: use off_policy_correction instead.
Enabled Truncated Importance Sampling (TIS) as proposed in https://fengyao.notion.site/off-policy-rl.
attr off_policy_correction
off_policy_correction: OffPolicyCorrectionConfig = field(default_factory=OffPolicyCorrectionConfig)See https://docs.skyrl.ai/docs/algorithms/off_policy_correction for a full guide.
attr sapo
sapo: SAPOConfig = field(default_factory=SAPOConfig)Only used when policy_loss_type="sapo".
attr value_clip
value_clip: float = 0.2Clip value for the value loss.
attr dynamic_sampling
dynamic_sampling: DynamicSamplingConfig = field(default_factory=DynamicSamplingConfig)Dynamic sampling configuration.
attr clip_cov
clip_cov: ClipCovConfig = field(default_factory=ClipCovConfig)Only used when policy_loss_type="clip_cov".
attr kl_cov
kl_cov: KLCovConfig = field(default_factory=KLCovConfig)Only used when policy_loss_type="kl_cov".
attr cispo
cispo: CISPOConfig = field(default_factory=CISPOConfig)Only used when policy_loss_type="cispo".
attr dppo
dppo: DPPOConfig = field(default_factory=DPPOConfig)Only used when policy_loss_type="dppo".
attr max_seq_len
max_seq_len: Optional[int] = NoneSequence-length normalization constant used for seq_mean_token_sum_norm loss reduction.
Must be set explicitly for that reduction mode; otherwise can remain None. This often
matches the model context window / vLLM max_model_len when that is the intended budget.
class KLCtrlConfig
KLCtrlConfig(type: str = 'fixed', kl_target: float = 0.1, horizon: int = 10000) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
type | str | "fixed" or "adaptive". |
kl_target | float | Target KL divergence for the adaptive KL controller. |
horizon | int | Controls the update rate of the adaptive KL controller. |
Source code in skyrl/train/config/config.py:690-698
@dataclass
class KLCtrlConfig(BaseConfig):
type: str = "fixed"
"""``"fixed"`` or ``"adaptive"``."""
kl_target: float = 0.1
"""Target KL divergence for the adaptive KL controller."""
horizon: int = 10000
"""Controls the update rate of the adaptive KL controller."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr type
type: str = 'fixed'"fixed" or "adaptive".
attr kl_target
kl_target: float = 0.1Target KL divergence for the adaptive KL controller.
attr horizon
horizon: int = 10000Controls the update rate of the adaptive KL controller.
Algorithm Extensions
class SAPOConfig
SAPOConfig(tau_pos: float = 1.0, tau_neg: float = 1.05) -> NoneBases: BaseConfig
SAPO parameters (https://arxiv.org/pdf/2511.20347). Only used when policy_loss_type="sapo".
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
tau_pos | float | Temperature for the gating function on tokens with positive advantages. |
tau_neg | float | Temperature for the gating function on tokens with negative (or zero) advantages. |
Source code in skyrl/train/config/config.py:701-709
@dataclass
class SAPOConfig(BaseConfig):
"""SAPO parameters (https://arxiv.org/pdf/2511.20347). Only used when ``policy_loss_type="sapo"``."""
tau_pos: float = 1.0
"""Temperature for the gating function on tokens with positive advantages."""
tau_neg: float = 1.05
"""Temperature for the gating function on tokens with negative (or zero) advantages.
The default matches the value used in the paper with Qwen3-30B-A3B-Base."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr tau_pos
tau_pos: float = 1.0Temperature for the gating function on tokens with positive advantages.
attr tau_neg
tau_neg: float = 1.05Temperature for the gating function on tokens with negative (or zero) advantages. The default matches the value used in the paper with Qwen3-30B-A3B-Base.
class DynamicSamplingConfig
DynamicSamplingConfig(type: Optional[str] = None, max_sample_batches: int = 30, min_replace_ratio: float = 0.3) -> NoneBases: BaseConfig
Dynamic sampling configuration: resample or filter training batches based on reward signal.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
type | Optional[str] | Dynamic sampling strategy: "filter", "replace", or None for no dynamic sampling. |
max_sample_batches | int | Sample at most this many batches before stopping. -1 to sample forever. |
min_replace_ratio | float | Minimum proportion of good samples to replace bad samples. Only used with "replace" strategy. |
Source code in skyrl/train/config/config.py:712-723
@dataclass
class DynamicSamplingConfig(BaseConfig):
"""Dynamic sampling configuration: resample or filter training batches based on reward signal."""
type: Optional[str] = None
"""Dynamic sampling strategy: ``"filter"``, ``"replace"``, or ``None`` for no dynamic sampling.
``"filter"`` is DAPO (https://dapo-sia.github.io/); ``"replace"`` is POLARIS
(https://hkunlp.github.io/blog/2025/Polaris/) / WebSailor (https://arxiv.org/abs/2507.02592)."""
max_sample_batches: int = 30
"""Sample at most this many batches before stopping. ``-1`` to sample forever."""
min_replace_ratio: float = 0.3
"""Minimum proportion of good samples to replace bad samples. Only used with ``"replace"`` strategy."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr type
type: Optional[str] = NoneDynamic sampling strategy: "filter", "replace", or None for no dynamic sampling.
"filter" is DAPO (https://dapo-sia.github.io/); "replace" is POLARIS
(https://hkunlp.github.io/blog/2025/Polaris/) / WebSailor (https://arxiv.org/abs/2507.02592).
attr max_sample_batches
max_sample_batches: int = 30Sample at most this many batches before stopping. -1 to sample forever.
attr min_replace_ratio
min_replace_ratio: float = 0.3Minimum proportion of good samples to replace bad samples. Only used with "replace" strategy.
class ClipCovConfig
ClipCovConfig(clip_ratio: float = 0.0002, clip_cov_lb: float = 1.0, clip_cov_ub: float = 5.0) -> NoneBases: BaseConfig
Clip-Cov parameters. Only used when policy_loss_type="clip_cov".
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
clip_ratio | float | Fraction of tokens to clip based on covariance. |
clip_cov_lb | float | Lower bound for covariance clipping. |
clip_cov_ub | float | Upper bound for covariance clipping. |
Source code in skyrl/train/config/config.py:726-735
@dataclass
class ClipCovConfig(BaseConfig):
"""Clip-Cov parameters. Only used when ``policy_loss_type="clip_cov"``."""
clip_ratio: float = 0.0002
"""Fraction of tokens to clip based on covariance."""
clip_cov_lb: float = 1.0
"""Lower bound for covariance clipping."""
clip_cov_ub: float = 5.0
"""Upper bound for covariance clipping."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr clip_ratio
clip_ratio: float = 0.0002Fraction of tokens to clip based on covariance.
attr clip_cov_lb
clip_cov_lb: float = 1.0Lower bound for covariance clipping.
attr clip_cov_ub
clip_cov_ub: float = 5.0Upper bound for covariance clipping.
class KLCovConfig
KLCovConfig(kl_cov_frac: float = 0.2, ppo_kl_coef: float = 1.0) -> NoneBases: BaseConfig
KL-Cov parameters. Only used when policy_loss_type="kl_cov".
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
kl_cov_frac | float | Fraction of tokens to apply KL regularization to. |
ppo_kl_coef | float | Coefficient for the KL regularization term. |
Source code in skyrl/train/config/config.py:738-745
@dataclass
class KLCovConfig(BaseConfig):
"""KL-Cov parameters. Only used when ``policy_loss_type="kl_cov"``."""
kl_cov_frac: float = 0.2
"""Fraction of tokens to apply KL regularization to."""
ppo_kl_coef: float = 1.0
"""Coefficient for the KL regularization term."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr kl_cov_frac
kl_cov_frac: float = 0.2Fraction of tokens to apply KL regularization to.
attr ppo_kl_coef
ppo_kl_coef: float = 1.0Coefficient for the KL regularization term.
class CISPOConfig
CISPOConfig(cispo_eps_clip_low: float = 1.0, cispo_eps_clip_high: float = 4.0, cispo_anchor: str = 'old') -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
cispo_eps_clip_low | float | Offset for lower bound of importance sampling ratio clipping (as opposed to PPO token update clipping). |
cispo_eps_clip_high | float | Offset for upper bound of importance sampling ratio clipping (as opposed to PPO token update clipping). |
cispo_anchor | str | Behavior policy the IS ratio is anchored on: "old" (default) uses the recomputed |
Source code in skyrl/train/config/config.py:748-772
@dataclass
class CISPOConfig(BaseConfig):
cispo_eps_clip_low: float = 1.0
"""Offset for lower bound of importance sampling ratio clipping (as opposed to PPO token update clipping).
The lower bound used is ``1-cispo_eps_clip_low``. The default lower bound is 0 following the ScaleRL recipe: https://arxiv.org/abs/2510.13786
"""
cispo_eps_clip_high: float = 4.0
"""Offset for upper bound of importance sampling ratio clipping (as opposed to PPO token update clipping).
The upper bound used is ``1+cispo_eps_clip_high``. The default upper bound is 5 following the ScaleRL recipe: https://arxiv.org/abs/2510.13786
"""
cispo_anchor: str = "old"
"""Behavior policy the IS ratio is anchored on: ``"old"`` (default) uses the recomputed
old log-probs (``ratio = pi_theta / pi_old``), matching the original CISPO paper. ``"rollout"``
uses the rollout/sampler log-probs (``ratio = pi_theta / pi_rollout``), which makes the clamped
objective engage under fully-async training where the sampler lags the trainer (with ``"old"``
the ratio is ~1 at a single gradient step and the clamp never bites). With ``"rollout"`` the
ratio is the full off-policy correction, so ``off_policy_correction.tis_ratio_type`` must be
``None`` (else the off-policy gap is double-counted)."""
def __post_init__(self):
if self.cispo_anchor not in ("old", "rollout"):
raise ValueError(f"cispo_anchor must be 'old' or 'rollout', got {self.cispo_anchor!r}")from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr cispo_eps_clip_low
cispo_eps_clip_low: float = 1.0Offset for lower bound of importance sampling ratio clipping (as opposed to PPO token update clipping).
The lower bound used is 1-cispo_eps_clip_low. The default lower bound is 0 following the ScaleRL recipe: https://arxiv.org/abs/2510.13786
attr cispo_eps_clip_high
cispo_eps_clip_high: float = 4.0Offset for upper bound of importance sampling ratio clipping (as opposed to PPO token update clipping).
The upper bound used is 1+cispo_eps_clip_high. The default upper bound is 5 following the ScaleRL recipe: https://arxiv.org/abs/2510.13786
attr cispo_anchor
cispo_anchor: str = 'old'Behavior policy the IS ratio is anchored on: "old" (default) uses the recomputed
old log-probs (ratio = pi_theta / pi_old), matching the original CISPO paper. "rollout"
uses the rollout/sampler log-probs (ratio = pi_theta / pi_rollout), which makes the clamped
objective engage under fully-async training where the sampler lags the trainer (with "old"
the ratio is ~1 at a single gradient step and the clamp never bites). With "rollout" the
ratio is the full off-policy correction, so off_policy_correction.tis_ratio_type must be
None (else the off-policy gap is double-counted).
class DPPOConfig
DPPOConfig(dppo_type: str = 'binary_tv', delta_low: float = 0.2, delta_high: float = 0.2) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
dppo_type | str | DPPO divergence variant: "binary_tv" or "binary_kl". Used if policy_loss_type="dppo". |
delta_low | float | Divergence threshold for negative advantages (0.2 for TV, 0.05 for KL recommended). |
delta_high | float | Divergence threshold for positive advantages (0.2 for TV, 0.05 for KL recommended). |
Source code in skyrl/train/config/config.py:777-788
@dataclass
class DPPOConfig(BaseConfig):
dppo_type: str = "binary_tv"
"""DPPO divergence variant: ``"binary_tv"`` or ``"binary_kl"``. Used if ``policy_loss_type="dppo"``."""
delta_low: float = 0.2
"""Divergence threshold for negative advantages (0.2 for TV, 0.05 for KL recommended)."""
delta_high: float = 0.2
"""Divergence threshold for positive advantages (0.2 for TV, 0.05 for KL recommended)."""
def __post_init__(self):
if self.dppo_type not in ["binary_tv", "binary_kl"]:
raise ValueError("Invalid DPPO type")from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr dppo_type
dppo_type: str = 'binary_tv'DPPO divergence variant: "binary_tv" or "binary_kl". Used if policy_loss_type="dppo".
attr delta_low
delta_low: float = 0.2Divergence threshold for negative advantages (0.2 for TV, 0.05 for KL recommended).
attr delta_high
delta_high: float = 0.2Divergence threshold for positive advantages (0.2 for TV, 0.05 for KL recommended).
class OffPolicyCorrectionConfig
OffPolicyCorrectionConfig(tis_ratio_type: Optional[str] = None, token_tis_ratio_clip_high: float = 2.0, sequence_tis_ratio_clip_high: float = 5.0, sequence_mask_metric: Optional[str] = None, geo_mask_high: float = 1.01, geo_mask_low: float = 0.99, product_mask_high: float = 2.0, product_mask_low: float = 0.5, outlier_token_is_threshold_low: Optional[float] = None, outlier_token_is_threshold_high: Optional[float] = None, token_mask_is_threshold_low: Optional[float] = None, token_mask_is_threshold_high: Optional[float] = None) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
tis_ratio_type | Optional[str] | Importance sampling ratio type for PPO loss correction: None, "token", or "sequence". |
token_tis_ratio_clip_high | float | Used when tis_ratio_type="token". Recommended range: 1.5--5.0. |
sequence_tis_ratio_clip_high | float | Used when tis_ratio_type="sequence". Recommended range: 2.0--10.0. |
sequence_mask_metric | Optional[str] | Method for masking sequences with cumulative IS ratios outside cap: None, "product", or "geometric". |
geo_mask_high | float | Used when sequence_mask_metric="geometric". Recommended ~0.99--1.01; MoE models may need a wider range. |
geo_mask_low | float | Used when sequence_mask_metric="geometric". |
product_mask_high | float | Used when sequence_mask_metric="product". Recommended ~0.5--2.0. |
product_mask_low | float | Used when sequence_mask_metric="product". |
outlier_token_is_threshold_low | Optional[float] | Set to mask sequences with any token IS ratio below this threshold. Suggested: 1e-4. None to disable. |
outlier_token_is_threshold_high | Optional[float] | Set to mask sequences with any token IS ratio above this threshold. Suggested: 100. None to disable. |
token_mask_is_threshold_low | Optional[float] | Set to mask per-token when IS ratio < token_mask_is_threshold_low. None to disable. |
token_mask_is_threshold_high | Optional[float] | Set to mask per-token when IS ratio > token_mask_is_threshold_high. None to disable. |
Source code in skyrl/train/config/config.py:792-818
@dataclass
class OffPolicyCorrectionConfig(BaseConfig):
tis_ratio_type: Optional[str] = None
"""Importance sampling ratio type for PPO loss correction: ``None``, ``"token"``, or ``"sequence"``.
The ratio is ``exp(logprobs_policy_old - logprobs_rollout_policy)``."""
token_tis_ratio_clip_high: float = 2.0
"""Used when ``tis_ratio_type="token"``. Recommended range: 1.5--5.0."""
sequence_tis_ratio_clip_high: float = 5.0
"""Used when ``tis_ratio_type="sequence"``. Recommended range: 2.0--10.0."""
sequence_mask_metric: Optional[str] = None
"""Method for masking sequences with cumulative IS ratios outside cap: ``None``, ``"product"``, or ``"geometric"``."""
geo_mask_high: float = 1.01
"""Used when ``sequence_mask_metric="geometric"``. Recommended ~0.99--1.01; MoE models may need a wider range."""
geo_mask_low: float = 0.99
"""Used when ``sequence_mask_metric="geometric"``."""
product_mask_high: float = 2.0
"""Used when ``sequence_mask_metric="product"``. Recommended ~0.5--2.0."""
product_mask_low: float = 0.5
"""Used when ``sequence_mask_metric="product"``."""
outlier_token_is_threshold_low: Optional[float] = None
"""Set to mask sequences with any token IS ratio below this threshold. Suggested: 1e-4. ``None`` to disable."""
outlier_token_is_threshold_high: Optional[float] = None
"""Set to mask sequences with any token IS ratio above this threshold. Suggested: 100. ``None`` to disable."""
token_mask_is_threshold_low: Optional[float] = None
"""Set to mask per-token when IS ratio < `token_mask_is_threshold_low`. ``None`` to disable."""
token_mask_is_threshold_high: Optional[float] = None
"""Set to mask per-token when IS ratio > `token_mask_is_threshold_high`. ``None`` to disable."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr tis_ratio_type
tis_ratio_type: Optional[str] = NoneImportance sampling ratio type for PPO loss correction: None, "token", or "sequence".
The ratio is exp(logprobs_policy_old - logprobs_rollout_policy).
attr token_tis_ratio_clip_high
token_tis_ratio_clip_high: float = 2.0Used when tis_ratio_type="token". Recommended range: 1.5--5.0.
attr sequence_tis_ratio_clip_high
sequence_tis_ratio_clip_high: float = 5.0Used when tis_ratio_type="sequence". Recommended range: 2.0--10.0.
attr sequence_mask_metric
sequence_mask_metric: Optional[str] = NoneMethod for masking sequences with cumulative IS ratios outside cap: None, "product", or "geometric".
attr geo_mask_high
geo_mask_high: float = 1.01Used when sequence_mask_metric="geometric". Recommended ~0.99--1.01; MoE models may need a wider range.
attr geo_mask_low
geo_mask_low: float = 0.99Used when sequence_mask_metric="geometric".
attr product_mask_high
product_mask_high: float = 2.0Used when sequence_mask_metric="product". Recommended ~0.5--2.0.
attr product_mask_low
product_mask_low: float = 0.5Used when sequence_mask_metric="product".
attr outlier_token_is_threshold_low
outlier_token_is_threshold_low: Optional[float] = NoneSet to mask sequences with any token IS ratio below this threshold. Suggested: 1e-4. None to disable.
attr outlier_token_is_threshold_high
outlier_token_is_threshold_high: Optional[float] = NoneSet to mask sequences with any token IS ratio above this threshold. Suggested: 100. None to disable.
attr token_mask_is_threshold_low
token_mask_is_threshold_low: Optional[float] = NoneSet to mask per-token when IS ratio < token_mask_is_threshold_low. None to disable.
attr token_mask_is_threshold_high
token_mask_is_threshold_high: Optional[float] = NoneSet to mask per-token when IS ratio > token_mask_is_threshold_high. None to disable.
class FullyAsyncConfig
FullyAsyncConfig(enabled: bool = False, max_staleness_steps: int = 4, num_parallel_generation_workers: int = 768, sample_full_batch: bool = False, clear_kv_cache_on_weight_sync: bool = False, simulate_training: bool = False, simulate_training_step_seconds: float = 30.0, simulate_weight_sync_seconds: float = 0.0) -> NoneBases: BaseConfig
Knobs for fully async training. See https://docs.skyrl.ai/docs/tutorials/fully_async#step-2-config-knobs-to-tune-for-fully-async-training.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
enabled | bool | Indicates whether fully async training is enabled |
max_staleness_steps | int | Maximum off-policy steps allowed. If a trajectory group is scheduled at step i and trained at step j, |
num_parallel_generation_workers | int | Number of generation workers to spawn. Should be >= policy_mini_batch_size and |
sample_full_batch | bool | Requires zero_variance_filter=True. Drop zero-variance groups and keep pulling until the |
clear_kv_cache_on_weight_sync | bool | Whether or not to clear the KV cache on weight sync. Defaults to False. |
simulate_training | bool | If True, run fully-async generation with a SIMULATED trainer (see FullyAsyncTrainerSim). |
simulate_training_step_seconds | float | Wall-clock seconds the simulated dummy training step sleeps (stands in for fwd/bwd/optim). |
simulate_weight_sync_seconds | float | Wall-clock seconds generation stays paused to stand in for the (skipped) weight broadcast. |
Source code in skyrl/train/config/config.py:944-987
@dataclass
class FullyAsyncConfig(BaseConfig):
"""Knobs for fully async training.
See https://docs.skyrl.ai/docs/tutorials/fully_async#step-2-config-knobs-to-tune-for-fully-async-training."""
enabled: bool = False
"""Indicates whether fully async training is enabled"""
max_staleness_steps: int = 4
"""Maximum off-policy steps allowed. If a trajectory group is scheduled at step *i* and trained at step *j*,
then ``j - i <= max_staleness_steps``. Larger values increase throughput but also off-policy-ness."""
num_parallel_generation_workers: int = 768
"""Number of generation workers to spawn. Should be >= ``policy_mini_batch_size`` and
<= ``policy_mini_batch_size * (max_staleness_steps + 1)``."""
sample_full_batch: bool = False
"""Requires ``zero_variance_filter=True``. Drop zero-variance groups and keep pulling until the
mini-batch is full of non-zero-variance groups (async-native DAPO ``dynamic_sampling="filter"``).
Dropped groups are marked consumed (not regenerated on resume), so the per-epoch step count becomes
an upper bound: if the epoch's prompts run out mid mini-batch, the partial batch is discarded and
the epoch ends."""
clear_kv_cache_on_weight_sync: bool = False
"""Whether or not to clear the KV cache on weight sync. Defaults to False.
If False, we reuse KV cache from stale policies during generation
(avoids recomputation at the cost of using slightly stale KV cache).
"""
# --- Trainer simulation (no real trainer components) ---
simulate_training: bool = False
"""If True, run fully-async generation with a SIMULATED trainer (see ``FullyAsyncTrainerSim``).
No policy/critic/ref models are instantiated and no weight broadcast happens. Each step consumes
a mini-batch from the generation buffer, sleeps for ``simulate_training_step_seconds``, then
issues pause/resume generation (as a real weight sync would) but skips
``broadcast_to_inference_engines``. The generation-side dynamics (staleness control, rate
limiting, pause/resume) remain faithful.
Because no models are built, this requires ``trainer.eval_interval``, ``trainer.ckpt_interval``,
and ``trainer.hf_save_interval`` to all be ``<= 0``, ``trainer.update_ref_every_epoch=False``,
and resumption to be disabled. See
https://docs.skyrl.ai/docs/tutorials/fully_async for usage."""
simulate_training_step_seconds: float = 30.0
"""Wall-clock seconds the simulated dummy training step sleeps (stands in for fwd/bwd/optim)."""
simulate_weight_sync_seconds: float = 0.0
"""Wall-clock seconds generation stays paused to stand in for the (skipped) weight broadcast.
0.0 = pause then immediately resume."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr enabled
enabled: bool = FalseIndicates whether fully async training is enabled
attr max_staleness_steps
max_staleness_steps: int = 4Maximum off-policy steps allowed. If a trajectory group is scheduled at step i and trained at step j,
then j - i <= max_staleness_steps. Larger values increase throughput but also off-policy-ness.
attr num_parallel_generation_workers
num_parallel_generation_workers: int = 768Number of generation workers to spawn. Should be >= policy_mini_batch_size and
<= policy_mini_batch_size * (max_staleness_steps + 1).
attr sample_full_batch
sample_full_batch: bool = FalseRequires zero_variance_filter=True. Drop zero-variance groups and keep pulling until the
mini-batch is full of non-zero-variance groups (async-native DAPO dynamic_sampling="filter").
Dropped groups are marked consumed (not regenerated on resume), so the per-epoch step count becomes
an upper bound: if the epoch's prompts run out mid mini-batch, the partial batch is discarded and
the epoch ends.
attr clear_kv_cache_on_weight_sync
clear_kv_cache_on_weight_sync: bool = FalseWhether or not to clear the KV cache on weight sync. Defaults to False. If False, we reuse KV cache from stale policies during generation (avoids recomputation at the cost of using slightly stale KV cache).
attr simulate_training
simulate_training: bool = FalseIf True, run fully-async generation with a SIMULATED trainer (see FullyAsyncTrainerSim).
No policy/critic/ref models are instantiated and no weight broadcast happens. Each step consumes
a mini-batch from the generation buffer, sleeps for simulate_training_step_seconds, then
issues pause/resume generation (as a real weight sync would) but skips
broadcast_to_inference_engines. The generation-side dynamics (staleness control, rate
limiting, pause/resume) remain faithful.
Because no models are built, this requires trainer.eval_interval, trainer.ckpt_interval,
and trainer.hf_save_interval to all be <= 0, trainer.update_ref_every_epoch=False,
and resumption to be disabled. See
https://docs.skyrl.ai/docs/tutorials/fully_async for usage.
attr simulate_training_step_seconds
simulate_training_step_seconds: float = 30.0Wall-clock seconds the simulated dummy training step sleeps (stands in for fwd/bwd/optim).
attr simulate_weight_sync_seconds
simulate_weight_sync_seconds: float = 0.0Wall-clock seconds generation stays paused to stand in for the (skipped) weight broadcast. 0.0 = pause then immediately resume.
Inference & Generation
class SamplingParams
SamplingParams(max_generate_length: int = 1024, repetition_penalty: float = 1.0, temperature: float = 1.0, top_p: float = 1.0, min_p: float = 0.0, top_k: int = -1, logprobs: Optional[int] = 1, stop: Optional[List[str]] = None, additional_kwargs: Optional[Dict[str, Any]] = None) -> NoneBases: BaseConfig
Sampling parameters passed to the inference engine during generation.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
max_generate_length | int | Maximum length of the generated response. |
repetition_penalty | float | Repetition penalty. 1.0 applies no penalty. |
temperature | float | Sampling temperature. |
top_p | float | Top-p (nucleus) sampling parameter. |
min_p | float | Min-p sampling parameter, as proposed in https://arxiv.org/pdf/2407.01082. |
top_k | int | Top-k sampling parameter. -1 disables it. |
logprobs | Optional[int] | Number of logprobs to return from the inference engine. |
stop | Optional[List[str]] | Optional list of stop strings for generation. |
additional_kwargs | Optional[Dict[str, Any]] | Extra sampling kwargs passed through to the inference engine. |
Source code in skyrl/train/config/config.py:995-1020
@dataclass
class SamplingParams(BaseConfig):
"""Sampling parameters passed to the inference engine during generation."""
max_generate_length: int = 1024
"""Maximum length of the generated response."""
repetition_penalty: float = 1.0
"""Repetition penalty. ``1.0`` applies no penalty.
Not forwarded by the typed sampling-params path -- pass it via ``additional_kwargs``."""
temperature: float = 1.0
"""Sampling temperature.
Automatically propagated to ``trainer.algorithm.temperature`` during config initialization."""
top_p: float = 1.0
"""Top-p (nucleus) sampling parameter."""
min_p: float = 0.0
"""Min-p sampling parameter, as proposed in https://arxiv.org/pdf/2407.01082."""
top_k: int = -1
"""Top-k sampling parameter. ``-1`` disables it."""
logprobs: Optional[int] = 1
"""Number of logprobs to return from the inference engine.
Must be ``None``, ``0``, or ``1``; both ``0`` and ``1`` return only the chosen token's
logprob, and larger values are rejected."""
stop: Optional[List[str]] = None
"""Optional list of stop strings for generation."""
additional_kwargs: Optional[Dict[str, Any]] = None
"""Extra sampling kwargs passed through to the inference engine."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr max_generate_length
max_generate_length: int = 1024Maximum length of the generated response.
attr repetition_penalty
repetition_penalty: float = 1.0Repetition penalty. 1.0 applies no penalty.
Not forwarded by the typed sampling-params path -- pass it via additional_kwargs.
attr temperature
temperature: float = 1.0Sampling temperature.
Automatically propagated to trainer.algorithm.temperature during config initialization.
attr top_p
top_p: float = 1.0Top-p (nucleus) sampling parameter.
attr min_p
min_p: float = 0.0Min-p sampling parameter, as proposed in https://arxiv.org/pdf/2407.01082.
attr top_k
top_k: int = -1Top-k sampling parameter. -1 disables it.
attr logprobs
logprobs: Optional[int] = 1Number of logprobs to return from the inference engine.
Must be None, 0, or 1; both 0 and 1 return only the chosen token's
logprob, and larger values are rejected.
attr stop
stop: Optional[List[str]] = NoneOptional list of stop strings for generation.
attr additional_kwargs
additional_kwargs: Optional[Dict[str, Any]] = NoneExtra sampling kwargs passed through to the inference engine.
class ChatTemplateConfig
ChatTemplateConfig(source: str = 'name', name_or_path: Optional[str] = None) -> NoneBases: BaseConfig
Custom chat template configuration.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
source | str | "name" to select a built-in template, or "file" to load one from disk. |
name_or_path | Optional[str] | Selects the template, interpreted according to source. |
Source code in skyrl/train/config/config.py:1023-1032
@dataclass
class ChatTemplateConfig(BaseConfig):
"""Custom chat template configuration."""
source: str = "name"
"""``"name"`` to select a built-in template, or ``"file"`` to load one from disk."""
name_or_path: Optional[str] = None
"""Selects the template, interpreted according to ``source``.
When ``source="name"``, one of the supported templates in ``skyrl/train/generators/utils.py``
(e.g. ``"qwen3_with_thinking"``). When ``source="file"``, the path to a Jinja2 template file."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr source
source: str = 'name'"name" to select a built-in template, or "file" to load one from disk.
attr name_or_path
name_or_path: Optional[str] = NoneSelects the template, interpreted according to source.
When source="name", one of the supported templates in skyrl/train/generators/utils.py
(e.g. "qwen3_with_thinking"). When source="file", the path to a Jinja2 template file.
class InferenceEngineConfig
InferenceEngineConfig(model_dtype: str = 'bfloat16', run_engines_locally: bool = True, num_engines: int = 1, backend: str = 'vllm', weight_sync_backend: str = 'nccl', weight_transfer_threshold_cuda_ipc_GB: float = 1.0, delta_weight_sync: Optional[DeltaWeightSyncConfig] = None, tensor_parallel_size: int = 1, pipeline_parallel_size: int = 1, expert_parallel_size: int = 1, data_parallel_size: int = 1, vllm_v1_disable_multiproc: bool = True, enable_prefix_caching: bool = True, enable_chunked_prefill: bool = True, enable_return_routed_experts: bool = False, max_num_batched_tokens: int = 8192, enforce_eager: bool = False, fully_sharded_loras: bool = False, enable_ray_prometheus_stats: bool = True, gpu_memory_utilization: float = 0.8, offload_kv_for_weight_sync: bool = False, use_expandable_segments: bool = False, max_num_seqs: int = 1024, served_model_name: Optional[str] = None, distributed_executor_backend: str = 'ray', language_model_only: bool = False, engine_init_kwargs: Dict[str, Any] = dict(), speculative_config: Optional[Dict[str, Any]] = None, external_proxy_url: Optional[str] = None, external_server_urls: Optional[List[str]] = None, enable_pd: bool = False, num_prefill: int = 0, router_init_kwargs: Dict[str, Any] = dict()) -> NoneBases: BaseConfig
Configuration for inference engine instantiation and management.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
model_dtype | str | Should match the dtype used by the inference engine. |
run_engines_locally | bool | Launch inference servers during the training run in the current Ray cluster. |
num_engines | int | Number of inference engines to launch when run_engines_locally=True. |
backend | str | "vllm". |
weight_sync_backend | str | Backend used for weight synchronization. |
weight_transfer_threshold_cuda_ipc_GB | float | When using cuda_ipc, send weights in batches of this size (GB). |
delta_weight_sync | Optional[DeltaWeightSyncConfig] | Required when weight_sync_backend="delta". |
tensor_parallel_size | int | Tensor parallel size for the inference engine. |
pipeline_parallel_size | int | Pipeline parallel size for the inference engine. Currently only supported for vLLM. |
expert_parallel_size | int | Expert parallel size for the inference engine. |
data_parallel_size | int | Data parallel size for the inference engine. Currently only supported for vLLM. |
vllm_v1_disable_multiproc | bool | Currently inert. |
enable_prefix_caching | bool | Enable vLLM prefix caching. |
enable_chunked_prefill | bool | Enable vLLM chunked prefill. |
enable_return_routed_experts | bool | Return per-layer expert routing indices, for rollout router replay (R3) when training an MoE model. |
max_num_batched_tokens | int | vLLM continuous-batching parameter: maximum number of tokens to pack into a batch. |
enforce_eager | bool | Disable CUDA graphs. |
fully_sharded_loras | bool | |
enable_ray_prometheus_stats | bool | Enable Ray Prometheus stats logger for inference engine metrics (vLLM v1 only). |
gpu_memory_utilization | float | GPU memory utilization for the inference engine. |
offload_kv_for_weight_sync | bool | Non-colocated only. Sleep the engine (freeing the KV cache from GPU) during weight |
use_expandable_segments | bool | Set PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True on the inference-engine |
max_num_seqs | int | vLLM continuous-batching parameter: maximum number of sequences to pack into a batch. |
served_model_name | Optional[str] | Model name for HTTP endpoint validation. If set, must be used in the model field of |
distributed_executor_backend | str | Distributed executor backend for vLLM. Set to "ray" to use the Ray backend |
language_model_only | bool | When True, pass language_model_only=True to the vLLM engine so that |
engine_init_kwargs | Dict[str, Any] | Pass-through kwargs for the vLLM engine. |
speculative_config | Optional[Dict[str, Any]] | Speculative-decoding config passed through to vLLM for MTP drafter decoding. |
external_proxy_url | Optional[str] | Data-plane URL (load-balanced router) for the new inference layer. |
external_server_urls | Optional[List[str]] | Control-plane URLs (direct backend access) for the new inference layer. |
enable_pd | bool | Enable prefill-decode disaggregation. Requires num_prefill > 0 and num_engines >= 2. |
num_prefill | int | Number of prefill engines when enable_pd=True. Decode engines = num_engines - num_prefill |
router_init_kwargs | Dict[str, Any] | Pass-through kwargs applied to RouterArgs for the vllm-router. |
Source code in skyrl/train/config/config.py:1095-1212
@dataclass
class InferenceEngineConfig(BaseConfig):
"""Configuration for inference engine instantiation and management."""
model_dtype: str = "bfloat16"
"""Should match the dtype used by the inference engine.
Also used during full-weight sync, where policy weights are cast to this dtype before being sent
to the inference engine. The LoRA-adapter sync path exports fp32 instead."""
run_engines_locally: bool = True
"""Launch inference servers during the training run in the current Ray cluster.
When ``False``, point SkyRL at an external HTTP/vLLM deployment via ``external_proxy_url`` and/or
``external_server_urls``. See https://docs.skyrl.ai/docs/tutorials/placement"""
num_engines: int = 1
"""Number of inference engines to launch when ``run_engines_locally=True``."""
backend: str = "vllm"
"""``"vllm"``."""
weight_sync_backend: str = "nccl"
"""Backend used for weight synchronization.
Use ``"nccl"`` (colocated ``nccl`` uses CUDA IPC internally), or ``"delta"`` for checkpoint-delta sync through
shared storage in non-colocated vLLM runs. See https://docs.skyrl.ai/docs/examples/delta_weight_sync"""
weight_transfer_threshold_cuda_ipc_GB: float = 1.0
"""When using ``cuda_ipc``, send weights in batches of this size (GB)."""
delta_weight_sync: Optional[DeltaWeightSyncConfig] = None
"""Required when ``weight_sync_backend="delta"``."""
tensor_parallel_size: int = 1
"""Tensor parallel size for the inference engine."""
pipeline_parallel_size: int = 1
"""Pipeline parallel size for the inference engine. Currently only supported for vLLM."""
expert_parallel_size: int = 1
"""Expert parallel size for the inference engine.
Currently only supported for vLLM. When set > 1, must equal
``data_parallel_size * tensor_parallel_size``."""
data_parallel_size: int = 1
"""Data parallel size for the inference engine. Currently only supported for vLLM."""
vllm_v1_disable_multiproc: bool = True
"""Currently inert.
``VLLM_ENABLE_V1_MULTIPROCESSING=0`` is set unconditionally whenever ``VLLM_USE_V1`` is absent
from the environment, which makes vLLM scheduling deterministic.
Useful for reproducibility."""
enable_prefix_caching: bool = True
"""Enable vLLM prefix caching.
Can be left at the default in most cases. With remote inference servers, this must match the setting the remote
servers were initialized with."""
enable_chunked_prefill: bool = True
"""Enable vLLM chunked prefill.
Currently not plumbed through to the engine; set ``engine_init_kwargs.enable_chunked_prefill``
to change it."""
enable_return_routed_experts: bool = False
"""Return per-layer expert routing indices, for rollout router replay (R3) when training an MoE model.
Used together with ``trainer.policy.megatron_config.moe_enable_routing_replay``."""
max_num_batched_tokens: int = 8192
"""vLLM continuous-batching parameter: maximum number of tokens to pack into a batch."""
enforce_eager: bool = False
"""Disable CUDA graphs.
Enabling this trades performance for stability; leaving it off (the default) is faster but may affect convergence
for long-running or long-context training jobs."""
fully_sharded_loras: bool = False
enable_ray_prometheus_stats: bool = True
"""Enable Ray Prometheus stats logger for inference engine metrics (vLLM v1 only)."""
gpu_memory_utilization: float = 0.8
"""GPU memory utilization for the inference engine.
Only applicable when ``run_engines_locally=True``."""
offload_kv_for_weight_sync: bool = False
"""Non-colocated only. Sleep the engine (freeing the KV cache from GPU) during weight
sync so ``gpu_memory_utilization`` can be pushed higher without OOMing on the weight-
transfer buffers. On the fully-async trainer, in-flight requests are frozen (KEEP
pause) and, unless ``trainer.fully_async.clear_kv_cache_on_weight_sync`` is set, their
KV cache is offloaded to CPU and restored so they resume with no abort or prefill
recompute (at the cost of a GPU<->CPU copy of the KV pool each sync). Requires
non-colocated and non-LoRA weight sync."""
use_expandable_segments: bool = False
"""Set ``PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True`` on the inference-engine
processes to reduce fragmentation. Independent of the trainer-side
``TrainerConfig.use_expandable_segments``. Default ``False``: it is a safe opt-in
on vLLM >= 0.20.1, where the CuMemAllocator auto-disables expandable segments around
its sleep/wake memory pool. On older vLLM, sleep mode + expandable segments is a hard
error, so leave this off."""
max_num_seqs: int = 1024
"""vLLM continuous-batching parameter: maximum number of sequences to pack into a batch."""
served_model_name: Optional[str] = None
"""Model name for HTTP endpoint validation. If set, must be used in the ``model`` field of
``/chat/completions`` requests instead of the model path. If ``None``, the model path is used."""
distributed_executor_backend: str = "ray"
"""Distributed executor backend for vLLM. Set to ``"ray"`` to use the Ray backend
or ``"mp"`` to use the multiprocessing backend (single-node serving only). Per-engine
placement groups are created when ``"mp"`` is used."""
language_model_only: bool = False
"""When True, pass ``language_model_only=True`` to the vLLM engine so that
multimodal models (e.g. Qwen3.5) skip vision encoder initialization."""
engine_init_kwargs: Dict[str, Any] = field(default_factory=dict)
"""Pass-through kwargs for the vLLM engine.
Names must match the engine's args. Applied last, so they silently override config-derived
engine args (e.g. ``tensor_parallel_size``).
For HuggingFace config overrides such as RoPE scaling, use
``engine_init_kwargs.hf_overrides.rope_parameters`` and set the matching trainer-side override
with ``trainer.policy.model_config_kwargs.rope_parameters`` (FSDP) or
``trainer.policy.megatron_config.transformer_config_kwargs.rope_parameters`` (Megatron). The two
must agree, and are validated against each other."""
speculative_config: Optional[Dict[str, Any]] = None
"""Speculative-decoding config passed through to vLLM for MTP drafter decoding.
(needs ``policy.megatron_config.mtp_num_layers`` > 0 to train mtp). ``None`` disables it."""
external_proxy_url: Optional[str] = None
"""Data-plane URL (load-balanced router) for the new inference layer.
Generation requests are sent here."""
external_server_urls: Optional[List[str]] = None
"""Control-plane URLs (direct backend access) for the new inference layer.
Used to fan out pause/resume, sleep/wake, and weight sync. If ``external_proxy_url`` is omitted,
SkyRL starts an internal router over these servers."""
enable_pd: bool = False
"""Enable prefill-decode disaggregation. Requires ``num_prefill > 0`` and ``num_engines >= 2``."""
num_prefill: int = 0
"""Number of prefill engines when ``enable_pd=True``. Decode engines = ``num_engines - num_prefill``
NOTE: SkyRL counts data parallel workers separately, so the total number of prefill workers will be ``data_parallel_size * num_prefill``."""
router_init_kwargs: Dict[str, Any] = field(default_factory=dict)
"""Pass-through kwargs applied to ``RouterArgs`` for the vllm-router.
Names must match ``vllm_router.RouterArgs`` fields (e.g. ``policy``, ``request_timeout_secs``)."""from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr model_dtype
model_dtype: str = 'bfloat16'Should match the dtype used by the inference engine. Also used during full-weight sync, where policy weights are cast to this dtype before being sent to the inference engine. The LoRA-adapter sync path exports fp32 instead.
attr run_engines_locally
run_engines_locally: bool = TrueLaunch inference servers during the training run in the current Ray cluster.
When False, point SkyRL at an external HTTP/vLLM deployment via external_proxy_url and/or
external_server_urls. See https://docs.skyrl.ai/docs/tutorials/placement
attr num_engines
num_engines: int = 1Number of inference engines to launch when run_engines_locally=True.
attr backend
backend: str = 'vllm'"vllm".
attr weight_sync_backend
weight_sync_backend: str = 'nccl'Backend used for weight synchronization.
Use "nccl" (colocated nccl uses CUDA IPC internally), or "delta" for checkpoint-delta sync through
shared storage in non-colocated vLLM runs. See https://docs.skyrl.ai/docs/examples/delta_weight_sync
attr weight_transfer_threshold_cuda_ipc_GB
weight_transfer_threshold_cuda_ipc_GB: float = 1.0When using cuda_ipc, send weights in batches of this size (GB).
attr delta_weight_sync
delta_weight_sync: Optional[DeltaWeightSyncConfig] = NoneRequired when weight_sync_backend="delta".
attr tensor_parallel_size
tensor_parallel_size: int = 1Tensor parallel size for the inference engine.
attr pipeline_parallel_size
pipeline_parallel_size: int = 1Pipeline parallel size for the inference engine. Currently only supported for vLLM.
attr expert_parallel_size
expert_parallel_size: int = 1Expert parallel size for the inference engine.
Currently only supported for vLLM. When set > 1, must equal
data_parallel_size * tensor_parallel_size.
attr data_parallel_size
data_parallel_size: int = 1Data parallel size for the inference engine. Currently only supported for vLLM.
attr vllm_v1_disable_multiproc
vllm_v1_disable_multiproc: bool = TrueCurrently inert.
VLLM_ENABLE_V1_MULTIPROCESSING=0 is set unconditionally whenever VLLM_USE_V1 is absent
from the environment, which makes vLLM scheduling deterministic.
Useful for reproducibility.
attr enable_prefix_caching
enable_prefix_caching: bool = TrueEnable vLLM prefix caching. Can be left at the default in most cases. With remote inference servers, this must match the setting the remote servers were initialized with.
attr enable_chunked_prefill
enable_chunked_prefill: bool = TrueEnable vLLM chunked prefill.
Currently not plumbed through to the engine; set engine_init_kwargs.enable_chunked_prefill
to change it.
attr enable_return_routed_experts
enable_return_routed_experts: bool = FalseReturn per-layer expert routing indices, for rollout router replay (R3) when training an MoE model.
Used together with trainer.policy.megatron_config.moe_enable_routing_replay.
attr max_num_batched_tokens
max_num_batched_tokens: int = 8192vLLM continuous-batching parameter: maximum number of tokens to pack into a batch.
attr enforce_eager
enforce_eager: bool = FalseDisable CUDA graphs. Enabling this trades performance for stability; leaving it off (the default) is faster but may affect convergence for long-running or long-context training jobs.
attr fully_sharded_loras
fully_sharded_loras: bool = Falseattr enable_ray_prometheus_stats
enable_ray_prometheus_stats: bool = TrueEnable Ray Prometheus stats logger for inference engine metrics (vLLM v1 only).
attr gpu_memory_utilization
gpu_memory_utilization: float = 0.8GPU memory utilization for the inference engine.
Only applicable when run_engines_locally=True.
attr offload_kv_for_weight_sync
offload_kv_for_weight_sync: bool = FalseNon-colocated only. Sleep the engine (freeing the KV cache from GPU) during weight
sync so gpu_memory_utilization can be pushed higher without OOMing on the weight-
transfer buffers. On the fully-async trainer, in-flight requests are frozen (KEEP
pause) and, unless trainer.fully_async.clear_kv_cache_on_weight_sync is set, their
KV cache is offloaded to CPU and restored so they resume with no abort or prefill
recompute (at the cost of a GPU<->CPU copy of the KV pool each sync). Requires
non-colocated and non-LoRA weight sync.
attr use_expandable_segments
use_expandable_segments: bool = FalseSet PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True on the inference-engine
processes to reduce fragmentation. Independent of the trainer-side
TrainerConfig.use_expandable_segments. Default False: it is a safe opt-in
on vLLM >= 0.20.1, where the CuMemAllocator auto-disables expandable segments around
its sleep/wake memory pool. On older vLLM, sleep mode + expandable segments is a hard
error, so leave this off.
attr max_num_seqs
max_num_seqs: int = 1024vLLM continuous-batching parameter: maximum number of sequences to pack into a batch.
attr served_model_name
served_model_name: Optional[str] = NoneModel name for HTTP endpoint validation. If set, must be used in the model field of
/chat/completions requests instead of the model path. If None, the model path is used.
attr distributed_executor_backend
distributed_executor_backend: str = 'ray'Distributed executor backend for vLLM. Set to "ray" to use the Ray backend
or "mp" to use the multiprocessing backend (single-node serving only). Per-engine
placement groups are created when "mp" is used.
attr language_model_only
language_model_only: bool = FalseWhen True, pass language_model_only=True to the vLLM engine so that
multimodal models (e.g. Qwen3.5) skip vision encoder initialization.
attr engine_init_kwargs
engine_init_kwargs: Dict[str, Any] = field(default_factory=dict)Pass-through kwargs for the vLLM engine.
Names must match the engine's args. Applied last, so they silently override config-derived
engine args (e.g. tensor_parallel_size).
For HuggingFace config overrides such as RoPE scaling, use
engine_init_kwargs.hf_overrides.rope_parameters and set the matching trainer-side override
with trainer.policy.model_config_kwargs.rope_parameters (FSDP) or
trainer.policy.megatron_config.transformer_config_kwargs.rope_parameters (Megatron). The two
must agree, and are validated against each other.
attr speculative_config
speculative_config: Optional[Dict[str, Any]] = NoneSpeculative-decoding config passed through to vLLM for MTP drafter decoding.
(needs policy.megatron_config.mtp_num_layers > 0 to train mtp). None disables it.
attr external_proxy_url
external_proxy_url: Optional[str] = NoneData-plane URL (load-balanced router) for the new inference layer. Generation requests are sent here.
attr external_server_urls
external_server_urls: Optional[List[str]] = NoneControl-plane URLs (direct backend access) for the new inference layer.
Used to fan out pause/resume, sleep/wake, and weight sync. If external_proxy_url is omitted,
SkyRL starts an internal router over these servers.
attr enable_pd
enable_pd: bool = FalseEnable prefill-decode disaggregation. Requires num_prefill > 0 and num_engines >= 2.
attr num_prefill
num_prefill: int = 0Number of prefill engines when enable_pd=True. Decode engines = num_engines - num_prefill
NOTE: SkyRL counts data parallel workers separately, so the total number of prefill workers will be data_parallel_size * num_prefill.
attr router_init_kwargs
router_init_kwargs: Dict[str, Any] = field(default_factory=dict)Pass-through kwargs applied to RouterArgs for the vllm-router.
Names must match vllm_router.RouterArgs fields (e.g. policy, request_timeout_secs).
class DeltaWeightSyncConfig
DeltaWeightSyncConfig(sync_dir: str, local_checkpoint_dir: Optional[str] = None, publish_staging_dir: Optional[str] = None, max_file_size_in_gb: float = 1.0, cloud_download_workers: int = 4, publish_num_workers: Optional[int] = None, checkpoint_load_format: Literal['vllm_multi_thread_safetensors', 'vllm_fastsafetensors'] = 'vllm_multi_thread_safetensors', multi_thread_safetensors_max_workers: int = 8) -> NoneBases: BaseConfig
Disk/cloud checkpoint-delta weight sync configuration.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
sync_dir | str | Shared directory/URI where the trainer publishes per-version delta payloads. |
local_checkpoint_dir | Optional[str] | Receiver-side directory used to cache patched checkpoint versions. |
publish_staging_dir | Optional[str] | Trainer-side local directory used to stage cloud payload files before upload. |
max_file_size_in_gb | float | Maximum compressed payload file size before starting a new safetensors file. |
cloud_download_workers | int | Maximum number of payload files to download concurrently for gs:// and s3:// sync dirs. |
publish_num_workers | Optional[int] | Number of trainer-side worker threads used to compute and compress delta payloads. |
checkpoint_load_format | Literal['vllm_multi_thread_safetensors', 'vllm_fastsafetensors'] | Receiver reload iterator for the prepared local checkpoint. |
multi_thread_safetensors_max_workers | int | Number of worker threads for vllm_multi_thread_safetensors. |
Source code in skyrl/train/config/config.py:1040-1092
@dataclass
class DeltaWeightSyncConfig(BaseConfig):
"""Disk/cloud checkpoint-delta weight sync configuration."""
sync_dir: str
"""Shared directory/URI where the trainer publishes per-version delta payloads.
Supports local paths, ``gs://`` URIs, and ``s3://`` URIs."""
local_checkpoint_dir: Optional[str] = None
"""Receiver-side directory used to cache patched checkpoint versions.
If unset, resolved in ``__post_init__`` to a ``sync_dir``-derived path under
``/tmp/skyrl_delta_checkpoints``."""
publish_staging_dir: Optional[str] = None
"""Trainer-side local directory used to stage cloud payload files before upload.
If unset, resolved in ``__post_init__`` to a ``sync_dir``-derived path under
``/tmp/skyrl_delta_publish_staging``."""
max_file_size_in_gb: float = 1.0
"""Maximum compressed payload file size before starting a new safetensors file."""
cloud_download_workers: int = 4
"""Maximum number of payload files to download concurrently for ``gs://`` and ``s3://`` sync dirs."""
publish_num_workers: Optional[int] = None
"""Number of trainer-side worker threads used to compute and compress delta payloads.
If unset, the publisher uses ``min(8, os.cpu_count())``."""
checkpoint_load_format: Literal["vllm_multi_thread_safetensors", "vllm_fastsafetensors"] = (
"vllm_multi_thread_safetensors"
)
"""Receiver reload iterator for the prepared local checkpoint.
`vllm_multi_thread_safetensors` loads safetensor files from disk to CPU storage with N parallel workers using vLLM's native safetensors iterator. Tensors are then loaded onto GPU memory iterately.
`vllm_fastsafetensors` loads tensors from safetensor files on disk directly into GPU memory in a highly parallelized way.
This setting is currently not recommended for large models because of large memory requirements.
See: https://github.com/vllm-project/vllm/issues/48644 for more details
"""
multi_thread_safetensors_max_workers: int = 8
"""Number of worker threads for ``vllm_multi_thread_safetensors``."""
def __post_init__(self) -> None:
from skyrl.backends.skyrl_train.weight_sync.delta_checkpoint import (
_default_local_checkpoint_dir,
_default_publish_staging_dir,
)
if self.local_checkpoint_dir is None:
self.local_checkpoint_dir = str(_default_local_checkpoint_dir(self.sync_dir))
if self.publish_staging_dir is None:
self.publish_staging_dir = str(_default_publish_staging_dir(self.sync_dir))from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr sync_dir
sync_dir: strShared directory/URI where the trainer publishes per-version delta payloads.
Supports local paths, gs:// URIs, and s3:// URIs.
attr local_checkpoint_dir
local_checkpoint_dir: Optional[str] = NoneReceiver-side directory used to cache patched checkpoint versions.
If unset, resolved in __post_init__ to a sync_dir-derived path under
/tmp/skyrl_delta_checkpoints.
attr publish_staging_dir
publish_staging_dir: Optional[str] = NoneTrainer-side local directory used to stage cloud payload files before upload.
If unset, resolved in __post_init__ to a sync_dir-derived path under
/tmp/skyrl_delta_publish_staging.
attr max_file_size_in_gb
max_file_size_in_gb: float = 1.0Maximum compressed payload file size before starting a new safetensors file.
attr cloud_download_workers
cloud_download_workers: int = 4Maximum number of payload files to download concurrently for gs:// and s3:// sync dirs.
attr publish_num_workers
publish_num_workers: Optional[int] = NoneNumber of trainer-side worker threads used to compute and compress delta payloads.
If unset, the publisher uses min(8, os.cpu_count()).
attr checkpoint_load_format
checkpoint_load_format: Literal['vllm_multi_thread_safetensors', 'vllm_fastsafetensors'] = 'vllm_multi_thread_safetensors'Receiver reload iterator for the prepared local checkpoint.
vllm_multi_thread_safetensors loads safetensor files from disk to CPU storage with N parallel workers using vLLM's native safetensors iterator. Tensors are then loaded onto GPU memory iterately.
vllm_fastsafetensors loads tensors from safetensor files on disk directly into GPU memory in a highly parallelized way.
This setting is currently not recommended for large models because of large memory requirements.
See: https://github.com/vllm-project/vllm/issues/48644 for more details
attr multi_thread_safetensors_max_workers
multi_thread_safetensors_max_workers: int = 8Number of worker threads for vllm_multi_thread_safetensors.
class GeneratorConfig
GeneratorConfig(inference_engine: InferenceEngineConfig = InferenceEngineConfig(), n_samples_per_prompt: int = 5, batched: bool = False, max_turns: int = 1, max_input_length: Optional[int] = None, chat_template: ChatTemplateConfig = ChatTemplateConfig(), chat_template_kwargs: Dict[str, Any] = dict(), sampling_params: SamplingParams = SamplingParams(), use_conversation_multi_turn: bool = True, append_eos_token_after_stop_str_in_multi_turn: bool = True, eval_sampling_params: Optional[SamplingParams] = None, eval_n_samples_per_prompt: int = 1, zero_reward_on_non_stop: bool = False, use_cache_salt: bool = True, apply_overlong_filtering: bool = False, step_wise_trajectories: bool = False, vision_language_generator: bool = False, merge_stepwise_output: bool = False) -> NoneBases: BaseConfig
Configuration for generation behavior.
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
inference_engine | InferenceEngineConfig | |
n_samples_per_prompt | int | Number of samples to generate per prompt. |
batched | bool | Use batched inference. Only applicable for single-turn generation. |
max_turns | int | Maximum number of turns for multi-turn RL generation. |
max_input_length | Optional[int] | Max generator input length. |
chat_template | ChatTemplateConfig | Custom chat template configuration, if needed. |
chat_template_kwargs | Dict[str, Any] | Kwargs passed to tokenizer.apply_chat_template. |
sampling_params | SamplingParams | Sampling parameters used during the trajectory generation phase. |
use_conversation_multi_turn | bool | If True, each multi-turn model response and env observation is stored in a separate assistant/user message. |
append_eos_token_after_stop_str_in_multi_turn | bool | When use_conversation_multi_turn=True and sampling_params.stop is set, append |
eval_sampling_params | Optional[SamplingParams] | Separate sampling params for evaluation. If None, then it defaults to SamplingParams(temperature=0.0, max_generate_length=generator.sampling_params.max_generate_length). |
eval_n_samples_per_prompt | int | Number of samples to generate per prompt during evaluation. |
zero_reward_on_non_stop | bool | Set reward to 0 when stop_reason is not "stop" (i.e., generation was truncated or aborted). |
use_cache_salt | bool | Salt vLLM's prefix cache with the policy version so cache blocks are only shared across trajectories that started |
apply_overlong_filtering | bool | Apply DAPO Overlong Filtering: mask out all tokens in the loss mask for trajectories that |
step_wise_trajectories | bool | Return outputs step-wise. |
vision_language_generator | bool | If True, use SkyRLVLMGymGenerator (multi-modal text+image rollouts) |
merge_stepwise_output | bool | When True (and step_wise_trajectories is True), apply prefix-aware merging |
Source code in skyrl/train/config/config.py:1220-1283
@dataclass
class GeneratorConfig(BaseConfig):
"""Configuration for generation behavior."""
inference_engine: InferenceEngineConfig = field(default_factory=InferenceEngineConfig)
n_samples_per_prompt: int = 5
"""Number of samples to generate per prompt.
The total size of the training batch is ``trainer.train_batch_size * n_samples_per_prompt``."""
batched: bool = False
"""Use batched inference. Only applicable for single-turn generation."""
max_turns: int = 1
"""Maximum number of turns for multi-turn RL generation."""
max_input_length: Optional[int] = None
"""Max generator input length.
For single-turn generation this can equal ``trainer.max_prompt_length`` (the initial prompt length); for multi-turn
it is the maximum input length used for the conversation at each turn. Defaults to ``trainer.max_prompt_length``."""
chat_template: ChatTemplateConfig = field(default_factory=ChatTemplateConfig)
"""Custom chat template configuration, if needed."""
chat_template_kwargs: Dict[str, Any] = field(default_factory=dict)
"""Kwargs passed to ``tokenizer.apply_chat_template``.
Requires non-batched generation: a non-empty value with ``batched=True`` raises."""
sampling_params: SamplingParams = field(default_factory=SamplingParams)
"""Sampling parameters used during the trajectory generation phase."""
use_conversation_multi_turn: bool = True
"""If ``True``, each multi-turn model response and env observation is stored in a separate assistant/user message.
If ``False``, they are appended to the original assistant response as-is in token space and generation continues
(after removing any EOS token in the response). Models can be sensitive to chat-history format (as observed in
SkyRL-SQL), so ``False`` gives full control over the exact tokens added after environment interaction."""
append_eos_token_after_stop_str_in_multi_turn: bool = True
"""When ``use_conversation_multi_turn=True`` and ``sampling_params.stop`` is set, append
``eos_token_id`` to generations that end with a matched stop string."""
eval_sampling_params: Optional[SamplingParams] = None
"""Separate sampling params for evaluation. If ``None``, then it defaults to ``SamplingParams(temperature=0.0, max_generate_length=generator.sampling_params.max_generate_length)``."""
eval_n_samples_per_prompt: int = 1
"""Number of samples to generate per prompt during evaluation."""
zero_reward_on_non_stop: bool = False
"""Set reward to 0 when ``stop_reason`` is not ``"stop"`` (i.e., generation was truncated or aborted).
Useful with format rewards, where an unfinished response should not earn format credit.
Applies to all environments."""
use_cache_salt: bool = True
"""Salt vLLM's prefix cache with the policy version so cache blocks are only shared across trajectories that started
with the same policy weight version. The salt is keyed on the engine's weight version, captured at the start of each
``generate`` call. Matters for fully-async RL; a no-op for synchronous training (which resets the
cache each sync) and when prefix caching is off, so it is safe to leave on by default."""
apply_overlong_filtering: bool = False
"""Apply DAPO Overlong Filtering: mask out all tokens in the loss mask for trajectories that
exceed max length (truncated, no EOS token)."""
step_wise_trajectories: bool = False
"""Return outputs step-wise.
When ``True``, multi-turn generations are returned with each turn's (prompt, response) pair as a separate
trajectory. Advantages are computed from the last step of each trajectory and propagated to the previous steps. See
https://docs.skyrl.ai/docs/tutorials/step-wise-training"""
vision_language_generator: bool = False
"""If True, use SkyRLVLMGymGenerator (multi-modal text+image rollouts)"""
merge_stepwise_output: bool = False
"""When True (and step_wise_trajectories is True), apply prefix-aware merging
to collapse multi-turn step-wise sequences into single sequences before training."""
def __post_init__(self):
if self.eval_sampling_params is None:
self.eval_sampling_params = SamplingParams(
temperature=0.0, max_generate_length=self.sampling_params.max_generate_length
)from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr inference_engine
inference_engine: InferenceEngineConfig = field(default_factory=InferenceEngineConfig)attr n_samples_per_prompt
n_samples_per_prompt: int = 5Number of samples to generate per prompt.
The total size of the training batch is trainer.train_batch_size * n_samples_per_prompt.
attr batched
batched: bool = FalseUse batched inference. Only applicable for single-turn generation.
attr max_turns
max_turns: int = 1Maximum number of turns for multi-turn RL generation.
attr max_input_length
max_input_length: Optional[int] = NoneMax generator input length.
For single-turn generation this can equal trainer.max_prompt_length (the initial prompt length); for multi-turn
it is the maximum input length used for the conversation at each turn. Defaults to trainer.max_prompt_length.
attr chat_template
chat_template: ChatTemplateConfig = field(default_factory=ChatTemplateConfig)Custom chat template configuration, if needed.
attr chat_template_kwargs
chat_template_kwargs: Dict[str, Any] = field(default_factory=dict)Kwargs passed to tokenizer.apply_chat_template.
Requires non-batched generation: a non-empty value with batched=True raises.
attr sampling_params
sampling_params: SamplingParams = field(default_factory=SamplingParams)Sampling parameters used during the trajectory generation phase.
attr use_conversation_multi_turn
use_conversation_multi_turn: bool = TrueIf True, each multi-turn model response and env observation is stored in a separate assistant/user message.
If False, they are appended to the original assistant response as-is in token space and generation continues
(after removing any EOS token in the response). Models can be sensitive to chat-history format (as observed in
SkyRL-SQL), so False gives full control over the exact tokens added after environment interaction.
attr append_eos_token_after_stop_str_in_multi_turn
append_eos_token_after_stop_str_in_multi_turn: bool = TrueWhen use_conversation_multi_turn=True and sampling_params.stop is set, append
eos_token_id to generations that end with a matched stop string.
attr eval_sampling_params
eval_sampling_params: Optional[SamplingParams] = NoneSeparate sampling params for evaluation. If None, then it defaults to SamplingParams(temperature=0.0, max_generate_length=generator.sampling_params.max_generate_length).
attr eval_n_samples_per_prompt
eval_n_samples_per_prompt: int = 1Number of samples to generate per prompt during evaluation.
attr zero_reward_on_non_stop
zero_reward_on_non_stop: bool = FalseSet reward to 0 when stop_reason is not "stop" (i.e., generation was truncated or aborted).
Useful with format rewards, where an unfinished response should not earn format credit.
Applies to all environments.
attr use_cache_salt
use_cache_salt: bool = TrueSalt vLLM's prefix cache with the policy version so cache blocks are only shared across trajectories that started
with the same policy weight version. The salt is keyed on the engine's weight version, captured at the start of each
generate call. Matters for fully-async RL; a no-op for synchronous training (which resets the
cache each sync) and when prefix caching is off, so it is safe to leave on by default.
attr apply_overlong_filtering
apply_overlong_filtering: bool = FalseApply DAPO Overlong Filtering: mask out all tokens in the loss mask for trajectories that exceed max length (truncated, no EOS token).
attr step_wise_trajectories
step_wise_trajectories: bool = FalseReturn outputs step-wise.
When True, multi-turn generations are returned with each turn's (prompt, response) pair as a separate
trajectory. Advantages are computed from the last step of each trajectory and propagated to the previous steps. See
https://docs.skyrl.ai/docs/tutorials/step-wise-training
attr vision_language_generator
vision_language_generator: bool = FalseIf True, use SkyRLVLMGymGenerator (multi-modal text+image rollouts)
attr merge_stepwise_output
merge_stepwise_output: bool = FalseWhen True (and step_wise_trajectories is True), apply prefix-aware merging to collapse multi-turn step-wise sequences into single sequences before training.
Environment
class EnvironmentConfig
EnvironmentConfig(env_class: str = 'gsm8k', skyrl_gym: SkyRLGymConfig = SkyRLGymConfig()) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
env_class | str | |
skyrl_gym | SkyRLGymConfig |
Source code in skyrl/train/config/config.py:1306-1309
@dataclass
class EnvironmentConfig(BaseConfig):
env_class: str = "gsm8k"
skyrl_gym: SkyRLGymConfig = field(default_factory=SkyRLGymConfig)from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr env_class
env_class: str = 'gsm8k'attr skyrl_gym
skyrl_gym: SkyRLGymConfig = field(default_factory=SkyRLGymConfig)class SkyRLGymConfig
SkyRLGymConfig(max_env_workers: int = 32, text2sql: Text2SQLEnvConfig = Text2SQLEnvConfig(), llm_as_a_judge: GSM8kLLMJudgeEnvConfig = GSM8kLLMJudgeEnvConfig(), search: SearchEnvConfig = SearchEnvConfig()) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
| Name | Type | Description |
|---|---|---|
max_env_workers | int | |
text2sql | Text2SQLEnvConfig | |
llm_as_a_judge | GSM8kLLMJudgeEnvConfig | |
search | SearchEnvConfig |
Source code in skyrl/train/config/config.py:1298-1303
@dataclass
class SkyRLGymConfig(BaseConfig):
max_env_workers: int = 32
text2sql: Text2SQLEnvConfig = field(default_factory=Text2SQLEnvConfig)
llm_as_a_judge: GSM8kLLMJudgeEnvConfig = field(default_factory=GSM8kLLMJudgeEnvConfig)
search: SearchEnvConfig = field(default_factory=SearchEnvConfig)from_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr max_env_workers
max_env_workers: int = 32attr text2sql
text2sql: Text2SQLEnvConfig = field(default_factory=Text2SQLEnvConfig)attr llm_as_a_judge
llm_as_a_judge: GSM8kLLMJudgeEnvConfig = field(default_factory=GSM8kLLMJudgeEnvConfig)attr search
search: SearchEnvConfig = field(default_factory=SearchEnvConfig)class GSM8kLLMJudgeEnvConfig
GSM8kLLMJudgeEnvConfig(model: str = 'gpt-4o-mini', base_url: Optional[str] = None) -> NoneBases: BaseConfig
Functions:
| Name | Description |
|---|---|
from_dict_config | Construct a typed BaseConfig from a Hydra DictConfig. |
Attributes:
Source code in skyrl/train/config/config.py:1292-1295
@dataclass
class GSM8kLLMJudgeEnvConfig(BaseConfig):
model: str = "gpt-4o-mini"
base_url: Optional[str] = Nonefrom_dict_config
from_dict_config(cfg: DictConfig) -> BaseConfigConstruct a typed BaseConfig from a Hydra DictConfig.
attr model
model: str = 'gpt-4o-mini'attr base_url
base_url: Optional[str] = None