Note
Click here to download the full example code
Grid Search
Forecast models have many hyperparameters that could significantly affect the accuracy. These hyperparameters control different components in the model including trend, seasonality, events, etc. You can learn more about how to configure the components or hyperparameters in the model tuning tutorial (Tune your first forecast model). Here we will see a step-by-step example of how to utilize the “grid search” functionality to choose the best set of hyperparameters.
All model templates support grid search.
Here we continue the model tuning tutorial
example to use the SILVERKITE
model on the Peyton Manning data set.
The mechanism of using grid search in PROPHET
is similar.
19 import warnings
20
21 warnings.filterwarnings("ignore")
22
23 from greykite.common.data_loader import DataLoader
24 from greykite.common.evaluation import EvaluationMetricEnum
25 from greykite.framework.templates.autogen.forecast_config import ComputationParam
26 from greykite.framework.templates.autogen.forecast_config import EvaluationMetricParam
27 from greykite.framework.templates.autogen.forecast_config import EvaluationPeriodParam
28 from greykite.framework.templates.autogen.forecast_config import ForecastConfig
29 from greykite.framework.templates.autogen.forecast_config import ModelComponentsParam
30 from greykite.framework.templates.forecaster import Forecaster
31 from greykite.framework.templates.model_templates import ModelTemplateEnum
32 from greykite.framework.utils.result_summary import summarize_grid_search_results
33
34 # Loads dataset into pandas DataFrame
35 dl = DataLoader()
36 df = dl.load_peyton_manning()
Grid search hyperparameters
In Tune your first forecast model
we learned how the components affect the prediction and how to choose the potential
candidate components. We also learned how to interpret the cross-validation results
for one set of hyperparameters. In this section, we will go over the grid_search
functionality that allows us to compare different sets of hyperparameters by running
cross-validation on them automatically.
In the ModelComponentsParam
class,
each attribute contains a dictionary mapping parameter names to parameter values. You may
specify either a specific parameter value to use, or a list of values to explore via grid search.
Grid search is done over every possible combination of hyperparameters across the lists.
Note
You may only provide lists for these attributes’ parameter values, not for the parameter values
of these attributes’ parameter values if they are dictionaries.
For example, seasonality
is an attribute in ModelComponentsParam
,
which has parameter names yearly_seasonality
, quarterly_seasonality
, etc.
We can provide lists for the parameter values of these names.
On the other hand, changepoints
is an attribute, too,
which has parameter names changepoints_dict
and seasonality_changepoints_dict
.
Both names take dictionaries as their parameter values.
We can provide lists of dictionaries as the values, however, within each dictionary,
we are not allowed to further wrap parameters in lists.
Cross-validation will be performed over these sets of hyperparameters, and the best set of hyperparameters
will be selected based on the metric you pick, specified by cv_selection_metric
in
EvaluationMetricParam
.
Now consider that we want to compare different yearly seasonalities (10 or 20), trend changepoints (None or “auto”) and fit algorithms (linear or ridge), while keeping all other model components the same. We could specify:
73 seasonality = {
74 "yearly_seasonality": [10, 20], # yearly seasonality could be 10 or 20
75 "quarterly_seasonality": False,
76 "monthly_seasonality": False,
77 "weekly_seasonality": False,
78 "daily_seasonality": False
79 }
80
81 changepoints = {
82 # Changepoints could be None or auto.
83 "changepoints_dict": [
84 None,
85 {"method": "auto"}
86 ]
87 }
88
89 # Specifies custom parameters
90 custom = {
91 "fit_algorithm_dict": [
92 {"fit_algorithm": "ridge"},
93 {"fit_algorithm": "linear", "fit_algorithm_params": dict(missing="drop")}
94 ]
95 }
96
97 # Specifies the model components
98 # Could leave the other components as default,
99 # or specify them in the normal way.
100 model_components = ModelComponentsParam(
101 seasonality=seasonality,
102 changepoints=changepoints,
103 custom=custom
104 )
105
106 # Specifies the metrics
107 evaluation_metric = EvaluationMetricParam(
108 # The metrics in ``cv_report_metrics`` will be calculated and reported.
109 cv_report_metrics=[EvaluationMetricEnum.MeanAbsolutePercentError.name,
110 EvaluationMetricEnum.MeanSquaredError.name],
111 # The ``cv_selection_metric`` will be used to select the best set of hyperparameters.
112 # It will be added to ``cv_report_metrics`` if it's not there.
113 cv_selection_metric=EvaluationMetricEnum.MeanAbsolutePercentError.name
114 )
115
116 # Specifies the forecast configuration.
117 # You could also specify ``forecast_horizon``, ``metadata_param``, etc.
118 config = ForecastConfig(
119 model_template=ModelTemplateEnum.SILVERKITE.name,
120 model_components_param=model_components,
121 evaluation_metric_param=evaluation_metric
122 )
For the configuration above, all other model components parameters are the same but yearly seasonality, changepoints and fit algorithm have 2 options each. The model will automatically run cross-validation over the 8 cases:
yearly seasonality = 10, no changepoints, fit algorithm = “linear”.
yearly seasonality = 20, no changepoints, fit algorithm = “linear”.
yearly seasonality = 10, automatic changepoints, fit algorithm = “linear”.
yearly seasonality = 20, automatic changepoints, fit algorithm = “linear”.
yearly seasonality = 10, no changepoints, fit algorithm = “ridge”.
yearly seasonality = 20, no changepoints, fit algorithm = “ridge”.
yearly seasonality = 10, automatic changepoints, fit algorithm = “ridge”.
yearly seasonality = 20, automatic changepoints, fit algorithm = “ridge”.
The CV test scores will be reported for all 8 cases using the metrics in cv_report_metrics
,
and the final model will be trained on the best set of hyperparameters according to the
cv_selection_metric
.
Selective grid search
Consider the case when you have 6 model components to tune, each with 3 different candidates. In this case, there will be 3^6=729 different sets of hyperparameters to grid search from. The results might be convincing because of the exhaustive grid search, however, the running time is going to pile up.
It’s very common that not all of the 729 sets of hyperparameters makes sense to us, so it would be good not to run all of them. There are two ways to do selective grid search:
Setting
hyperparameter_budget
.Utilizing
hyperparameter_override
.
Setting hyperparameter_budget
The hyperparameter_budget
parameter directly controls how many sets of hyperparameters
will be used in grid search. If this number is less than the number of all possible sets
of hyperparameters, the algorithm will randomly pick hyperparameter_budget
number of
hyperparameter sets. Set hyperparameter_budget
to -1
to search all possible sets.
You may set the budget in the ComputationParam
class. This is a simple way to search a
large space of hyperparameters if you are not sure which are likely to succeed. After you
identify parameter values with better performance, you may run a more precise grid search
to fine tune around these values.
Note
If you have a small number of timeseries to forecast, we recommend using the model tuning tutorial (Tune your first forecast model) to help identify good parameters candidates. This is likely more effective than random grid search over a large grid.
172 # Specifies the hyperparameter_budget.
173 # Randomly picks 3 sets of hyperparameters.
174 computation = ComputationParam(
175 hyperparameter_budget=3
176 )
177 # Specifies the forecast configuration.
178 # You could also specify ``forecast_horizon``, ``metadata_param``, etc.
179 config = ForecastConfig(
180 model_template=ModelTemplateEnum.SILVERKITE.name,
181 model_components_param=model_components,
182 evaluation_metric_param=evaluation_metric,
183 computation_param=computation
184 )
Utilizing hyperparameter_override
The hyperparameter_override
functionality allows us to customize the sets of hyperparameters
to search within. The way is to specify the hyperparameter_override
parameter in the
ModelComponentsParam
class.
First, model components are translated to the parameters in the corresponding sklearn Estimator
for the template (SimpleSilverkiteEstimator
and ProphetEstimator
). The name is usually the same as the
key, for example, “estimator__yearly_seasonality” and “estimator__fit_algorithm_dict” (the ModelComponentsParam
attribute is ignored). This creates a default hyperparameter_grid dictionary. Then for each dict in
hyperparameter_override
, the default grid’s values are replaced by the override values, producing a
list of customized grids to search over. Grid search done across all the grids in the list.
For more details, see
hyperparameter override.
Now assume we have the following parameter options, as above:
yearly seasonality orders: 10 and 20.
trend changepoints: None and “auto”.
fit algorithm: linear and ridge.
We do not want to run all 8 sets of hyperparameters. For example, we think that ridge is not needed for the model without changepoints because the model is simple, while linear should not be used when there are changepoints because the model is complex. So we want:
for no changepoints we use linear regression only.
for automatic changepoints we use ridge regression only.
Then we can specify:
216 seasonality = {
217 "yearly_seasonality": [10, 20],
218 "quarterly_seasonality": False,
219 "monthly_seasonality": False,
220 "weekly_seasonality": False,
221 "daily_seasonality": False
222 }
223
224 changepoints = {
225 "changepoints_dict": None
226 }
227
228 # Specifies custom parameters
229 custom = {
230 "fit_algorithm_dict": {"fit_algorithm": "linear"}
231 }
232
233 # Hyperparameter override can be a list of dictionaries.
234 # Each dictionary will be one set of hyperparameters.
235 override = [
236 {},
237 {
238 "estimator__changepoints_dict": {"method": "auto"},
239 "estimator__fit_algorithm_dict": {"fit_algorithm": "ridge"}
240 }
241 ]
242
243 # Specifies the model components
244 # Could leave the other components as default,
245 # or specify them in the normal way.
246 model_components = ModelComponentsParam(
247 seasonality=seasonality,
248 changepoints=changepoints,
249 custom=custom,
250 hyperparameter_override=override
251 )
252
253 # Specifies the evaluation period
254 evaluation_period = EvaluationPeriodParam(
255 test_horizon=365, # leaves 365 days as testing data
256 cv_horizon=365, # each CV test size is 365 days (same as forecast horizon)
257 cv_max_splits=3, # 3 folds CV
258 cv_min_train_periods=365 * 4 # uses at least 4 years for training because we have 8 years data
259 )
260
261 config = ForecastConfig(
262 forecast_horizon=365,
263 model_template=ModelTemplateEnum.SILVERKITE.name,
264 model_components_param=model_components,
265 evaluation_metric_param=evaluation_metric,
266 evaluation_period_param=evaluation_period
267 )
The forecast configuration above specifies the yearly seasonality orders in a list, therefore, both 10 and 20 will be searched. For the hyperparameter override list, there are two elements. The first one is an empty dictionary, which corresponds to the original changepoint and fit algorithm in the configuration. The second dictionary overrides changepoint method with automatic changepoint detection and fit algorithm with ridge. In total, the model will run 4 different configurations:
yearly seasonality 10, no changepoint, fit algorithm linear.
yearly seasonality 20, no changepoint, fit algorithm linear.
yearly seasonality 10, automatic changepoints, fit algorithm ridge.
yearly seasonality 20, automatic changepoints, fit algorithm ridge.
In this way, we could only search the sets of hyperparameters we need and save a lot of time.
Also note that the above configuration also configures the CV splits using
EvaluationPeriodParam
.
We can see the configs and evaluations with summarize_grid_search_results
.
287 # Runs the forecast
288 forecaster = Forecaster()
289 result = forecaster.run_forecast_config(
290 df=df,
291 config=config
292 )
293
294 # Summarizes the CV results
295 cv_results = summarize_grid_search_results(
296 grid_search=result.grid_search,
297 decimals=1,
298 # The below saves space in the printed output. Remove to show all available metrics and columns.
299 cv_report_metrics=None,
300 column_order=["rank", "mean_test", "split_test", "mean_train", "split_train", "mean_fit_time", "mean_score_time", "params"])
301 cv_results["params"] = cv_results["params"].astype(str)
302 cv_results.set_index("params", drop=True, inplace=True)
303 cv_results
Out:
Fitting 3 folds for each of 4 candidates, totalling 12 fits
Tip
The simple silverkite templates that use
SimpleSilverkiteEstimator
are the easiest templates to do grid search, because they support a list of model templates
and a list of ModelComponentsParam
. For more information, see
Template Overview.
Total running time of the script: ( 2 minutes 31.848 seconds)