Skip to content

Document Behavior of optuna.pruners.PercentilePruner, optuna.pruners.SuccessiveHalvingPruner and optuna.pruners.HyperbandPruner #6092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

ParagEkbote
Copy link
Contributor

Motivation

Fixes #5202

I have added documentation of how the Percentile Pruner, SuccessiveHalvingPruner and HyperbandPruner handles Nan values.

It is important to note that we are using synthetic dataset for testing.

Could you please review?

cc: @HideakiImamura

Description of the changes

I have used the following scripts to test it out:

  1. Percentile Pruner
import optuna
import numpy as np
import logging
import sys
from optuna.pruners import SuccessiveHalvingPruner

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def nan_objective(trial):
    """An objective function that returns NaN for every 3rd trial."""
    trial_number = trial.number
    
    # Every 3rd trial returns NaN
    if trial_number % 3 == 0:
        logger.info(f"Trial {trial_number}: Returning NaN")
        return float('nan')
    else:
        value = trial.suggest_float('x', -10, 10)
        result = value ** 2  # Simple quadratic function
        logger.info(f"Trial {trial_number}: Returning {result}")
        return result

def partial_nan_objective(trial):
    """An objective function where some intermediate values are NaN,
    specifically designed to test SuccessiveHalvingPruner."""
    x = trial.suggest_float('x', -10, 10)
    n_steps = 10
    
    # Report intermediate values
    for step in range(n_steps):
        # Calculate a result (simple quadratic plus step index)
        raw_value = x ** 2 + step
        
        # Determine if this step should report NaN based on different patterns
        report_nan = False
        
        # Pattern 1: Every 3rd step is NaN
        if step % 3 == 0:
            report_nan = True
            
        # Pattern 2: For trials divisible by 5, make later steps NaN
        if trial.number % 5 == 0 and step > 5:
            report_nan = True
            
        # Report value
        if report_nan:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting NaN")
            trial.report(float('nan'), step)
        else:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting {raw_value}")
            trial.report(raw_value, step)
        
        # Check if the trial should be pruned
        if trial.should_prune():
            logger.info(f"Trial {trial.number} pruned at step {step}")
            raise optuna.exceptions.TrialPruned()
    
    return x ** 2

def pruning_pattern_objective(trial):
    """Objective function with specific NaN patterns at pruning-relevant steps."""
    x = trial.suggest_float('x', -10, 10)
    
    # These are the reduction factors we'll test
    reduction_factors = [3, 4]
    
    for rf in reduction_factors:
    
        max_step = rf ** 3  # Go up to rf^3 steps
        steps = []
        val = 0
        while val <= max_step:
            steps.append(val)
            if val == 0:
                val = 1
            else:
                val *= rf
        
        # Run a mini-test with this reduction factor
        logger.info(f"\n--- Testing with reduction_factor={rf} ---")
        study = optuna.create_study(
            pruner=SuccessiveHalvingPruner(
                min_resource=1,
                reduction_factor=rf,
                min_early_stopping_rate=0
            ),
            direction="minimize"
        )
        
        # Create a custom objective for this reduction factor
        def rf_objective(trial):
            value = trial.suggest_float('x', -10, 10)
            result = value ** 2
            
            for i, step in enumerate(steps):
                # For some trials, introduce NaNs at specific points
                if trial.number % 4 == 0 and i % 2 == 0:  # Every 4th trial, every other checkpoint
                    logger.info(f"Trial {trial.number}, Step {step}: Reporting NaN")
                    trial.report(float('nan'), step)
                else:
                    # Add some noise to the result based on step
                    step_result = result + step * 0.1
                    logger.info(f"Trial {trial.number}, Step {step}: Reporting {step_result}")
                    trial.report(step_result, step)
                
                if trial.should_prune():
                    logger.info(f"Trial {trial.number} pruned at step {step}")
                    raise optuna.exceptions.TrialPruned()
            
            return result
        
        study.optimize(rf_objective, n_trials=12)
        
        # Print results
        logger.info(f"Results for reduction_factor={rf}:")
        for trial in study.trials:
            logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
            if trial.intermediate_values:
                logger.info(f"  Intermediate values: {trial.intermediate_values}")

def test_successive_halving_pruner_with_nan_values():
    """Test how SuccessiveHalvingPruner handles NaN values in different configurations."""
    
    # Test 1: Basic study with NaN return values
    logger.info("\n=== Test 1: Basic study with NaN final values ===")
    study1 = optuna.create_study(
        pruner=SuccessiveHalvingPruner(min_resource=1, reduction_factor=2, min_early_stopping_rate=0),
        direction="minimize"
    )
    study1.optimize(nan_objective, n_trials=10)
    
    # Print results
    logger.info("Completed trials:")
    for trial in study1.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
    
    # Test 2: Study with NaN intermediate values
    logger.info("\n=== Test 2: Study with NaN intermediate values ===")
    study2 = optuna.create_study(
        pruner=SuccessiveHalvingPruner(min_resource=1, reduction_factor=2, min_early_stopping_rate=0),
        direction="minimize"
    )
    study2.optimize(partial_nan_objective, n_trials=10)
    
    # Print results
    logger.info("Completed trials with intermediate values:")
    for trial in study2.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
        if trial.intermediate_values:
            logger.info(f"  Intermediate values: {trial.intermediate_values}")
    
    # Test 3: Study with higher reduction factor
    logger.info("\n=== Test 3: Study with higher reduction factor ===")
    study3 = optuna.create_study(
        pruner=SuccessiveHalvingPruner(min_resource=1, reduction_factor=4, min_early_stopping_rate=0),
        direction="minimize"
    )
    study3.optimize(partial_nan_objective, n_trials=10)
    
    # Print results
    logger.info("Completed trials with higher reduction factor:")
    for trial in study3.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
        if trial.intermediate_values:
            logger.info(f"  Intermediate values: {trial.intermediate_values}")
    
    # Test 4: Test specific pruning patterns with NaN values
    logger.info("\n=== Test 4: Testing specific pruning patterns with NaN values ===")
    pruning_pattern_objective(trial)  # No trial needed here as we create studies inside

if __name__ == "__main__":
    test_successive_halving_pruner_with_nan_values()
  1. SuccessiveHalvingPruner
import optuna
import numpy as np
import logging
import sys
from optuna.pruners import SuccessiveHalvingPruner

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def nan_objective(trial):
    """An objective function that returns NaN for every 3rd trial."""
    trial_number = trial.number
    
    # Every 3rd trial returns NaN
    if trial_number % 3 == 0:
        logger.info(f"Trial {trial_number}: Returning NaN")
        return float('nan')
    else:
        value = trial.suggest_float('x', -10, 10)
        result = value ** 2  # Simple quadratic function
        logger.info(f"Trial {trial_number}: Returning {result}")
        return result

def partial_nan_objective(trial):
    """An objective function where some intermediate values are NaN,
    specifically designed to test SuccessiveHalvingPruner."""
    x = trial.suggest_float('x', -10, 10)
    n_steps = 10
    
    # Report intermediate values
    for step in range(n_steps):
        # Calculate a result (simple quadratic plus step index)
        raw_value = x ** 2 + step
        
        # Determine if this step should report NaN based on different patterns
        report_nan = False
        
        # Pattern 1: Every 3rd step is NaN
        if step % 3 == 0:
            report_nan = True
            
        # Pattern 2: For trials divisible by 5, make later steps NaN
        if trial.number % 5 == 0 and step > 5:
            report_nan = True
            
        # Report value
        if report_nan:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting NaN")
            trial.report(float('nan'), step)
        else:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting {raw_value}")
            trial.report(raw_value, step)
        
        # Check if the trial should be pruned
        if trial.should_prune():
            logger.info(f"Trial {trial.number} pruned at step {step}")
            raise optuna.exceptions.TrialPruned()
    
    return x ** 2

def pruning_pattern_objective(trial):
    """Objective function with specific NaN patterns at pruning-relevant steps."""
    x = trial.suggest_float('x', -10, 10)
    
    # These are the reduction factors we'll test
    reduction_factors = [3, 4]
    
    for rf in reduction_factors:
        # Create steps that align with SuccessiveHalvingPruner's expected checkpoints
        # For reduction_factor=3, these would be [0, 1, 3, 9, 27, ...]
        # For reduction_factor=4, these would be [0, 1, 4, 16, 64, ...]
        max_step = rf ** 3  # Go up to rf^3 steps
        steps = []
        val = 0
        while val <= max_step:
            steps.append(val)
            if val == 0:
                val = 1
            else:
                val *= rf
        
        # Run a mini-test with this reduction factor
        logger.info(f"\n--- Testing with reduction_factor={rf} ---")
        study = optuna.create_study(
            pruner=SuccessiveHalvingPruner(
                min_resource=1,
                reduction_factor=rf,
                min_early_stopping_rate=0
            ),
            direction="minimize"
        )
        
        # Create a custom objective for this reduction factor
        def rf_objective(trial):
            value = trial.suggest_float('x', -10, 10)
            result = value ** 2
            
            for i, step in enumerate(steps):
                # For some trials, introduce NaNs at specific points
                if trial.number % 4 == 0 and i % 2 == 0:  # Every 4th trial, every other checkpoint
                    logger.info(f"Trial {trial.number}, Step {step}: Reporting NaN")
                    trial.report(float('nan'), step)
                else:
                    # Add some noise to the result based on step
                    step_result = result + step * 0.1
                    logger.info(f"Trial {trial.number}, Step {step}: Reporting {step_result}")
                    trial.report(step_result, step)
                
                if trial.should_prune():
                    logger.info(f"Trial {trial.number} pruned at step {step}")
                    raise optuna.exceptions.TrialPruned()
            
            return result
        
        study.optimize(rf_objective, n_trials=12)
        
        # Print results
        logger.info(f"Results for reduction_factor={rf}:")
        for trial in study.trials:
            logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
            if trial.intermediate_values:
                logger.info(f"  Intermediate values: {trial.intermediate_values}")

def test_successive_halving_pruner_with_nan_values():
    """Test how SuccessiveHalvingPruner handles NaN values in different configurations."""
    
    # Test 1: Basic study with NaN return values
    logger.info("\n=== Test 1: Basic study with NaN final values ===")
    study1 = optuna.create_study(
        pruner=SuccessiveHalvingPruner(min_resource=1, reduction_factor=2, min_early_stopping_rate=0),
        direction="minimize"
    )
    study1.optimize(nan_objective, n_trials=10)
    
    # Print results
    logger.info("Completed trials:")
    for trial in study1.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
    
    # Test 2: Study with NaN intermediate values
    logger.info("\n=== Test 2: Study with NaN intermediate values ===")
    study2 = optuna.create_study(
        pruner=SuccessiveHalvingPruner(min_resource=1, reduction_factor=2, min_early_stopping_rate=0),
        direction="minimize"
    )
    study2.optimize(partial_nan_objective, n_trials=10)
    
    # Print results
    logger.info("Completed trials with intermediate values:")
    for trial in study2.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
        if trial.intermediate_values:
            logger.info(f"  Intermediate values: {trial.intermediate_values}")
    
    # Test 3: Study with higher reduction factor
    logger.info("\n=== Test 3: Study with higher reduction factor ===")
    study3 = optuna.create_study(
        pruner=SuccessiveHalvingPruner(min_resource=1, reduction_factor=4, min_early_stopping_rate=0),
        direction="minimize"
    )
    study3.optimize(partial_nan_objective, n_trials=10)
    
    # Print results
    logger.info("Completed trials with higher reduction factor:")
    for trial in study3.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
        if trial.intermediate_values:
            logger.info(f"  Intermediate values: {trial.intermediate_values}")
    
    # Test 4: Test specific pruning patterns with NaN values
    logger.info("\n=== Test 4: Testing specific pruning patterns with NaN values ===")
    pruning_pattern_objective(trial)  # No trial needed here as we create studies inside

if __name__ == "__main__":
    test_successive_halving_pruner_with_nan_values()
  1. HyperbandPruner
import optuna
import numpy as np
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def test_hyperband_with_nan_final_values():
    """Test 1: Basic study with NaN final values"""
    logger.info("\n=== Test 1: HyperbandPruner with NaN final values ===")
    
    def objective(trial):
        x = trial.suggest_float("x", -10, 10)
        # Return NaN for specific trials
        if trial.number % 4 == 0:
            logger.info(f"Trial {trial.number}: Returning NaN")
            return float('nan')
        
        value = (x - 0)**2
        logger.info(f"Trial {trial.number}: Returning {value}")
        return value
    
    study = optuna.create_study(
        pruner=optuna.pruners.HyperbandPruner(
            min_resource=1,
            max_resource=10,
            reduction_factor=3
        ),
        direction="minimize"
    )
    
    try:
        study.optimize(objective, n_trials=10)
    except Exception as e:
        logger.error(f"Optimization failed: {e}")
    
    logger.info("Completed trials:")
    for trial in study.trials:
        logger.info(f"Trial {trial.number}: State={trial.state.value}, Value={trial.value}")

def test_hyperband_with_nan_intermediate_values():
    """Test 2: Study with NaN intermediate values"""
    logger.info("\n=== Test 2: HyperbandPruner with NaN intermediate values ===")
    
    def objective(trial):
        x = trial.suggest_float("x", -10, 10)
        final_value = (x - 0)**2
        
        for step in range(10):
            # Report NaN at specific steps
            if step % 3 == 0:
                value_to_report = float('nan')
            else:
                value_to_report = final_value + step
            
            logger.info(f"Trial {trial.number}, Step {step}: Reporting {value_to_report}")
            trial.report(value_to_report, step)
            
            if trial.should_prune():
                logger.info(f"Trial {trial.number} pruned at step {step}")
                raise optuna.TrialPruned()
        
        return final_value
    
    study = optuna.create_study(
        pruner=optuna.pruners.HyperbandPruner(
            min_resource=1,
            max_resource=10,
            reduction_factor=3
        ),
        direction="minimize"
    )
    
    try:
        study.optimize(objective, n_trials=10)
    except Exception as e:
        logger.error(f"Optimization failed: {e}")
    
    logger.info("Completed trials with intermediate values:")
    for trial in study.trials:
        logger.info(f"Trial {trial.number}: State={trial.state.value}, Value={trial.value}")
        logger.info(f"  Intermediate values: {trial.intermediate_values}")

if __name__ == "__main__":
    test_hyperband_with_nan_final_values()
    test_hyperband_with_nan_intermediate_values()

@nabenabe0928
Copy link
Contributor

To reviewers, please note this PR:

At first glance, the changes in this PR do not follow the pattern in the previous PR.

@HideakiImamura
Copy link
Member

@gen740 @kAIto47802 @sawa3030 Could you review this PR?

@sawa3030
Copy link
Collaborator

As @nabenabe0928 pointed out, I think it would be better to follow the approach in #6055 by at least addressing the following two points: what would happen if all intermediate values are NaN , and how typical NaN values are handled.

@y0z y0z added the document Documentation related. label Jun 4, 2025
@nabenabe0928
Copy link
Contributor

@ParagEkbote
Are you still down for the update?

@ParagEkbote
Copy link
Contributor Author

I apologize for not updating the PR. I was a bit busy and in the following week, I will update the PR as suggested.

cc: @nabenabe0928

@ParagEkbote
Copy link
Contributor Author

I'd like to thank the reviewers for their patience :)

I have updated the docs as per the previous PR, the updated scripts are:

  1. Percentile Pruner:
import optuna
import numpy as np
import logging
import sys

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def nan_objective(trial):
    trial_number = trial.number
    if trial_number % 3 == 0:
        logger.info(f"Trial {trial_number}: Returning NaN")
        return float('nan')
    else:
        value = trial.suggest_float('x', -10, 10)
        result = value ** 2
        logger.info(f"Trial {trial_number}: Returning {result}")
        return result

def partial_nan_objective(trial):
    x = trial.suggest_float('x', -10, 10)
    for step in range(10):
        value = x ** 2 + step
        if step % 3 == 0:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting NaN")
            trial.report(float('nan'), step)
        else:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting {value}")
            trial.report(value, step)
        if trial.should_prune():
            logger.info(f"Trial {trial.number} pruned at step {step}")
            raise optuna.exceptions.TrialPruned()
    return x ** 2

def test_percentile_pruner_with_nan_values():
    logger.info("\n=== Test 1: Basic study with NaN final values ===")
    study1 = optuna.create_study(
        pruner=optuna.pruners.PercentilePruner(percentile=25.0, n_startup_trials=0, n_warmup_steps=0),
        direction="minimize"
    )
    study1.optimize(nan_objective, n_trials=10)

    logger.info("Completed trials:")
    for trial in study1.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")

    logger.info("\n=== Test 2: Study with NaN intermediate values ===")
    study2 = optuna.create_study(
        pruner=optuna.pruners.PercentilePruner(percentile=25.0, n_startup_trials=5, n_warmup_steps=2),
        direction="minimize"
    )
    study2.optimize(partial_nan_objective, n_trials=10)

    logger.info("Completed trials with intermediate values:")
    for trial in study2.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
        if trial.intermediate_values:
            logger.info(f"  Intermediate values: {trial.intermediate_values}")

if __name__ == "__main__":
    test_percentile_pruner_with_nan_values()
  1. SuccessiveHalving Pruner:
import optuna
import numpy as np
import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def nan_objective(trial):
    if trial.number % 3 == 0:
        logger.info(f"Trial {trial.number}: Returning NaN")
        return float('nan')
    value = trial.suggest_float('x', -10, 10)
    result = value ** 2
    logger.info(f"Trial {trial.number}: Returning {result}")
    return result

def partial_nan_objective(trial):
    x = trial.suggest_float('x', -10, 10)
    for step in range(10):
        value = x ** 2 + step
        if step % 3 == 0:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting NaN")
            trial.report(float('nan'), step)
        else:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting {value}")
            trial.report(value, step)
        if trial.should_prune():
            logger.info(f"Trial {trial.number} pruned at step {step}")
            raise optuna.exceptions.TrialPruned()
    return x ** 2

def test_successive_halving_with_nan_values():
    logger.info("\n=== Test 1: SuccessiveHalving with NaN final values ===")
    study1 = optuna.create_study(
        pruner=optuna.pruners.SuccessiveHalvingPruner(min_resource=1, reduction_factor=2),
        direction="minimize"
    )
    study1.optimize(nan_objective, n_trials=10)

    logger.info("Completed trials:")
    for trial in study1.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")

    logger.info("\n=== Test 2: Intermediate NaNs with SuccessiveHalving ===")
    study2 = optuna.create_study(
        pruner=optuna.pruners.SuccessiveHalvingPruner(min_resource=1, reduction_factor=2),
        direction="minimize"
    )
    study2.optimize(partial_nan_objective, n_trials=10)

    logger.info("Completed trials:")
    for trial in study2.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
        if trial.intermediate_values:
            logger.info(f"  Intermediate values: {trial.intermediate_values}")

if __name__ == "__main__":
    test_successive_halving_with_nan_values()
  1. Hyperband Pruner:
import optuna
import numpy as np
import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def nan_objective(trial):
    if trial.number % 3 == 0:
        logger.info(f"Trial {trial.number}: Returning NaN")
        return float('nan')
    value = trial.suggest_float('x', -10, 10)
    result = value ** 2
    logger.info(f"Trial {trial.number}: Returning {result}")
    return result

def partial_nan_objective(trial):
    x = trial.suggest_float('x', -10, 10)
    for step in range(10):
        value = x ** 2 + step
        if step % 3 == 0:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting NaN")
            trial.report(float('nan'), step)
        else:
            logger.info(f"Trial {trial.number}, Step {step}: Reporting {value}")
            trial.report(value, step)
        if trial.should_prune():
            logger.info(f"Trial {trial.number} pruned at step {step}")
            raise optuna.exceptions.TrialPruned()
    return x ** 2

def test_hyperband_pruner_with_nan_values():
    logger.info("\n=== Test 1: Study with Hyperband and NaN final values ===")
    study1 = optuna.create_study(
        pruner=optuna.pruners.HyperbandPruner(),
        direction="minimize"
    )
    study1.optimize(nan_objective, n_trials=10)

    logger.info("Completed trials:")
    for trial in study1.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")

    logger.info("\n=== Test 2: Hyperband study with intermediate NaNs ===")
    study2 = optuna.create_study(
        pruner=optuna.pruners.HyperbandPruner(min_resource=1, max_resource=10, reduction_factor=3),
        direction="minimize"
    )
    study2.optimize(partial_nan_objective, n_trials=10)

    logger.info("Completed trials:")
    for trial in study2.trials:
        logger.info(f"Trial {trial.number}: State={trial.state}, Value={trial.value}")
        if trial.intermediate_values:
            logger.info(f"  Intermediate values: {trial.intermediate_values}")

if __name__ == "__main__":
    test_hyperband_pruner_with_nan_values()

Could you please review the changes?

Copy link
Member

@gen740 gen740 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the minor comment. PTAL!

Copy link

codecov bot commented Jun 13, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.42%. Comparing base (5ccdf30) to head (81cec3c).
Report is 23 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6092      +/-   ##
==========================================
+ Coverage   88.40%   88.42%   +0.02%     
==========================================
  Files         207      207              
  Lines       14029    14029              
==========================================
+ Hits        12402    12405       +3     
+ Misses       1627     1624       -3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ParagEkbote ParagEkbote requested a review from gen740 June 13, 2025 05:45
@@ -17,6 +17,11 @@ class SuccessiveHalvingPruner(BasePruner):
`Asynchronous Successive Halving <https://proceedings.mlsys.org/paper_files/paper/2020/file/
a06f20b349c6cf09a6b171c71b88bbfc-Paper.pdf>`__ for detailed descriptions.

The pruner handles NaN values in the following manner:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the implementation, the pruning decision is based on the intermediate value at the last reported step, as well as the intermediate values of other trials at the same rung key. Could you update the explanation to reflect this behavior more accurately?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
document Documentation related.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Document how each pruner handles nan
7 participants