> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/sdgm/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/sdgm/_mcp/server.

# Model Plan Guide

> Customize Kumo Engine training, model architecture, sampling, and column encoders

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](/kumo-engine/1.0.0/user-code-guide/set-up-a-graph/encoder-selection).
Apply your encoder overrides in this plan's [Column Processing](#column-processing) section before training.

## Create and Use a Plan

Start with the `query`, `snapshot`, and `training_table` from [Predictive Queries](/kumo-engine/1.0.0/user-code-guide/train-a-model/predictive-queries):

```python
from kumo.engine import Trainer
from kumoapi.model_plan import RunMode

plan = query.suggest_model_plan(snapshot, run_mode=RunMode.FAST)
print(plan.as_json())

trainer = Trainer(plan)
fit_result = trainer.fit(training_table, snapshot=snapshot)
print(fit_result.metrics)
```

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](/kumo-engine/1.0.0/user-code-guide/train-a-model/training-diagnostics) for experiment and epoch history.

### Read Values and Search Spaces

The plan is a `kumoapi.model_plan.ModelPlan` with five sections:

| Section              | Purpose                                                  |
| -------------------- | -------------------------------------------------------- |
| `training_job`       | Experiment count, evaluation, trial pruning, and refits. |
| `column_processing`  | Column encoders and missing values.                      |
| `neighbor_sampling`  | Graph neighborhood sampling.                             |
| `optimization`       | Training budget, losses, optimizers, and batch sizes.    |
| `model_architecture` | Message passing, prediction heads, and embeddings.       |

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.

<details>
  <summary>
    Training job parameters and pruning
  </summary>

  | Parameter         | Supported values                         | Meaning                                                                                                                                          |
  | ----------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
  | `num_experiments` | Positive integer                         | Maximum number of AutoML experiments. Suggested budget depends on run mode.                                                                      |
  | `manual_seed`     | Integer or `None`; default `None`        | Seed model training and the trial search to help repeat an experiment.                                                                           |
  | `metrics`         | List of metric names valid for the task  | Metrics computed during evaluation. See [Choose Metrics](#choose-metrics).                                                                       |
  | `tune_metric`     | One metric name                          | Metric used to compare experiments and select a model. Include it in `metrics`; `"loss"` is also available for tasks other than link prediction. |
  | `pruning`         | `PruningConfig` or `None`                | Stop unpromising trials using previous trials as a reference. `None` disables trial pruning.                                                     |
  | `refit_trainval`  | `True` or `False`; suggested by run mode | Refit the selected configuration on training plus validation rows.                                                                               |
  | `refit_full`      | `True` or `False`; default `False`       | Also refit on training, validation, and test rows. Reserve separate unseen data to evaluate this model.                                          |

  `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.
</details>

### Choose Metrics

Use metric names for the query's task.
Common choices are:

| Task                                   | Metric choices                                                                                                       |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Binary classification                  | `"auroc"`, `"ap"`, `"auprc"`, `"acc"`, `"f1"`, `"precision"`, `"recall"`.                                            |
| Multiclass classification              | `"acc"`, `"f1"`, `"precision"`, `"recall"`.                                                                          |
| Multilabel classification              | `"ap_macro"`, `"ap_micro"`, `"auroc_macro"`, `"auroc_micro"`, `"auprc_macro"`, `"auprc_micro"`.                      |
| Regression and forecasting             | `"mae"`, `"mse"`, `"rmse"`, `"mape"`, `"smape"`.                                                                     |
| Link prediction and multilabel ranking | `"map@10"`, `"precision@10"`, `"recall@10"`, `"ndcg@10"`, `"mrr@10"`. Replace `10` with the desired positive cutoff. |

For example, for a regression query:

```python
plan.training_job.metrics = ["mae", "mse", "rmse"]
plan.training_job.tune_metric = "mae"
```

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`.

| Parameter           | Supported values                                          | Meaning                                                                                                |
| ------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `encoder_overrides` | Dictionary from `"table.column"` to an encoder, or `None` | Replace the inferred encoder for specific columns. Names are case sensitive and use graph table names. |
| `na_strategy`       | Dictionary from `Stype` to `NAStrategy`, or `None`        | Set missing-value defaults by semantic type for compatible inferred feature encoders.                  |

Both fields default to `None`.
See [Missing Values](/kumo-engine/1.0.0/user-code-guide/set-up-a-graph/encoder-selection#missing-values) for the type-wide defaults recipe, column-specific overrides, precedence, and validation behavior.
[Encoder Selection](/kumo-engine/1.0.0/user-code-guide/set-up-a-graph/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.

| Parameter                  | Supported values                                                  | Meaning                                                                                    |
| -------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `num_neighbors`            | List of per-hop integer lists, or `NumNeighborsConfig` candidates | Up to six hops per candidate. Each count is `-1` (all neighbors), `0` (none), or 1 to 128. |
| `sample_from_entity_table` | `True` or `False`                                                 | Include the entity table when sampling. Applies to static node prediction tasks.           |
| `adaptive_sampling`        | `True` or `False`; default `False`                                | Compensate for undersampling at an earlier hop by sampling more at later hops.             |

For one candidate with at most 20 neighbors at the first hop and 10 at the second:

```python
plan.neighbor_sampling.num_neighbors = [[20, 10]]
```

### Override a Relationship's Fanout

Use `NumNeighborsConfig` when different relationships need different amounts of context.

<details>
  <summary>
    Configure fanouts by relationship and adaptive sampling
  </summary>

  The following example uses the `SalesOrderHeader.CustomerID` relationship to `Customer.CustomerID` in [Create a Graph](/kumo-engine/1.0.0/user-code-guide/set-up-a-graph/graphs#create-a-graph):

  ```python
  from kumoapi.model_plan import HopConfig, NumNeighborsConfig

  hop1 = HopConfig(default=20)
  hop1["Customer.CustomerID->SalesOrderHeader.CustomerID"] = 40
  hop1["SalesOrderHeader.CustomerID->Customer.CustomerID"] = 1
  plan.neighbor_sampling.num_neighbors = [
      NumNeighborsConfig(hop1=hop1, hop2=HopConfig(default=10)),
  ]
  plan.neighbor_sampling.adaptive_sampling = False
  ```

  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.
</details>

## 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.

<details>
  <summary>
    Optimization parameters and learning-rate search example
  </summary>

  | Parameter                 | Supported values                                            | Meaning                                                                                                                                                                                                                                     |
  | ------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `max_epochs`              | Positive integer                                            | Maximum epochs per experiment.                                                                                                                                                                                                              |
  | `min_steps_per_epoch`     | Integer 1 to 4000                                           | Minimum training batches per epoch.                                                                                                                                                                                                         |
  | `max_steps_per_epoch`     | Positive integer                                            | Maximum training batches per epoch. Keep it at least as large as `min_steps_per_epoch`.                                                                                                                                                     |
  | `max_val_steps`           | Integer 1 to 8000                                           | Maximum batches in a validation pass.                                                                                                                                                                                                       |
  | `max_test_steps`          | Integer 1 to 8000                                           | Maximum batches in a test pass.                                                                                                                                                                                                             |
  | `loss`                    | List of loss names or loss configurations                   | Training objective. Must match the task; see [Loss Functions](#loss-functions).                                                                                                                                                             |
  | `optimizer`               | List containing `"Adam"`, `"AdamW"`, or `"Adagrad"`         | Optimizer candidates.                                                                                                                                                                                                                       |
  | `base_lr`                 | List of numbers greater than 0                              | Initial learning rates.                                                                                                                                                                                                                     |
  | `weight_decay`            | List of numbers at least 0                                  | Weight regularization coefficients.                                                                                                                                                                                                         |
  | `batch_size`              | List of integers 1 to 2048                                  | Training examples per batch.                                                                                                                                                                                                                |
  | `early_stopping`          | List containing `EarlyStoppingConfig` instances or `None`   | Stop a trial when validation improvement stalls. `[None]` disables it.                                                                                                                                                                      |
  | `lr_scheduler`            | List containing `LRSchedulerConfig` instances or `None`     | Learning rate schedules. `[None]` disables scheduling.                                                                                                                                                                                      |
  | `majority_sampling_ratio` | List containing positive numbers or `None`                  | Majority-class sampling ratios for binary classification. `[None]` disables class rebalancing. A numeric candidate requires every `weight_mode` candidate to be non-`None`.                                                                 |
  | `weight_mode`             | List containing `"sample"`, `"weighted_loss"`, or `None`    | Sample rows according to weights, weight their loss, or ignore weights during training. Supported for binary classification or weighted training tables, except forecasting; weighted link prediction supports `"weighted_loss"` or `None`. |
  | `lookup_optimization`     | List containing `OptimizerConfig` instances or `"inferred"` | Optimizer and learning rate for link prediction lookup embeddings. `OptimizerConfig` takes `optimizer` and positive `base_lr`.                                                                                                              |
  | `target_fraction`         | List of numbers from 0 to 1, inclusive                      | Fraction of ground-truth links used for supervision in static link prediction; at least one link per entity is retained.                                                                                                                    |
  | `overlap_ratio`           | List of numbers from 0 to 1, inclusive                      | Overlap between message passing and supervision links in static link prediction.                                                                                                                                                            |

  `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:

  ```python
  from kumoapi.model_plan import EarlyStoppingConfig

  plan.training_job.num_experiments = 2
  plan.training_job.manual_seed = 42
  plan.optimization.base_lr = [0.001, 0.003]
  plan.optimization.batch_size = [256]
  plan.optimization.early_stopping = [
      EarlyStoppingConfig(min_delta=0.0, patience=3),
  ]
  ```

  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.
</details>

### 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.

<details>
  <summary>
    Configure row weights and class balancing
  </summary>

  Start with the scalar weighted [custom training table](/kumo-engine/1.0.0/user-code-guide/train-a-model/predictive-queries#use-supplied-training-rows).
  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:

  ```python
  plan = custom_query.suggest_model_plan(
      custom_snapshot, run_mode=RunMode.FAST, train_table_spec=spec
  )
  plan.optimization.weight_mode = ["weighted_loss"]
  plan.optimization.majority_sampling_ratio = [None]
  ```

  Choose one mode before creating `Trainer(plan)` and calling `fit(custom_training_table, snapshot=custom_snapshot)`:

  | `weight_mode`       | Training behavior                                               |
  | ------------------- | --------------------------------------------------------------- |
  | `["weighted_loss"]` | Multiply each example's loss contribution by its weight.        |
  | `["sample"]`        | Use weights to choose training rows more or less often.         |
  | `[None]`            | Ignore row weights for training; evaluation can still use them. |

  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:

  ```python
  plan.optimization.weight_mode = ["sample"]
  plan.optimization.majority_sampling_ratio = [1.0]
  ```

  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](/kumo-engine/1.0.0/user-code-guide/train-a-model/training#train-a-model), 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.
</details>

### Loss Functions

Choose distribution losses only when their assumptions match your target values.

<details>
  <summary>
    Loss names and configuration arguments
  </summary>

  | Task                                             | Supported loss names                                                                                                                                 |
  | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
  | Binary and multilabel classification             | `"binary_cross_entropy"`, `"focal"`.                                                                                                                 |
  | Multiclass classification and multilabel ranking | `"cross_entropy"`, `"ordinal_log"`.                                                                                                                  |
  | Static and temporal link prediction              | `"cross_entropy"`, `"binary_cross_entropy"`.                                                                                                         |
  | Regression and forecasting                       | `"mae"`, `"mse"`, `"huber"`, `"wape"`, `"normal_distribution"`, `"negative_binomial_distribution"`, `"log_normal_distribution"`, `"multi_quantile"`. |

  For custom loss parameters, import the corresponding configuration from `kumoapi.model_plan`:

  | Configuration          | Arguments                                                                                                                                                                 |
  | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `FocalLossConfig`      | `name="focal"`; `alpha` greater than 0 and less than 1 (default `0.25`); `gamma` at least 1 (default `2.0`). Controls class weighting and emphasis on difficult examples. |
  | `HuberLossConfig`      | `name="huber"`; `delta` greater than 0 (default `1.0`). Controls the transition between squared and absolute error.                                                       |
  | `OrdinalLogLossConfig` | `name="ordinal_log"`; `alpha` at least 0 (default `1.0`). Controls the ordinal loss coefficient.                                                                          |
  | `QuantileLossConfig`   | `name="quantile"`; `q` from 0 to 1, inclusive. Selects one quantile for regression or forecasting.                                                                        |

  For a regression query, `plan.optimization.loss = [HuberLossConfig(name="huber", delta=2.0)]` selects a Huber loss with a custom threshold.
</details>

## 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:

```python
from kumoapi.model_plan import GNNModelPlan

plan.model_architecture.model = [
    GNNModelPlan(
        channels=[64, 128],
        aggregation=[["sum", "mean", "max"]],
        dropout=[0.0],
    ),
]
```

### 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`.

<details>
  <summary>
    GNN and Graph Transformer parameters
  </summary>

  | Configuration     | Parameter              | Supported values and meaning                                                                                                                 |
  | ----------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
  | Both              | `channels`             | List of even integers from 2 to 512. Hidden representation size.                                                                             |
  | GNN               | `aggregation`          | List of lists containing `"sum"`, `"mean"`, `"min"`, `"max"`, `"std"`, or `"var"`. Each inner list combines neighbor aggregation operations. |
  | Both              | `dropout`              | List of rates at least 0 and less than 1. Fraction of features dropped during training.                                                      |
  | Graph Transformer | `num_layers`           | List of integers 1 to 12. Transformer depth.                                                                                                 |
  | Graph Transformer | `num_heads`            | List of integers 1 to 32. Attention heads; every candidate channel count must be divisible by every candidate head count.                    |
  | Graph Transformer | `positional_encodings` | List of lists containing `"hop"` or `"random_gnn"`. Use `[[]]` for no positional encoding.                                                   |
</details>

### Shared Architecture Settings

These fields belong directly to `plan.model_architecture`.

<details>
  <summary>
    Shared architecture parameter reference
  </summary>

  | Parameter                         | Supported values                                                                    | Meaning                                                                                                               |
  | --------------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
  | `num_pre_message_passing_layers`  | List of integers 0 to 4                                                             | MLP layers before message passing.                                                                                    |
  | `num_post_message_passing_layers` | List of integers 1 to 8                                                             | MLP layers after message passing.                                                                                     |
  | `activation`                      | List containing `"relu"`, `"leaky_relu"`, `"elu"`, or `"gelu"`                      | Activation function candidates.                                                                                       |
  | `normalization`                   | List containing `"layer_norm"`, `"batch_norm"`, or `None`                           | Normalization layer candidates.                                                                                       |
  | `use_seq_id`                      | List of booleans                                                                    | Encode the order of fact records as a model feature.                                                                  |
  | `prediction_time_encodings`       | List of booleans                                                                    | Encode absolute prediction time for temporal node prediction.                                                         |
  | `past_encoder`                    | List containing `"decomposed"`, `"normalized"`, `"mlp"`, `"transformer"`, or `None` | Encode historical labels for forecasting with positive `lag_timesteps`. Does not apply to temporal regression.        |
  | `handle_new_entities`             | Boolean                                                                             | Forecasting only. `True` uses a shared prediction head; `False` adds learned entity-specific parameters to that head. |
</details>

### 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.

<details>
  <summary>
    Configure forecasting history and entity handling
  </summary>

  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](/kumo-engine/1.0.0/user-code-guide/train-a-model/predictive-queries#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:

  ```python
  plan.model_architecture.past_encoder = ["decomposed"]
  plan.model_architecture.handle_new_entities = True
  ```

  `"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:

  ```python
  plan.model_architecture.past_encoder = [None]
  ```

  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](/kumo-engine/1.0.0/user-code-guide/making-predictions#select-the-population) and the [forecast output example](/kumo-engine/1.0.0/user-code-guide/code-examples/linux-deployment/forecasting#inspect-the-saved-forecast).
  The default output has `ENTITY`, `TIMESTAMP`, and `TARGET_PRED`; select optional `ANCHOR_TIMESTAMP` explicitly when you need the common forecast anchor.
</details>

### Link Prediction and Embeddings

These fields also belong directly to `plan.model_architecture`, and apply to link prediction.

<details>
  <summary>
    Link prediction and embedding parameters
  </summary>

  | Parameter                      | Supported values                                                            | Meaning                                                                                                                                         |
  | ------------------------------ | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
  | `module`                       | `"shallow_rhs"`, `"two_tower"`, `"context"`, `"pairwise"`                   | Prediction head. `"context"` and `"pairwise"` require temporal link prediction.                                                                 |
  | `handle_new_target_entities`   | Boolean                                                                     | Allow predictions involving target entities unseen during training. Keep target feature and embedding choices compatible with this requirement. |
  | `target_embedding_mode`        | List containing `"lookup"`, `"feature"`, `"shallow_feature"`, or `"fusion"` | Use learned target lookup embeddings, target features, shallow target features, or a combination of lookup and features.                        |
  | `output_embedding_dim`         | List of integers 1 to 256                                                   | Output embedding dimension.                                                                                                                     |
  | `ranking_embedding_loss_coeff` | List of numbers at least 0                                                  | Auxiliary embedding loss coefficient for temporal link prediction with `module="context"`.                                                      |
  | `embedding_norm_reg_coeff`     | List of numbers at least 0                                                  | L2 regularization coefficient for final embeddings.                                                                                             |
  | `distance_measure`             | List containing `"dot_product"` or `"cosine"`                               | Similarity function for link scores.                                                                                                            |
</details>

`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](/kumo-engine/1.0.0/user-code-guide/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](/kumo-engine/1.0.0/user-code-guide/train-a-model/predictive-queries#generate-a-training-table) for generation settings and supplied training tables.

Return to [Training](/kumo-engine/1.0.0/user-code-guide/train-a-model/training#train-a-model) to fit your customized plan.