This repository accompanies the ICML 2026 paper:
It trains a partial-information-decomposition (PID) estimator over a multimodal dataset and uses the resulting per-sample interaction terms to gate a captioning step during supervised fine-tuning (SFT).
The four interaction terms are:
- R: redundant information shared by both modalities
- U1 (a.k.a. U_V): unique information from modality 1 (image)
- U2 (a.k.a. U_T): unique information from modality 2 (text)
- S: synergistic information
Lower-case letters (r, u1, u2, s) denote the point-wise interaction terms.
The repository covers three things you can do, each independently runnable:
- Reproduce the paper's interaction-transfer table from precomputed features shipped in this repo β no GPU-heavy preprocessing required. (See Quick Start.)
- Run additional PID experiments (dominance distribution, Ο ablations).
- Run the full SFT pipeline end-to-end (download images, generate captions, score interactions, gate, fine-tune SmolVLM2).
Note: The might be some slight differences in the values as that depends on how your trained estimators converged. That said, you should expect the same general trends in Table 1 of the paper (ablation of interaction transfers).
I have tried my best to ensure reproducibility in this work. Do reach out to me (the corresponding author) if there are any issues in the setup / data. ππ»
Most stages assume a CUDA-capable GPU. The interaction-transfer Quick Start runs on CPU but is much faster on GPU.
# 1) Clone and enter the repo
git clone https://github.com/yurielryan/Multimodal-Interaction-Tuning.git
cd Multimodal-Interaction-Tuning
# 2) Create and activate the environment
conda create -n MIT python=3.10 -y
conda activate MIT
# 3) Install dependencies
pip install -r requirements.txt
This experiment from the paper compares how four text-modality variants reshape the PID decomposition relative to a baseline, at three
PCA embedding sizes (1536 = raw SigLIP2, 1024, 512). The required SigLIP2-encoded features are shipped with the repo under Features/interaction_transfers/, so you can reproduce the table without downloading images, captioning, or running the full pipeline.
From the repo root:
python Experiments/interaction_transfer.py
What this does:
- Iterates every
.ptinFeatures/interaction_transfers/(12 files: 4 variants Γ 3 sizes). - For each file, trains a fresh discriminator + entropy estimator
(
Estimator/mi_estimator.py:obtain_discriminatorandobtain_entropy_estimator). - Evaluates
LSMI_estimationon the train, val, and test splits. - Prints a grouped table per embedding size with each non-baseline cell
annotated as
value (+xx%)relative to the Baseline at that same size. - Streams results to
Experiments/outputs/interaction_transfer.jsonafter every file (atomic write), so a partial sweep still leaves usable numbers on disk.
The four variants are inferred from the filename:
| Variant | Filename pattern | Text content |
|---|---|---|
| Baseline | hateful_memes_features_siglip2_{1536,pca1024,pca512}.pt |
Original meme text only |
| Random Text | hateful_memes_features_with_random_text_siglip2_{1536,pca1024,pca512}.pt |
gibberish strings (no label-relevant signal) |
| SmolVLM 2B | combined_smolvlm_features_siglip2_{1536,pca1024,pca512}.pt |
original_text + " " + smolvlm_caption |
| Qwen2.5 32B | hateful_memes_features_with_captions_siglip2_{1536,pca1024,pca512}.pt |
original_text + " " + qwen_caption |
For the full schema of these .pt files see
Features/README.md.
The full sweep trains 12 estimators back-to-back. To verify the pipeline end-to-end in a few minutes, restrict to a single embedding size:
python Experiments/interaction_transfer.py --only_size 1024
| Flag | Default | Meaning |
|---|---|---|
--features_dir |
Features/interaction_transfers |
Directory of .pt files to sweep |
--out_dir |
Experiments/outputs |
Where the JSON dump lands |
--only_size |
unset | Restrict to one embedding size (e.g., 512) for quick runs |
--epochs_disc / --epochs_ent |
30 / 80 | Per-file training budgets (early stopping is on) |
--seed |
42 |
Reset before each file's training run |
--device |
auto | cuda if available else cpu |
See Experiments/experiments_readme.md
for the full flag table.
MIT/
Estimator/ # PID estimator training + saved checkpoints
mi_estimator.py # train + evaluate the LSMI decomposition
estimate_batch.py # callable batch-level scoring (R/U1/U2/S)
entropy_estimator.py # KNIFE-based marginal entropy models
utils.py # dataset / loader / cls_network
train.yaml # Hydra config for mi_estimator.py
saved_estimators/ # output: trained estimator checkpoints
Features/ # SigLIP2 feature extraction + shipped .pt files
prepare_features.py # batch-level feature extraction (used by SFT)
utils_features.py # SigLIP2 loader, PCA, stratified split helpers
download_images.py # idempotent HatefulMemes image downloader
interaction_transfers/ # SHIPPED .pt files for the Quick Start
per_tau/ # generated on demand by tau_ablations.py (not shipped)
README.md # schema + provenance for everything in here
Experiments/ # standalone analyses on top of the estimators
interaction_transfer.py # Quick-Start headline experiment
proportion_of_interactions.py
tau_ablations.py
outputs/ # generated figures + JSON dumps
experiments_readme.md
SFT/ # MI-Gated supervised fine-tuning of SmolVLM2
caption.py # SmolVLM2 captioner CLI + shared loader
preprocess_mi_gate.py # score interactions, apply gate, write data.json
multimodal_interaction_tuning.py # SFT entrypoint
config.yaml # SFT config (key=value CLI overrides supported)
scripts/
run_pipeline.sh # one-command pipeline (download β β¦ β SFT)
submit_slurm.sh # SLURM wrapper around run_pipeline.sh
logs/ # SLURM stdout/stderr land here
requirements.txt
README.md
The high-level workflow for the MI-Gate pipeline:
- Prepare multimodal features (image and text) β
Features/. - Train PID estimators on those features β
Estimator/mi_estimator.py. - Save estimator checkpoints for reuse β
Estimator/saved_estimators/. - Run
SFT/preprocess_mi_gate.pyto score every sample's R/U1/U2/S, build a train/val/test split, apply the MI Gate, and write the augmented text back intodata.json. - Run
SFT/multimodal_interaction_tuning.pyto fine-tune SmolVLM2 on the gated dataset.
The Quick Start above only depends on (1) and (2). The other experiments add (3); the SFT pipeline adds (4) and (5).
Experiments/ contains analyses that build on the trained estimators
without rerunning the SFT pipeline. Each script is self-contained β see
Experiments/experiments_readme.md
for full docs, defaults, and example invocations.
-
Experiments/proportion_of_interactions.pyβ reports the proportion of samples whose dominant interaction term is R, U1, U2, or S, both globally and per train/val/test split. Two passes: (1) score with the frozen estimator on baseline text β donut atExperiments/outputs/proportion_of_interactions.png; (2) re-encode every sample's text with the caption appended, save standard-schema features atFeatures/features_all_augmented_siglip2_pca512.pt, retrain the estimator and checkpoint it asEstimator/saved_estimators/mi_estimators_all_augmented_state_dict.pt, rescore, and produce a second donut atExperiments/outputs/proportion_of_interactions_retrained.png. Pass--skip_retrainto disable Part 2. -
Experiments/tau_ablations.pyβ replays the MI Gate at Ο β {0%, 10%, β¦, 100%} and tracks how the dominance distribution shifts as more U1-dominant samples receive the caption augmentation. Two passes: (1) score with the original frozen estimator, and (2) at every Ο, materialise a fresh feature.pt(Features/per_tau/features_tau{tau:.2f}_siglip2_pca512.pt) with its own PCA fit, retrain the estimator on it from scratch, and rescore. Each retrained estimator is checkpointed underEstimator/saved_estimators/mi_estimators_tau{tau:.2f}_state_dict.pt. Outputs a 2 Γ 2 (or 1 Γ 2 with--skip_retrain) figure atExperiments/outputs/tau_ablations.pngplus a JSON of per-Ο records.
Both of these require the data layout described under Data folder structure β they re-encode raw images and text. The Quick Start does not.
This repository is released under the MIT License. It adapts code
from the LSMI Estimator (MIT)
and the KNIFE entropy estimator
(BSD 3-Clause); both upstream licenses are retained in LICENSE and the
file-level attributions in Estimator/.
This work builds directly on:
- The Cauldron dataset (HatefulMemes subset) β https://huggingface.co/datasets/HuggingFaceM4/the_cauldron
- LSMI Estimator (multimodal interaction estimator) β https://github.com/GeWu-Lab/LSMI_Estimator
- KNIFE (the entropy estimator within the LSMI estimator) β https://github.com/g-pichler/knife
- SmolVLM β https://github.com/huggingface/smollm/tree/main/vision
The downstream hallucination / robustness evaluation in the paper is run on top of two existing benchmarks:
- Adaptation-method robustness benchmark (Chen et al., NeurIPS 2023) β Chen, S., Gu, J., Han, Z., Ma, Y., Torr, P., and Tresp, V. Benchmarking Robustness of Adaptation Methods on Pre-trained Vision-Language Models. Advances in Neural Information Processing Systems, vol. 36, pp. 51758β51777, 2023.
- HallusionBench (Guan et al., CVPR 2024) β Guan, T. et al. HallusionBench: An Advanced Diagnostic Suite for Entangled Language Hallucination and Visual Illusion in Large Vision-Language Models. Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition, 2024, pp. 14375β14385. https://openaccess.thecvf.com/content/CVPR2024/html/Guan_HallusionBench_An_Advanced_Diagnostic_Suite_for_Entangled_Language_Hallucination_and_CVPR_2024_paper.html
If you do use this work, please do cite them as well! ππ»
Note: To be updated when the officil PMLR issue is made public.
@inproceedings{ryan2026selfcaptioning,
title = {Self-Captioning Multimodal Interaction Tuning: Amplifying
Exploitable Redundancies for Robust Vision Language Models},
author = {Ryan, Yuriel and Ip, Hei Man and Kuek, Adriel and Liang,
Paul Pu and Lee, Roy Ka-Wei},
booktitle = {Proceedings of the 43rd International Conference on Machine
Learning (ICML)},
year = {2026},
eprint = {2605.08145},
archivePrefix = {arXiv},
primaryClass = {cs.CV},
url = {https://arxiv.org/abs/2605.08145}
}
I had some leftover documentation and thought it might be useful for those who might be interested. Thus, I cleaned it up slightly and added additional details in this section in an attempt to be more "complete".
- Three discriminators
- modality 1 classifier
- modality 2 classifier
- joint modality classifier (early fusion: concatenation of modalities 1 and 2)
- Two entropy estimators (based on the KNIFE Differentiable Entropy Estimator)
- modality 1 entropy model
- modality 2 entropy model
Pointwise mutual information is computed with a class-prior correction:
By default cfg.class_priors = [...] in Estimator/train.yaml (or pass
provided_priors= directly to _resolve_log_class_priors).
Fine-tunes HuggingFaceTB/SmolVLM2-2.2B-Instruct on the augmented
dataset produced by preprocess_mi_gate.py. The user prompt for sample
n is mi_gate_text[n], which equals original_text + " " + caption for
samples selected by the MI Gate, and original_text otherwise. The
assistant target is correct_answer.
LoRA by default: training uses
PEFT LoRA on the language-model
projections (q_proj, k_proj, v_proj, o_proj, gate_proj,
up_proj, down_proj) with r=16, lora_alpha=32, lora_dropout=0.05,
bias="none", task_type="CAUSAL_LM". With these defaults only β21 M
of 2.27 B parameters are trainable (β0.93 %), so a full sweep fits
comfortably on a single H200 with bf16 and gradient checkpointing. To
switch to full fine-tuning, override use_lora=false.
Given a dataset
- Estimate per-sample interactions
$r_n, u_{V,n}, u_{T,n}, s_n$ on the train split. - Identify the valid set $\mathcal{S}{valid} = {n : u{V,n} = \max(r_n, u_{V,n}, u_{T,n}, s_n)}$ β samples where image-uniqueness is the dominant interaction term.
- Pick $k = \lfloor \tau \cdot |\mathcal{S}{valid}| \rfloor$ samples by descending $u{V,n}$.
- Concatenate a caption
$c_n$ to the text for those samples; leave others unchanged.
SFT/preprocess_mi_gate.py
(--tau). For example, with Ο=0.25 and 114 U1-dominant train samples,
the gate captions floor(0.25 Γ 114) = 28 of them. Ο is independent of
any per-sample redundancy_level field in data.json.
Saved under Estimator/saved_estimators/ by default:
mi_estimators_latest_state_dict.ptβ state-dict bundle (always saved)mi_estimators_latest_full_models.ptβ optional full-model bundle
Names are configurable in Estimator/train.yaml via
estimator_save_dir, estimator_save_tag, and save_full_models.
SFT/preprocess_mi_gate.py writes:
Features/hateful_memes_features_id_aligned.ptβ re-extracted features indata.jsonid order, after applying the legacy PCA fit so they sit in the same 512-dim space the trained estimators were trained on.- New keys appended to each row of
data.json:split: one oftrain,val,test,excludedmi_r,mi_u1,mi_u2,mi_s: per-sample PID termsmi_gate_in_subset: bool β whether the sample was selected by the gatemi_gate_text: the user prompt to feed during SFT (original_textororiginal_text + " " + caption)
For ad-hoc per-batch interaction scoring (separate from the MI Gate
pipeline), see Estimator/estimate_batch.py:
- Main callable:
estimate_rus_batch - Inputs:
- dataloader batch with modality 1 and modality 2 (and labels)
- already-loaded discriminator + entropy estimators
- already-loaded SigLIP2 feature extractor stack
- Output:
rus_pointwise:[N, 4]with columns[R, U1, U2, S]rus_mean:[4]- the modality features used for that batch
This module is callable-only β no estimator loading happens inside it; pass loaded estimators in.
For library usage of the per-sample LSMI decomposition during estimator
evaluation, Estimator/mi_estimator.LSMI_estimation accepts
return_per_sample=True, returning the per-sample (r, u1, u2, s)
tensors aligned with the dataloader's iteration order.
Features/prepare_features.py is designed for dataloader batches and
returns modality feature tensors:
extract_features_from_batchsupports- dict batch with keys
modal_1(image) andmodal_2(text) - tuple/list batch where the first two elements are image and text batches
- dict batch with keys
- Optional PCA to 512 dimensions via the
pca_512flag.
For the schema of the precomputed feature .pt files shipped under
Features/, see Features/README.md.
