Unified framework for comparing sequence-model architectures for in-context learning on tabular classification tasks. Includes modular pretraining pipelines, shared priors, and evaluations of Transformer, (Gated) Linear Attention, (Gated) DeltaNet, Kimi Delta Attention, and Mamba2 backbones.
- Installation
- Repository User Guide
- Repository (PFNs) explanation
- Credits
- Similar relevant repositories
Clone the repository with submodules:
git clone --recurse-submodules git@github.com:schnurrd/ICL-Architectures.git
cd ICL-ArchitecturesInstall the required packages and editable installs for PFNs and the TabPFN-v1 prior:
conda create -n icl_arch python=3.11
conda activate icl_arch
pip install -r requirements/requirements.txt \
-e ./PFNs \
-e ./prior-repos/tabpfn-v1-prior
pip install --no-build-isolation causal-conv1d mamba-ssmTested for Nvidia RTX 5070 and Nvidia RTX 2080Ti with CUDA 12.8 and 12.9. For older GPUs with compute capability < 7.0 you might need to install requirements/requirements_old_gpus.txt instead (e.g. Tesla P100, Titan Xp, Titan X). Additionally, torch.compile will not work.
On the clusters with CUDA 11.8, the following versions work:
conda create -n icl_arch python=3.11
conda activate icl_arch
conda install -y -c nvidia/label/cuda-11.8.0 cuda-toolkit
export CUDA_HOME=$CONDA_PREFIX
export PATH=$CUDA_HOME/bin:$PATH
export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH
python -m pip install --no-cache-dir \
--index-url https://download.pytorch.org/whl/cu118 \
torch==2.7.1
python -m pip install --no-cache-dir --no-build-isolation causal-conv1d mamba-ssm
pip install -r requirements/requirements_obsession.txt \
-e ./PFNs \
-e ./prior-repos/tabpfn-v1-priorTo pull the latest changes including submodules, run:
git pull
git submodule update --init --recursiveAdditionally to clean the submodules or main repository run: git submodule foreach git clean -fdx and git clean -fdx for main repository. To see the status of the submodules run: git submodule status.
The training CLI allows you to train PFNs models using configuration from Python files. This provides a flexible and programmable way to configure training parameters, allowing for dynamic configuration generation, conditional logic, and easy reuse of configuration components. Configuration files define either a config variable or a get_config(...) function returning the training configuration.
Transformer example:
python PFNs/pfns/run_training_cli.py PFNs/configs/transformer/transformer_config.py \
--checkpoint-save-load-prefix PFNs/models_diff \
--checkpoint-save-load-suffix no_seed \
--device cuda:0 \
--no-wandb \
--config-index 0FLA example:
python PFNs/pfns/run_training_cli.py PFNs/configs/fla/fla_config.py \
--device cuda:0 \
--checkpoint-save-load-prefix PFNs/models_diff \
--checkpoint-save-load-suffix gla_seed0 \
--config-arg model_type=gla \
--config-arg sequence_mode=Comb_ST \
--config-arg training_setup=high \
--no-wandb \
--config-index 0config_file(required): Path to the Python configuration file that defines either aconfigvariable or aget_config(...)function--device: Device to use for training (e.g., 'cuda:0', 'cpu'). If not specified, will auto-detect.--compile: Use torch.compile for the model (requires PyTorch 2.0+)--checkpoint-save-load-prefix: Path to save/load checkpoint (and default wandb dir).--checkpoint-save-load-suffix: Suffix to add to the checkpoint save/load path. This can, e.g., be the seed.--wandb/--no-wandb: Enable/disable wandb logging (wandb settings come from the config file).--continue-from-wandb: Continue training from a wandb run path (entity/project/run_idorproject/runs/run_id), downloading the checkpoint if needed.--config-index: Index of the config to use. This is used to select a config from the config file.--config-arg: Extraget_configkeyword argument asKEY=VALUE; repeat for multiple overrides.--overwrite: Start fresh even if a checkpoint/config exists at the target path (do not load, overwrite on save).--train-mixed-precision/--no-train-mixed-precision: Override mixed precision on/off after loading the config/checkpoint.--train-mixed-precision-dtype: Override mixed precision dtype after loading the config/checkpoint (e.g.auto,fp16,bf16,fp32).
The evaluation CLI allows you to evaluate trained PFNs/TabPFN-style models on OpenML benchmarks. It reports tabular classification metrics and can load either a local checkpoint directory or a wandb run.
python PFNs/pfns/run_evaluation_cli.py \
--model_path PFNs/models_diff/transformer_config_0_no_seed_default \
--benchmark opencc \
--n_splits 5 \
--output results.csv \
--batch_size_inference 16This --model_path matches the transformer training example above when run with --no-wandb. If wandb is enabled, replace default with the wandb run ID printed by the training command.
--model_path: Path to the trained model checkpoint directory. Provide this or--wandb_run_id.--checkpoint_name: Name of the checkpoint file within the model path (default: 'checkpoint.pt')--wandb_run_id: wandb run path or ID to download/evaluate instead of a local checkpoint path.--device: Device to use for evaluation (e.g., 'cuda:0', 'cpu'). Default: auto-detect--benchmark: Benchmark suite to evaluate on. Choices: 'opencc' (OpenML-CC18), 'openml_large_dataset', 'tabarena_full', 'tabarena_medium'. Default: 'opencc'--max_samples: Maximum number of samples per dataset (default: 1000)--max_features: Maximum number of features per dataset (default: 20)--max_classes: Maximum number of classes per dataset (default: 10)--n_splits: Number of cross-validation splits (default: 5)--output: Path to save results as CSV file. If not provided, results are only printed to console--n_jobs: Number of CPU cores passed to evaluation helpers where applicable. Default: 4--batch_size_inference: Batch size for TabPFN inference (default: 32). Lower values reduce GPU memory usage without affecting accuracy - useful for memory-constrained environments--n_ensemble_configurations: Number of ensemble configurations for TabPFN (default: 32)--preprocess_transforms: Preprocessing transforms to ensemble over (default:none power robust)--sample_order_permutation: Permute training sample order for each ensemble configuration--fla_cache_chunk_size: Chunk size for cache-backed inference when using an FLA backbone
wandb is configured via MainConfig.wandb. The CLI can toggle logging via --wandb / --no-wandb or continue from an existing run via --continue-from-wandb.
For restricted environments, set mode="offline" in the config file (or WANDB_MODE=offline) and sync later with wandb sync.
The Python configuration file must define either a config variable or a
get_config(config_index: int = 0) function, which when called returns a
MainConfig object. An example configuration file can be found at
PFNs/configs/example_config.py; the main TabPFN-style transformer config is
PFNs/configs/transformer/transformer_config.py.
The main FLA config is PFNs/configs/fla/fla_config.py. It supports
model_type values such as kda, gla, mamba2, deltanet,
gated_deltanet, and linear_attn, plus sequence-mode,
bidirectional, state-passing, cache, categorical-feature, and mimetic-init
options via --config-arg.
Curriculum learning is configured via get_config(...) arguments in configs such as
PFNs/configs/transformer/transformer_config.py and PFNs/configs/fla/fla_config.py.
From the CLI, pass these through repeatable --config-arg KEY=VALUE arguments.
max_seq_len(default:1000): Upper bound for sampled sequence length.seq_len_stages(default:None): Optional staged sequence-length settings by epoch. Entries are applied in order. After the last stage, sampling falls back to a fixed sequence length ofmax_seq_len. Every stage max sequence length must be<= max_seq_len. Supported formats:(end_epoch, stage_max_seq_len)(end_epoch, stage_max_seq_len, eval_pos_split_pct_min, eval_pos_split_pct_max)(end_epoch, stage_min_seq_len, stage_max_seq_len, seq_len_distribution)(end_epoch, stage_min_seq_len, stage_max_seq_len, seq_len_distribution, eval_pos_split_pct_min, eval_pos_split_pct_max)Whereseq_len_distributionis one of:fixed: usestage_max_seq_len.uniform: sample integer sequence length uniformly in[min_seq_len, max_seq_len].log_uniform: sample sequence length log-uniformly in[min_seq_len, max_seq_len].shifted_lognormal: sample sequence length from a shifted log-normal distribution calibrated for long-sequence staged training.
Examples:
--config-arg max_seq_len=16000 --config-arg seq_len_stages='[(5, 2048), (20, 8192), (60, 16000)]'--config-arg max_seq_len=12000 --config-arg seq_len_stages='[(10, 4000, 80, 80), (30, 12000, 30, 90)]'- First stage: fixed eval split at 80%.
- Second stage: eval split sampled from 30%-90%.
--config-arg max_seq_len=64000 --config-arg seq_len_stages='[(150, 1000, 5000, "uniform"), (200, 5000, 64000, "log_uniform")]'- First stage: sample seq len uniformly from 1k to 5k.
- Second stage: sample seq len log-uniformly from 5k to 64k.
eval_pos_split_pct(default:None): Global eval split in percent forsingle_eval_pos.- Scalar: fixed split, e.g.
80means always 80% of sequence length. - Pair: range, e.g.
(30, 90)means sampled uniformly between 30% and 90%.
- Scalar: fixed split, e.g.
- Stage-level split values in
seq_len_stagesoverride the globaleval_pos_split_pctfor those epochs. - Split percentages must be between 0 and 100, with min
<=max.
batch_size_stages(default:None): Optional sequence-length thresholds for batch size.- Format:
[(seq_len_threshold, batch_size), ...]with increasing thresholds. - The first threshold
>= sampled_seq_lenis used. - If
sampled_seq_lenexceeds the largest threshold, the last configured batch size is used. - Example:
[(4096, 16), (16000, 8), (64000, 4)].
- Format:
dynamic_batch_size_compensate_grad_accumulation(default:False):- If enabled, each micro-batch contributes optimizer-step progress proportional to
dynamic_batch_size / base_batch_size. - This keeps effective batch size approximately stable when dynamic batch sizing is active.
- If enabled, each micro-batch contributes optimizer-step progress proportional to
These are part of BatchShapeSamplerConfig and influence the same sampling process:
min_single_eval_pos: Minimum position where evaluation targets start (single_eval_poslower bound).fixed_num_test_instances: If set, enforces a fixed number of test items and derives finalseq_lenfromsingle_eval_pos + fixed_num_test_instances.min_num_features,max_num_features: Feature-count sampling range per batch.seed(default:42): Seed used with(epoch, step)for deterministic batch-shape sampling.
Main sequence-length, real-world, and hidden-state analysis notebooks
The main sequence-length, real-world, and hidden-state analysis notebooks are:
- Sequence-length comparison and generalization
- Real-world experiments
- Minimal linear-attention sequence-length generalization
- Sequence-length hidden-state debugging
The Sequence-length comparison and generalization, Real-world experiments, and Sequence-length hidden-state debugging notebooks require trained model checkpoints. Before running these notebooks, register the checkpoints in model_registry.py. The minimal sequence-length degradation notebook is intended as a lightweight standalone reproduction.
The minimal reproduction for the linear-attention sequence-length degradation question is the notebook minimal_linear_attention_seq_len_generalization.ipynb. It trains small causal and non-causal linear-attention PFN variants on short contexts and evaluates them on longer context lengths.
For non-interactive runs, the notebook has a script companion:
minimal_linear_attention_seq_len_generalization.py.
It writes outputs under minimal_linear_attention_seq_len_generalization_runs/
unless --output-root is set, and can log to the
minimal_linear_attention_seq_len_generalization wandb project with --wandb.
- The CLI script
run_training_cli.pyis executed with the path to a configuration file and the CLI parameters. This first parses the CLI arguments and then loads the configuration file as a Python module. It retrieves theconfigvariable or calls theget_configfunction to obtain theMainConfigobject. - The
MainConfigobject includes all the necessary objects for the training process, including the prior, model, batch shape sampler, optimizer and training loop configuration. If we have already started a training with the same name and have stored a checkpoint the config gets updated to load the checkpoint. - The training loop is started by calling the
pfns.train.trainfunction with the createdMainConfigobject.
Dataclass (see PFNs/pfns/train.py) that includes all necessary components for training. Specifically includes:
- Prior and optimizer:
- Prior: prior.PriorConfig objects defining the prior
- Optimizer: OptimizerConfig object defining the optimizer
- Model:
- model: ModelConfig object defining the model architecture
- Training:
- batch_shape_sampler: BatchShapeSamplerConfig object which samples num_features, and single_eval_pos for each batch
- epochs: Number of training epochs
- steps_per_epoch: Number of steps per epoch (we don't really have a concept of epochs since data is infinite, so this defines how many steps we call an epoch)
- aggregate_k_gradients: Number of batches to aggregate gradients over before performing an optimizer step, allowing a larger effective batch size than fits in GPU memory
- n_targets_per_input: Used if a model is trained to predict multiple targets per input
- train_mixed_precision, train_mixed_precision_dtype
- skip_grad_norm_spike_factor
- LR Scheduler:
- scheduler, warmup_epochs, min_lr
- Checkpointing:
- train_state_dict_save_path, train_state_dict_load_path
- Validation:
- test_priors: prior.PriorConfig objects to use for validation during training
- validation_period: How often to run validation (in epochs)
- Logging:
- verbose, progress_bar, wandb, wandb_run_id: Logging options
- Data loading
- dataloader_class, num_workers
Encoders are a sequence of (learned) transformations (encoding steps) that process the input data (x and y) before mapping it into an embedding that is fed into the main sequence model (e.g. Transformer). Different encoding steps can be stacked to form the final encoder. The different encoders currently implemented are in PFNs/pfns/model/encoders.py and implement the abstract base class SeqEncStep:
- ConstantNormalizationInputEncoderStep: Input normalization with a provided mean and std.
- InputNormalizationEncoderStep: Performs simple outlier soft clipping using logarithmic compression and input normalization to mean 0 and std 1.
- VariableNumFeaturesEncoderStep: Transforms input to a fixed number of features by appending zeros and performs normalization by number of features used to keep variance consistent.
- NanHandlingEncoderStep: Creates NaN masks for input and target and replaces NaNs with feature mean.
- OrdinalEncoderStep: Encodes categorical feature values as ordinal IDs using the training context.
- MixedFeatureEncoderStep: Applies categorical or continuous preprocessing per feature based on categorical feature metadata.
- LinearInputEncoderStep: Linear layer to map input features to model dimension (num_features -> embedding size). Normally a single layer but with optional 2-layer MLP with GELU activation.
These individual encoders can be combined using the SequentialEncoder class to form a complete encoding pipeline.
Style Encoder: Special encoder that encodes metadata (e.g. hyperparameters) that describes how the data was generated, allowing the model to condition on this information.
The default encoding of the transformer model creates one embedding per feature. TabPFN v1 used one embedding per row (features_per_group = num_features). The larger features_per_group is set, the fewer tokens the sequence model has to process, reducing memory and compute requirements. However, this also reduces the model capacity.
The model both encodes the input features (X) and the target (y) separately. Each of which goes through its own pipeline and has its own learned parameters.
Without positional embeddings, the model cannot distinguish between different feature groups as attention is permutation-invariant. The feature_positional_embedding adds a unique identifier to each feature group's embedding. Options are:
None: No embedding (features indistinguishable)normal_rand_vec: Random Gaussian vectors (fixed per seed)uni_rand_vec: Random uniform [-1, 1] vectorslearned: Lookup table of 1000 learnable embeddingssubspace(recommended): Random vectors projected through a learned linear layer — combines random uniqueness with learnable representations
The random embeddings use a fixed seed, ensuring consistent feature IDs across forward passes while different models get different IDs.
The model core is selected via ModelConfig.backbone, which uses the Backbone / BackboneConfig interfaces in PFNs/pfns/model/backbones.py. Current backbone implementations include:
- TransformerBackbone: PFN-style per-feature Transformer stack.
- FLABackbone and BidirectionalFLABackbone: Wrappers for Flash Linear Attention models such as GLA, DeltaNet, Gated DeltaNet, KDA, Mamba2, Linear Attention, and MesaNet.
- LinearAttentionBackbone and related experimental backbones for local linear-attention variants.
The Transformer backbone extends the standard Transformer architecture to operate on a per-feature basis, which allows for processing each feature separately. It only consists of encoder blocks (no decoder blocks). Specifically, the Transformer backbone is a stack of PerFeatureLayer layers.
Transformer encoder layer that processes each feature block separately. Does Multi-head attention between features, multi-head attention between items, and feedforward neural networks (MLPs).
Architecture flow:
- Attention between features (optional): Each feature group attends to other feature groups. Operates independently for each item in the sequence.
- Second MLP (optional): Extra feedforward between attention layers
- Attention between items: Items/samples attend to other items in the sequence. Each feature group attends to itself across items.
- MLP: Standard feedforward network
Each sublayer is followed by layer normalization (post-norm).
The main features here are:
- Two attention axes: Attends across both features AND items (unlike standard transformers)
- Train/test split:
single_eval_posseparates training context from test items, enabling causal masking for in-context learning
The decoder is a simple MLP output head that maps the y-token embeddings from test items to prediction logits:
- After the transformer layers, extract the y-token embedding (last token in feature dimension) for each test item
- Pass through MLP:
Linear(d_model → nhid) → GELU → Linear(nhid → n_outputs)
The y-token for test items initially encodes "unknown label" (via NaN handling), and through attention with training context, accumulates information needed for prediction.
TabPFNClassifier is the main prediction interface with a modular architecture supporting swappable model backbones. The training set is provided via fit(X_train, y_train), and predictions are made on new data with predict(X_test) or predict_proba(X_test).
The inference pipeline consists of three main components:
-
EnsembleConfig: Dataclass defining configuration for each ensemble member (class shift, feature shift, preprocessing transform type)
-
InferenceEngine: Handles preprocessing, ensemble prediction, and aggregation
- Manages preprocessing transformations (PowerTransformer, QuantileTransformer, RobustScaler)
- Applies class/feature shifts for ensemble diversity
- Batches inference across ensemble members and aggregates results
-
Backbone interface: Swappable neural architecture interface implemented in
PFNs/pfns/model/backbones.pyTransformerBackbone: Wrapper for the PFN-style Transformer stackFLABackbone: Wrapper for Flash Linear Attention backbones used by GLA, DeltaNet, KDA, Mamba2, Linear Attention, MesaNet, and related variants
During the fit call, the training data is preprocessed:
- Y values are encoded via sklearn's LabelEncoder (outputs 0,...,n_classes-1)
- X and y are stored for use during prediction (no actual training occurs here)
During predict/predict_proba calls:
- Generate ensemble configurations: Create N configurations with random class/feature shifts and preprocessing transforms
- Preprocess data: InferenceEngine applies transforms (with caching by transform type), removes constant features, handles outliers
- Apply shifts: Circular shift classes/features according to each configuration
- Batch inference: Forward passes through model backbone in batches
- Aggregate: Reverse class shifts, average logits across ensemble, apply softmax
This repo builds on:
- PFNs (Apache 2.0) for the core training pipeline and priors. Used as the starting repository.
- TabPFN-v1-prior (Apache 2.0) for the tabpfn v1 prior implementation.
- TabPFN the TabPFN model and prior implementation.
- TFM-Playground (Apache 2.0) open source playground containing nanoTabPFN with more diverse prior support.
- nanoTabPFN small educational version of TabPFN.
- TabICL For the TabICL model and prior implementation from Inria.