Model Plan Guide
Use a model plan to control how Kumo Engine searches for and trains a model.
Start with a suggested plan, change the settings you need, and pass the plan to Trainer.
This guide covers the public model controls shared by Linux, Snowflake notebooks, and Databricks notebooks.
For the column types and encoder choices introduced during graph setup, see Encoder Selection.
Apply your encoder overrides in this plan’s Column Processing section before training.
Create and Use a Plan
Start with the query, snapshot, and training_table from Predictive Queries:
Suggestion uses graph and query metadata and does not start training.
Choose RunMode.FAST, RunMode.NORMAL, or RunMode.BEST for progressively larger search budgets.
RunMode.DEBUG is for diagnostic runs, not model quality evaluation.
For a supplied training table with sample weights, pass its TrainingTableSpec as train_table_spec= to the suggestion call.
Keep suggested values for the first run; change a setting when its behavior matches a specific requirement. Compare validation results on the same data and splits when evaluating a change; reserve holdout data for the final assessment. See Training Diagnostics for experiment and epoch history.
Read Values and Search Spaces
The plan is a kumoapi.model_plan.ModelPlan with five sections:
Most tunable settings take a nonempty list of candidates.
For example, base_lr=[0.001, 0.003] offers two learning rates, while base_lr=[0.001] fixes that choice.
num_experiments limits the trials; Kumo does not necessarily exhaust every combination.
Nested lists group one candidate: num_neighbors=[[20, 10]] means one two-hop sampling configuration.
Scalar settings such as max_epochs and num_experiments take a single value.
None is an explicit option only where the tables below allow it; it does not universally mean “infer a default.”
Unspecified settings are filled from the task, graph, and run mode.
Inspect plan.as_json() instead of assuming the same suggested values for every dataset.
The bounds below describe valid configuration values, not recommended capacity settings.
Training Job Plan
Set these fields on plan.training_job.
Keep the suggested search budget unless you need to cap trials. Choose tune_metric for the outcome you want to select on.
Disable refits when you only need trial results; use refit_full only with separate unseen evaluation data.
Training job parameters and pruning
PruningConfig takes min_epochs (integer at least 1), k (integer at least 1), min_delta (number at least 0), and patience (positive integer).
It compares the trial with the best k previous trials after min_epochs, using the improvement threshold and patience to decide when to stop it.
Trial pruning differs from early stopping, which monitors one trial’s own validation progress.
Choose Metrics
Use metric names for the query’s task. Common choices are:
For example, for a regression query:
These fields select built-in metrics, not Python callbacks. To evaluate a custom metric, score held-out predictions against separately retained ground truth.
Column Processing
Set these fields on plan.column_processing.
Both fields default to None.
See Missing Values for the type-wide defaults recipe, column-specific overrides, precedence, and validation behavior.
Encoder Selection lists encoder arguments and examples.
Neighbor Sampling
Set these fields on plan.neighbor_sampling.
Keep suggested fanouts unless a relationship needs a different context limit. Larger neighborhoods usually require more memory and time.
For one candidate with at most 20 neighbors at the first hop and 10 at the second:
Override a Relationship’s Fanout
Use NumNeighborsConfig when different relationships need different amounts of context.
Configure fanouts by relationship and adaptive sampling
The following example uses the SalesOrderHeader.CustomerID relationship to Customer.CustomerID in Create a Graph:
Use graph table names, including aliases, and the actual primary-key and foreign-key columns.
The two directions have separate overrides. Unlisted relationships use that hop’s default; at hop2, both directions above use 10.
Each default accepts integers from -1 to 128; a named edge accepts integers from -1 to 512.
0 samples none and -1 requests all neighbors, which can exhaust memory on a large relationship.
Define consecutive hops beginning with hop1, up to six hops. An unknown relationship or a gap in hop numbers is invalid; correct the graph names or configuration before fitting.
Some suggested plans use "inferred" for a target-to-entity connection in hop1.
This is a task-specific fanout estimated from the data, not a general substitute for an integer on any edge.
It is invalid on other connections or later hops. Use explicit integer overrides when setting your own edge counts.
To compensate for sparse earlier hops, set plan.neighbor_sampling.adaptive_sampling = True.
Later hops can then sample more neighbors than their nominal count. All counts must be nonnegative: -1 is incompatible with adaptive sampling.
Inspect memory use and runtime before increasing the graph context; enabling adaptation does not guarantee better validation quality.
Optimization
Set these fields on plan.optimization.
Retain suggested losses and optimizer settings unless your task requires a different objective or a bounded comparison.
Cap epochs or steps to limit work; a shorter run is not evidence of equivalent model quality.
Optimization parameters and learning-rate search example
EarlyStoppingConfig(min_delta=0.0, patience=3) requires a nonnegative improvement threshold and positive integer patience.
LRSchedulerConfig takes name, interval ("step" or "epoch"), and an optional kwargs dictionary for that scheduler.
Supported warmup schedule names include "constant_with_warmup", "linear_with_warmup", "cosine_with_warmup", and "cosine_with_warmup_restarts".
Additional scheduler names and arguments must resolve in the installed training runtime.
For a bounded learning-rate search:
A fixed seed helps repeat a run with the same data, plan, package versions, and execution environment.
It does not guarantee identical scores across devices, library versions, or parallel execution.
Retain plan.as_json() and the data snapshot identity with your results. The search selects a model; it does not ensemble its trials.
Use Row Weights and Balance Binary Classes
Use row weights when examples should contribute differently, or a class ratio when binary class influence needs rebalancing.
Configure row weights and class balancing
Start with the scalar weighted custom training table.
Reuse its custom_query, custom_snapshot, custom_training_table, and spec. Pass the same specification when suggesting the plan so Kumo knows the table contains weights:
Choose one mode before creating Trainer(plan) and calling fit(custom_training_table, snapshot=custom_snapshot):
Use finite, nonnegative scalar weights, with positive weight remaining in the training population.
A zero weight removes that row’s training contribution in weighted loss or its sampling probability in weighted sampling.
This scalar example does not define weights for list targets or forecast sequences. Weighted link prediction permits "weighted_loss" or None, not "sample"; forecasting does not support these training weight modes.
For binary classification, optionally add a class-balancing ratio:
The ratio is the desired majority-to-minority balance. 1.0 requests equal class influence when the original classes are imbalanced.
Kumo increases the minority class weight only when the observed imbalance exceeds the requested ratio.
When row weights are also present, Kumo multiplies their effect by the class weights, so arbitrary row weights can change the final class balance.
With "sample", these weights affect row selection; with "weighted_loss", they affect the loss. Neither mode promises an exact class count in each batch.
A numeric ratio requires every weight_mode candidate to be non-None. To ignore weights, set both weight_mode=[None] and majority_sampling_ratio=[None].
Fit using the bounded procedure under Training, then compare validation metrics and class-specific behavior before retaining a configuration. Different sampling frequencies or a lower training loss do not by themselves establish better prediction quality.
Loss Functions
Choose distribution losses only when their assumptions match your target values.
Loss names and configuration arguments
For custom loss parameters, import the corresponding configuration from kumoapi.model_plan:
For a regression query, plan.optimization.loss = [HuberLossConfig(name="huber", delta=2.0)] selects a Huber loss with a custom threshold.
Model Architecture
Set plan.model_architecture.model to a list of architecture configurations.
Keep the suggested architecture initially. Set explicit candidates to compare architectures on the same task and data.
The following illustrates candidate syntax, not recommended channel counts:
GNN and Graph Transformer
GNNModelPlan supports all task types.
GraphTransformerModelPlan supports node prediction tasks, including forecasting, but not link prediction.
Import both from kumoapi.model_plan.
GNN and Graph Transformer parameters
Shared Architecture Settings
These fields belong directly to plan.model_architecture.
Shared architecture parameter reference
Forecasting Architecture and Historical Inputs
For a forecasting query, the suggested architecture uses a GNN with a forecasting head. You can choose GNN or Graph Transformer candidates using the configuration classes above. The forecasting head combines graph context with the historical target inputs available in the training table; these controls do not turn a regression query into a forecasting query.
Configure forecasting history and entity handling
Historical inputs are created by TrainingTableGenerationPlan, separately from the model plan.
Generated forecasts require a positive integer lag_timesteps; leaving it unspecified uses one previous target window, while 0 is rejected.
year_over_year=True requests the corresponding previous-year sequence. The encoder is activated only when those values are present in the materialized table.
Changing past_encoder after generation does not change the table’s lag windows or create missing historical values.
Follow Generate Forecast Inputs to generate the intended horizon and historical inputs before fitting.
For a forecasting table with positive lag windows, select a historical encoder before fitting:
"decomposed" is the suggested historical encoder. "normalized", "mlp", and "transformer" are alternative candidates.
handle_new_entities=True uses a shared head. False adds learned parameters for individual training entities; it does not merely replace the shared head.
Keep it True when you need forecasts for new entities, subject to the graph and feature requirements of your model.
These settings apply to forecasting, not ordinary temporal regression.
To disable only the historical target encoder, set this before creating the trainer and fitting:
Keep the generated training table’s positive lag setting unchanged. The forecasting head still receives the raw lag values; disabling their encoder does not remove historical inputs or stop generation of the lag columns.
It also does not disable the separate year-over-year encoder when the table contains those inputs.
This choice is distinct from lag_timesteps=0, which is rejected when constructing generated or supplied forecast training tables.
After fitting or loading the model, reuse trainer.training_table_generation_plan when generating prediction rows so the horizon, lags, year-over-year inputs, and step size match training.
See Select the Prediction Population and the forecast output example.
The default output has ENTITY, TIMESTAMP, and TARGET_PRED; select optional ANCHOR_TIMESTAMP explicitly when you need the common forecast anchor.
Link Prediction and Embeddings
These fields also belong directly to plan.model_architecture, and apply to link prediction.
Link prediction and embedding parameters
target_embedding_mode controls the target representation for "shallow_rhs" and "context".
For these modules, handle_new_target_entities=True requires "feature" or "shallow_feature"; "lookup" and "fusion" are incompatible.
The "two_tower" and "pairwise" modules do not use target lookup embeddings.
Use "shallow_rhs" or "two_tower" when exported embeddings need to represent the model’s ranking.
"context" produces approximate embeddings, and "pairwise" does not support embedding output.
Legacy "ranking" and "embedding" module names remain compatibility aliases; use the explicit module names in new plans.
See Making Predictions for embedding export.
Training Table Generation
Labels, time windows, and train/validation/test splits use a separate TrainingTableGenerationPlan passed to query.generate_training_table().
Changing a model plan does not regenerate existing training rows or splits.
See Generate a Training Table for generation settings and supplied training tables.
Return to Training to fit your customized plan.