Variational quantum classifier#
Trains a
VQCClassifieron a synthetic dataset, on thetorchbackend.Then
VQCRegressor, the same circuit read as a value.
1. Data#
make_classification, 200 samples, 4 features, 2 classes.normalize="minmax"is fit on the train split only.AngleEmbeddingprescaling maps it to [0, pi] duringsetup().
[9]:
import numpy as np
from sklearn.datasets import make_classification
X, y = make_classification(
n_samples=200,
n_features=4,
n_informative=4,
n_redundant=0,
n_classes=2,
random_state=42,
)
[10]:
from pyqit import DataModule, set_backend
set_backend("torch")
dm = DataModule(
X=X,
y=y,
normalize="minmax",
batch_size=16,
split=(0.7, 0.15, 0.15),
seed=42,
)
2. Model and training#
4 qubits, 3 layers,
SELAnsatz,AngleEmbedding.15 epochs at lr 0.05.
fitreturns aTrainingHistory.
[11]:
from pyqit import Trainer
from pyqit.ansatzes import SELAnsatz
from pyqit.core import AngleEmbedding
from pyqit.models import VQCClassifier
# Initialize the VQC
model = VQCClassifier(
n_qubits=4,
n_layers=3,
n_classes=2,
ansatz=SELAnsatz,
encoder=AngleEmbedding,
)
# Set up the Trainer
trainer = Trainer(max_epochs=15, learning_rate=0.05)
history = trainer.fit(model, datamodule=dm)
Parameter Value Model Name VQCClassifier Backend Torch Qubits 4 Ansatz SELAnsatz Encoder AngleEmbedding Trainable Params 36 Device default.qubit Diff Method backprop Optimizer ADAM Learning Rate 0.05 Train / Val Samples 140 / 30
GPU available: True (cuda), used: False
TPU available: False, using: 0 TPU cores
/home/aryan/PyQit/.venv/lib/python3.12/site-packages/lightning/pytorch/trainer/setup.py:175: GPU available but not used. You can set it by doing `Trainer(accelerator='gpu')`.
💡 Tip: For seamless cloud logging and experiment tracking, try installing [litlogger](https://pypi.org/project/litlogger/) to enable LitLogger, which logs metrics and artifacts automatically to the Lightning Experiments platform.
`Trainer(limit_val_batches=1.0)` was configured so 100% of the batches will be used..
/home/aryan/PyQit/.venv/lib/python3.12/site-packages/lightning/pytorch/utilities/_pytree.py:21: `isinstance(treespec, LeafSpec)` is deprecated, use `isinstance(treespec, TreeSpec) and treespec.is_leaf()` instead.
/home/aryan/PyQit/.venv/lib/python3.12/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:434: The 'val_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=15` in the `DataLoader` to improve performance.
/home/aryan/PyQit/.venv/lib/python3.12/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:434: The 'train_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=15` in the `DataLoader` to improve performance.
`Trainer.fit` stopped: `max_epochs=15` reached.
[Trainer] Training complete.
3. Loss curve#
history.as_dict()returns the per-epoch metrics.
[12]:
import matplotlib.pyplot as plt
# Extract metrics from the history
train_loss = history.as_dict()["train_loss"]
val_loss = history.as_dict()["val_loss"]
epochs = range(1, len(train_loss) + 1)
plt.figure(figsize=(8, 5))
plt.plot(epochs, train_loss, label="Train Loss", marker="o")
plt.plot(epochs, val_loss, label="Validation Loss", marker="o")
plt.title("VQC Training History")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()
plt.grid(True)
plt.show()
4. Evaluation#
predictruns on the test split.return_format="numpy"forces numpy output on the torch backend.
[13]:
from sklearn.metrics import accuracy_score, confusion_matrix
# Predict
predictions = trainer.predict(model, datamodule=dm, return_format="numpy")
actuals = dm.y_test.astype(int)
# Calculate Accuracy
acc = accuracy_score(actuals, predictions)
print(f"Standalone VQC Test Accuracy: {acc * 100:.2f}%")
# Plot Confusion Matrix
cm = confusion_matrix(actuals, predictions)
plt.figure(figsize=(5, 4))
plt.imshow(cm)
plt.title("Standalone VQC Confusion Matrix")
plt.xlabel("Predicted Label")
plt.ylabel("True Label")
for i in range(cm.shape[0]):
for j in range(cm.shape[1]):
plt.text(j, i, cm[i, j], ha="center", va="center")
plt.xticks(np.arange(cm.shape[1]))
plt.yticks(np.arange(cm.shape[0]))
plt.colorbar()
plt.tight_layout()
plt.show()
Standalone VQC Test Accuracy: 83.33%
Variational quantum regressor#
VQCRegressorreads the same circuit as one value: the parity<Z...Z>in [-1, 1], then a trainedscale * <Z> + offset.The default
loss_fn="mse"applies. Accuracy is recorded as NaN for a regressor.Target:
sin(pi * x)on one feature.minmaxandAngleEmbeddingprescaling map x to [0, pi].
[ ]:
from pyqit.models import VQCRegressor
X_r = np.linspace(-1, 1, 80).reshape(-1, 1)
y_r = np.sin(np.pi * X_r).ravel()
dm_r = DataModule(
X=X_r, y=y_r, normalize="minmax", batch_size=16, split=(0.7, 0.15, 0.15), seed=42
)
regressor = VQCRegressor(n_qubits=2, n_layers=3)
trainer_r = Trainer(max_epochs=30, learning_rate=0.05)
history_r = trainer_r.fit(regressor, datamodule=dm_r)
predictreturns one value per row, no thresholding.dm_r.X_testis the prescaled input, so the x axis is in [0, pi].
[ ]:
preds_r = trainer_r.predict(regressor, datamodule=dm_r, return_format="numpy")
print(f"Test MSE: {np.mean((preds_r - dm_r.y_test) ** 2):.4f}")
order = np.argsort(dm_r.X_test[:, 0])
plt.plot(dm_r.X_test[order, 0], dm_r.y_test[order], "o", label="target")
plt.plot(dm_r.X_test[order, 0], preds_r[order], "x", label="prediction")
plt.xlabel("x (prescaled)")
plt.ylabel("y")
plt.legend()
plt.show()