Skip to content

Commit 92c8b1f

Browse files
gonlairostesMMathisLab
authored
Add xCEBRA implementation (AISTATS 2025) (#225)
* Add multiobjective solver and regularized training (#783) * Add multiobjective solver and regularized training * Add example for multiobjective training * Add jacobian regularizer and SAM * update license headers * add api draft for multiobjective training * add all necessary modules to run the complete xcebra pipeline * add notebooks to reproduce xcebra pipeline * add first working notebook * add notebook with hybrid learning * add notebook with creation of synthetic data * add notebook with hybrid training * add plot with R2 for different parts of the embedding * add new API * update api wrapper with more checks and messages * add tests and notebook with new api * merge xcebra into attribution * separate xcebra dataset from cebra * some minor refactoring of cebra dataset * separate xcebra loader from cebra * remove xcebra distributions from cebra * minor refactoring with distributions * separate xcebra criterions from cebra * minor refactoring on criterion * separate xcebra models/criterions/layers from cebra * refactoring multiobjective * more refactoring... * separate xcebra solvers from cebra * more refactoring * move xcebra to its own package * move more files into xcebra package * more files and remove changes with the registry * remove unncessary import * add folder structure * move back distributions * add missing init * remove wrong init * make loader and dataset run with new imports * making it run! * make attribution run * Run pre-commit * move xcebra repo one level up * update gitignore and add __init__ from data * add init to distributions * add correct init for attribution pacakge * add correct init for model package * fix remaining imports * fix tests * add examples back to xcebra repo * update imports from graphs_xcebra * add setup.py to create a package * update imports of graph_xcebra * update notebooks * Formatting code for submission Co-authored-by: Rodrigo Gonzalez <[email protected]> * move test into xcebra * Add README * move distributions back to main package * clean up examples * adapt tests * Add LICENSE * add train/eval notebook again * add notebook with clean results * rm synthetic data * change name from xcebra to regcl * change names of modules and adapt imports * change name from graphs_xcebra to synthetic_data * Integrate into CEBRA * Fix remaining imports and make notebook runnable * Add dependencies, add version flag * Remove synthetic data files * reset dockerfile, move vmf * apply pre-commit * Update notice * add some docstrings * Apply license headers * add new scd notebook * add notebook with scd --------- Co-authored-by: Steffen Schneider <[email protected]> * Fix tests * bump version * update dockerfile * fix progress bar * remove outdated test * rename models * Apply fixes to pass ruff tests * Fix typos * Update license headers, fix additional ruff errors * remove unused comment * rename regcl in codebase * change regcl name in dockerfile * Improve attribution module * Fix imports name naming * add basic integration test * temp disable of binary check * Add legacy multiobjective model for backward compat * add synth import back in * Fix docstrings and type annot in cebra/models/jacobian_regularizer.py * add xcebra to tests * add missing cvxpy dep * fix docstrings * more docstrings to fix attr error * Improve build setup for docs * update pydata theme options * Add README for docs folder * Fix demo notebook build * Finish build setup * update git workflow * Move demo notebooks to CEBRA-demos repo See AdaptiveMotorControlLab/CEBRA-demos#28 * revert unneeded changes in solver * formatting in solver * further minimize solver diff * Revert unneeded updates to the solver * fix citation * fix docs build, missing refs * remove file dependency from xcebra int test * remove unneeded change in registry * update gitignore * update docs * exclude some assets * include binary file check again * add timeout to workflow * add timeout also to docs build * switch build back to sphinx for gh actions * pin sphinx version in setup.cfg * attempt workflow fix * attempt to fix build workflow * update to sphinx-build * fix build workflow * fix indent error * fix build system * revert demos to main * adapt workflow for testing * bump version to 0.6.0rc1 * format imports * docs writing * enable build on dev branch * fix some review comments * extend multiobjective docs * Set version to alpha * make tempdir platform independent * Remove ratinabox and ephysiopy as deps * Apply review comments * Update Makefile - setting coverage threshold to 80% to not delay good code being made public. In the near future this can be fixed and raised again to 90%. --------- Co-authored-by: Steffen Schneider <[email protected]> Co-authored-by: Steffen Schneider <[email protected]> Co-authored-by: Mackenzie Mathis <[email protected]>
1 parent d86ccf0 commit 92c8b1f

40 files changed

+3605
-45
lines changed

.github/workflows/docs.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ jobs:
4747
with:
4848
repository: AdaptiveMotorControlLab/cebra-demos
4949
path: docs/source/demo_notebooks
50-
ref: main
50+
# NOTE(stes): This is a temporary branch to add the xCEBRA demo notebooks
51+
# to the docs. Once the notebooks are merged into main, we can remove this
52+
# branch and change the ref to main.
53+
# ref: main
54+
ref: stes/add-xcebra
5155

5256
- name: Set up Python 3.10
5357
uses: actions/setup-python@v5

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ experiments/sweeps
77
exports/
88
demo_notebooks/
99
assets/
10+
.remove
11+
12+
# demo run
13+
.vscode/
14+
auxiliary_behavior_data.h5
15+
cebra_model.pt
16+
data.npz
17+
grid_search_models/
18+
neural_data.npz
19+
saved_models/
1020

1121
# demo run
1222
.vscode/

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ RUN make dist
4040
FROM cebra-base
4141

4242
# install the cebra wheel
43-
ENV WHEEL=cebra-0.5.0-py3-none-any.whl
43+
ENV WHEEL=cebra-0.6.0a1-py3-none-any.whl
4444
WORKDIR /build
4545
COPY --from=wheel /build/dist/${WHEEL} .
4646
RUN pip install --no-cache-dir ${WHEEL}'[dev,integrations,datasets]'

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CEBRA_VERSION := 0.5.0
1+
CEBRA_VERSION := 0.6.0a1
22

33
dist:
44
python3 -m pip install virtualenv
@@ -55,7 +55,7 @@ interrogate:
5555
--ignore-private \
5656
--ignore-magic \
5757
--omit-covered-files \
58-
-f 90 \
58+
-f 80 \
5959
cebra
6060

6161
# Build documentation using sphinx

NOTICE.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,83 @@
3535
- 'tests/**/*.py'
3636
- 'docs/**/*.py'
3737
- 'conda/**/*.yml'
38+
39+
- header: |
40+
CEBRA: Consistent EmBeddings of high-dimensional Recordings using Auxiliary variables
41+
© Mackenzie W. Mathis & Steffen Schneider (v0.4.0+)
42+
Source code:
43+
https://github.com/AdaptiveMotorControlLab/CEBRA
44+
45+
Please see LICENSE.md for the full license document:
46+
https://github.com/AdaptiveMotorControlLab/CEBRA/blob/main/LICENSE.md
47+
48+
Adapted from https://github.com/rpatrik96/nl-causal-representations/blob/master/care_nl_ica/dep_mat.py,
49+
licensed under the following MIT License:
50+
51+
MIT License
52+
53+
Copyright (c) 2022 Patrik Reizinger
54+
55+
Permission is hereby granted, free of charge, to any person obtaining a copy
56+
of this software and associated documentation files (the "Software"), to deal
57+
in the Software without restriction, including without limitation the rights
58+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
59+
copies of the Software, and to permit persons to whom the Software is
60+
furnished to do so, subject to the following conditions:
61+
62+
The above copyright notice and this permission notice shall be included in all
63+
copies or substantial portions of the Software.
64+
65+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
66+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
67+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
68+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
69+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
70+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
71+
SOFTWARE.
72+
73+
include:
74+
- 'cebra/attribution/jacobian.py'
75+
76+
77+
- header: |
78+
CEBRA: Consistent EmBeddings of high-dimensional Recordings using Auxiliary variables
79+
© Mackenzie W. Mathis & Steffen Schneider (v0.4.0+)
80+
Source code:
81+
https://github.com/AdaptiveMotorControlLab/CEBRA
82+
83+
Please see LICENSE.md for the full license document:
84+
https://github.com/AdaptiveMotorControlLab/CEBRA/blob/main/LICENSE.md
85+
86+
This file contains the PyTorch implementation of Jacobian regularization described in [1].
87+
Judy Hoffman, Daniel A. Roberts, and Sho Yaida,
88+
"Robust Learning with Jacobian Regularization," 2019.
89+
[arxiv:1908.02729](https://arxiv.org/abs/1908.02729)
90+
91+
Adapted from https://github.com/facebookresearch/jacobian_regularizer/blob/main/jacobian/jacobian.py
92+
licensed under the following MIT License:
93+
94+
MIT License
95+
96+
Copyright (c) Facebook, Inc. and its affiliates.
97+
98+
Permission is hereby granted, free of charge, to any person obtaining a copy
99+
of this software and associated documentation files (the "Software"), to deal
100+
in the Software without restriction, including without limitation the rights
101+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
102+
copies of the Software, and to permit persons to whom the Software is
103+
furnished to do so, subject to the following conditions:
104+
105+
The above copyright notice and this permission notice shall be included in all
106+
copies or substantial portions of the Software.
107+
108+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
109+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
110+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
111+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
112+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
113+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
114+
SOFTWARE.
115+
116+
include:
117+
- 'cebra/models/jacobian_regularizer.py'

PKGBUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Maintainer: Steffen Schneider <[email protected]>
22
pkgname=python-cebra
33
_pkgname=cebra
4-
pkgver=0.5.0
4+
pkgver=0.6.0a1
55
pkgrel=1
66
pkgdesc="Consistent Embeddings of high-dimensional Recordings using Auxiliary variables"
77
url="https://cebra.ai"

cebra/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666

6767
import cebra.integrations.sklearn as sklearn
6868

69-
__version__ = "0.5.0"
69+
__version__ = "0.6.0a1"
7070
__all__ = ["CEBRA"]
7171
__allow_lazy_imports = False
7272
__lazy_imports = {}

cebra/attribution/__init__.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#
2+
# CEBRA: Consistent EmBeddings of high-dimensional Recordings using Auxiliary variables
3+
# © Mackenzie W. Mathis & Steffen Schneider (v0.4.0+)
4+
# Source code:
5+
# https://github.com/AdaptiveMotorControlLab/CEBRA
6+
#
7+
# Please see LICENSE.md for the full license document:
8+
# https://github.com/AdaptiveMotorControlLab/CEBRA/blob/main/LICENSE.md
9+
#
10+
# Licensed under the Apache License, Version 2.0 (the "License");
11+
# you may not use this file except in compliance with the License.
12+
# You may obtain a copy of the License at
13+
#
14+
# http://www.apache.org/licenses/LICENSE-2.0
15+
#
16+
# Unless required by applicable law or agreed to in writing, software
17+
# distributed under the License is distributed on an "AS IS" BASIS,
18+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19+
# See the License for the specific language governing permissions and
20+
# limitations under the License.
21+
#
22+
"""Attribution methods for CEBRA.
23+
24+
This module was added in v0.6.0 and contains attribution methods described and benchmarked
25+
in [Schneider2025]_.
26+
27+
28+
.. [Schneider2025] Schneider, S., González Laiz, R., Filippova, A., Frey, M., & Mathis, M. W. (2025).
29+
Time-series attribution maps with regularized contrastive learning.
30+
The 28th International Conference on Artificial Intelligence and Statistics.
31+
https://openreview.net/forum?id=aGrCXoTB4P
32+
"""
33+
import cebra.registry
34+
35+
cebra.registry.add_helper_functions(__name__)
36+
37+
from cebra.attribution.attribution_models import *
38+
from cebra.attribution.jacobian_attribution import *

cebra/attribution/_jacobian.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#
2+
# CEBRA: Consistent EmBeddings of high-dimensional Recordings using Auxiliary variables
3+
# © Mackenzie W. Mathis & Steffen Schneider (v0.4.0+)
4+
# Source code:
5+
# https://github.com/AdaptiveMotorControlLab/CEBRA
6+
#
7+
# Please see LICENSE.md for the full license document:
8+
# https://github.com/AdaptiveMotorControlLab/CEBRA/blob/main/LICENSE.md
9+
#
10+
# Adapted from https://github.com/rpatrik96/nl-causal-representations/blob/master/care_nl_ica/dep_mat.py,
11+
# licensed under the following MIT License:
12+
#
13+
# MIT License
14+
#
15+
# Copyright (c) 2022 Patrik Reizinger
16+
#
17+
# Permission is hereby granted, free of charge, to any person obtaining a copy
18+
# of this software and associated documentation files (the "Software"), to deal
19+
# in the Software without restriction, including without limitation the rights
20+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21+
# copies of the Software, and to permit persons to whom the Software is
22+
# furnished to do so, subject to the following conditions:
23+
#
24+
# The above copyright notice and this permission notice shall be included in all
25+
# copies or substantial portions of the Software.
26+
#
27+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33+
# SOFTWARE.
34+
#
35+
36+
from typing import Union
37+
38+
import numpy as np
39+
import torch
40+
41+
42+
def tensors_to_cpu_and_double(vars_: list[torch.Tensor]) -> list[torch.Tensor]:
43+
"""Convert a list of tensors to CPU and double precision.
44+
45+
Args:
46+
vars_: List of PyTorch tensors to convert
47+
48+
Returns:
49+
List of tensors converted to CPU and double precision
50+
"""
51+
cpu_vars = []
52+
for v in vars_:
53+
if v.is_cuda:
54+
v = v.to("cpu")
55+
cpu_vars.append(v.double())
56+
return cpu_vars
57+
58+
59+
def tensors_to_cuda(vars_: list[torch.Tensor],
60+
cuda_device: str) -> list[torch.Tensor]:
61+
"""Convert a list of tensors to CUDA device.
62+
63+
Args:
64+
vars_: List of PyTorch tensors to convert
65+
cuda_device: CUDA device to move tensors to
66+
67+
Returns:
68+
List of tensors moved to specified CUDA device
69+
"""
70+
cpu_vars = []
71+
for v in vars_:
72+
if not v.is_cuda:
73+
v = v.to(cuda_device)
74+
cpu_vars.append(v)
75+
return cpu_vars
76+
77+
78+
def compute_jacobian(
79+
model: torch.nn.Module,
80+
input_vars: list[torch.Tensor],
81+
mode: str = "autograd",
82+
cuda_device: str = "cuda",
83+
double_precision: bool = False,
84+
convert_to_numpy: bool = True,
85+
hybrid_solver: bool = False,
86+
) -> Union[torch.Tensor, np.ndarray]:
87+
"""Compute the Jacobian matrix for a given model and input.
88+
89+
This function computes the Jacobian matrix using PyTorch's autograd functionality.
90+
It supports both CPU and CUDA computation, as well as single and double precision.
91+
92+
Args:
93+
model: PyTorch model to compute Jacobian for
94+
input_vars: List of input tensors
95+
mode: Computation mode, currently only "autograd" is supported
96+
cuda_device: Device to use for CUDA computation
97+
double_precision: If True, use double precision
98+
convert_to_numpy: If True, convert output to numpy array
99+
hybrid_solver: If True, concatenate multiple outputs along dimension 1
100+
101+
Returns:
102+
Jacobian matrix as either PyTorch tensor or numpy array
103+
"""
104+
if double_precision:
105+
model = model.to("cpu").double()
106+
input_vars = tensors_to_cpu_and_double(input_vars)
107+
if hybrid_solver:
108+
output = model(*input_vars)
109+
output_vars = torch.cat(output, dim=1).to("cpu").double()
110+
else:
111+
output_vars = model(*input_vars).to("cpu").double()
112+
else:
113+
model = model.to(cuda_device).float()
114+
input_vars = tensors_to_cuda(input_vars, cuda_device=cuda_device)
115+
116+
if hybrid_solver:
117+
output = model(*input_vars)
118+
output_vars = torch.cat(output, dim=1)
119+
else:
120+
output_vars = model(*input_vars)
121+
122+
if mode == "autograd":
123+
jacob = []
124+
for i in range(output_vars.shape[1]):
125+
grads = torch.autograd.grad(
126+
output_vars[:, i:i + 1],
127+
input_vars,
128+
retain_graph=True,
129+
create_graph=False,
130+
grad_outputs=torch.ones(output_vars[:, i:i + 1].shape).to(
131+
output_vars.device),
132+
)
133+
jacob.append(torch.cat(grads, dim=1))
134+
135+
jacobian = torch.stack(jacob, dim=1)
136+
137+
jacobian = jacobian.detach().cpu()
138+
139+
if convert_to_numpy:
140+
jacobian = jacobian.numpy()
141+
142+
return jacobian

0 commit comments

Comments
 (0)