zhiminy/EvalEng huggingface dataset:
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Default Domain of Quantus Metrics
Root cause: Documentation Deficiency

I am wondering which metrics in this library are designed to support tabular data as input and not images? based on the tutorial, it seems that the methods supported for tabular data are complexity, sparseness and MPRT. 
Am I missing other metrics? I tried a majority of them, and they all have asserts requiring image data as input.

I have found that there is a data_applicability field for every class, but I feel it is not very accurate as some methods like Faithfulness Correlation do not seem to work for data types beside image-based data.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Default normalisation function
Root cause: Configuration Error

For a lot of quantification metrics (only checked the faithfulness_metrics.py for this) the default seems to be

```
self.normalise = self.kwargs.get("normalise", True)
self.normalise_func` = self.kwargs.get("normalise_func", normalise_by_negative)
```
with `normalise_by_negative` being defined in normalise_func.py as 

```
def normalise_by_negative(a: np.ndarray) -> np.ndarray:
    """Normalise relevance given a relevance matrix (r) [-1, 1]."""
    if a.min() >= 0.0:
        return a / a.max()
    if a.max() <= 0.0:
        return -a / a.min()
    return (a > 0.0) * a / a.max() - (a < 0.0) * a / a.min()
```
I think this type of normalisation (as default) may lead to some unexpected/unintended behavior for many metrics (RegionPerturbation, for instance), since it normalises positive and negative parts of an attribution map by different values, and then changes the sign of the negative parts (thus basically taking the abs()). I believe this changes not only the ordering of attribution values (as abs() would), but also their relative magnitudes.

For this reason, a better default may be either `self.normalise = self.kwargs.get("normalise", False)` or `self.normalise_func` = self.kwargs.get("normalise_func", normalise_by_max)` ? 

nvm, missed the sign of the negatives
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Allow for more variable shapes of attributions and inputs
Root cause: Unimplemented Feature Gap

Shapes of accepted inputs/attributions in metrics are hard-coded and very restrictve to specific data domains currently.

Mainly opening this issue as a reminder to extend functionality to other, non-image domains, and allow for shape flexibility.
For instance, in some applications, channel-wise attributions may carry meaningful information.

Of course, this may only be feasible for a subset of quantification metrics.

agree, it's on the todo list to make x_batch and a_batch shapes a bit more flexible. ping @Wickstrom how far did you get on developing this one?

I have come quite far, it should be ready in the coming days.

It turns out, that allowing for flexible image size was a bigger job than expected ping @leanderweber @annahedstroem. I will incrementally adapt the metrics individually to allow for flexible image size in the "flexible-imgsize" branch. But it will take some time before all of them are ready.

it might be worthwhile to already consider arbitrarily shaped tensor data, to eg. also support (multi channel) time series data and other stuff

this is an effort ongoing, see 2 separate PRs:
1)  https://github.com/understandable-machine-intelligence-lab/Quantus/pull/73
2) https://github.com/understandable-machine-intelligence-lab/Quantus/pull/74

Support for variable shapes of inputs was added by [1d and non squared 2d input shapes #74](https://github.com/understandable-machine-intelligence-lab/Quantus/pull/74)

This enhancement should actually support any `numpy.ndarray` shapes, as long as there's a batch dimension (axis=0), the channel is at the beginning (axis=1) or at the end (axis=-1) and `channel_first` is passed explicitly. Inference of channel order (channel first or last) supports only unambiguous 1d and 2d inputs. Tests are only implemented for 1d and 2d.

Unfortunately 1d-support is NOT implemented for the following functions/metrics:
- `baseline_replacement_by_blur`: uses `conv2D_numpy`, `scipy.signal.convolve` could solve the issue
- `rotation, translation_x_direction`, `translation_y_direction`: `cv2` expects images as input
- `get_superpixels`: `skimage` also expects 2d input
- `IterativeRemovalOfFeatures` therefore won't work for 1d yet.



Ping @leanderweber,

given @dkrako concluding comment, would you agree that we can now close this issue?

Let me know your thoughts - if there is anything else you believe Quantus should support related to this issue.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Potentially dead code

Hi Anna, please check this potentially dead/erroneous code. I think me might need to remove it.

https://github.com/understandable-machine-intelligence-lab/Quantus/blob/4dda6f53b8bc0356cb9659c32329b9d68e4b2f3a/quantus/metrics/robustness_metrics.py#L759-L775

https://github.com/understandable-machine-intelligence-lab/Quantus/blob/4dda6f53b8bc0356cb9659c32329b9d68e4b2f3a/quantus/metrics/randomisation_metrics.py#L318-L329

Thanks Dilya! 

> Quantus/quantus/metrics/randomisation_metrics.py
is removed, will be included in upcoming commit to main

> Quantus/quantus/metrics/robustness_metrics.py
I think can be useful to keep, included an example to tutorial.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Rotten link in README/Tutorials

Hi,

It seems that the link of this tutorial is rotten: https://github.com/understandable-machine-intelligence-lab/Quantus/blob/main/README.md?plain=1#L226.

The link is
```
https://.../quantus/blob/main/tutorials/tutorial_[sensitivity]_parameterisation.ipynb
```
and the tutorial actually locates at
 
```
https://.../Quantus/blob/main/tutorials/tutorial_[sensivitivty]_parameterisation.ipynb
``` 

Noting that I added the brackets to emphasize the part that the two links differ and causes 404.  

Given that it looks like a small typo in the filename, we can fix it there and the link in README.md the same.


Thanks for noticing this! Very appreciated. It is fixed now and will be incorporated in the upcoming commit :)
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Update setup.py for including zennit library
Root cause: Configuration Error

For pytorch case: Check if zennit is installed. If it is, neither captum nor zennit need to be installed

fixed in https://github.com/understandable-machine-intelligence-lab/Quantus/pull/59

No zennit installation option in the setup.py yet right?

@leanderweber ping, see suggestion in https://github.com/understandable-machine-intelligence-lab/Quantus/pull/114.

Issue fixed here https://github.com/understandable-machine-intelligence-lab/Quantus/pull/114#pullrequestreview-943850575.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Include parameterizations for zennit xai computations.
Root cause: Unimplemented Feature Gap

At the moment, the zennit wrapper only uses default parameterizations. The user should be able to pass parameters to canonizer, composite, and attributor as kwargs.

fixed in https://github.com/understandable-machine-intelligence-lab/Quantus/pulls

not yet fixed. Zennit offers a bit more parameterisation options than the wrapper currently does. Would be nice to be able to pass those.

I'll second this and I would need that feature not just for zennit, but for captum, too.

I think for a complete parametrisation of both frameworks we would need to pass two kinds of kwargs:
* `kwargs` for the `__init__` constructor method (e.g. `IntegratedGradients`)
* `kwargs` for the `__call__` calling method of the explanation object (e.g. `IntegratedGradients().attribute()`)

Just passing down the kwargs from the original Metric constructor (e.g. `RegionPerturbation`) or its call-method won't work, as those packages will throw an error if they get unexpected arguments.

I would therefore propose the following:

Add two arguments to the metric `__init__` and `__call__` methods:
* `explain_init_kwargs`: this will hold the kwargs passed to the attribution class constructor (e.g. `IntegratedGradients(**explain_init_kwargs)`)
* `explain_call_kwargs`: this will hold the kwargs passed to the attribute method of the attributor object (e.g. `IntegratedGradients().attribute(**explain_call_kwargs)` )

All in all an example call would then look like this:
`IntegratedGradients(**explain_init_kwargs).attribute(inputs, targets, **explain_call_kwargs)`

I think this will be the cleanest solution for the issue.

Actually thinking more about this, the explanation functions should be reimplemented as classes. Otherwise, we would need even more arguments for zennit canonizer and composite (e.g. `explain_canonizer_kwargs`,  `explain_composite_kwargs`). This would then be dragged through all the metrics and will create unnecessary bloat. If a new XAI-package will be integrated, even more arguments could be introduced. All in all, these are symptoms of an anti-pattern.

Instead, a good architectural choice could be to create classes which implement an interface or abstract class (e.g. `ExplainerInterface`) with methods every inheriting `ExplainerClass` will have to implement. We could even create an intermediate abstract class like `ZennitExplainer` which will have some kind of keyword-arguments like these proposed yesterday.

Before or on calling the metrics, such an `ExplainerClass` will have to be instantiated, but all the bloat will then be completely separated from the metrics.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Suggestion on Readability of README 

While going through `README`, I have noticed that the section that describes metrics implemented is very long. Perhaps, we could use the `<details></details>` to hide the content.

More precisely, we could do it like:

*(below is snippet from `README` with the suggested approach)*

...
The library contains implementations of the following evaluation metrics:

<details>
<summary><b>Faithfulness:</b> ...</summary>

- Paper 1
- Paper 2
</details> 

<details>
<summary><b>Robustness:</b> ...</summary>

- Paper 1
- Paper 2
</details> 

Great suggestion - change just committed.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Small typo in Tutorial

Hi,

I have found a small typo in https://github.com/understandable-machine-intelligence-lab/Quantus/blob/main/tutorials/tutorial_basic_example_all_metrics.ipynb.

![image](https://user-images.githubusercontent.com/1214890/155402363-2d529239-ecb7-46a9-b912-8ffc6fd37fed.png)




Thanks a lot - fixed.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Ability to Specify Seed for RandomLogit
Root cause: Unimplemented Feature Gap

The current implementation of `RandomLogit` uses `random` to select target labels, but it doesn't  seem to provide ways to control the random process.

I just wonder whether it would be a good idea to provide another argument (e.g., `seed`) for that. 

The same idea might be applicable for `ModelParameterRandomisation`.

it might make sense to globally set a random seed rather than per function call?

Sounds like a good idea @heytitle! I will include that in upcoming commits :-)

Fixed
Repository: understandable-machine-intelligence-lab/Quantus
Issue: New tutorial: on how to customise metrics with own user-defined functions
GitHub labels: enhancement

Would be great with a tutorial that shows:

- how to employ user-defined explanation functions into the tests
- how to customise the metric tests like perturb_func, similarity_func etc

Maybe call the tutorial something like: tutorial-customise-metrics-with-user-defined-functions

Regarding `similarity_func`,  I'm not sure to what extent the current API allows, but we could show how to compose a number of `similarity_func`'s together. For example, in randomization tests, I have seen people used both cosine similarity and SSIM. So, with this composition, we could have results for both metrics with one experiment. 

@heytitle like the suggestion! would you be interested in contributing with a tutorial including that? :-) feel free to make a PR with it in that case!
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Tutorial on how to use tensorflow models
Root cause: Documentation Deficiency

Would be great with a tutorial that shows:

- how to use tensorflow models

Maybe call the tutorial something like: tutorial-evaluate-with-tensorflow-model

+1

Fixed in this PR https://github.com/understandable-machine-intelligence-lab/Quantus/pull/81 :) 

@sebastianlutter
Repository: understandable-machine-intelligence-lab/Quantus
Issue: New metric: implement Infidelity
Root cause: Unimplemented Feature Gap

Implement Infidelity metric by Yeh et al., 2019 under `faithfulness_metrics.py`

References:
- Paper: https://arxiv.org/abs/1901.09392
- Captum implementation: https://captum.ai/api/_modules/captum/metrics/_core/infidelity.html#infidelity


@dilyabareeva updates?
Repository: understandable-machine-intelligence-lab/Quantus
Issue: PixelFlipping metric only flips first color channel
Root cause: Algorithmic Error

Hi,
I think I found a bug in the PixelFlipping implementation. Using the perturbation baseline "black", I noticed that only the first color channel (red) is set to 0. I would have expected all channels to be set to 0.
I initialized the metric as demonstrated in the tutorials with the following code:
```
quantus.PixelFlipping(**{
      "features_in_step": 28, 
      "perturb_baseline": "black", 
      "perturb_func": quantus.baseline_replacement_by_indices
})
```

Plotting the perturbed images for a couple of iterations leads to the following images, where **top** is produced by the current implementation and **bottom** is what I expected (perturbing all color channels):
<img src="https://user-images.githubusercontent.com/5980264/156534521-0336cdfc-2bf3-41b3-b896-3d7b35d3c249.png"  width="70%">

I think the problem is caused [here](https://github.com/understandable-machine-intelligence-lab/Quantus/blob/7f96cc6ca28dc0fdd10ee74d045a2890bdb17d8d/quantus/metrics/faithfulness_metrics.py#L1114), because `x_perturbed` has dimension _num_col_channels_ x _img_size_ x _img_size_ and `a_ix` only has dimension _img_size_ x _img_size_. 

I solved this locally with a quick workaround (which produced the **bottom** images in the figure above):
```
num_channels = 3
a_ix = np.concatenate([a_ix + (ch * len(a)) for ch in range(num_channels)])
```
However, since the perturbation is performed on normalized images, the normalized value for 0 can differ by color channel. This is not addressed in this quick fix.  


Thanks @frederikpahde for making me aware of this issue and for documenting it very well. You can expect the fixes to be incorporated in next commit to main :-)

Fixed in the following commit: https://github.com/understandable-machine-intelligence-lab/Quantus/commit/b0d6554f40556ce12ede0cb5abceba2114f83ffc
Repository: understandable-machine-intelligence-lab/Quantus
Issue: New metric: implement ROAD evaluation procedure
Root cause: Unimplemented Feature Gap

Implement ROAD https://github.com/tleemann/road_evaluation under `faithfulness_metrics.py`

Paper: https://arxiv.org/pdf/2202.00449.pdf

@dilyabareeva updates?

https://github.com/understandable-machine-intelligence-lab/Quantus/pull/107
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Unify Requirements of Perturb Functions and their Usage in the Metrics
Root cause: Architectural Constraint

The currently implemented perturb functions have different requirements, e.g., in terms of expected input shape, and are thus not really interchangable for all metrics. Requirements should either be unified for perturb functions, or at least an informative error message should be thrown in the metrics if an inapplicable perturb function is used.

I think the most clean way of doing this would be to create some abstract classes or interfaces with abstract methods which specify the expected inputs, e.g. `IndexPerturbatorInterface` or `PatchPerturbatorInterface`. The calling metric then would just need to check if the passed perturbator object inherits from the expected type of perturbator.
This would also have the benefit of instantiating the perturbator object beforehand with any arguments wanted without unnecessarily dragging these arguments through the `Metric` implementations.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Create a "disable_parameter_printing" feature

Quantus is designed to be easy to use: users are allowed to initialise the metrics without explicitly setting any metrics arguments (there are default params for everything) - which means that metrics can be easily looped over etc, making the library very flexible.

But since "the devil is in the details" when it comes to metric parameterisation - we should create a feature that highlights the current parameter setting of each metric - so to identify potential typos etc.

Could be a simple feature that prints the values of metrics' argument at metric initialisation

Merged to existing issue: https://github.com/understandable-machine-intelligence-lab/Quantus/issues/82.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: raise exceptions instead of asserting conditions
Root cause: Validation Gap

This is just a minor issue most of the time, but using assertions for checking input variables can lead to problems for people using this package.

The problem is, that assertions are deactivated when you use the optimization parameter `-O` on launching python. So as an example if a user wants to optimize the interpreter/compiler for memory-efficiency, all of the assertions in this package will be ignored.
Most people don't use this optimization parameter, but I think we should be aware of this issue and maybe even enforce this for newly written code.

Here are some discussions on stackoverflow which can be helpful:
https://stackoverflow.com/questions/944592/best-practice-for-using-assert
https://stackoverflow.com/questions/28608385/assert-asserting-when-debug-false
https://stackoverflow.com/questions/56990925/is-this-assert-for-development-not-for-production


TLDR:
* use exceptions for the user-side of the package, where things can go wrong by unintended input/output
* use assertions for the developer-side of the package, to assert conditions that should absolutely never go wrong, independent of user input
Repository: understandable-machine-intelligence-lab/Quantus
Issue: torch-xai: zennit
Root cause: Unimplemented Feature Gap

let's use zennit for computing xai for stuff captum can not deliver, ie in https://github.com/xai-quantification-toolbox/xai-quantification-toolbox/blob/main/nbs/nb_test_measures.ipynb

zennit supported in https://github.com/understandable-machine-intelligence-lab/Quantus/pull/59
Repository: understandable-machine-intelligence-lab/Quantus
Issue: use batched processing instead of processing by instance
Root cause: Algorithmic Error

Currently all of the metrics are more or less structured by the following scheme:

```
x: array
y: array
a: array

for x_instance, y_instance, a_instance in zip(x, y, a):
    for perturbation_step in range(perturbation_steps):
        x_perturbed = perturb_instance(x_instance, a_instance, perturbation_step)
        y_perturbed = model(x_perturbed)
        score = calculate_score_for_instance(y_instance, y_perturbed)
```

The choice of perturb_instance arguments are just for simplicity, the code is of course more complex than presented.

But this kind of implementation doesn't use the performance benefits from batched model-prediction and vectorized numpy functions.
Instead we could speed up computations by a magnitude if we would instead use the following approach:

```
x: array
y: array
a: array
batch_size: int

generator = BatchGenerator(x, y, a, batch_size)
for x_batch, y_batch, a_batch in next(generator):
    for perturbation_step in range(perturbation_steps):
        x_batch_perturbed = perturb_batch(x_batch, a_batch, perturbation_step)
        y_batch_perturbed = model(x_batch_perturbed)
        score = calculate_score_for_batch(y_batch, y_batch_perturbed)
```

Some of `perturb_batch` functions may need an inner for-loop again, but others could be computed on the whole batch for sure.
Depending on the dataset size and model complexity, this should lead to significant improvements in performance.

Solved in batched processing.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Enhancement: out metrics' **kwargs in *args and set default values
Root cause: Unimplemented Feature Gap

To make the parametrisation of metrics in Quantus more explicit (in order to mitigate the risks of user typos and other undefined behaviours e.g., when passing a larger kwargs for different perturb_func calls if large-scale experiments are performed), we want to update the arguments list of all metrics initialisations like `def __init__(self, ...)` in the library as follows:

- Split kwargs for every Callable used in the metric init like `explain_func`, `perturb_func` and `similar_func` as follows: `explain_func_kwargs`, `perturb_kwargs` and `similar_func_kwargs`
- Make sure to set default values to None where types are immutable in arguments list and reset it after to its actual data type like `perturb_kwargs: Union[None, dict] = None`
- Remove `*args`since it is useless

AND:
- Update the docstrings to reflect these changes
- Update code in the library where the metrics are called e.g., in the tutorials and pytests


Merging with another issue: https://github.com/understandable-machine-intelligence-lab/Quantus/issues/78.

Quantus is designed to be easy to use: users are allowed to initialise the metrics without explicitly setting any metrics arguments (there are default params for everything) - which means that metrics can be easily looped over etc, making the library very flexible.

But since "the devil is in the details" when it comes to metric parameterisation - we should create a feature that highlights the current parameter setting of each metric - so to identify potential typos etc.

Could be a simple feature that prints the values of metrics' argument at metric initialisation, suggestively:

- create a "disable_parameter_printing" function that checks for deviation of default values

Completed in #124
Repository: understandable-machine-intelligence-lab/Quantus
Issue: New tutorial: for how to use Quantus with 1D shapes
GitHub labels: enhancement

- Make a tutorial for how to use Quantus with 1D shapes
- Reference PR: https://github.com/understandable-machine-intelligence-lab/Quantus/pull/74 

using suggestively https://github.com/greydanus/mnist1d ?

Solved.
Repository: understandable-machine-intelligence-lab/Quantus
Issue: Include softmax_act in model.predict in params of metrics
Root cause: Unimplemented Feature Gap

Allow the user to specify `softmax_act` to `True` or `False` (for softmax or logit application) that is used in `model.predict` by adding it to `kwargs` of all the metrics

Fixed here @https://github.com/understandable-machine-intelligence-lab/Quantus/pull/102 thanks @Wickstrom 

Fixed here @https://github.com/understandable-machine-intelligence-lab/Quantus/pull/102 thanks @Wickstrom