Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix/halving search #210

Merged
merged 27 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ba33451
reduce grid search
gcattan Nov 17, 2023
6e9ec01
reduce search, add random_state
gcattan Nov 17, 2023
8268702
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 17, 2023
c644a09
reduce again space search
gcattan Nov 18, 2023
c6a9a06
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 18, 2023
c62c2b2
remove `min_ressources=smallest`
gcattan Nov 18, 2023
f89ef57
switch back to gridsearchcv
gcattan Nov 18, 2023
804a4ff
debug string
gcattan Nov 19, 2023
3f4b22a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 19, 2023
4ccdd4f
debug -> we need the example to finish so we can see the debug trace
gcattan Nov 19, 2023
1e9f30b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 19, 2023
b804733
- feed best estimator for CI
gcattan Nov 19, 2023
aea41a1
remove try catch
gcattan Nov 19, 2023
92a8a02
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 19, 2023
c266520
add debug strings (again)
gcattan Nov 20, 2023
ad31eff
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 20, 2023
65884ca
add random_seed for quantum
gcattan Nov 20, 2023
be91722
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 20, 2023
6c3d7ff
decrease threshold
gcattan Nov 20, 2023
35fd03d
update version of qiskit
gcattan Nov 20, 2023
16c3cea
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 20, 2023
15cf23f
typo
gcattan Nov 20, 2023
bd39100
upgrade to qiskit 0.45.0
gcattan Nov 20, 2023
caaf47b
downgrade qiskit_aer (perf pb with local windows)
gcattan Nov 20, 2023
f96bf81
add random_state to random forest
gcattan Nov 20, 2023
123dbbd
Update doc/installing.rst
gcattan Nov 21, 2023
e9eff4c
correct case of repo name
qbarthelemy Nov 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 31 additions & 23 deletions doc/installing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,52 @@
Installing pyRiemann-qiskit
===========================

There is no yet stable version of pyRiemann-qiskit.
_We recommend the use of [Anaconda](https://www.anaconda.com/) to manage python
environements._

Therefore, it is recommanded to clone the source code on `github <https://github.com/pyRiemann/pyRiemann-qiskit>`__ and install directly the package from source.
`pyRiemann-qiskit` currently supports Windows, Mac and Linux OS with Python 3.9 - 3.11.

``pip install -e .``
You can install `pyRiemann-qiskit` release from PyPI:

The install script will install the required dependencies. If you want also to build the documentation and to run the test locally, you could install all development dependencies with
```
pip install pyriemann-qiskit
```

``pip install -e .[docs,tests]``
The development version can be installed by cloning this repository and installing the
package on your local machine using the `setup.py` script:

If you use a zsh shell, you need to write `pip install -e .\[docs,tests\]`. If you do not know what zsh is, you could use the above command.
```
python setup.py develop
```

You may check that the package was correctly installed by starting a python shell and writing:
Or directly pip:

``import pyriemann_qiskit``
```
pip install .
```

Note that the steps above need to be re-executed in your local environment after any
changes inside your local copy of the `pyriemann_qiskit` folder, including pulling from
remote.

To check the installation, open a python shell and type:

```
import pyriemann_qiskit
```

Dependencies
~~~~~~~~~~~~

- Python (>= 3.6)
- Python (>= 3.9)

Mandatory dependencies
^^^^^^^^^^^^^^^^^^^^^^

- `cython <https://cython.org/>`__

- `pyriemann <https://github.com/pyRiemann/pyRiemann-qiskit>`__

- `qiskit==0.20.0 <https://qiskit.org/>`__

- `cvxpy=1.1.12 <https://www.cvxpy.org/>`__

Recommended dependencies
^^^^^^^^^^^^^^^^^^^^^^^^
These dependencies are recommanded to use the plotting functions of pyriemann or to run examples and tutorials, but they are not mandatory:
The project relies mainly on:

- `matplotlib>=2.2 <https://matplotlib.org/>`__
- `pyRiemann==0.5.0 <https://github.com/pyRiemann/pyRiemann-qiskit>`
gcattan marked this conversation as resolved.
Show resolved Hide resolved

- `mne-python <http://mne-tools.github.io/>`__
- `qiskit==0.45.0 <https://qiskit.org/>`__

- `seaborn <https://seaborn.pydata.org>`__
Other dependencies can be checked in the `setup.py` file.
2 changes: 1 addition & 1 deletion doc/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ cvxpy==1.4.1
qiskit_machine_learning==0.6.1
qiskit-ibm-provider==0.7.2
qiskit-optimization==0.5.0
qiskit-aer==0.13.0
qiskit-aer==0.12.2
scipy==1.11.3
moabb>=1.0.0
pyriemann==0.5
Expand Down
53 changes: 35 additions & 18 deletions examples/other_datasets/plot_financial_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

In this example, we will use RG to identify whether or no a fraud is a probable
collusion.
Because this method work on a small number of components, it is also compatible
Because this method works on a small number of components, it is also compatible
with quantum computing.
"""
# Authors: Gregoire Cattan, Filipe Barroso
Expand All @@ -48,6 +48,7 @@
import warnings
import pandas as pd
import numpy as np
import os

print(__doc__)

Expand Down Expand Up @@ -278,7 +279,7 @@ def transform(self, X):


# Create a RandomForest for baseline comparison of direct classification:
rf = RandomForestClassifier()
rf = RandomForestClassifier(random_state=42)

# Classical pipeline: puts together transformers,
# then adds at the end a classical SVM
Expand All @@ -291,23 +292,37 @@ def transform(self, X):
SVC(probability=True),
)

if os.getenv("CI") == "true":
print("Feeding a good estimator for CI (skipping grid search)")
param_grid: dict = {
"toepochs__n": [30],
"xdawncovariances__nfilter": [1],
"optionalwhitening__process": [True],
"optionalwhitening__n_components": [4],
"slimvector__keep_diagonal": [True],
"svc__C": [1],
"svc__gamma": ["auto"],
}
else:
param_grid: dict = {
"toepochs__n": [20, 30],
"xdawncovariances__nfilter": [1, 2],
"optionalwhitening__process": [True, False],
"optionalwhitening__n_components": [2, 4],
"slimvector__keep_diagonal": [True, False],
"svc__C": [0.1, 1],
"svc__gamma": ["auto", "scale"],
}

# Optimize the pipeline:
# let's save some time and run the optimization with the classical SVM
gs = HalvingGridSearchCV(
pipe,
param_grid={
"toepochs__n": [10, 20, 30],
"xdawncovariances__nfilter": [1, 2, 3],
"optionalwhitening__process": [True, False],
"optionalwhitening__n_components": [2, 4, 6],
"slimvector__keep_diagonal": [True, False],
"svc__C": [0.1, 1, 10, 100],
"svc__gamma": ["auto", "scale", 1, 10],
},
param_grid=param_grid,
scoring="balanced_accuracy",
cv=4,
min_resources="smallest",
verbose=1,
random_state=0,
)


Expand All @@ -324,12 +339,14 @@ def transform(self, X):
# So `NearMiss` we choose the closest non-fraud epochs to the fraud-epochs.
# Here we will keep a ratio of 2 non-fraud epochs for 1 fraud epochs.
# Note: at this stage `features` also contains the `index` column.
X, y = NearMiss(sampling_strategy=0.5).fit_resample(

# Possibly avoids tie-break situations
np.random.seed(42)

X, y = NearMiss(sampling_strategy=0.5, n_jobs=-1, n_neighbors=3).fit_resample(
features.to_numpy(), target.to_numpy()
)
# X, y = EditedNearestNeighbours().fit_resample(features.to_numpy(), target.to_numpy())
# X = features.to_numpy()
# y = target.to_numpy()

X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
Expand Down Expand Up @@ -377,7 +394,7 @@ def transform(self, X):
# for the quantum SVM as for the classical one.
gs.best_estimator_.steps[-1] = (
"quanticsvm",
QuanticSVM(quantum=True, C=best_C, gamma=best_gamma),
QuanticSVM(quantum=True, C=best_C, gamma=best_gamma, seed=42),
)
train_pred_qsvm = gs.best_estimator_.fit(X_train, y_train).predict(X_train)
train_score_qsvm = balanced_accuracy_score(y_train, train_pred_qsvm)
Expand Down Expand Up @@ -426,7 +443,7 @@ def transform(self, X):


class ERP_CollusionClassifier(ClassifierMixin):
def __init__(self, row_clf, erp_clf, threshold=0.7):
def __init__(self, row_clf, erp_clf, threshold=0.5):
self.row_clf = row_clf
self.erp_clf = erp_clf
self.threshold = threshold
Expand Down
50 changes: 34 additions & 16 deletions pyriemann_qiskit/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
NaiveQAOAOptimizer,
set_global_optimizer,
)
from qiskit.utils import QuantumInstance, algorithm_globals
from qiskit.utils import QuantumInstance
from qiskit.utils.quantum_instance import logger
from qiskit_ibm_provider import IBMProvider, least_busy
from qiskit_machine_learning.algorithms import QSVC, VQC, PegasosQSVC
Expand Down Expand Up @@ -62,12 +62,16 @@ class QuanticClassifierBase(BaseEstimator, ClassifierMixin):
gen_feature_map : Callable[int, QuantumCircuit | FeatureMap] \
(default : Callable[int, ZZFeatureMap])
Function generating a feature map to encode data into a quantum state.
seed: int | None (default: None)
Random seed for the simulation

Notes
-----
.. versionadded:: 0.0.1
.. versionchanged:: 0.1.0
Added support for multi-class classification.
.. versionchanged:: 0.2.0
Add seed parameter

Attributes
----------
Expand Down Expand Up @@ -95,20 +99,20 @@ def __init__(
verbose=True,
shots=1024,
gen_feature_map=gen_zz_feature_map(),
seed=None,
):
self.verbose = verbose
self._log("Initializing Quantum Classifier")
self.q_account_token = q_account_token
self.quantum = quantum
self.shots = shots
self.seed = datetime.now().microsecond if seed is None else seed
self.gen_feature_map = gen_feature_map
# protected field for child classes
self._training_input = {}

def _init_quantum(self):
if self.quantum:
algorithm_globals.random_seed = datetime.now().microsecond
self._log("seed = ", algorithm_globals.random_seed)
if self.q_account_token:
self._log("Real quantum computation will be performed")
if not self.q_account_token == "load_account":
Expand Down Expand Up @@ -186,14 +190,13 @@ def fit(self, X, y):
except Exception:
self._log("Devices are all busy. Getting the first one...")
self._backend = devices[0]
self._log("Quantum backend = ", self._backend)
seed_sim = algorithm_globals.random_seed
seed_trs = algorithm_globals.random_seed
self._log("Quantum backend = ", self._backend)
self._log("seed = ", self.seed)
self._quantum_instance = QuantumInstance(
self._backend,
shots=self.shots,
seed_simulator=seed_sim,
seed_transpiler=seed_trs,
seed_simulator=self.seed,
seed_transpiler=self.seed,
)
self._classifier = self._init_algo(n_features)
self._train(X, y)
Expand Down Expand Up @@ -248,9 +251,11 @@ class QuanticSVM(QuanticClassifierBase):
-----
.. versionadded:: 0.0.1
.. versionchanged:: 0.0.2
Qiskit's Pegasos implementation [4]_, [5]_.
Qiskit's Pegasos implementation [4]_, [5]_.
.. versionchanged:: 0.1.0
Fix: copy estimator not keeping base class parameters.
Fix: copy estimator not keeping base class parameters.
.. versionchanged:: 0.2.0
Add seed parameter

Parameters
----------
Expand Down Expand Up @@ -285,6 +290,8 @@ class QuanticSVM(QuanticClassifierBase):
gen_feature_map : Callable[int, QuantumCircuit | FeatureMap] \
(default : Callable[int, ZZFeatureMap])
Function generating a feature map to encode data into a quantum state.
seed: int | None (default: None)
Random seed for the simulation

See Also
--------
Expand Down Expand Up @@ -324,9 +331,10 @@ def __init__(
verbose=True,
shots=1024,
gen_feature_map=gen_zz_feature_map(),
seed=None,
):
QuanticClassifierBase.__init__(
self, quantum, q_account_token, verbose, shots, gen_feature_map
self, quantum, q_account_token, verbose, shots, gen_feature_map, seed
)
self.gamma = gamma
self.C = C
Expand Down Expand Up @@ -435,13 +443,17 @@ class QuanticVQC(QuanticClassifierBase):
gen_feature_map : Callable[int, QuantumCircuit | FeatureMap] \
(default : Callable[int, ZZFeatureMap])
Function generating a feature map to encode data into a quantum state.
seed: int | None (default: None)
Random seed for the simulation

Notes
-----
.. versionadded:: 0.0.1
.. versionchanged:: 0.1.0
Fix: copy estimator not keeping base class parameters.
Added support for multi-class classification.
Fix: copy estimator not keeping base class parameters.
Added support for multi-class classification.
.. versionchanged:: 0.2.0
Add seed parameter

See Also
--------
Expand Down Expand Up @@ -477,14 +489,15 @@ def __init__(
verbose=True,
shots=1024,
gen_feature_map=gen_zz_feature_map(),
seed=None,
):
if quantum is False:
raise ValueError(
"VQC can only run on a quantum \
computer or simulator."
)
QuanticClassifierBase.__init__(
self, quantum, q_account_token, verbose, shots, gen_feature_map
self, quantum, q_account_token, verbose, shots, gen_feature_map, seed
)
self.optimizer = optimizer
self.gen_var_form = gen_var_form
Expand Down Expand Up @@ -568,7 +581,9 @@ class QuanticMDM(QuanticClassifierBase):
-----
.. versionadded:: 0.0.4
.. versionchanged:: 0.1.0
Fix: copy estimator not keeping base class parameters.
Fix: copy estimator not keeping base class parameters.
.. versionchanged:: 0.2.0
Add seed parameter

Parameters
----------
Expand Down Expand Up @@ -598,6 +613,8 @@ class QuanticMDM(QuanticClassifierBase):
gen_feature_map : Callable[int, QuantumCircuit | FeatureMap] \
(default : Callable[int, ZZFeatureMap])
Function generating a feature map to encode data into a quantum state.
seed: int | None (default: None)
Random seed for the simulation

See Also
--------
Expand Down Expand Up @@ -626,9 +643,10 @@ def __init__(
verbose=True,
shots=1024,
gen_feature_map=gen_zz_feature_map(),
seed=None,
):
QuanticClassifierBase.__init__(
self, quantum, q_account_token, verbose, shots, gen_feature_map
self, quantum, q_account_token, verbose, shots, gen_feature_map, seed
)
self.metric = metric

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ git+https://github.com/pyRiemann/pyRiemann#egg=pyriemann
qiskit_machine_learning==0.6.1
qiskit-ibm-provider==0.7.2
qiskit-optimization==0.5.0
qiskit-aer==0.13.0
qiskit-aer==0.12.2
cvxpy==1.4.1
scipy==1.11.3
docplex>=2.21.207
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@
'numpy<1.27',
'cython',
'pyriemann==0.5',
'qiskit==0.45.0',
'qiskit_machine_learning==0.6.1',
'qiskit-ibm-provider==0.7.2',
'qiskit-optimization==0.5.0',
'qiskit-aer==0.13.0',
'qiskit-aer==0.12.2',
'cvxpy==1.4.1',
'scipy==1.11.3',
'docplex>=2.21.207',
Expand Down