Skip to content

Commit 6a92479

Browse files
committed
Document new capabilities, add changelog, update contact info
Documents three-tabular-modality support, main_modality/attention_modality selection, and image transforms - all previously undocumented. Adds CHANGELOG.md covering everything unreleased since v1.2.3. Updates the README bio to past tense and points contact queries to GitHub issues instead of a UCL email address.
1 parent 1f7a6fb commit 6a92479

8 files changed

Lines changed: 180 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Changelog
2+
3+
## v2.0.0
4+
5+
Everything below covers all unreleased work since the last published version, v1.2.3.
6+
7+
### Breaking changes
8+
9+
- `data_dims` and data `sources` are now dictionaries (e.g. `{"mod1_dim": ..., "mod2_dim": ...}`) instead of lists,
10+
to support a variable number of tabular modalities. Anything calling the lower-level classes directly with the
11+
old list format will need updating; `prepare_fusion_data` users are unaffected.
12+
- Fusion model `forward()` methods now take modalities as separate tensor arguments and return a single tensor,
13+
instead of taking/returning lists. This makes model outputs compatible with libraries like SHAP that expect a
14+
single tensor in, single tensor out.
15+
- The binary classification final layer no longer applies `Sigmoid` internally; the loss function now uses
16+
`BCEWithLogitsLoss` on raw logits directly (more numerically stable). `preds` are still thresholded probabilities
17+
as before, computed via `sigmoid(logits) > 0.5`.
18+
19+
### New features
20+
21+
- **Three-tabular-modality support**: most tabular-tabular fusion methods (`TabularDecision`, `ConcatTabularData`,
22+
`ConcatTabularFeatureMaps`, `TabularChannelWiseMultiAttention`, `TabularCrossmodalMultiheadAttention`,
23+
`ActivationFusion`, `AttentionAndSelfActivation`) now accept a third tabular modality via a `tabular3` data source.
24+
Attention-based methods gained a configurable `main_modality`/`attention_modality` for choosing which modality
25+
gets special treatment.
26+
- **Image transforms**: `prepare_fusion_data` accepts a `transforms` argument (`torchio.transforms`-style) for
27+
image augmentation/preprocessing, for 2D and 3D images.
28+
- **GPU/device configuration**: a `training_modifications` argument (accelerator, number of devices) is now
29+
supported on `prepare_fusion_data` and `train_and_save_models`; metric calculations follow the data's device.
30+
- MCVAE early-stopping patience and tolerance are now configurable via the layer modifications dictionary.
31+
32+
### Robustness fixes
33+
34+
- Fixed the binary classification activation function (see "Breaking changes" above) - models were previously
35+
double-squashing predictions through a `Sigmoid`.
36+
- Fixed a bug where MCVAE's early-stopping patience attribute was misnamed internally.
37+
- Fixed the custom early-stopping callback.
38+
- Image-based methods no longer error out when the image is too small for the default network architecture -
39+
they now require `layer_mods` to fix the architecture instead of crashing outright.
40+
- The attention reduction ratio for channel-attention methods now auto-corrects to a working value instead of
41+
raising when it doesn't evenly divide the modality's feature dimension.
42+
- `torch.load` calls updated for current PyTorch versions (`weights_only`).
43+
44+
### Output / logging improvements
45+
46+
- Training and validation logits are now recorded on trained models, in addition to reals and predictions.
47+
- `ModelComparison` now also returns the underlying reals/preds for further analysis.
48+
- Multiclass dimensions and image downsample size can now be passed to more of the `from_new_data` evaluation
49+
functions.
50+
- WandB's local log directory is now configurable via an environment variable.
51+
- Loading CSVs with a stray `Unnamed: 0` index column now raises a clear warning instead of silently including it.
52+
53+
### Documentation and packaging
54+
55+
- Documented the three-tabular-modality feature, `main_modality`/`attention_modality` selection, and image
56+
transforms (previously undocumented).
57+
- Fixed a broken link and a class-name typo in the docs.
58+
- Bumped a vulnerable `urllib3` dependency pin.
59+
- Fixed CI so the vendored `mcvae` git submodule is actually fetched during test runs - this had been silently
60+
giving the MCVAE fusion model 0% test coverage.
61+
- Fixed a ReadTheDocs build timeout caused by an earlier docs cleanup accidentally discarding the sphinx-gallery
62+
example cache.
63+
- General branch cleanup and consolidation; test coverage raised from 89% to 93% (304/304 tests passing).

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ the [contributions documentation](https://fusilli.readthedocs.io/en/latest/contr
102102

103103
`fusilli` is authored by Florence J Townend, James Chapman, and James H Cole.
104104

105-
Florence J Townend is supported by a UCL UKRI Centre for Doctoral Training in AI-enabled Healthcare studentship (
106-
EP/S021612/1).
105+
Florence J Townend was supported by a UCL UKRI Centre for Doctoral Training in AI-enabled Healthcare studentship (
106+
EP/S021612/1) during the initial development of this software.
107107

108108
## License
109109

docs/choosing_model.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _choosing-a-model:
2+
13
Trait-Driven Model Imports
24
============================
35

@@ -67,4 +69,38 @@ Examples of Criteria
6769
6870
criteria = {
6971
"class_name": ["Tabular1Unimodal", "Tabular2Unimodal", "ConcatTabularData"],
72+
}
73+
74+
- **Models That Support Three Tabular Modalities**:
75+
76+
.. code-block:: python
77+
78+
criteria = {
79+
"three_tabular_modalities": True,
80+
"modality_type": "tabular_tabular", # exclude the tabular unimodal models
81+
}
82+
83+
Choosing the "Main" Modality for Attention-Based Models
84+
---------------------------------------------------------
85+
86+
Some attention-based tabular-tabular models (:class:`.ActivationFusion` and :class:`.AttentionAndSelfActivation`)
87+
let you choose which modality is treated as the "main" one - i.e. whose feature maps get concatenated with the
88+
fused output, and (for :class:`.AttentionAndSelfActivation`) which modality the channel attention is applied to.
89+
By default this is modality 1. You can change it either directly on an instantiated model:
90+
91+
.. code-block:: python
92+
93+
model = ActivationFusion(prediction_task=..., data_dims=..., multiclass_dimensions=...)
94+
model.main_modality = 2 # 1, 2, or 3
95+
96+
or via the layer modification dictionary passed to :func:`fusilli.data.prepare_fusion_data` and
97+
:func:`fusilli.train.train_and_save_models` (see :ref:`modifying-models`):
98+
99+
.. code-block:: python
100+
101+
layer_mods = {
102+
"AttentionAndSelfActivation": {
103+
"main_modality": 2,
104+
"attention_modality": 3,
105+
},
70106
}

docs/data_loading.rst

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Loading your Data
44
==================
55

6-
``fusilli`` facilitates fusion of **tabular data with tabular data** or **tabular data with images**.
6+
``fusilli`` facilitates fusion of **tabular data with tabular data** (two or three modalities) or **tabular data with images**.
77

88
Data Format Requirements
99
----------------------------
@@ -17,6 +17,7 @@ The paths to the data source files must be in a dictionary before being passed t
1717
data_paths = {
1818
"tabular1": "path/to/tabular1_data.csv",
1919
"tabular2": "path/to/tabular2_data.csv",
20+
"tabular3": "path/to/tabular3_data.csv",
2021
"image": "path/to/image_data.pt",
2122
}
2223
@@ -26,6 +27,12 @@ The paths to the data source files must be in a dictionary before being passed t
2627

2728
For example, if you are not using ``tabular2``, set ``tabular2`` in the dictionary to ``""``.
2829

30+
.. note::
31+
32+
``tabular3`` is optional. Most tabular-tabular fusion methods support a third tabular modality, but not all of
33+
them do, and it isn't supported for tabular-image fusion. See :ref:`choosing-a-model` for how to filter for
34+
models that support three tabular modalities.
35+
2936
Tabular and Tabular Data
3037
~~~~~~~~~~~~~~~~~~~~~~~~~~
3138

@@ -54,6 +61,27 @@ Columns named ``ID`` and ``prediction_label`` are required:
5461
data_paths=data_paths,
5562
output_paths=...)
5663
64+
**Example of loading three tabular modalities:**
65+
66+
Most tabular-tabular fusion methods also accept a third tabular modality. Just add a ``tabular3`` key with
67+
the same CSV format (``ID`` and ``prediction_label`` columns) as the other tabular sources.
68+
69+
.. code-block:: python
70+
71+
from fusilli.data import prepare_fusion_data
72+
73+
data_paths = {
74+
"tabular1": "path/to/tabular1_data.csv",
75+
"tabular2": "path/to/tabular2_data.csv",
76+
"tabular3": "path/to/tabular3_data.csv",
77+
"image": "",
78+
}
79+
80+
data_module = prepare_fusion_data(prediction_task=...,
81+
fusion_model=some_example_model_with_3_modalities,
82+
data_paths=data_paths,
83+
output_paths=...)
84+
5785
Tabular and Image Data
5886
~~~~~~~~~~~~~~~~~~~~~~~
5987

@@ -97,6 +125,32 @@ To downsample images before model input, use the ``image_downsample_size`` param
97125
output_paths=...,
98126
image_downsample_size=(16, 16))
99127
128+
Applying Image Transforms
129+
*********************************
130+
131+
To apply data augmentation or preprocessing transforms to your images, use the ``transforms`` parameter in the
132+
:func:`fusilli.data.prepare_fusion_data` function. Pass a list of ``torchio.transforms`` functions with their
133+
arguments already filled in - each one is applied to every image in turn. (For 2D images, ``fusilli`` handles adding
134+
and removing the extra depth dimension that ``torchio`` expects internally, so you don't need to worry about that
135+
yourself.)
136+
137+
**Example of applying a random flip and a random affine transform:**
138+
139+
.. code-block:: python
140+
141+
import torchio.transforms as T
142+
143+
my_transforms = [
144+
T.RandomFlip(axes=(0,), flip_probability=0.5),
145+
T.RandomAffine(degrees=10),
146+
]
147+
148+
data_module = prepare_fusion_data(prediction_task=...,
149+
fusion_model=some_example_model,
150+
data_paths=data_paths,
151+
output_paths=...,
152+
transforms=my_transforms)
153+
100154
101155
-----
102156

docs/developers_guide.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,4 @@ Additional Notes
5050

5151
Thank you for your interest in contributing to Fusilli! Your contributions are highly appreciated.
5252

53-
For any further assistance or queries, feel free to reach out to florence.townend.21@ucl.ac.uk
53+
For any further assistance or queries, please open an issue on the `GitHub issues page <https://github.com/florencejt/fusilli/issues>`_.

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Why would you want to use fusilli?
2525
* - Problem
2626
- Solution
2727
* - You have a dataset that contains multiple modalities. 🩻 📈
28-
- Either two types of tabular data or one type of tabular data and one type of image data. Ever thought that maybe they'd be more powerful together? Fusilli can help you find out if multimodal fusion is right for you! ✨
28+
- Two or three types of tabular data, or one type of tabular data and one type of image data. Ever thought that maybe they'd be more powerful together? Fusilli can help you find out if multimodal fusion is right for you! ✨
2929
* - You've looked at methods for multimodal fusion and thought "wow, that's a lot of code" and "wow, there are so many names for the same concept". 🤔 🆘
3030
- *So* relatable. Fusilli provides a simple way for comparing multimodal fusion models without having to trawl through Google Scholar! ✨
3131
* - You've found a multimodal fusion method that you want to try out, but you're not sure how to implement it or it's not quite right for your data. 😵‍💫 🙌

docs/introduction.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ Templates and specific guidance on how to do this are in :ref:`contributing`.
3333
Contact
3434
--------
3535

36-
If you have any questions, please feel free to contact me at florence.townend.21@ucl.ac.uk or on Twitter:
37-
`@FlorenceTownend <https://twitter.com/florencetownend>`_.
36+
If you have any questions, please open an issue on the `GitHub issues page <https://github.com/florencejt/fusilli/issues>`_.
3837

3938

4039

docs/modifying_models.rst

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,12 @@ Modifiable Attributes
7777
- ``nn.ModuleDict``
7878
* - :attr:`~.ActivationFusion.mod2_layers`
7979
- ``nn.ModuleDict``
80+
* - :attr:`~.ActivationFusion.mod3_layers`
81+
- ``nn.ModuleDict``. Only used if a third tabular modality is provided.
8082
* - :attr:`~.ActivationFusion.fused_layers`
8183
- ``nn.Sequential``
84+
* - :attr:`~.ActivationFusion.main_modality`
85+
- int (1, 2, or 3). Which modality's feature maps get concatenated with the fused feature map.
8286

8387
:class:`.AttentionAndSelfActivation`
8488
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -94,10 +98,16 @@ Modifiable Attributes
9498
- ``nn.ModuleDict``
9599
* - :attr:`~.AttentionAndSelfActivation.mod2_layers`
96100
- ``nn.ModuleDict``
101+
* - :attr:`~.AttentionAndSelfActivation.mod3_layers`
102+
- ``nn.ModuleDict``. Only used if a third tabular modality is provided.
97103
* - :attr:`~.AttentionAndSelfActivation.fused_layers`
98104
- ``nn.Sequential``
99105
* - :attr:`~.AttentionAndSelfActivation.attention_reduction_ratio`
100106
- int
107+
* - :attr:`~.AttentionAndSelfActivation.main_modality`
108+
- int (1, 2, or 3). Which modality's feature maps get concatenated with the fused feature map.
109+
* - :attr:`~.AttentionAndSelfActivation.attention_modality`
110+
- int (1, 2, or 3). Which modality the channel attention is applied to.
101111

102112

103113
:class:`.AttentionWeightedGNN`
@@ -268,6 +278,8 @@ Modifiable Attributes
268278
- ``nn.ModuleDict``
269279
* - :attr:`~.ConcatTabularFeatureMaps.mod2_layers`
270280
- ``nn.ModuleDict``
281+
* - :attr:`~.ConcatTabularFeatureMaps.mod3_layers`
282+
- ``nn.ModuleDict``. Only used if a third tabular modality is provided.
271283
* - :attr:`~.ConcatTabularFeatureMaps.fused_layers`
272284
- ``nn.Sequential``
273285

@@ -498,10 +510,12 @@ Modifiable Attributes
498510
* Overrides modification of ``mod1_layers`` made to "all"
499511
* Must have same number of layers as :attr:`~.TabularCrossmodalMultiheadAttention.mod2_layers`
500512
* - :attr:`~.TabularCrossmodalMultiheadAttention.mod2_layers`
501-
-
513+
-
502514
* ``nn.ModuleDict``
503515
* Overrides modification of ``mod2_layers`` made to "all"
504516
* Must have same number of layers as :attr:`.TabularCrossmodalMultiheadAttention.mod1_layers`
517+
* - :attr:`~.TabularCrossmodalMultiheadAttention.mod3_layers`
518+
- ``nn.ModuleDict``. Only used if a third tabular modality is provided.
505519

506520
------
507521

@@ -562,10 +576,12 @@ Modifiable Attributes
562576
* Overrides modification of ``mod1_layers`` made to "all"
563577
* Must have same number of layers as :attr:`~.TabularChannelWiseMultiheadAttention.mod2_layers`
564578
* - :attr:`~.TabularChannelWiseMultiAttention.mod2_layers`
565-
-
579+
-
566580
* ``nn.ModuleDict``
567581
* Overrides modification of ``mod1_layers`` made to "all"
568582
* Must have same number of layers as :attr:`~.TabularChannelWiseMultiheadAttention.mod1_layers`
583+
* - :attr:`~.TabularChannelWiseMultiAttention.mod3_layers`
584+
- ``nn.ModuleDict``. Only used if a third tabular modality is provided.
569585
* - :attr:`~.TabularChannelWiseMultiAttention.fused_layers`
570586
- ``nn.Sequential``
571587

@@ -587,8 +603,10 @@ Modifiable Attributes
587603
* ``nn.ModuleDict``
588604
* Overrides modification of ``mod1_layers`` made to "all"
589605
* - :attr:`~.TabularDecision.mod2_layers`
590-
-
606+
-
591607
* ``nn.ModuleDict``
592608
* Overrides modification of ``mod2_layers`` made to "all"
609+
* - :attr:`~.TabularDecision.mod3_layers`
610+
- ``nn.ModuleDict``. Only used if a third tabular modality is provided.
593611
* - :attr:`~.TabularDecision.fusion_operation`
594612
- Function (such as mean, median, etc.). Should act on the 1st dimension.

0 commit comments

Comments
 (0)