Skip to content

Commit

Permalink
Qiskit wrapper (#2)
Browse files Browse the repository at this point in the history
* Quantum classification and example

* add test_classification.py

* flake8

* Revert "remove tests"

This reverts commit d4317c3.

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update tests/test_classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* lighten asserts

* Remove hardcoded values and use explicit names

* Refactor names to be more explicit

* shorten assert using numpy shape function

* Code lisibility (extracting and renaming of const)

* Prefix private method with `_`

* add naming convention for private/public field

* #2 (comment)

* Move quantum init to fit

* add test for sklearn pipeline (get_set params)

* Appli sklearn pattern

* flake8

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Add reference to QSVM and VQC

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* clean up attributes section

* Rename QuanticBase -> QuanticClassifierBase

* Add documentation to public methods

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* low case convention for variable

* - add README in example
- add classification in __init__

* add quantum before q_account_token

* - Use np.atleast_2d for better concision
-  Complete splitTargetAndNonTarget test with test of already vectorized inputs
Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* use `ndarray shape (n_trials,)` instead of `ndarray shape (n_trials, 1)`

* Complete documentation on raw and vectorized matrices

* extract test_per parameter

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update tests/test_classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* complete tests with 2d matrices

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* refactor target -> labels WIP

* rename xta, xnt -> x_class1, x_class0

* leftover target -> labels

* Remove support for 3d matrices

* flake8

* use stratify in self_calibration, to avoid situation where the training/testing sets contains only one classes (may happens when covset length is low)

* flake8

* flake8
push base example with toy sets.

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* - Change example sublevel repository
- move reference to Qiskit in mother class

* remove labels

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* clean leftovers after labels refactoring

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* refactor _split_classes

* rename all vect*

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* rename n_trials ->n_sample and n_channels**2 -> n_features

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Leftover in testing workflow

* flake8

* Update tests/test_classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update examples/ERP/README.txt

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update examples/ERP/plot_classify_EEG_quantum.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update tests/test_classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update tests/test_classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* add readme in toys_dataset

* revert score_test

* Update tests/test_classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* cvxpy workaround for pot_classifier_comparison.py

* cvxpy workaround

* complete readme

* add header

* apply reviewer's suggestion to test and score

* remove _process_vector
update quantum example

* flake8

* Update examples/toys_dataset/README.txt

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update examples/toys_dataset/plot_classifier_comparison.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update examples/toys_dataset/plot_classifier_comparison.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update examples/toys_dataset/plot_classifier_comparison.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update examples/ERP/plot_classify_EEG_quantum.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* remove feature_dim tags

* Update tests/test_classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* rename test in lower case
clean parameters inside QuanticVQC

* get_feats

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* flake8

* #4

* clean comments and remove references to covariance matrices

* Update example QSVM vs SVC

* fix bug (disp not definied)

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* remove useless line

* Refactoring of fit/score/predict/.
Removing "run" methods and calling underlying methods.

* update of example (WIP)

* fix predict_proba

* improve image size

* remove errors

* Update examples/toys_dataset/plot_classifier_comparison.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* flake8

* Simple downsampling after projection to tangentspace inspired by electrode selection

* remove unused comment

* revert TgDown

* Add quantum drawbacks

* Clean quantum example

* Update examples/ERP/plot_classify_EEG_quantum.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update examples/ERP/plot_classify_EEG_quantum.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update examples/ERP/plot_classify_EEG_quantum.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* delete test_input

* fix bug: labels should be only 0 or 1

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* #2 (comment)

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update examples/ERP/plot_classify_EEG_quantum.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* change SVC hyperparameters for rbf

* flake8

* Update pyriemann_qiskit/classification.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* flake8

Co-authored-by: gcattan <gregoire.cattan@ibm.com>
Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>
  • Loading branch information
3 people authored Nov 16, 2021
1 parent a6107f8 commit cbe99f6
Show file tree
Hide file tree
Showing 13 changed files with 912 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
python -m pip install .[tests]
- name: Lint with flake8
run: |
flake8 examples tests pyriemann
flake8 examples tests pyriemann_qiskit
- name: Test with pytest
run: |
pytest
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ classification with riemanian geometry. A use case would be to use vectorized
covariance matrices in the TangentSpace as an input for these classifiers,
enabling a possible sandbox for researchers and engineers in the field.

## Quantum drawbacks

- Limitation of the feature dimension

The number of qubits (and therefore the feature dimension) is limited to:
- 24 on a local quantum simulator, and up to:
- 5000 on a remote quantum simulator;
- 5 on free real quantum computers, and up to:
- 65 on exploratory quantum computers (not available for public use).

- Time complexity

A higher number of trials or dimension increases time to completion of the quantum algorithm, especially when running on a local machine. This is why the number of trials is limited in the examples we provided. However, you should avoid such practices in your own analysis.

Although these aspects are less important in a remote backend, it may happen that the quantum algorithm is queued depending on the number of concurrent users.

For all these aspects, the use of pyRiemann-qiskit should be limited to offline analysis only.

## References

[1] A. Blance and M. Spannowsky,
Expand Down
15 changes: 14 additions & 1 deletion doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,17 @@

=============
API reference
=============
=============

Classification
--------------
.. _classification_api:
.. currentmodule:: pyriemann_qiskit.classification

.. autosummary::
:toctree: generated/
:template: class.rst

QuanticClassifierBase
QuanticSVM
QuanticVQC
24 changes: 24 additions & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,30 @@
pyRiemann-qiskit: Qiskit wrapper for pyRiemann
=============================================================

.. raw:: html

<div style="clear: both"></div>
<div class="container-fluid hidden-xs hidden-sm">
<div class="row">
<a href="auto_examples/ERP/plot_classify_EEG_quantum.html">
<div class="col-md-3 thumbnail">
<img src="_images/sphx_glr_plot_single_thumb.png">
</div>
</a>
<a href="auto_examples/toys_dataset/plot_classifier_comparison.html">
<div class="col-md-3 thumbnail">
<img src="_images/sphx_glr_plot_classify_MEG_mdm_thumb.png">
</div>
</a>
</div>
</div>

<br>

<div class="container-fluid">
<div class="row">
<div class="col-md-9">

pyRiemann-qiskit is a Qiskit wrapper around pyRiemann.
It allows to use quantum classification with Riemannian geometry.
pyRiemann-qiskit provides through Qiskit:
Expand Down
22 changes: 22 additions & 0 deletions doc/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@ classification with riemanian geometry. A use case would be to use vectorized
covariance matrices in the TangentSpace as an input for these classifiers,
enabling a possible sandbox for researchers and engineers in the field.

Quantum drawbacks
================================

- Limitation of the feature dimension

The number of qubits (and therefore the feature dimension) is limited to:
- 24 on a local quantum simulator, and up to:
- 5000 on a remote quantum simulator;
- 5 on free real quantum computers, and up to:
- 65 on exploratory quantum computers (not available for public use).

- Time complexity

A higher number of trials or dimension increases time to completion of the quantum algorithm, especially when running on a local machine. This is why the number of trials is limited in the examples we provided. However, you should avoid such practices in your own analysis.

Although these aspects are less important in a remote backend, it may happen that the quantum algorithm is queued depending on the number of concurrent users.

For all these aspects, the use of pyRiemann-qiskit should be limited to offline analysis only.

References
================================

[1] A. Blance and M. Spannowsky,
‘Quantum machine learning for particle physics using a variational quantum classifier’,
J. High Energ. Phys., vol. 2021, no. 2, p. 212, Feb. 2021,
Expand Down
4 changes: 4 additions & 0 deletions examples/ERP/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Classification of ERP
---------------------

Event related potential classification with quantum algorithm and RG.
138 changes: 138 additions & 0 deletions examples/ERP/plot_classify_EEG_quantum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
"""
====================================================================
ERP EEG decoding with Quantum Classifier.
====================================================================
Decoding applied to EEG data in sensor space using RG.
Xdawn spatial filtering is applied on covariances matrices, which are
then projected in the tangent space and classified with a quantum SVM
classifier. It is compared to the classical SVM on binary classification.
"""
# Author: Gregoire Cattan
# Modified from plot_classify_EEG_tangentspace.py of pyRiemann
# License: BSD (3-clause)

from pyriemann.estimation import XdawnCovariances
from pyriemann.tangentspace import TangentSpace
from pyriemann_qiskit.classification import QuanticSVM
from mne import io, read_events, pick_types, Epochs
from mne.datasets import sample
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import train_test_split
from sklearn.metrics import (confusion_matrix, ConfusionMatrixDisplay,
balanced_accuracy_score)
from sklearn.base import TransformerMixin
from matplotlib import pyplot as plt

# cvxpy is not correctly imported due to wheel not building
# in the doc pipeline
__cvxpy__ = True
try:
import cvxpy
del cvxpy
except Exception:
__cvxpy__ = False

print(__doc__)

data_path = sample.data_path()

###############################################################################
# Set parameters and read data
raw_fname = data_path + "/MEG/sample/sample_audvis_filt-0-40_raw.fif"
event_fname = data_path + "/MEG/sample/sample_audvis_filt-0-40_raw-eve.fif"
tmin, tmax = -0.0, 1
event_id = dict(vis_l=3, vis_r=4) # select only two classes

# Setup for reading the raw data
raw = io.Raw(raw_fname, preload=True, verbose=False)
raw.filter(2, None, method="iir") # replace baselining with high-pass
events = read_events(event_fname)

raw.info["bads"] = ["MEG 2443"] # set bad channels
picks = pick_types(
raw.info, meg=False, eeg=True, stim=False, eog=False, exclude="bads"
)

# Read epochs
epochs = Epochs(
raw,
events,
event_id,
tmin,
tmax,
proj=False,
picks=picks,
baseline=None,
preload=True,
verbose=False,
)

X = epochs.get_data()
y = epochs.events[:, -1]

# ...skipping the KFold validation parts (for the purpose of the test only)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=1)

###############################################################################
# Decoding in tangent space with a quantum classifier

# Time complexity of quantum algorithm depends on the number of trials and
# the number of elements inside the covariance matrices
# Thus we reduce elements number by using restrictive spatial filtering
sf = XdawnCovariances(nfilter=1)

# Projecting correlation matrices into the tangent space
# as quantum algorithms take vectors as inputs
# (If not, then matrices will be inlined inside the quantum classifier)
tg = TangentSpace()


# ...and dividing the number of remaining elements by two
class NaiveDimRed(TransformerMixin):
def fit(self, X, y=None):
return self

def transform(self, X, y=None):
return X[:, ::2]


# https://stackoverflow.com/questions/61825227/plotting-multiple-confusion-matrix-side-by-side
f, axes = plt.subplots(1, 2, sharey='row')

disp = None

# Results will be computed for QuanticSVM versus SKLearnSVM for comparison
for quantum in [True, False]:
# This is a hack for the documentation pipeline
if(not __cvxpy__):
continue

qsvm = QuanticSVM(verbose=True, quantum=quantum)
clf = make_pipeline(sf, tg, NaiveDimRed(), qsvm)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)

# Printing the results
acc = balanced_accuracy_score(y_pred, y_test)
acc_str = "%0.2f" % acc

names = ["vis left", "vis right"]
title = ("Quantum (" if quantum else "Classical (") + acc_str + ")"
axe = axes[0 if quantum else 1]
cm = confusion_matrix(y_pred, y_test)
disp = ConfusionMatrixDisplay(cm, display_labels=names)
disp.plot(ax=axe, xticks_rotation=45)
disp.ax_.set_title(title)
disp.im_.colorbar.remove()
disp.ax_.set_xlabel('')
if not quantum:
disp.ax_.set_ylabel('')

if disp:
f.text(0.4, 0.1, 'Predicted label', ha='left')
plt.subplots_adjust(wspace=0.40, hspace=0.1)
f.colorbar(disp.im_, ax=axes)
plt.show()
4 changes: 4 additions & 0 deletions examples/toys_dataset/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Comparison with toys datasets
-----------------------------

Comparison of classification using quantum versus classical SVM classifiers on toys datasets.
Loading

0 comments on commit cbe99f6

Please sign in to comment.