This repository contains an implementation of FiMMIA - a modular Framework for Multimodal Membership Inference Attacks (FiMMIA)
📚 Documentation: Full documentation is available at https://fimmia.readthedocs.io/
Install the package in development mode (use uv instead of plain pip):
uv pip install -e .This will install the fimmia and shift_detection packages along with all dependencies, and make the CLI commands (fimmia and shift-attack) available in your PATH.
The system is the first collection of models and pipelines for membership inference attacks against multimodal large language models, built initially with a priority for the Russian language, and extendable to any other language or dataset. Pipeline supports different modalities: image, audio and video. In our experiments, we focus on MERA datasets, however, the presented pipeline can be generalized to other languages. The system is a set of models and Python scripts in a GitHub repository.
We support two major functionalities for image, audio and video modalities: inference of membership detection model and training pipeline for new datasets.
Pretrained models available on 🤗 HuggingFace FiMMIA collection.
Additionally, in shift_detection we release baseline attacks for multimodal data, tailored for distribution shift detection on target MIA datasets. Evaluation results as well as scripts for known datasets are provided in the respective folder.
We encourage the community to run these baselines on their MIA benchmarks prior to their release or new methods evaluations to ensure fair and credible results.
We are grateful to Das et al., 2024 for the initial text pipelines that has served as a base of this tool.
FiMMIA provides a structured CLI with subcommands. The recommended way to use FiMMIA is through the CLI commands:
Training:
fimmia train \
--train_dataset_path="train/mds/path" \
--val_dataset_path="test/mds/path" \
--model_name="FiMMIAModalityAllModelLossNormSTDV2" \
--embedding_size=4096 \
--modality_embedding_size=1024 \
--output_dir="path/to/model/save" \
--num_train_epochs=10Inference:
fimmia infer \
--model_name="FiMMIABaseLineModelLossNormSTDV2" \
--model_path="path/to/model/save" \
--test_path="test/mds/path" \
--save_path="path/to/save/predictions.csv" \
--save_metrics_path="path/to/save/metrics" \
--sigmas_path="path/to/sigmas.json" \
--sigmas_type="std"Neighbor generation:
fimmia neighbors \
--model_path="ai-forever/FRED-T5-1.7B" \
--dataset_path="path/to/train.csv" \
--max_text_len=4000
# Optional (multimodal): also write modality_neighbors, e.g.
# --modality_column=videoEmbedding generation:
fimmia embeds \
--df_path="path/to/train.csv" \
--embed_model="intfloat/e5-mistral-7b-instruct" \
--max_seq_length=4096 \
--user_answer=0 \
--device=cuda \
--part_size=5000 \
--run_single_file=1
# Optional (multimodal): same run also computes modality embeds, e.g.
# --modality_key=videoLoss computation:
# For image modality (model load path is --model_name only)
fimmia loss image \
--model_name=Qwen/Qwen2.5-VL-3B-Instruct \
--label=0 \
--df_path="path/to/train.csv" \
--part_size=5000
# For video modality
fimmia loss video \
--model_id=Qwen/Qwen2.5-VL-3B-Instruct \
--model_name=Qwen2.5-VL-3B-Instruct \
--label=0 \
--df_path="path/to/train.csv" \
--part_size=5000
# For audio modality
fimmia loss audio \
--model_id=Qwen/Qwen2-Audio-7B-Instruct \
--model_name=Qwen2-Audio-7B-Instruct \
--label=0 \
--df_path="path/to/train.csv" \
--part_size=5000SFT-LoRA finetuning:
# Image
fimmia sft image \
--train_df_path="path/to/train.csv" \
--test_df_path="path/to/test.csv" \
--num_train_epochs=5 \
--model_id="Qwen/Qwen2.5-VL-3B-Instruct" \
--output_dir="data/models/sft/Qwen2.5-VL-3B-Instruct"
# Video
fimmia sft video \
--train_df_path="path/to/train.csv" \
--test_df_path="path/to/test.csv" \
--num_train_epochs=5 \
--model_id="Qwen/Qwen2.5-VL-3B-Instruct" \
--output_dir="data/models/sft/Qwen2.5-VL-3B-Instruct"
# Audio
fimmia sft audio \
--train_df_path="path/to/train.csv" \
--test_df_path="path/to/test.csv" \
--num_train_epochs=5 \
--model_id="Qwen/Qwen2.5-VL-3B-Instruct" \
--output_dir="data/models/sft/Qwen2.5-VL-3B-Instruct"MDS dataset preparation:
fimmia mds-dataset \
--save_dir="path/to/save/mds/dataset" \
--model_name="Qwen2.5-VL-3B-Instruct" \
--origin_df_path="path/to/train.csv" \
--labels="0,1" \
--modality_key="video"Gradient attribution:
fimmia attribute \
--model_dir="path/to/fimmia_model_folder" \
--mds_dataset_path="path/to/mds_dataset_folder" \
--model_cls="BaseLineModelV2" \
--embedding_size=4096 \
--modality_embedding_size=1024Shift detection attacks:
shift-attack \
--dataset=bookmia \
--attack=bag_of_words \
--fpr_budget=1.0 \
--plot_rocshift-attack \
--dataset=laion_mi_image \
--attack=bag_of_visual_words \
--fpr_budget=1.0 \
--plot_roc \
--hypersearchThe job_launcher.py script is still available for backward compatibility but is deprecated. Use the structured CLI instead:
# Legacy (deprecated)
python job_launcher.py --script="fimmia.train" --train_dataset_path=...
# Recommended
fimmia train --train_dataset_path=...The inference pipeline is shown at image below.
See examples of finetuning and inference in the packaged walkthrough: examples/Finetune_and_Inference_example_package.ipynb (see also examples/Finetune_and_Inference_example.ipynb).
For start working we should convert our dataset into pandas format with following structure:
| input | answer | audio | ds_name |
|---|
inputexample:
Помогите мне, пожалуйста.
Есть задача такого типа. Задача на понимание музыки и невербальных аудио сигналов.
Имеется 1 аудиофайл
Аудиофайл: <audio>
Вопрос:
Сколько раз слышен сильный всплеск воды?
A. 10
B. 4
C. 12
D. 8
Определите ответ к задаче, учитывая, что первому из предложенных вариантов ответа присваивается литера А, второму литера B, третьему литера C и так далее по английскому алфавиту. В качестве ответа выведите, пожалуйста, литеру, соответствующую верному варианту ответа из предложенных. Финальный ответ прошу написать после слова ОТВЕТ (литера через пробел после этого слова).
answerexample: 'B'.audio- is the modality column. For video we should putvideo, for image -image.ds_nameis the dataset name. For exampleruEnvAQA.
Whole pipeline contains the following steps:
- SFT-Lora MLLM finetuning (if need)
- Neighbor generation
- Embedding generation – unified text + optional modality via
fimmia.embedding_models(BaseEmbedder; default text: SentenceTransformer, default modality: ImageBind). When a modality column is used, both models are loaded before processing. - Loss computation
- Attack model training
For finetuning, use the structured CLI (see examples above) or the legacy interface:
Structured CLI (Recommended):
fimmia sft image --train_df_path="..." --test_df_path="..." --model_id="..." --output_dir="..."
fimmia sft video --train_df_path="..." --test_df_path="..." --model_id="..." --output_dir="..."
fimmia sft audio --train_df_path="..." --test_df_path="..." --model_id="..." --output_dir="..."Legacy interface (Deprecated):
python job_launcher.py --script="fimmia.sft_finetune_image" --train_df_path="..." ...
python job_launcher.py --script="fimmia.video.train_qwen25vl" --train_df_path="..." ...
python job_launcher.py --script="fimmia.audio.train_qwen2" --train_df_path="..." ...Arguments:
train_df_path- train dataset pathtest_df_path- test dataset pathmodel_id- path to initial modeloutput_dir- path for saving finetuning model
Structured CLI (Recommended):
fimmia neighbors \
--model_path="ai-forever/FRED-T5-1.7B" \
--dataset_path="path/to/train.csv" \
--max_text_len=4000
# Optional: --modality_column=video (or image/audio) for modality_neighborsLegacy interface (Deprecated):
python job_launcher.py --script="fimmia.neighbors" \
--model_path="ai-forever/FRED-T5-1.7B" \
--dataset_path="path/to/train.csv" \
--max_text_len=4000Arguments:
model_path- embedder model for masking neighbors generationdataset_path- path to dataset for generating neighborsmax_text_len- max of text length in number of charactersmodality_column- optional;video,image, oraudioto generate aligned modality perturbations (modality_neighborscolumn)
Embeddings are produced by a unified pipeline in fimmia.embeds_joint, which uses the embedding_models abstraction (fimmia.embedding_models): a BaseEmbedder interface for both text and modality. The default text embedder is SentenceTransformer (e.g. E5); the default modality embedder is ImageBind. When --modality_key is set, both the text and modality models are loaded before dataset processing starts.
Structured CLI (Recommended):
fimmia embeds \
--df_path="path/to/train.csv" \
--embed_model="intfloat/e5-mistral-7b-instruct" \
--max_seq_length=4096 \
--user_answer=0 \
--modality_key=video \
--device="cuda" \
--part_size=5000 \
--run_single_file=1Legacy interface (Deprecated):
python job_launcher.py --script="fimmia.embeds_joint" \
--df_path="path/to/train.csv" \
--embed_model="intfloat/e5-mistral-7b-instruct" \
--max_seq_length=4096 \
--user_answer=0 \
--modality_key=video \
--device="cuda" \
--part_size=5000 \
--run_single_file=1For text-only datasets, omit --modality_key. For multimodal data, set --modality_key=image, --modality_key=video, or --modality_key=audio to compute modality embeddings (ImageBind) in the same pass; the modality model is loaded once at startup.
Arguments:
df_path– path to dataset CSV (must containneighborsfrom the neighbor step)embed_model– text embedder model name or path (default:intfloat/e5-mistral-7b-instruct)max_seq_length– max sequence length for the text encoder (default: 4096)user_answer– if 1, neighbor text isinput + neighbor; if 0,neighbor + answer(default: 0)modality_key– optional; column name for modality (image/video/audio) to embed in the same pass; omit for text-onlydevice– device for text and modality models (default:cuda)part_size– lines per output part file (default: 5000)run_single_file– 1 to process onlydf_path; 0 to process all CSVs under{df_path stem}_ng_parts/(default: 1)
Text-only vs multimodal: If you omit --modality_key, the pipeline produces only text embeddings (no {modality}_embeds/ folder). The FiMMIA attack model is then trained on reduced input: loss + text embedding only (no modality branch). Use the BaseLine model family (e.g. FiMMIABaseLineModelLossNormSTDV2). When you set --modality_key, both text and modality embeddings are produced; use the ModalityAll model family (e.g. FiMMIAModalityAllModelLossNormSTDV2) so the model receives loss + text embedding + modality embedding. The MDS dataset step and data collator handle both cases; modality-related arguments (e.g. modality_embedding_size) apply only when using ModalityAll models.
Structured CLI (Recommended):
# Image (--model_name is the Hugging Face or local path to the vision-language model)
fimmia loss image \
--model_name=Qwen/Qwen2.5-VL-3B-Instruct \
--label=0 \
--df_path="path/to/train.csv" \
--part_size=5000
# Audio
fimmia loss audio \
--model_id=Qwen/Qwen2-Audio-7B-Instruct \
--model_name=Qwen2-Audio-7B-Instruct \
--label=0 \
--df_path="path/to/train.csv" \
--part_size=5000
# Video
fimmia loss video \
--model_id=Qwen/Qwen2.5-VL-3B-Instruct \
--model_name=Qwen/Qwen2.5-VL-3B-Instruct \
--label=0 \
--df_path="path/to/train.csv" \
--part_size=5000Legacy interface (Deprecated):
python job_launcher.py --script="fimmia.image.loss_calc" --model_name=... --label=0 --df_path=...
python job_launcher.py --script="fimmia.audio.loss_calc_qwen2" --model_id=... --model_name=... --label=0 --df_path=...
python job_launcher.py --script="fimmia.video.loss_calc_qwen25" --model_id=... --model_name=... --label=0 --df_path=...Arguments:
model_id/model_name- video and audio loss scripts require both (model_idloads weights;model_namenames output folders). Image loss usesmodel_nameonly (same argument holds the model path forfrom_pretrained).label- label of dataset0or1df_path- path to dataset for calculating losspart_size- lines for splitting dataframe into smaller frames
Before training we need prepare data and merge all parts of files containing embeddings and losses:
Structured CLI (Recommended):
fimmia mds-dataset \
--save_dir="path/to/save/mds/dataset" \
--model_name="Qwen2.5-VL-3B-Instruct" \
--origin_df_path="path/to/train.csv" \
--shuffle=0 \
--labels="0,1" \
--modality_key="video" \
--single_file=1Legacy interface (Deprecated):
python job_launcher.py --script="fimmia.utils.mds_dataset" \
--save_dir="path/to/save/mds/dataset" \
--model_name="Qwen2.5-VL-3B-Instruct" \
--origin_df_path="path/to/train.csv" \
--shuffle=0 \
--labels="0,1" \
--modality_key="video" \
--single_file=1Arguments:
save_dir- path for saving merged datasetmodel_name- name of MLLM model (used for storing results)shuffle- not shuffle data0or shuffle1labels- list of labels in datasetmodality_key- modality columnsingle_file- run on single file or batches
After data preparation run training of an attack model neural network FiMMIA:
Structured CLI (Recommended):
fimmia train \
--train_dataset_path="train/mds/path" \
--val_dataset_path="test/mds/path" \
--model_name="FiMMIAModalityAllModelLossNormSTDV2" \
--embedding_size=4096 \
--modality_embedding_size=1024 \
--output_dir="path/to/model/save" \
--num_train_epochs=10 \
--optim="adafactor" \
--learning_rate=0.00005 \
--max_grad_norm=10 \
--warmup_ratio=0.03 \
--sigmas_path="data/pd_datasets/video/sigmas.json" \
--sigmas_type="std"Legacy interface (Deprecated):
python job_launcher.py --script="fimmia.train" \
--train_dataset_path="train/mds/path" \
--val_dataset_path="test/mds/path" \
--model_name="FiMMIAModalityAllModelLossNormSTDV2" \
--embedding_size=4096 \
--modality_embedding_size=1024 \
--output_dir="path/to/model/save" \
--num_train_epochs=10 \
--optim="adafactor" \
--learning_rate=0.00005 \
--max_grad_norm=10 \
--warmup_ratio=0.03 \
--sigmas_path="data/pd_datasets/video/sigmas.json" \
--sigmas_type="std"Training arguments:
train_dataset_path- path to train mds datasetval_dataset_path- path to validation MDS data; optional. If omitted, training still completes and the model is saved, buttest.csv/test_metrics.csvare not written underoutput_dir.model_name- FiMMIA architecture: useFiMMIABaseLineModelLossNormSTDV2for text-only (no modality); useFiMMIAModalityAllModelLossNormSTDV2when the MDS dataset includes modality embeddingsembedding_size- text embedding dimension (default: 4096)modality_embedding_size- modality embedding dimension for ModalityAll models (default: 1024)num_train_epochs- number of training epochsoutput_dir- path to save FiMMIA modeloptim- pytorch optimizer namelearning_rate- learning ratemax_grad_norm- max gradient normalizationwarmup_ratio- warmup ratio for optimizationsigmas_path- path for dict with normalization parameterssigmas_type- type of normalization
For inference we repeat 2, 3, 4 steps from training stage: 2. Neighbor generation 3. Embedding generation 4. Loss computation
For inference FiMMIA model on new data:
Structured CLI (Recommended):
fimmia infer \
--model_name="FiMMIABaseLineModelLossNormSTDV2" \
--model_path="path/to/model/save" \
--test_path="test/mds/path" \
--save_path="path/to/save/predictions.csv" \
--save_metrics_path="path/to/save/metrics" \
--sigmas_path="path/to/sigmas.json" \
--sigmas_type="std"Legacy interface (Deprecated):
python job_launcher.py --script="fimmia.fimmia_inference" \
--model_name="FiMMIABaseLineModelLossNormSTDV2" \
--model_path="path/to/model/save" \
--test_path="test/mds/path" \
--save_path="path/to/save/predictions.csv" \
--save_metrics_path="path/to/save/metrics" \
--sigmas_path="path/to/sigmas.json" \
--sigmas_type="std"Arguments:
model_name- name of FiMMIA neural network architecturemodel_path- path to load FiMMIA modeltest_path- path to test datasetsave_path- path to save predictionssave_metrics_path- path to save metricssigmas_path/sigmas_type- passed to the data collator for normalization (same as training; use the JSON produced alongside your MDS pipeline)
We also support running an gradient-based feature attribution on the FiMMIA model, intended to calculate a relative impact of loss and embedding related parts. The pipeline saves results and provides an option to draw graphs of attrbution metrics. The results are saved into the same folder as an FiMMIA model.
To run attribution:
Structured CLI (Recommended):
fimmia attribute \
--model_dir="path/to/fimmia_model_folder" \
--mds_dataset_path="path/to/mds_dataset_folder" \
--model_cls="BaseLineModelV2" \
--embedding_size=4096 \
--modality_embedding_size=1024 \
--add_attribution_noise=False \
--create_graphs=TrueLegacy interface (Deprecated):
python job_launcher.py --script="fimmia.attribute_fimmia" \
--model_dir="path/to/fimmia_model_folder" \
--mds_dataset_path="path/to/mds_dataset_folder" \
--model_cls="BaseLineModelV2" \
--embedding_size=4096 \
--modality_embedding_size=1024 \
--add_attribution_noise=False \
--create_graphs=TrueArguments:
model_cls- name of a FiMMIA neural network architecturemodel_dir- path to load FiMMIA modelmds_dataset_path- path to the dataset to attributeembedding_size- dimension of the embedding inputmodality_embedding_size- dimension of the modality embedding input (only used in case modal embeddings are used)add_attribution_noise- whether to use stochastic perturbations (e.g. NoiseTunnel) to enhance reliability of the methodcreate_graphs- whether to create graphs of attribution results
- Emelyanov Anton
- Kudriashov Sergei
- Alena Fenogenova