Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Commit

Permalink
QSVM L2 Reg. introduction for convergence and over-fitting issue (#1378)
Browse files Browse the repository at this point in the history
* First update on qp_solver with L2

* Update test for lambda2

* Add reno

Co-authored-by: woodsp <[email protected]>
Co-authored-by: Steve Wood <[email protected]>
  • Loading branch information
3 people authored Oct 23, 2020
1 parent 8957a61 commit 739e330
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 8 deletions.
3 changes: 2 additions & 1 deletion qiskit/aqua/algorithms/classifiers/qsvm/_qsvm_binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ def train(self, data, labels):
"""
scaling = 1.0 if self._qalgo.quantum_instance.is_statevector else None
kernel_matrix = self._qalgo.construct_kernel_matrix(data)
lambda2 = self._qalgo.lambda2
labels = labels * 2 - 1 # map label from 0 --> -1 and 1 --> 1
labels = labels.astype(np.float)
[alpha, b, support] = optimize_svm(kernel_matrix, labels, scaling=scaling)
[alpha, b, support] = optimize_svm(kernel_matrix, labels, scaling=scaling, lambda2=lambda2)
support_index = np.where(support)
alphas = alpha[support_index]
svms = data[support_index]
Expand Down
3 changes: 3 additions & 0 deletions qiskit/aqua/algorithms/classifiers/qsvm/qsvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def __init__(self, feature_map: Union[QuantumCircuit, FeatureMap],
test_dataset: Optional[Dict[str, np.ndarray]] = None,
datapoints: Optional[np.ndarray] = None,
multiclass_extension: Optional[MulticlassExtension] = None,
lambda2: float = 0.001,
quantum_instance: Optional[
Union[QuantumInstance, BaseBackend, Backend]] = None) -> None:
"""
Expand All @@ -90,6 +91,7 @@ def __init__(self, feature_map: Union[QuantumCircuit, FeatureMap],
datapoints: Prediction dataset.
multiclass_extension: If number of classes is greater than 2 then a multiclass scheme
must be supplied, in the form of a multiclass extension.
lambda2: L2 norm regularization factor
quantum_instance: Quantum Instance or Backend
Raises:
Expand Down Expand Up @@ -118,6 +120,7 @@ def __init__(self, feature_map: Union[QuantumCircuit, FeatureMap],
self.setup_training_data(training_dataset)
self.setup_test_data(test_dataset)
self.setup_datapoint(datapoints)
self.lambda2 = lambda2

self.feature_map = feature_map
self.num_qubits = self.feature_map.num_qubits
Expand Down
7 changes: 5 additions & 2 deletions qiskit/aqua/utils/qp_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def optimize_svm(kernel_matrix: np.ndarray,
scaling: Optional[float] = None,
maxiter: int = 500,
show_progress: bool = False,
max_iters: Optional[int] = None) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
max_iters: Optional[int] = None,
lambda2: float = 0.001) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""
Solving quadratic programming problem for SVM; thus, some constraints are fixed.
Expand All @@ -45,6 +46,7 @@ def optimize_svm(kernel_matrix: np.ndarray,
maxiter: number of iterations for QP solver
show_progress: showing the progress of QP solver
max_iters: Deprecated, use maxiter.
lambda2: L2 Norm regularization factor
Returns:
np.ndarray: Sx1 array, where S is the number of supports
Expand Down Expand Up @@ -81,12 +83,13 @@ def optimize_svm(kernel_matrix: np.ndarray,
P = np.array(H)
q = np.array(f)
G = -np.eye(n)
I = np.eye(n)
h = np.zeros(n)
A = y.reshape(y.T.shape)
b = np.zeros((1, 1))
x = cvxpy.Variable(n)
prob = cvxpy.Problem(
cvxpy.Minimize((1 / 2) * cvxpy.quad_form(x, P) + q.T@x),
cvxpy.Minimize((1 / 2) * cvxpy.quad_form(x, P) + q.T@x + lambda2 * cvxpy.quad_form(x, I)),
[G@x <= h,
A@x == b])
prob.solve(verbose=show_progress, qcp=True)
Expand Down
7 changes: 7 additions & 0 deletions releasenotes/notes/QSVM-L2-Norm-3382893ecafee124.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
optimize_svm method of qp_solver would sometimes fail resulting in an error like this
`ValueError: cannot reshape array of size 1 into shape (200,1)` This addresses the issue
by adding an L2 norm parameter, lambda2, which defaults to 0.001 but can be changed via
the QSVM algorithm, as needed, to facilitate convergence.
10 changes: 5 additions & 5 deletions test/aqua/test_qsvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def test_binary(self, mode):
else:
data_preparation = self.data_preparation

svm = QSVM(data_preparation, self.training_data, self.testing_data, None)
svm = QSVM(data_preparation, self.training_data, self.testing_data, None, lambda2=0)

try:
result = svm.run(self.qasm_simulator)
Expand All @@ -104,7 +104,7 @@ def test_binary_directly_statevector(self):
Also tests saving and loading models."""
data_preparation = self.data_preparation
svm = QSVM(data_preparation, self.training_data, self.testing_data, None)
svm = QSVM(data_preparation, self.training_data, self.testing_data, None, lambda2=0)

file_path = self.get_resource_path('qsvm_test.npz')
try:
Expand Down Expand Up @@ -213,7 +213,7 @@ def test_multiclass(self, multiclass_extension):
data_preparation = self.data_preparation
try:
svm = QSVM(data_preparation, train_input, test_input, total_array,
multiclass_extension=method[multiclass_extension])
multiclass_extension=method[multiclass_extension], lambda2=0)
result = svm.run(self.qasm_simulator)
self.assertAlmostEqual(result['testing_accuracy'], accuracy[multiclass_extension],
places=4)
Expand Down Expand Up @@ -252,7 +252,7 @@ def test_matrix_psd(self):
seed_transpiler=seed)
kernel_matrix = QSVM.get_kernel_matrix(quantum_instance, feature_map=feature_map,
x1_vec=training_data, enforce_psd=False)
_ = optimize_svm(kernel_matrix, labels)
_ = optimize_svm(kernel_matrix, labels, lambda2=0)

# This time we enforce that the matrix be positive semi-definite which runs logic to
# make it so.
Expand All @@ -261,7 +261,7 @@ def test_matrix_psd(self):
seed_transpiler=seed)
kernel_matrix = QSVM.get_kernel_matrix(quantum_instance, feature_map=feature_map,
x1_vec=training_data, enforce_psd=True)
alpha, b, support = optimize_svm(kernel_matrix, labels)
alpha, b, support = optimize_svm(kernel_matrix, labels, lambda2=0)

expected_alpha = [0.855861781, 2.59807482, 0, 0.962959215,
1.08141696, 0.217172547, 0, 0,
Expand Down

0 comments on commit 739e330

Please sign in to comment.