Foundation Model Size & Memory
This page covers everything that determines how training uses your hardware — device selection, distributed strategies, data loading, model size, query parallelization, and caching. For parameters that affect what the model learns, see Model Tuning.
For a small one-GPU foundation run, use the supported memory_constraining_params: reduce hidden_dim first, use num_layers to control depth, and lower emde_quality to reduce sketch input width.
Devices & Distribution
By default, BaseModel trains on a single automatically selected GPU (accelerator: "gpu", devices: "auto", strategy: null). The "auto" setting picks the least-occupied GPU on the machine. It does not switch to CPU when no GPU is available. This is enough for most datasets. Set accelerator: "cpu" only for quick smoke tests — CPU is too slow for real training.
To pin training to a specific GPU, set devices: [0] or any other device index. You may need multi-GPU training if a single card runs out of memory or if you want to speed up a large run. List the specific GPU indices in devices (e.g., [0, 1]) — avoid -1 (all GPUs), because features are loaded onto each device and using all at once may cause out-of-memory errors.
When using multiple devices, set a strategy:
"ddp"(Distributed Data Parallel) — each GPU gets a full copy of the model and processes a different slice of the data. Use this when the model fits on a single card but you want faster training by parallelising across data. Requires at least 2 devices."fsdp"(Fully Sharded Data Parallel) — shards the model across all devices so no single GPU needs to hold the full model. Use this when the model is too large for a single card's memory. Requires at least 2 devices."fsdp:%d:%d"— explicit control over FSDP parallelism: the first integer sets data parallelism (how many model replicas), the second sets tensor parallelism (how many devices share each replica). Use this when you have many GPUs and want to balance memory savings with throughput — e.g.,"fsdp:2:4"on 8 GPUs creates 2 replicas, each sharded across 4 devices.
Start simple, scale if needed
Train on a single GPU first. Move to "ddp" if training is too slow, or to "fsdp" if you hit out-of-memory errors. Check GPU utilization before adding more devices — underutilized GPUs suggest a data loading bottleneck, not a compute one.
See Training Parameters reference for all available fields.
Precision
Precision is set in training_params alongside devices:
| Precision | Details |
|---|---|
"bf16-mixed" | Speed: ~2× Memory: ~50% Best default — auto-selected on CUDA. Use whenever your hardware supports it (A100/H100 and newer) |
"16-mixed" | Speed: ~2× Memory: ~50% Default choice for GPUs without bfloat16 support (pre-Ampere) |
"32" | Speed: baseline Memory: baseline Debugging or when you suspect precision-related convergence issues |
Data Loading
The data_loader_params block controls how data is fed to the model during training. These are PyTorch DataLoader settings:
When to adjust:
- OOM errors — decrease
batch_size(default256). If memory is plentiful, increase it for better GPU utilization. - Slow data pipeline — increase
num_workers(default5;0loads data in the main process) to parallelise data loading. This also splits queries into smaller pieces, reducing memory on the database side. - GPU idle between batches — increase
prefetch_factor(default2) so more batches are loaded in advance per worker. Decrease if prefetching causes memory pressure. - Pinned memory —
pin_memoryis on by default (from 1.14): tensors are copied into pinned host memory so that transfers to the GPU can run asynchronously. Set it tofalseif pinned host memory is constrained. In multi-GPU setups, usepin_memory_deviceto target a specific device. - Final-batch instability — enable
drop_lastto skip the last incomplete batch of each epoch, which can have a much smaller size and cause training noise.
Automatic DataLoader Calibration
Instead of manually tuning num_workers and prefetch_factor, you can let BaseModel find the best values automatically. Enable calibration in your YAML config:
Before foundation model training begins, BaseModel will:
- Estimate a safe worker cap — based on available CPUs and, by default, available RAM. The RAM check measures per-worker buffer memory by probing a sample of entities and caps workers to avoid out-of-memory errors.
- Benchmark candidate configurations — sweeps through combinations of
num_workersandprefetch_factor, measuring throughput in batches per second. Skips warmup batches and stops early when throughput plateaus. - Select the most efficient config — picks the cheapest configuration that achieves at least 90 % of peak throughput, then applies it to the trainer.
The calibration result is saved to the output directory. On resume, the saved result is reloaded without re-running the sweep.
When to adjust:
- Tight memory — lower
ram_safety_margin(default0.2) to allow more workers, or raise it to be more conservative. - Known hardware limits — specify exact worker counts to test via
candidate_workers(e.g.,[0, 4, 6, 8, 12, 14]) instead of the default sweep up to 32. - Fast calibration — reduce
timeout_seconds(default20.0) ormax_measure_batches(default200) to shorten the sweep at the cost of less precise measurements. - Disable RAM cap — set
cap_workers_by_ram: falseif you want to rely only on the CPU-based cap (not recommended for memory-constrained environments).
Calibration vs. manual tuning
If you already know the optimal num_workers for your hardware, set it directly in data_loader_params. Use calibration when deploying to new or heterogeneous hardware where the optimal settings aren't known in advance.
See YAML Configuration → calibration_params for the full parameter reference.
Model Size
The memory_constraining_params block controls the architecture size — use it to fit the model to your available memory or to scale up for richer representations:
When to adjust:
- Memory constraints — reduce
hidden_dim(default2048). This is the primary lever for trading capacity for speed and memory. - Rich data, large datasets — increase
hidden_dimfor more model capacity. Only increasenum_layers(default4) if you still see clear underfitting after tuninghidden_dim. - Reducing input size — lower
emde_quality(default1.0) to produce smaller sketch inputs at the cost of some fidelity. Useful when the model input is very wide.
Query Parallelization
The query_optimization block controls how BaseModel queries data from your backend. Useful for large datasets where a single query would exhaust database or local memory:
query_optimization:
cleora_num_query_chunks: 4
data_loading_num_query_chunks: 1
num_cpus: 4
num_concurrent_features: 4
Start without query_optimization and add it only if you hit memory constraints during data loading.
When to adjust:
- Database memory pressure — increase
cleora_num_query_chunks(fit/embedding phase, default1) and/ordata_loading_num_query_chunks(train/validation/test/predict, default1) to split queries into more partitions. Higher values reduce peak memory at the cost of more sequential reads. Start with4and increase as needed. Mid-epoch resume is unsupported whendata_loading_num_query_chunksis greater than 1. - Faster fit stage — increase
num_concurrent_features(default4) to process more columns in parallel, reducing total fit time. Should not exceed the number of available CPU cores. If image or cleora columns are present, account fornum_cpusthreads per such task: keepnum_concurrent_features × num_cpus ≤ available coresto avoid oversubscription. - Limiting CPU utilization — lower
num_cpus(default4) to restrict how many CPUs are used per column calculator at the start of the pretrain phase.
Data Partitioning
When queries are split into chunks, each data source is split by its partition_column, using its partition_values_transformation:
- type: event
name: transactions
partition_column: customer_id
partition_values_transformation: hash_mod
...
By default, partition_column is the source's main_entity_column and partition_values_transformation is hash_mod, which distributes entities into roughly equal chunks. This avoids loading the entire table at once. For the other transformations, see YAML Configuration → Data Source Fields.
This is configured per data source (inside data_sources), not as a global setting.
- From 1.14,
partition_columnmay be a column listed indisallowed_columns, for example a partition key of the source table that should not become a model input. The column is still used to split queries. - From 1.14, the fit-phase Cleora queries (split by
cleora_num_query_chunks) also use the source'spartition_columnandpartition_values_transformation; previously they always split by hashing the entity column.exact_groupis the exception: for these queries it falls back tohash_modon the entity column.
Use the same chunk rule for all sources
From 1.14, when data loading is split into more than one chunk, all event and main_entity_attribute sources must use the same partition_column and partition_values_transformation. Otherwise the run fails with InvalidConfigurationError: Data sources declare different chunk rules. A source that leaves partition_column unset, or sets it to its own main_entity_column, counts as splitting by its entity column, so the default configuration passes. The number of chunks is the total number of data-loader workers (num_workers, default 5, across all GPUs) multiplied by data_loading_num_query_chunks, so the rule applies with the default settings. In 1.13 and earlier, this was not checked.
To split every source by a derived value during data loading, define the value as an alias in data_params.extra_columns with the same expression for each source, and set partition_column to that alias.
Caching
Cache queried data locally to avoid re-reading from the database on subsequent epochs or downstream tasks:
When set, BaseModel stores query results as Parquet files at the given path and reuses them for later epochs, scenario training, and inference. This is especially useful when the database connection is slow or unstable.
Cache configuration varies by data source type
cache_path in data_params caches query results for every source type, including Parquet. Parquet sources also have their own cache_path inside connection_params, which controls the DuckDB database the Parquet files are loaded into; see Connect Sources.