feat(train): add dry_run=True to train()#6027
Conversation
164a14c to
7b06162
Compare
008794d to
16c783a
Compare
Add dry_run parameter to all trainers (SFT, DPO, RLVR, RLAIF). When dry_run=True: - All existing validation runs inline (IAM role, hyperparameters, recipe constraints, infrastructure availability) - Returns None without submitting a job or consuming compute - Raises with clear error message on validation failure Additionally, validate_data_path_exists() is called unconditionally (regardless of dry_run) before job submission to catch non-existent S3 paths or dataset ARNs early. Design follows nova-forge-sdk pattern: validation always runs as part of the normal code path, dry_run short-circuits before the actual TrainingJob.create API call. Changes: - data_utils.py: add validate_data_path_exists() utility (S3 + DataSet ARN) - base_trainer.py: add dry_run to abstract train(), _train_serverful_smtj(), and _train_hyperpod() - sft/dpo/rlvr/rlaif_trainer.py: add dry_run param, pass through to shared methods, short-circuit serverless path - Notebook examples added to SFT, DPO, RLVR, RLAIF notebooks - Unit tests added to existing test files - Integration test added
f6bd43d to
8a3936b
Compare
Add dry_run parameter to BaseEvaluator.evaluate() and all subclasses (BenchMarkEvaluator, CustomScorerEvaluator, LLMAsJudgeEvaluator). When dry_run=True: - All existing validation runs (IAM role, model resolution, recipe, pipeline rendering) - Dataset S3 path / DataSet ARN validated via validate_data_path_exists() - Returns None without submitting a pipeline execution - Raises on validation failure Dataset validation runs unconditionally (not just during dry_run) for CustomScorerEvaluator and LLMAsJudgeEvaluator which accept user datasets. Changes: - base_evaluator.py: add dry_run to evaluate() signature - benchmark_evaluator.py: add dry_run, short-circuit before _start_execution() - custom_scorer_evaluator.py: add dry_run, validate dataset, short-circuit - llm_as_judge_evaluator.py: add dry_run, validate dataset, short-circuit - Notebook examples added to benchmark, custom_scorer, llm_as_judge notebooks
8a3936b to
6375702
Compare
| raise FileLoadError(f"Failed to read file {file_path}: {e}") | ||
|
|
||
|
|
||
| def validate_data_path_exists( |
There was a problem hiding this comment.
Will have to check this but some trainers may also support a Dataset object. In that case the arn is stored as dataset.arn.
| ValueError: If the path does not exist or is inaccessible. | ||
| """ | ||
| # Handle SageMaker hub-content DataSet ARNs | ||
| if data_path.startswith("arn:aws:sagemaker:") and "/DataSet/" in data_path: |
There was a problem hiding this comment.
Can we just call _validate_dataset_arn_exists that's defined below to avoid duplicate code?
|
|
||
|
|
||
| # Validate dataset path exists | ||
| if hasattr(self, 'dataset') and self.dataset and isinstance(self.dataset, str): |
There was a problem hiding this comment.
Will have to check if Dataset object is also supported by Evaluator.
| @_telemetry_emitter(feature=Feature.MODEL_CUSTOMIZATION, func_name="RLVRTrainer.train") | ||
| def train(self, training_dataset: Optional[Union[str, DataSet]] = None, | ||
| validation_dataset: Optional[Union[str, DataSet]] = None, wait: bool = True, wait_timeout: Optional[int] = None, poll: int = 5): | ||
| validation_dataset: Optional[Union[str, DataSet]] = None, wait: bool = True, wait_timeout: Optional[int] = None, poll: int = 5, dry_run: bool = False): |
There was a problem hiding this comment.
Does CPTTrainer also require additional dry_run: bool parameter?
| ]}, | ||
| ] | ||
| body = "\n".join(json.dumps(s) for s in samples) | ||
| s3.put_object(Bucket=bucket, Key=DATASET_KEY, Body=body.encode("utf-8")) |
There was a problem hiding this comment.
nit: Why create and delete on every test run. Just check if the object exists at that path. If it doesn't, create it.
| The MLflow experiment name for organizing runs. | ||
| mlflow_run_name (Optional[str]): | ||
| The MLflow run name for this training job. | ||
| training_dataset (Optional[Union[str, DataSet]]): |
There was a problem hiding this comment.
Yes, we support Dataset object as well. So dry_run needs to support Dataset object too. Should be an easy change IMO.
| trainer.train(dry_run=True) | ||
|
|
||
|
|
||
| class TestDryRunPassesWithValidInputs: |
There was a problem hiding this comment.
I would consider adding a test for serverful and hyperpod too. To make sure dry_runs in def train_hyperpod and train_serverful are also covered.
| return None | ||
|
|
||
| # Execute training | ||
| model_trainer.train( |
There was a problem hiding this comment.
Why didn't we add dry_run feature to Model trainer class. Customers can submit training jobs using model_trainer directly as well? I'm ok with not adding it if there's a good reason.
|
|
||
|
|
||
| @pytest.fixture(scope="module") | ||
| def nonexistent_dataset(sagemaker_session): |
There was a problem hiding this comment.
Should run the test with nonexistent_dataset_s3 and nonexistent_dataset_obj (ie Dataset object or Dataset arn)
Summary
Add
dry_run=Trueparameter to all trainers (SFT, DPO, RLVR, RLAIF) and evaluators (BenchMark, CustomScorer, LLMAsJudge). Whendry_run=True, all validation runs but no job is submitted and no compute is consumed.What it does
validate_data_path_exists()validates S3 URIs and DataSet ARNs unconditionally before submissiondry_run=Trueshort-circuits before the API call, returningNoneChanges
Commit 1:
feat(train): add dry_run=True to train()data_utils.py— newvalidate_data_path_exists()(S3 vialist_objects_v2, DataSet ARN viadescribe_hub_content)base_trainer.py— adddry_runtotrain(),_train_serverful_smtj(),_train_hyperpod()sft/dpo/rlvr/rlaif_trainer.py— adddry_run, validate data paths, short-circuittest_dry_run_integration.py)Commit 2:
feat(evaluate): add dry_run=True to evaluate()base_evaluator.py— adddry_runtoevaluate()signaturebenchmark/custom_scorer/llm_as_judge_evaluator.py— adddry_run, validate dataset paths (custom scorer + LLM-as-judge), short-circuit before_start_execution()Testing
result is None, verifies no job created via SageMaker APIIssue #, if available:
Description of changes:
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.