def _get_optimization_history_plot(study: Study) -> "go.Figure": layout = go.Layout( title="Optimization History Plot", xaxis={"title": "#Trials"}, yaxis={"title": "Objective Value"}, ) trials = [t for t in study.trials if t.state == TrialState.COMPLETE] if len(trials) == 0: logger.warning("Study instance does not contain trials.") return go.Figure(data=[], layout=layout) best_values = [float("inf")] if study.direction == StudyDirection.MINIMIZE else [-float("inf")] comp = min if study.direction == StudyDirection.MINIMIZE else max for trial in trials: trial_value = trial.value assert trial_value is not None # For mypy best_values.append(comp(best_values[-1], trial_value)) best_values.pop(0) traces = [ go.Scatter( x=[t.number for t in trials], y=[t.value for t in trials], mode="markers", name="Objective Value", ), go.Scatter(x=[t.number for t in trials], y=best_values, name="Best Value"), ] figure = go.Figure(data=traces, layout=layout) return figure
def _get_intermediate_plot(study): # type: (Study) -> go.Figure layout = go.Layout(title='Intermediate Values Plot', xaxis={'title': 'Step'}, yaxis={'title': 'Intermediate Value'}, showlegend=False) target_state = [TrialState.PRUNED, TrialState.COMPLETE, TrialState.RUNNING] trials = [trial for trial in study.trials if trial.state in target_state] if len(trials) == 0: logger.warning('Study instance does not contain trials.') return go.Figure(data=[], layout=layout) traces = [] for trial in trials: if trial.intermediate_values: trace = go.Scatter(x=tuple(trial.intermediate_values.keys()), y=tuple(trial.intermediate_values.values()), mode='lines+markers', marker={'maxdisplayed': 10}, name='Trial{}'.format(trial.number)) traces.append(trace) if not traces: logger.warning( 'You need to set up the pruning feature to utilize `plot_intermediate_values()`' ) return go.Figure(data=[], layout=layout) figure = go.Figure(data=traces, layout=layout) return figure
def _get_slice_plot(study: Study, params: Optional[List[str]] = None) -> "go.Figure": layout = go.Layout(title="Slice Plot", ) trials = [ trial for trial in study.trials if trial.state == TrialState.COMPLETE ] if len(trials) == 0: logger.warning("Your study does not have any completed trials.") return go.Figure(data=[], layout=layout) all_params = {p_name for t in trials for p_name in t.params.keys()} if params is None: sorted_params = sorted(list(all_params)) else: for input_p_name in params: if input_p_name not in all_params: raise ValueError( "Parameter {} does not exist in your study.".format( input_p_name)) sorted_params = sorted(list(set(params))) n_params = len(sorted_params) if n_params == 1: figure = go.Figure( data=[_generate_slice_subplot(study, trials, sorted_params[0])], layout=layout) figure.update_xaxes(title_text=sorted_params[0]) figure.update_yaxes(title_text="Objective Value") if _is_log_scale(trials, sorted_params[0]): figure.update_xaxes(type="log") else: figure = make_subplots(rows=1, cols=len(sorted_params), shared_yaxes=True) figure.update_layout(layout) showscale = True # showscale option only needs to be specified once. for i, param in enumerate(sorted_params): trace = _generate_slice_subplot(study, trials, param) trace.update(marker={"showscale": showscale}) # showscale's default is True. if showscale: showscale = False figure.add_trace(trace, row=1, col=i + 1) figure.update_xaxes(title_text=param, row=1, col=i + 1) if i == 0: figure.update_yaxes(title_text="Objective Value", row=1, col=1) if _is_log_scale(trials, param): figure.update_xaxes(type="log", row=1, col=i + 1) if n_params > 3: # Ensure that each subplot has a minimum width without relying on autusizing. figure.update_layout(width=300 * n_params) return figure
def _get_intermediate_plot(study): # type: (Study) -> go.Figure layout = go.Layout( title="Intermediate Values Plot", xaxis={"title": "Step"}, yaxis={"title": "Intermediate Value"}, showlegend=False, ) target_state = [TrialState.PRUNED, TrialState.COMPLETE, TrialState.RUNNING] trials = [trial for trial in study.trials if trial.state in target_state] if len(trials) == 0: logger.warning("Study instance does not contain trials.") return go.Figure(data=[], layout=layout) traces = [] for trial in trials: if trial.intermediate_values: sorted_intermediate_values = sorted( trial.intermediate_values.items()) trace = go.Scatter( x=tuple((x for x, _ in sorted_intermediate_values)), y=tuple((y for _, y in sorted_intermediate_values)), mode="lines+markers", marker={"maxdisplayed": 10}, name="Trial{}".format(trial.number), ) traces.append(trace) if not traces: logger.warning( "You need to set up the pruning feature to utilize `plot_intermediate_values()`" ) return go.Figure(data=[], layout=layout) figure = go.Figure(data=traces, layout=layout) return figure
def _get_optimization_history_plot(study): # type: (Study) -> Figure layout = go.Layout( title='Optimization History Plot', xaxis={'title': '#Trials'}, yaxis={'title': 'Objective Value'}, ) trials = [t for t in study.trials if t.state == TrialState.COMPLETE] if len(trials) == 0: logger.warning('Study instance does not contain trials.') return go.Figure(data=[], layout=layout) best_values = [ float('inf') ] if study.direction == StudyDirection.MINIMIZE else [-float('inf')] comp = min if study.direction == StudyDirection.MINIMIZE else max for trial in trials: trial_value = trial.value assert trial_value is not None # For mypy best_values.append(comp(best_values[-1], trial_value)) best_values.pop(0) traces = [ go.Scatter(x=[t.number for t in trials], y=[t.value for t in trials], mode='markers', name='Objective Value'), go.Scatter(x=[t.number for t in trials], y=best_values, name='Best Value') ] figure = go.Figure(data=traces, layout=layout) return figure
def _get_parallel_coordinate_plot(study: Study, params: Optional[List[str]] = None ) -> "go.Figure": layout = go.Layout(title="Parallel Coordinate Plot", ) trials = [ trial for trial in study.trials if trial.state == TrialState.COMPLETE ] if len(trials) == 0: logger.warning("Your study does not have any completed trials.") return go.Figure(data=[], layout=layout) all_params = {p_name for t in trials for p_name in t.params.keys()} if params is not None: for input_p_name in params: if input_p_name not in all_params: ValueError("Parameter {} does not exist in your study.".format( input_p_name)) all_params = set(params) sorted_params = sorted(list(all_params)) dims = [{ "label": "Objective Value", "values": tuple([t.value for t in trials]), "range": (min([t.value for t in trials]), max([t.value for t in trials])), }] # type: List[Dict[str, Any]] for p_name in sorted_params: values = [] for t in trials: if p_name in t.params: values.append(t.params[p_name]) is_categorical = False try: tuple(map(float, values)) except (TypeError, ValueError): vocab = defaultdict( lambda: len(vocab)) # type: DefaultDict[str, int] values = [vocab[v] for v in values] is_categorical = True dim = { "label": p_name if len(p_name) < 20 else "{}...".format(p_name[:17]), "values": tuple(values), "range": (min(values), max(values)), } if is_categorical: dim["tickvals"] = list(range(len(vocab))) dim["ticktext"] = list(sorted(vocab.items(), key=lambda x: x[1])) dims.append(dim) traces = [ go.Parcoords( dimensions=dims, labelangle=30, labelside="bottom", line={ "color": dims[0]["values"], "colorscale": "blues", "colorbar": { "title": "Objective Value" }, "showscale": True, "reversescale": study.direction == StudyDirection.MINIMIZE, }, ) ] figure = go.Figure(data=traces, layout=layout) return figure
def _get_contour_plot(study, params=None): # type: (Study, Optional[List[str]]) -> Figure layout = go.Layout( title='Contour Plot', ) trials = [trial for trial in study.trials if trial.state == TrialState.COMPLETE] if len(trials) == 0: logger.warning('Your study does not have any completed trials.') return go.Figure(data=[], layout=layout) all_params = {p_name for t in trials for p_name in t.params.keys()} if params is None: sorted_params = sorted(list(all_params)) elif len(params) <= 1: logger.warning('The length of params must be greater than 1.') return go.Figure(data=[], layout=layout) else: for input_p_name in params: if input_p_name not in all_params: raise ValueError('Parameter {} does not exist in your study.'.format(input_p_name)) sorted_params = sorted(list(set(params))) param_values_range = {} for p_name in sorted_params: values = [t.params[p_name] for t in trials if p_name in t.params] param_values_range[p_name] = (min(values), max(values)) if len(sorted_params) == 2: x_param = sorted_params[0] y_param = sorted_params[1] sub_plots = _generate_contour_subplot( trials, x_param, y_param, study.direction) figure = go.Figure(data=sub_plots) figure.update_xaxes(title_text=x_param, range=param_values_range[x_param]) figure.update_yaxes(title_text=y_param, range=param_values_range[y_param]) if _is_log_scale(trials, x_param): log_range = [math.log10(p) for p in param_values_range[x_param]] figure.update_xaxes(range=log_range, type='log') if _is_log_scale(trials, y_param): log_range = [math.log10(p) for p in param_values_range[y_param]] figure.update_yaxes(range=log_range, type='log') else: figure = make_subplots(rows=len(sorted_params), cols=len(sorted_params), shared_xaxes=True, shared_yaxes=True) showscale = True # showscale option only needs to be specified once for x_i, x_param in enumerate(sorted_params): for y_i, y_param in enumerate(sorted_params): if x_param == y_param: figure.add_trace(go.Scatter(), row=y_i + 1, col=x_i + 1) else: sub_plots = _generate_contour_subplot( trials, x_param, y_param, study.direction) contour = sub_plots[0] scatter = sub_plots[1] contour.update(showscale=showscale) # showscale's default is True if showscale: showscale = False figure.add_trace(contour, row=y_i + 1, col=x_i + 1) figure.add_trace(scatter, row=y_i + 1, col=x_i + 1) figure.update_xaxes(range=param_values_range[x_param], row=y_i + 1, col=x_i + 1) figure.update_yaxes(range=param_values_range[y_param], row=y_i + 1, col=x_i + 1) if _is_log_scale(trials, x_param): log_range = [math.log10(p) for p in param_values_range[x_param]] figure.update_xaxes(range=log_range, type='log', row=y_i + 1, col=x_i + 1) if _is_log_scale(trials, y_param): log_range = [math.log10(p) for p in param_values_range[y_param]] figure.update_yaxes(range=log_range, type='log', row=y_i + 1, col=x_i + 1) if x_i == 0: figure.update_yaxes(title_text=y_param, row=y_i + 1, col=x_i + 1) if y_i == len(sorted_params) - 1: figure.update_xaxes(title_text=x_param, row=y_i + 1, col=x_i + 1) return figure
def _get_parallel_coordinate_plot(study, params=None): # type: (Study, Optional[List[str]]) -> go.Figure layout = go.Layout(title='Parallel Coordinate Plot', ) trials = [ trial for trial in study.trials if trial.state == TrialState.COMPLETE ] if len(trials) == 0: logger.warning('Your study does not have any completed trials.') return go.Figure(data=[], layout=layout) all_params = {p_name for t in trials for p_name in t.params.keys()} if params is not None: for input_p_name in params: if input_p_name not in all_params: ValueError('Parameter {} does not exist in your study.'.format( input_p_name)) all_params = set(params) sorted_params = sorted(list(all_params)) dims = [{ 'label': 'Objective Value', 'values': tuple([t.value for t in trials]), 'range': (min([t.value for t in trials]), max([t.value for t in trials])) }] # type: List[Dict[str, Any]] for p_name in sorted_params: values = [] for t in trials: if p_name in t.params: values.append(t.params[p_name]) is_categorical = False try: tuple(map(float, values)) except (TypeError, ValueError): vocab = defaultdict( lambda: len(vocab)) # type: DefaultDict[str, int] values = [vocab[v] for v in values] is_categorical = True dim = { 'label': p_name, 'values': tuple(values), 'range': (min(values), max(values)) } if is_categorical: dim['tickvals'] = list(range(len(vocab))) dim['ticktext'] = list(sorted(vocab.items(), key=lambda x: x[1])) dims.append(dim) traces = [ go.Parcoords(dimensions=dims, line={ 'color': dims[0]['values'], 'colorscale': 'blues', 'colorbar': { 'title': 'Objective Value' }, 'showscale': True, 'reversescale': study.direction == StudyDirection.MINIMIZE, }) ] figure = go.Figure(data=traces, layout=layout) return figure
def plot_param_importances(study: Study, evaluator: BaseImportanceEvaluator = None, params: Optional[List[str]] = None) -> "go.Figure": """Plot hyperparameter importances. Example: The following code snippet shows how to plot hyperparameter importances. .. testcode:: import optuna def objective(trial): x = trial.suggest_int("x", 0, 2) y = trial.suggest_float("y", -1.0, 1.0) z = trial.suggest_float("z", 0.0, 1.5) return x ** 2 + y ** 3 - z ** 4 study = optuna.create_study(sampler=optuna.samplers.RandomSampler()) study.optimize(objective, n_trials=100) optuna.visualization.plot_param_importances(study) .. raw:: html <iframe src="../_static/plot_param_importances.html" width="100%" height="500px" frameborder="0"> </iframe> .. seealso:: This function visualizes the results of :func:`optuna.importance.get_param_importances`. Args: study: An optimized study. evaluator: An importance evaluator object that specifies which algorithm to base the importance assessment on. Defaults to :class:`~optuna.importance._mean_decrease_impurity.MeanDecreaseImpurityImportanceEvaluator`. params: A list of names of parameters to assess. If :obj:`None`, all parameters that are present in all of the completed trials are assessed. Returns: A :class:`plotly.graph_objs.Figure` object. """ _imports.check() layout = go.Layout( title="Hyperparameter Importances", xaxis={"title": "Feature"}, yaxis={"title": "Importance"}, showlegend=False, ) # Importances cannot be evaluated without completed trials. # Return an empty figure for consistency with other visualization functions. trials = [ trial for trial in study.trials if trial.state == TrialState.COMPLETE ] if len(trials) == 0: logger.warning("Study instance does not contain completed trials.") return go.Figure(data=[], layout=layout) importances = optuna.importance.get_param_importances(study, evaluator=evaluator, params=params) fig = go.Figure(data=[ go.Bar(x=list(importances.keys()), y=list(importances.values())) ], layout=layout) return fig