Skip to main content

logo

A Deep Learning Framework for Multi-target Prediction

CI PyPi Version PyPi Version Alt PyPi Python Versions GitHub license

GitHub issues GitHub stars


DeepMTP is a PyTorch framework for multi-target prediction (MTP). It supports multi-label classification (MLC), multivariate regression (MTR), multi-task learning (MTL), dyadic prediction (DP), and matrix completion (MC) through a common two-branch architecture.

Current capabilities

  • Dense MLP, sparse, mixed tabular, token-sequence GRU, Conv1D, Transformer, molecular graph GIN/GINE, image, learned ID-embedding, and custom branch encoders.
  • Dot-product, concatenation-plus-MLP, and Kronecker-product fusion.
  • Validation settings A–D for known and novel instances and targets.
  • Binary and multiclass classification plus regression metrics, early stopping, checkpoints, deterministic undersampling, and top-k grouped metrics where applicable.
  • Random-search and Hyperband optimization, plus optional TensorBoard, Weights & Biases, and Streamlit integrations.
  • Typed configuration, model-ready batches, and early validation of invalid data or model combinations.

DeepMTP 0.0.23 contains substantial changes beyond the previous 0.0.22 release. Read the changelog and migration guide before upgrading an existing experiment. The neural-network roadmap tracks implemented and planned model extensions.

Documentation

Installing DeepMTP

DeepMTP is tested on Python 3.10 through 3.14. CPU execution is fully supported; a CUDA-capable GPU is optional and is most useful for larger experiments.

Installing from PyPI

python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
python -m pip install --upgrade pip
pip install DeepMTP

For GPU acceleration, install the appropriate PyTorch build for your platform using the official PyTorch selector before installing DeepMTP.

Optional integrations are installed explicitly:

pip install "DeepMTP[datasets]"   # downloadable benchmark datasets
pip install "DeepMTP[hpo]"        # ConfigSpace-based optimization
pip install "DeepMTP[graph]"      # PyTorch Geometric graph encoders
pip install "DeepMTP[image]"      # Torchvision image models/transforms
pip install "DeepMTP[sparse]"     # SciPy sparse matrices
pip install "DeepMTP[streamlit]"  # Streamlit progress adapters
pip install "DeepMTP[tracking]"   # TensorBoard and Weights & Biases
pip install "DeepMTP[all]"        # every runtime integration

Streamlit-specific trainers, optimizers, and progress observers live under the optional integration namespace:

from DeepMTP.integrations.streamlit import (
    DeepMTP as StreamlitDeepMTP,
    HyperBand,
    RandomSearch,
)

Installing from Source

git clone https://github.com/diliadis/DeepMTP.git
cd DeepMTP
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install -e . --group dev
python -m pytest

Conda users can instead bootstrap the environment and install the same development group:

conda env create -f environment.yml
conda activate deepmtp
python -m pip install --group dev

Development commands and contribution expectations are documented in CONTRIBUTING.md.

Upgrading an experiment from the published 0.0.22 release requires a few behavioral checks. See the 0.0.22 to 0.0.23 migration guide for before-and-after examples covering configuration, data preparation, predictions, checkpoints, and optional integrations.

Project maintenance is documented in the changelog, contributor guide, security policy, and release checklist.

Background

What is MTP?

Multi-target prediction (MTP) serves as an umbrella term for machine learning tasks that concern the simultaneous prediction of multiple target variables. These include:

  • Multi-label Classification
  • Multivariate Regression
  • Multitask Learning
  • Hierarchical Multi-label Classification
  • Dyadic Prediction
  • Zero-shot Learning
  • Matrix Completion
  • (Hybrid) Matrix Completion
  • Cold-start Collaborative Filtering

Despite the significant similarities, all these domains have evolved separately into distinct research areas over the last two decades. To better understand these similarities and differences it is important to get accustomed to the terminology and main concepts used in this field.

logo

logo

A multi-target prediction problem is characterized by instances $x \in X$ and targets $t \in T$ with the following properties:

  1. A training dataset $\mathcal{D}$ contains triplets $(x_{i},t_{j},y_{ij})$, where $x_i \in \mathcal{X}$ represents an instance, $t_j \in \mathcal{T}$ represents a target, and $y_{ij} \in \mathcal{Y}$ is the score that quantifies the relationship between an instance and a target, with $i\in{1,\ldots,n}$ and $j\in{1,\ldots,m}$. The scores can be arranged in an $n \times m$ matrix $\mathbf{Y}$ that is usually incomplete.

  2. The score set $\mathcal{Y}$ consists of nominal, ordinal or real values.

  3. During testing, the objective is to predict the score for any unobserved instance-target couple $(\mathbf{x},\mathbf{t}) \in \mathcal{X} \times \mathcal{T}$.

The practical questions for a multi-target prediction problem are:

  1. What are the instances, targets, and observed interaction scores?
  2. Is the score categorical, ordinal, or continuous?
  3. Which side features are available for instances and targets?
  4. Does evaluation include instances or targets that were absent from training?

How does DeepMTP work?

DeepMTP maps an instance and a target through separate branch encoders, producing representation vectors $p_x$ and $q_t$. A branch can consume dense features, sparse high-dimensional vectors, explicitly declared numeric and categorical columns, token sequences, images, zero-based entity IDs, named combinations of those representations, or a custom input type. The two representations are combined with a dot product, concatenation followed by an MLP, or a Kronecker product to predict the score of the instance-target pair. Dot-product models require equal branch widths; the other fusion strategies can combine different widths.

For classification, the combined model produces logits. Binary classification uses BCEWithLogitsLoss and sigmoid probabilities. Multiclass classification uses CrossEntropyLoss, one logit per mutually exclusive class, and softmax probabilities. Regression defaults to mean squared error and can instead optimize mean absolute error or Huber loss through the validated loss configuration field.

Reusable branch models, combined architectures, and the model factory are available from the focused model namespace:

from DeepMTP.models import (
    CompositeEncoder,
    ConvNet,
    IDEmbedding,
    MLP,
    ModelFactory,
    SparseMLP,
    TabularEncoder,
)

Model-ready dataloaders return a typed MTPBatch. It retains the historical dictionary keys while exposing modality-specific instance_input and target_input objects:

from DeepMTP.data import (
    CompositeBranchBatch,
    CompositeInput,
    DenseBranchBatch,
    IDBranchBatch,
    MaskedComponentInput,
    MTPBatch,
    SparseBranchBatch,
    TabularBranchBatch,
)
from DeepMTP.models import BranchEncoder

Every built-in encoder declares its input kind and output dimension. Fusion models validate that each encoder returns a floating tensor shaped [batch_size, output_dim], producing focused errors before an invalid representation reaches the fusion operation.

logo

logo

The following examples adapt the same compound-protein interaction task to different feature-availability scenarios.

Handling missing features for instances and/or targets

Click to expand!
  1. In the first example, compound features are available but protein features are not. The first branch uses compound side information and the second branch uses one-hot encoded protein IDs. The real-valued interaction scores make this a regression task.

logo

logo

  1. The second example reverses the available side information: the first branch uses one-hot encoded compound IDs and the second branch uses the provided protein features.

logo

logo

  1. In the third example, side information is provided for both proteins and compounds, so both branches can utilize it.

logo

logo

  1. In the fourth and final example of this subsection, we are missing features for both instances and targets. This is not a realistic setting in our compound-protein interaction prediction task but has many applications in the area of recommender systems. In terms of the neural network, one-hot encoded vectors are used for both branches.

logo

logo

Existing MLP configurations retain this one-hot behavior. An EMBEDDING branch provides an opt-in, memory-efficient alternative that learns a dense vector directly from each zero-based entity ID:

from DeepMTP import DeepMTPConfig

number_of_instances = 24
number_of_targets = 4

config = DeepMTPConfig(
    validation_setting="A",
    problem_mode="classification",
    general_architecture_version="dot_product",
    metrics_average=["micro"],
    instance_branch_architecture="EMBEDDING",
    instance_branch_input_dim=number_of_instances,
    target_branch_architecture="EMBEDDING",
    target_branch_input_dim=number_of_targets,
    embedding_size=32,
)

instance_branch_input_dim and target_branch_input_dim are vocabulary sizes for embedding branches. Interaction IDs must be integers in the range [0, input_dim). Because a lookup table cannot represent an unseen entity, support depends on the validation setting:

Validation setting Instance embedding Target embedding
A: known instances and targets Supported Supported
B: novel instances Rejected Supported
C: novel targets Supported Rejected
D: novel instances and targets Rejected Rejected

Handling different types of input features

Click to expand!

Each DeepMTP branch can use an encoder appropriate for its input modality. In the example below, protein features are dense vectors while compounds are represented by 2D images. The framework combines an MLP branch for the protein features with a convolutional branch for the compound images.

logo

logo

Handling different validation settings

Click to expand!

The four validation settings describe whether evaluation contains entities that were observed during training.

  1. Setting A: Completing the missing values in the interaction matrix

In setting A the test set contains a subset of the instances and targets that we observe in the training set. This setting is usually selected when the interaction matrix contains missing values and becomes the only validation choice when instance and target features are not available.

logo

logo

  1. Setting B: predict for novel instances

In setting B the test set contains instances never before observed in the training set. This setting is the default option for popular MTP problem settings like multi-label classification and multivariate regression. In order to generalize to new instances, their side information has to be provided!

logo

logo

  1. Setting C: predict for novel targets

In setting C the test set contains targets never before observed in the training set. This setting can be seen as the reverse of Setting B, as we can easily switch the instances and targets and arrive in Setting C. In order to generalize to new targets, their side information has to be provided!

logo

logo

  1. Setting D: predict for pairs of novel instances and targets

Finally, in setting D the test set contains pairs of novel instances and targets never before observed in the training set. This is usually considered the most difficult generalization task compared to the others. In order to generalize to pairs of new instances and targets, the side information for both has to be provided!

logo

logo

Quick start

This complete example trains on a small synthetic multi-label dataset, runs on the CPU, and requires no downloads or optional dependencies. DeepMTP writes the experiment summary and configuration below results/quickstart.

import numpy as np

from DeepMTP import DeepMTP, DeepMTPConfig, data_process

rng = np.random.default_rng(42)
scores = (
    np.arange(24)[:, np.newaxis] + np.arange(4)[np.newaxis, :]
) % 2
data = {
    "train": {
        "y": scores,
        "X_instance": rng.normal(size=(24, 3)),
        "X_target": None,
    }
}
train, validation, test, data_info = data_process(
    data,
    validation_setting="B",
)

config = DeepMTPConfig(
    validation_setting=data_info["detected_validation_setting"],
    problem_mode=data_info["detected_problem_mode"],
    general_architecture_version="dot_product",
    compute_mode="cpu",
    num_workers=0,
    train_batchsize=16,
    val_batchsize=16,
    num_epochs=1,
    metrics=["accuracy"],
    metrics_average=["macro"],
    evaluate_val=True,
    use_early_stopping=False,
    save_model=False,
    results_path="results",
    experiment_name="quickstart",
    instance_branch_architecture="MLP",
    instance_branch_input_dim=data_info["instance_branch_input_dim"],
    instance_branch_nodes_per_layer=[8],
    target_branch_architecture="MLP",
    target_branch_input_dim=data_info["target_branch_input_dim"],
    target_branch_nodes_per_layer=[8],
    embedding_size=4,
)

model = DeepMTP(config)
validation_results = model.train(train, validation, test)
test_results, predictions = model.predict(test, return_predictions=True)

Multiclass classification

Multiclass mode predicts exactly one of three or more classes for each instance-target pair. Labels must be zero-based integer IDs in [0, C). Declare the interpretation during data preparation because integer-valued regression scores cannot be distinguished safely from class IDs:

import numpy as np

from DeepMTP import DeepMTPConfig, data_process

scores = (
    np.arange(18)[:, np.newaxis] + np.arange(3)[np.newaxis, :]
) % 3
train, validation, test, data_info = data_process(
    {"train": {"y": scores}},
    validation_setting="A",
    classification_mode="multiclass",
)

config = DeepMTPConfig(
    validation_setting=data_info["detected_validation_setting"],
    problem_mode="classification",
    classification_mode=data_info["detected_classification_mode"],
    num_classes=data_info["detected_num_classes"],
    metrics=["accuracy", "f1_score", "auroc"],
    metrics_average=["micro"],
    multiclass_average="macro",
    compute_mode="cpu",
    instance_branch_architecture="EMBEDDING",
    instance_branch_input_dim=data_info["instance_branch_input_dim"],
    target_branch_architecture="EMBEDDING",
    target_branch_input_dim=data_info["target_branch_input_dim"],
    embedding_size=8,
)

CrossEntropyLoss and macro class averaging are selected automatically. metrics_average still controls whether observations are grouped globally, per target, or per instance; multiclass_average controls how classes are combined inside precision, recall, F1, AUROC, and AUPR. Set it to micro, macro, or weighted.

All declared classes must occur in the training interactions. Prediction frames contain predicted_values as class IDs, predicted_probability for the winning class, and one probability_class_<id> column per class. Interaction-ranking top_k metrics are not available in multiclass mode. See the multiclass guide for the complete contract.

Mixed tabular inputs

Use a TABULAR branch when entity side information contains both continuous measurements and categories. Pass a pandas DataFrame with a unique id column and declare the remaining columns explicitly:

import pandas as pd

from DeepMTP import DeepMTPConfig

instance_features = pd.DataFrame(
    {
        "id": [0, 1, 2],
        "age": [22.0, None, 41.0],
        "site": ["Ghent", "Paris", "Ghent"],
    }
)

tabular_schema = {
    "numeric_columns": ["age"],
    "categorical_columns": {
        "site": {
            "categories": ["Ghent", "Paris"],
            "embedding_dim": 2,
        }
    },
    "numeric_normalization": "standard",
    "numeric_missing": "mean",
    "categorical_unknown": "unknown",
    "feature_gating": True,
}

number_of_targets = 4

config = DeepMTPConfig(
    validation_setting="B",
    problem_mode="classification",
    general_architecture_version="dot_product",
    instance_branch_architecture="TABULAR",
    instance_branch_tabular_schema=tabular_schema,
    instance_branch_nodes_per_layer=[16],
    target_branch_architecture="EMBEDDING",
    target_branch_input_dim=number_of_targets,
    embedding_size=8,
)

Numeric preprocessing is fitted only on the training entities. Its imputation and normalization statistics are stored in the experiment configuration and checkpoint, then reused for validation, testing, and restored-model prediction. Category index zero represents missing or unknown values by default. See the mixed tabular input guide for policies and a complete configuration.

Sparse high-dimensional inputs

Use a SPARSE branch for fingerprints, bag-of-words features, and large indicator matrices whose stored values are mostly zero. PyTorch COO/CSR tensors work with the core installation. SciPy matrices require pip install "DeepMTP[sparse]".

from scipy import sparse

from DeepMTP import DeepMTPConfig

instance_features = sparse.csr_matrix(dense_or_generated_features)

config = DeepMTPConfig(
    validation_setting="B",
    problem_mode="classification",
    general_architecture_version="dot_product",
    instance_branch_architecture="SPARSE",
    instance_branch_input_dim=instance_features.shape[1],
    instance_branch_nodes_per_layer=[128, 32],
    target_branch_architecture="MLP",
    target_branch_input_dim=number_of_targets,
    target_branch_nodes_per_layer=[32],
    embedding_size=32,
)

Sparse rows remain sparse through data preparation, splitting, collation, and the first linear projection. Later layers operate on the projected dense representation. Legacy feature scaling rejects sparse inputs rather than silently densifying them; apply sparse-safe preprocessing upstream. See the sparse input guide for explicit-ID DataFrames, compatibility details, and the included memory and throughput benchmark.

Token-sequence inputs

Use a SEQUENCE branch for already-tokenized proteins, chemical strings, or text. Declare the representation during data preparation so variable-length integer rows are preserved:

instance_sequences = [[5, 12, 8], [7], [3, 14, 9, 6]]

train, validation, test, data_info = data_process(
    {
        "train": {
            "y": interaction_scores,
            "X_instance": instance_sequences,
            "X_target": None,
        }
    },
    validation_setting="B",
    instance_feature_kind="sequence",
)

The configured input dimension is the complete vocabulary size, not the maximum sequence length:

from DeepMTP import DeepMTPConfig

vocabulary_size = 32
number_of_targets = 4

config = DeepMTPConfig(
    validation_setting="B",
    problem_mode="classification",
    general_architecture_version="dot_product",
    instance_branch_architecture="SEQUENCE",
    instance_branch_input_dim=vocabulary_size,
    instance_branch_sequence_encoder="transformer",
    instance_branch_sequence_embedding_dim=16,
    instance_branch_sequence_transformer_num_heads=4,
    instance_branch_sequence_transformer_feedforward_dim=64,
    instance_branch_sequence_num_layers=1,
    instance_branch_sequence_padding_idx=0,
    target_branch_architecture="MLP",
    target_branch_input_dim=number_of_targets,
    target_branch_nodes_per_layer=[8],
    embedding_size=8,
)

The dataloader dynamically creates padded token IDs, attention masks, and original lengths. Choose gru for recurrence, conv1d for masked temporal convolutions, or transformer for position-aware self-attention with masked mean pooling. All three ignore padded positions and emit the same fixed-width branch representation expected by every existing fusion model. Raw sequences must be unpadded and cannot contain the configured padding ID. See the token-sequence input guide for the structured batch contract, configuration options, and compatibility details.

Molecular graph inputs

Install pip install "DeepMTP[graph]" and pass precomputed homogeneous torch_geometric.data.Data objects. Each object needs floating node features x, COO edge_index, and optionally floating edge_attr. Declare the graph representation during preparation:

train, validation, test, data_info = data_process(
    {
        "train": {
            "y": interaction_scores,
            "X_instance": molecular_graphs,
            "X_target": None,
        }
    },
    validation_setting="B",
    instance_feature_kind="graph",
)

Configure GRAPH with the inferred node and edge widths:

config = DeepMTPConfig(
    validation_setting="B",
    problem_mode="classification",
    instance_branch_architecture="GRAPH",
    instance_branch_input_dim=data_info["instance_branch_input_dim"],
    instance_branch_graph_edge_dim=data_info["instance_branch_graph_edge_dim"],
    instance_branch_graph_hidden_dim=64,
    instance_branch_graph_output_dim=32,
    instance_branch_graph_num_layers=3,
    instance_branch_graph_pooling="mean",
    instance_branch_graph_use_edge_features=True,
    target_branch_architecture="MLP",
    target_branch_input_dim=number_of_targets,
    target_branch_nodes_per_layer=[32],
    embedding_size=32,
)

DeepMTP uses GINE when edge features are enabled and GIN when graph_use_edge_features=False. PyG performs batching; the rest of DeepMTP sees a typed GraphInput containing node features, offset edge indices, optional edge features, graph membership, and the graph count. GRAPH is also available as a required or optional COMPOSITE component. See the graph input guide.

Composite inputs

Use a COMPOSITE branch when one entity has multiple representations, such as dense descriptors plus a token sequence:

train, validation, test, data_info = data_process(
    {
        "train": {
            "y": interaction_scores,
            "X_instance": {
                "descriptors": descriptor_matrix,
                "tokens": token_sequences,
            },
            "X_target": None,
        }
    },
    validation_setting="B",
    instance_feature_kind={
        "descriptors": None,
        "tokens": "sequence",
    },
)

component_dims = data_info["instance_branch_component_input_dims"]
config = DeepMTPConfig(
    validation_setting="B",
    problem_mode="classification",
    metrics=["accuracy"],
    metrics_average=["macro"],
    instance_branch_architecture="COMPOSITE",
    instance_branch_composite_fusion="attention",
    instance_branch_composite_attention_dim=32,
    instance_branch_composite_attention_num_heads=4,
    instance_branch_composite_components={
        "descriptors": {
            "architecture": "MLP",
            "input_dim": component_dims["descriptors"],
            "output_dim": 16,
        },
        "tokens": {
            "architecture": "SEQUENCE",
            "input_dim": component_dims["tokens"],
            "output_dim": 16,
            "embedding_dim": 16,
        },
    },
    target_branch_architecture="MLP",
    target_branch_input_dim=number_of_targets,
    target_branch_nodes_per_layer=[32],
    embedding_size=32,
)

Composite branches combine named dense, graph, sparse, sequence, and known-ID encoder outputs. The default concat fusion preserves the historical behavior. Opt-in gated fusion learns one sample-specific sigmoid gate per component, scales each component output, and then concatenates the gated representations. Opt-in attention fusion projects differently sized components to a shared width, applies multi-head self-attention across modalities, and projects contextualized components back to their original widths. The composite output width is unchanged for all three strategies.

A component can be missing for selected entities by marking it optional in both data preparation and model configuration:

instance_feature_kind={
    "descriptors": None,
    "tokens": {"kind": "sequence", "optional": True},
}

instance_branch_composite_components={
    "descriptors": descriptor_component,
    "tokens": {**token_component, "optional": True},
}

instance_branch_composite_modality_dropout=0.2

Optional components carry explicit presence masks and use a checkpointed learned representation for missing rows. Existing components remain required by default. Gated fusion includes the component-presence indicators in its gate input. Attention fusion masks missing components as keys and values while allowing their learned representations to query available modalities. An always-present fusion token keeps fully missing rows finite.

The branch-level modality-dropout probability defaults to 0.0. During training, it randomly replaces genuinely present optional components with their learned missing representations and updates the presence indicators used by gated or attention fusion. Required components are never dropped, and at least one genuinely available component is retained per sample. Evaluation and prediction use only the actual presence masks. See the composite input guide for the complete component, fusion, validation-setting, batching, and checkpoint contract.

Input data

Loading a built-in benchmark dataset

The quick start above uses synthetic data and requires no download. DeepMTP also provides optional benchmark loaders. Install the datasets extra and import them from DeepMTP.data.datasets:

pip install "DeepMTP[datasets]"
Function Description
load_process_MLC() Multi-label classification datasets such as emotions, scene, and yeast
load_process_MTR() Multivariate regression datasets such as atp1d, oes10, and rf1
load_process_MTL() The bird and dog crowdsourcing multi-task datasets
load_process_MC() The MovieLens 100K matrix-completion dataset
load_process_DP() The ern, srn, dpie, and dpii biological-network datasets

The historical DeepMTP.dataset import path remains available as a compatibility facade. See the dataset-loading guide for supported names and examples.

Creating a custom MTP dataset

data_process accepts a mapping with train, val, and test splits. Each split contains interactions under y and optional instance and target side information:

data = {
    "train": {
        "y": train_interactions,
        "X_instance": train_instance_features,
        "X_target": train_target_features,
    },
    "val": {
        "y": validation_interactions,
        "X_instance": validation_instance_features,
        "X_target": validation_target_features,
    },
    "test": {
        "y": test_interactions,
        "X_instance": test_instance_features,
        "X_target": test_target_features,
    },
}

When validation or test data is omitted, data_process can construct the requested validation setting from the training data. Feature requirements depend on whether the split contains novel instances, novel targets, or both. Dense features use arrays or DataFrames; sparse features use SciPy matrices, PyTorch COO/CSR tensors, or explicit-ID DataFrames of sparse rows; mixed numeric/categorical features use the explicit TABULAR schema described above.

Configuration options

New code should construct DeepMTPConfig directly. It normalizes architecture names, validates incompatible combinations before training, and can also validate an existing dictionary with DeepMTPConfig.from_mapping(...). generate_config remains available for compatibility and returns a dictionary. The table below summarizes the commonly configured public options.

Parameter name Description
Training
validation_setting Generalization setting A, B, C, or D
problem_mode classification or regression
classification_mode binary (the backward-compatible classification default) or multiclass
num_classes Number of mutually exclusive classes; required and at least 3 for multiclass classification
loss Training objective. Binary classification defaults to binary_cross_entropy_with_logits, multiclass classification uses cross_entropy, and regression defaults to mean_squared_error with optional mean_absolute_error or huber
num_epochs The max number of epochs allowed for training
learning_rate The learning rate used to determine the step size at each iteration of the optimization process
decay The weight decay (L2 penalty) used by the Adam optimizer
compute_mode cpu, cuda, or cuda:<index>; unavailable CUDA devices fall back to CPU
num_workers The number of sub-processes to use for data loading. Larger values usually improve performance but after a point training speed will become worse
train_batchsize The number of samples that comprise a batch from the training set
val_batchsize The number of samples that comprise a batch from the validation and test sets
random_seed Non-negative seed for isolated model initialization and data-loader shuffling, or None for nondeterministic behavior
patience The number of epochs that the network is allowed to continue training for while observing worse overall performance
delta Minimum change in the monitored quantity to qualify as an improvement
return_results_per_target Whether to include per-target metric values in the results; requires macro averaging
evaluate_train Whether or not to calculate performance metrics over the training set
evaluate_val Whether or not to calculate performance metrics over the validation set
eval_every_n_epochs The interval that indicates when the performance metrics are computed
use_early_stopping Whether or not to use early stopping while training
Metrics
metrics The performance metrics that will be calculated. For classification tasks the available metrics are ['hamming_loss', 'auroc', 'f1_score', 'aupr', 'accuracy', 'recall', 'precision'] while for regression tasks the available metrics are ['RMSE', 'MSE', 'MAE', 'R2']
metrics_average The averaging strategy used to calculate metrics. Available options are ['macro', 'micro', 'instance']; validation setting A supports only ['micro'].
multiclass_average Class averaging for multiclass precision, recall, F1, AUROC, and AUPR: micro, macro (default), or weighted
top_k Number of top predictions used to calculate grouped metric variants; requires macro or instance averaging and is unavailable for multiclass classification
metric_to_optimize_early_stopping The metric that will be used for tracking by the early stopping routine. The value can be the loss or one of the available performance metrics.
metric_to_optimize_best_epoch_selection The validation metric that will be used to determine the best configuration. The value can be the loss or one of the available performance metrics.
Printing - Saving - Logging
verbose Whether to print training progress in the terminal
use_tensorboard_logger Whether to write TensorBoard event files
wandb_project_name W&B project name; set together with wandb_project_entity to enable W&B
wandb_project_entity W&B team or account entity
wandb_mode online, offline, disabled, or None to use the SDK/environment default
wandb_run_name Optional W&B display name
wandb_group Optional group for related runs
wandb_job_type W&B job type; defaults to train
wandb_tags Searchable W&B run tags
wandb_notes Free-form W&B run notes
wandb_watch Model monitoring: gradients (default), parameters, all, or None
wandb_watch_log_freq Positive model-monitoring interval
wandb_log_graph Include the model graph in W&B monitoring; opt-in
wandb_log_code Upload project source with Run.log_code; opt-in
wandb_log_model_artifact Publish saved checkpoint, config, and summary files as a versioned W&B model Artifact
wandb_model_artifact_name Optional explicit model Artifact name
wandb_model_artifact_aliases Model Artifact aliases; defaults to ["latest", "best"]
wandb_input_artifacts Online Artifact references to mark as run inputs for lineage
wandb_registry_name Existing online W&B Registry to link the model version into
wandb_registry_collection Registry collection paired with wandb_registry_name
wandb_log_predictions Log a bounded test-prediction Table and classification charts; opt-in
wandb_prediction_table_max_rows Maximum sampled rows in the prediction Table; defaults to 1000
results_path Parent directory for experiment artifacts
experiment_name Experiment subdirectory and reporting name
save_model Whether or not to save the model of the epoch with the best validation performance
data_preparation_state Split provenance and fitted dense-scaler state; normally captured automatically from data_process outputs
General architecture
general_architecture_version Fusion strategy: mlp, dot_product, or kronecker; defaults to dot_product
batch_norm Whether to use batch normalization between fully connected layers
dropout_rate Default dropout rate for both branches
dropout_rate_instance_branch The amount of dropout used in the layers of the instance branch
dropout_rate_target_branch The amount of dropout used in the layers of the target branch
Instance branch architecture
instance_branch_architecture The instance encoder: MLP for dense vectors, SPARSE for SciPy/PyTorch sparse vectors, GRAPH for PyG graphs, SEQUENCE for token IDs, TABULAR for explicit numeric/categorical columns, COMPOSITE for named component encoders, CONV for images, EMBEDDING for zero-based IDs, or CUSTOM for a user-supplied branch
instance_branch_input_dim The dense/sparse width, graph node-feature width, sequence vocabulary size, or number of instance IDs for an EMBEDDING branch
instance_branch_graph_edge_dim Graph edge-feature width, or None when edge features are disabled
instance_branch_graph_hidden_dim Hidden message-passing width for an instance GRAPH branch
instance_branch_graph_output_dim Instance graph output width for MLP and Kronecker fusion; dot-product fusion uses embedding_size
instance_branch_graph_num_layers Number of GIN/GINE message-passing layers
instance_branch_graph_pooling Graph-level pooling: mean, sum, or max
instance_branch_graph_use_edge_features Use GINE with edge_attr; set False to use GIN without edge features
instance_branch_composite_components Ordered component mappings with per-component architecture, input dimension, output dimension, encoder options, and optional missing-modality handling
instance_branch_composite_fusion Composite component fusion: concat (default), sample-specific gated concatenation, or modality self-attention
instance_branch_composite_attention_dim Shared positive projection width for composite attention fusion
instance_branch_composite_attention_num_heads Positive attention-head count; instance_branch_composite_attention_dim must be divisible by this value
instance_branch_composite_modality_dropout Training-only probability of replacing a present optional component with its learned missing representation; defaults to 0.0
instance_branch_sequence_encoder Sequence encoder name: gru, conv1d, or transformer
instance_branch_sequence_embedding_dim Trainable token embedding width for an instance SEQUENCE branch
instance_branch_sequence_output_dim Instance sequence output width for MLP and Kronecker fusion; dot-product fusion uses embedding_size
instance_branch_sequence_conv_kernel_size Positive odd Conv1D kernel width; used only when the sequence encoder is conv1d
instance_branch_sequence_transformer_num_heads Transformer attention-head count; the sequence embedding width must be divisible by this value
instance_branch_sequence_transformer_feedforward_dim Transformer feed-forward sublayer width
instance_branch_sequence_num_layers Number of stacked GRU, Conv1D, or Transformer layers
instance_branch_sequence_padding_idx Reserved non-negative padding token ID
instance_branch_tabular_schema Column names, category vocabularies, normalization, missing-value policies, and optional feature gating for an instance TABULAR branch
instance_train_transforms PyTorch-compatible transforms for instance training samples, typically images
instance_inference_transforms PyTorch-compatible transforms for instance validation and test samples
Target branch architecture
target_branch_architecture The target encoder: MLP for dense vectors, SPARSE for SciPy/PyTorch sparse vectors, GRAPH for PyG graphs, SEQUENCE for token IDs, TABULAR for explicit numeric/categorical columns, COMPOSITE for named component encoders, CONV for images, EMBEDDING for zero-based IDs, or CUSTOM for a user-supplied branch
target_branch_input_dim The dense/sparse width, graph node-feature width, sequence vocabulary size, or number of target IDs for an EMBEDDING branch
target_branch_graph_edge_dim Graph edge-feature width, or None when edge features are disabled
target_branch_graph_hidden_dim Hidden message-passing width for a target GRAPH branch
target_branch_graph_output_dim Target graph output width for MLP and Kronecker fusion; dot-product fusion uses embedding_size
target_branch_graph_num_layers Number of GIN/GINE message-passing layers
target_branch_graph_pooling Graph-level pooling: mean, sum, or max
target_branch_graph_use_edge_features Use GINE with edge_attr; set False to use GIN without edge features
target_branch_composite_components Ordered component mappings with per-component architecture, input dimension, output dimension, encoder options, and optional missing-modality handling
target_branch_composite_fusion Composite component fusion: concat (default), sample-specific gated concatenation, or modality self-attention
target_branch_composite_attention_dim Shared positive projection width for composite attention fusion
target_branch_composite_attention_num_heads Positive attention-head count; target_branch_composite_attention_dim must be divisible by this value
target_branch_composite_modality_dropout Training-only probability of replacing a present optional component with its learned missing representation; defaults to 0.0
target_branch_sequence_encoder Sequence encoder name: gru, conv1d, or transformer
target_branch_sequence_embedding_dim Trainable token embedding width for a target SEQUENCE branch
target_branch_sequence_output_dim Target sequence output width for MLP and Kronecker fusion; dot-product fusion uses embedding_size
target_branch_sequence_conv_kernel_size Positive odd Conv1D kernel width; used only when the sequence encoder is conv1d
target_branch_sequence_transformer_num_heads Transformer attention-head count; the sequence embedding width must be divisible by this value
target_branch_sequence_transformer_feedforward_dim Transformer feed-forward sublayer width
target_branch_sequence_num_layers Number of stacked GRU, Conv1D, or Transformer layers
target_branch_sequence_padding_idx Reserved non-negative padding token ID
target_branch_tabular_schema Column names, category vocabularies, normalization, missing-value policies, and optional feature gating for a target TABULAR branch
target_train_transforms PyTorch-compatible transforms for target training samples, typically images
target_inference_transforms PyTorch-compatible transforms for target validation and test samples
Combination branch architecture
comb_mlp_nodes_per_layer Positive layer widths for the combination branch. A list defines each layer; an integer repeats that width comb_mlp_layers times. Only used if general_architecture_version == mlp
comb_mlp_layers Positive number of repeated combination layers, required when comb_mlp_nodes_per_layer is an integer. Only used if general_architecture_version == mlp
embedding_size The output width of both branches for a dot-product model; for a COMPOSITE branch it must equal the sum of component output widths
Other
additional_info Extra experiment metadata included in reporting

For example, Huber loss is less sensitive to large regression errors than mean squared error:

config = DeepMTPConfig(
    validation_setting="B",
    problem_mode="regression",
    loss="huber",
    # branch configuration...
)

The low-level loss registry also retains binary_cross_entropy for deliberate reproduction of the historical sigmoid-plus-BCELoss training path. New classification experiments should keep the stable binary_cross_entropy_with_logits default. Incompatible task/loss combinations are rejected during configuration validation.

RRMSE remains available through the low-level get_performance_results utility for macro evaluation when a training mean is provided for every target. The trainer does not yet retain those baselines, so RRMSE is rejected in trainer configurations instead of returning silent NaN results.

The legacy momentum, weighted_loss, use_instance_features, use_target_features, load_pretrained_model, pretrained_model_path, and non-default comb_mlp_nodes_reducing_factor options have no runtime effect. Setting them to non-default values emits ConfigDeprecationWarning.

generate_config applies documented branch defaults silently. If it changes metrics_average to satisfy or recommend a validation-setting policy, it emits ConfigNormalizationWarning so applications can display, filter, or escalate that adjustment using Python's standard warnings controls.

Instance and target branch hyperparameters

With DeepMTPConfig, branch hyperparameters are ordinary flattened fields. The legacy generate_config helper also accepts instance_branch_params and target_branch_params dictionaries and expands them to these fields.

Key Description
Instance branch
instance_branch_nodes_per_layer Instance MLP widths. A list defines each layer; an integer repeats that width instance_branch_layers times
instance_branch_layers The number of layers in the MLP version of the instance branch. (Only used if instance_branch_nodes_per_layer is int)
instance_branch_conv_architecture Instance convolutional architecture: resnet or VGG
instance_branch_conv_architecture_version Instance ResNet version: resnet18 or resnet101
instance_branch_conv_architecture_dense_layers Number of replacement instance ResNet dense layers: 1 or 2
instance_branch_conv_architecture_last_layer_trained Earliest trainable instance ResNet block: last or layer4 through layer1
instance_branch_conv_pretrained Use torchvision's default pretrained weights. Defaults to True; set to False to construct the model without downloading weights
Target branch
target_branch_nodes_per_layer Target MLP widths. A list defines each layer; an integer repeats that width target_branch_layers times
target_branch_layers The number of layers in the MLP version of the target branch. (Only used if target_branch_nodes_per_layer is int)
target_branch_conv_architecture Target convolutional architecture: resnet or VGG
target_branch_conv_architecture_version Target ResNet version: resnet18 or resnet101
target_branch_conv_architecture_dense_layers Number of replacement target ResNet dense layers: 1 or 2
target_branch_conv_architecture_last_layer_trained Earliest trainable target ResNet block: last or layer4 through layer1
target_branch_conv_pretrained Use torchvision's default pretrained weights. Defaults to True; set to False to construct the model without downloading weights

Pretrained convolutional branches use torchvision's current DEFAULT weight enum. Torchvision may download those weights into its local cache the first time a model is created. Set the corresponding *_branch_conv_pretrained option to False for offline construction; this passes weights=None.

Logging results

DeepMTP always writes experiment configuration and summary artifacts below results_path/experiment_name. TensorBoard and Weights & Biases are optional; install both integrations with:

pip install "DeepMTP[tracking]"

Text summary

The default reporter writes three semi-structured tables to summary.txt in the experiment directory.

logo

TensorBoard

Set use_tensorboard_logger=True to write TensorBoard events alongside the other experiment artifacts. Start TensorBoard with the configured results directory:

tensorboard --logdir results

logo

Weights & Biases

Set both wandb_project_entity and wandb_project_name to send configuration and metrics to a Weights & Biases project. Leaving both values as None disables the integration. DeepMTP defines epoch as the metric step, records best/test values in the run summary, reports parameter counts and failure status, and supports W&B's online, offline, and disabled modes.

config = generate_config(
    # model and training options...
    wandb_project_entity="my-team",
    wandb_project_name="deepmtp",
    wandb_run_name="fingerprint-baseline",
    wandb_group="ablations",
    wandb_job_type="train",
    wandb_tags=["sparse", "baseline"],
    wandb_mode="online",
    wandb_watch="gradients",
    wandb_log_model_artifact=True,
    wandb_model_artifact_aliases=["latest", "best"],
    wandb_log_predictions=True,
    wandb_prediction_table_max_rows=1000,
)

Remote uploads with larger privacy or storage implications are opt-in: wandb_log_code, wandb_log_model_artifact, and wandb_log_predictions all default to False. Model Artifacts contain model.pt plus the saved configuration and summary. Input Artifact references can be declared through wandb_input_artifacts to capture lineage. In online mode, a model version can also be linked to an existing Registry collection:

config["wandb_registry_name"] = "Models"
config["wandb_registry_collection"] = "DeepMTP"

Restore a model from a W&B Artifact without manually downloading its files:

model = DeepMTP.from_wandb_artifact(
    "my-team/deepmtp/deepmtp-model:best",
    {
        "results_path": "./results",
        "experiment_name": "restored",
    },
)

See the W&B integration guide and reproducible checkpoint guide for lineage, Registry, offline-mode, preprocessing-replay, and compatibility details.

logo

Hyperparameter Optimization

DeepMTP includes random-search and Hyperband optimizers for automating model selection. Hyperband is a practical option for many of the MTP problem settings supported by the project.

Hyperband

One of the core steps in any standard HPO method is the performance evaluation of a given configuration. This can be manageable for simple models that are relatively cheap to train and test, but can be a significant bottleneck for more complex models that need hours or even days to train. This is particularly evident in deep learning, as big neural networks with millions of parameters trained on increasingly larger datasets can deem traditional black-box HPO methods impractical.

Addressing this issue, multi-fidelity HPO methods have been devised to discard unpromising hyperparameter configurations already at an early stage. To this end, the evaluation procedure is adapted to support cheaper evaluations of hyperparameter configurations, such as evaluating on sub-samples (feature-wise or instance-wise) of the provided data set or executing the training procedure only for a certain number of epochs in the case of iterative learners. The more promising candidates are subsequently evaluated on increasing budgets until a maximum assignable budget is reached.

A popular representative of such methods is Hyperband. Hyperband builds upon Successive Halving (SH), where a set of n candidates is first evaluated on a small budget. Based on these low-fidelity performance estimates, the $\frac{n}{\eta}$ ($\eta \geq 2)$ best candidates are preserved, while the remaining configurations are already discarded. Iteratively increasing the evaluation budget and reevaluating the remaining candidates with the increased budget while discarding the inferior candidates results in fewer resources wasted on inferior candidates. In return, one focuses more on the promising candidates.

Despite the efficiency of the successive halving strategy, it is well known that it suffers from the exploration-exploitation trade-off. In simple terms, a static budget $\mathcal{B}$ means that the user has to manually decide whether to explore a number of configurations $n$ or give each configuration a sufficient budget to develop. An incorrect decision can lead to an inadequate exploration of the search space (small $n$) or the early rejection of promising configurations (large $n$). Hyperband overcomes the exploration-exploitation trade-off by repeating the successive halving strategy with different initializations of SH, varying the budget and the number of initial candidate configurations.

Combining Hyperband with DeepMTP

Install the HPO dependency with pip install "DeepMTP[hpo]". The example below uses synthetic data and one epoch so it can also serve as a quick API check; increase max_budget and expand the configuration space for real experiments. Sampled branch-specific parameters must retain their instance_ or target_ prefixes so BaseWorker can route them to the correct branch.

import ConfigSpace as CS
import numpy as np

from DeepMTP import DeepMTP, data_process
from DeepMTP.hpo import BaseWorker, HyperBand

rng = np.random.default_rng(42)
scores = (
    np.arange(16)[:, np.newaxis] + np.arange(3)[np.newaxis, :]
) % 2
data = {
    "train": {
        "y": scores,
        "X_instance": rng.normal(size=(16, 3)),
        "X_target": None,
    }
}
train, validation, test, data_info = data_process(
    data,
    validation_setting="B",
)

config_space = CS.ConfigurationSpace(seed=42)
config_space.add(
    [
        CS.Float(
            "learning_rate",
            (1e-4, 1e-2),
            default=1e-3,
            log=True,
        ),
        CS.Integer("embedding_size", (2, 4), default=3),
    ]
)

base_config = {
    "hpo_results_path": "hpo_results",
    "validation_setting": data_info["detected_validation_setting"],
    "problem_mode": data_info["detected_problem_mode"],
    "general_architecture_version": "dot_product",
    "compute_mode": "cpu",
    "num_workers": 0,
    "train_batchsize": 16,
    "val_batchsize": 16,
    "metrics": [],
    "metrics_average": ["macro"],
    "evaluate_train": False,
    "evaluate_val": False,
    "use_early_stopping": False,
    "save_model": True,
    "verbose": False,
    "instance_branch_architecture": "MLP",
    "instance_branch_input_dim": data_info["instance_branch_input_dim"],
    "target_branch_architecture": "MLP",
    "target_branch_input_dim": data_info["target_branch_input_dim"],
}

worker = BaseWorker(
    train,
    validation,
    test,
    data_info,
    base_config,
    metric_to_optimize="loss",
)
optimizer = HyperBand(
    base_worker=worker,
    configspace=config_space,
    eta=2,
    max_budget=1,
    direction="min",
)
best_experiment = optimizer.run_optimizer()

best_model = DeepMTP(
    best_experiment.info["config"],
    checkpoint_dir=best_experiment.info["model_dir"],
)
best_model_results = best_model.predict(test, verbose=True)

DEMOS

These notebooks use small local datasets and are executed by the test suite. Each Colab link opens the version-controlled notebook rather than a separate copy. In a fresh Colab runtime, the first code cell installs the matching DeepMTP source and its datasets extra from the repository's main branch; the HPO notebooks also install the hpo extra. Outside Colab, that bootstrap is skipped so the same notebooks continue to run against the active local environment.

The links are checked weekly and can be verified manually with:

python scripts/check_colab_links.py
Example Notebook
Local dataset preparation Open In Colab
Multi-label classification (MLC) Open In Colab
Multivariate regression (MTR) Open In Colab
Multi-task learning (MTL) Open In Colab
Matrix completion (MC) Open In Colab
Dyadic prediction (DP) Open In Colab
Hyperband Open In Colab
Random search Open In Colab

Cite Us

If you use this package, please cite our paper:

@article{iliadis2023deepmtp,
  title={DeepMTP: A Python-based deep learning framework for multi-target prediction},
  author={Iliadis, Dimitrios and De Baets, Bernard and Waegeman, Willem},
  journal={SoftwareX},
  volume={23},
  pages={101516},
  year={2023},
  publisher={Elsevier}
}

Related publications to this work:

  • Paper that showed the feasibility of using the two-branch architecture for different multi-target prediction settings: link
  • Paper that benchmarks different hyperparameter optimization methods using the two-branch neural network as the base model: link
  • Paper that compares different embedding aggregation strategies specifically in the area of drug-target interaction prediction: link

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

deepmtp-0.0.23.tar.gz (3.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

deepmtp-0.0.23-py3-none-any.whl (197.2 kB view details)

Uploaded Python 3

File details

Details for the file deepmtp-0.0.23.tar.gz.

File metadata

  • Download URL: deepmtp-0.0.23.tar.gz
  • Upload date:
  • Size: 3.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for deepmtp-0.0.23.tar.gz
Algorithm Hash digest
SHA256 4d805d5df916a27f956e98ed06578ffd0a5676d62817df3f666613d505fad455
MD5 12f9faf3dcd697f4e4071433dd7e6bf5
BLAKE2b-256 717a34688935a8507e8bb1a9eb892fd0f33795f2db34bc947163bf3ed7d09a2b

See more details on using hashes here.

Provenance

The following attestation bundles were made for deepmtp-0.0.23.tar.gz:

Publisher: publish.yml on diliadis/DeepMTP

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file deepmtp-0.0.23-py3-none-any.whl.

File metadata

  • Download URL: deepmtp-0.0.23-py3-none-any.whl
  • Upload date:
  • Size: 197.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for deepmtp-0.0.23-py3-none-any.whl
Algorithm Hash digest
SHA256 854c6eb930b049b6244b826ffd816572f071be799eaf8848c7e32d7919b945f8
MD5 a3ccb6590243b791648556cafe186d89
BLAKE2b-256 8a698d6813b29d875b9d906ba73040f4b29c883044118bf56203e78e5b2b8436

See more details on using hashes here.

Provenance

The following attestation bundles were made for deepmtp-0.0.23-py3-none-any.whl:

Publisher: publish.yml on diliadis/DeepMTP

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.0.23 This release

2 files

0.0.22

2 files

0.0.21

2 files

0.0.20

2 files

0.0.19

2 files

0.0.18

2 files

0.0.17

2 files

0.0.16

2 files

0.0.15

2 files

0.0.14

2 files

0.0.13

2 files

0.0.12

2 files

0.0.10

1 file

0.0.9

2 files

0.0.8

1 file

0.0.7

2 files

0.0.6

2 files

0.0.5

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page