This pytorch class implements Emulator-based component analysis (ECA) as described in J. Niskanen, A. Vladyka, J. Niemi, and C. J. Sahle, “Emulator-based decomposition for structural sensitivity of core-level spectra,” Royal Society Open Science, vol. 9, 2022, doi: 10.1098/rsos.220093.
Idea:
- For a given trained predictor Emu: X -> Y (e.g., neural network)
- We define N basis vectors V in X space, such that the covered variance for the prediction of the X, projected on V space, is maximized in respect to Y.
- These vectors are calculated one by one, i.e. projections on the first vector cover most of the variance.
Being applied to spectroscopy: the model predictd spectrum from the structure. The goal of ECA is to find a subspace
Similar concept: see w:Projection pursuit regression
V - space of ECA vectors
fit(x, y) calculation of the V basis
transform x -> t, t = x @ V.T - scores of X in V space (i.e. length of the projections of X on V space)
expand t -> x', x' = t @ V - projection of X data to V space
project x -> x', x' = expand(transform(x))
inverse y -> t', optimization search of the t-scores for the given Y
reconstruct y -> (t') -> x', via inverse
pytorch (>2.0), tqdm
from eca import ECA
# define options
options = {
'tol' : 1E-5,
'epochs': 5000,
'lr' : 1E-3,
'batch_size': 512,
'seed' : 123
}
# assuming model is a torch-based (instance of nn.Module) neural network to predict X -> Y
eca = ECA(model)
# run evaluation of the vectors
# data_x, data_y are torch.Tensor(torch.float32) tensors
v, y_var, x_var = eca.fit(data_x, data_y, n_comp=3, options=options, verbose=True)
To run inverse transformation (find an approximation in V-space for a given y):
# inverse transformation
options_inv = {
'tol' : 1E-4,
'epochs': 1000,
'lr' : 5E-2,
}
t = eca.inverse(y, options=options_inv, verbose=True)