टिप्पणी
यह पृष्ठ docs/tutorials/05_torch_connector.ipynb से उत्पन्न किया गया है।
टॉर्च कनेक्टर और संकर QNNs¶
यह ट्यूटोरियल Qiskit के TorchConnector
वर्ग का परिचय देता है, और दर्शाता है कि कैसे TorchConnector
Qiskit Machine Learning से PyTorch वर्कफ़्लो में किसी भी NeuralNetwork
के प्राकृतिक एकीकरण की अनुमति देता है। TorchConnector
एक Qiskit NeuralNetwork
लेता है और इसे एक PyTorch Module
के रूप में उपलब्ध कराता है। परिणामी मॉड्यूल को मूल रूप से PyTorch शास्त्रीय आर्किटेक्चर में शामिल किया जा सकता है और अतिरिक्त विचारों के बिना संयुक्त रूप से प्रशिक्षित किया जा सकता है, जिससे उपन्यास hybrid quantum-classical मशीन लर्निंग आर्किटेक्चर के विकास और परीक्षण को सक्षम किया जा सकता है।
विषय-सूची¶
भाग 1: सरल वर्गीकरण और प्रतिगमन
इस ट्यूटोरियल का पहला भाग दिखाता है कि कैसे PyTorch के स्वचालित विभेदन इंजन का उपयोग करके क्वांटम न्यूरल नेटवर्क को प्रशिक्षित किया जा सकता है (torch.autograd
, link) सरल वर्गीकरण और प्रतिगमन कार्यों के लिए।
-
PyTorch और
OpflowQNN
के साथ वर्गीकरणPyTorch और
OpflowQNN
के साथ वर्गीकरण
-
PyTorch और
OpflowQNN
के साथ प्रतिगमन
भाग 2: MNIST वर्गीकरण, हाइब्रिड QNNs
इस ट्यूटोरियल का दूसरा भाग बताता है कि हाइब्रिड क्वांटम-शास्त्रीय तरीके से MNIST डेटा को वर्गीकृत करने के लिए एक (क्वांटम) न्यूरलनेटवर्क
को लक्ष्य PyTorch वर्कफ़्लो (इस मामले में, एक विशिष्ट CNN आर्किटेक्चर) में कैसे एम्बेड किया जाए।
[1]:
# Necessary imports
import numpy as np
import matplotlib.pyplot as plt
from torch import Tensor
from torch.nn import Linear, CrossEntropyLoss, MSELoss
from torch.optim import LBFGS
from qiskit import Aer, QuantumCircuit
from qiskit.utils import QuantumInstance, algorithm_globals
from qiskit.opflow import AerPauliExpectation
from qiskit.circuit import Parameter
from qiskit.circuit.library import RealAmplitudes, ZZFeatureMap
from qiskit_machine_learning.neural_networks import CircuitQNN, TwoLayerQNN
from qiskit_machine_learning.connectors import TorchConnector
# Set seed for random generators
algorithm_globals.random_seed = 42
[2]:
# declare quantum instance
qi = QuantumInstance(Aer.get_backend("aer_simulator_statevector"))
भाग 1: सरल वर्गीकरण एवं प्रतिगमन¶
1. वर्गीकरण¶
सबसे पहले, हम दिखाते हैं कि कैसे TorchConnector
क्वांटम NeuralNetwork
को प्रशिक्षित करने की अनुमति देता है ताकि PyTorch के स्वचालित विभेदन इंजन का उपयोग करके वर्गीकरण कार्यों को हल किया जा सके। इसे स्पष्ट करने के लिए, हम बेतरतीब ढंग से उत्पन्न डेटासेट पर binary classification करेंगे।
[3]:
# Generate random dataset
# Select dataset dimension (num_inputs) and size (num_samples)
num_inputs = 2
num_samples = 20
# Generate random input coordinates (X) and binary labels (y)
X = 2 * algorithm_globals.random.random([num_samples, num_inputs]) - 1
y01 = 1 * (np.sum(X, axis=1) >= 0) # in { 0, 1}, y01 will be used for CircuitQNN example
y = 2 * y01 - 1 # in {-1, +1}, y will be used for OplowQNN example
# Convert to torch Tensors
X_ = Tensor(X)
y01_ = Tensor(y01).reshape(len(y)).long()
y_ = Tensor(y).reshape(len(y), 1)
# Plot dataset
for x, y_target in zip(X, y):
if y_target == 1:
plt.plot(x[0], x[1], "bo")
else:
plt.plot(x[0], x[1], "go")
plt.plot([-1, 1], [1, -1], "--", color="black")
plt.show()

A. PyTorch और OpflowQNN
के साथ वर्गीकरण¶
एक OpflowQNN
को PyTorch से जोड़ना अपेक्षाकृत सरल है। यहां हम इसे TwoLayerQNN
, OpflowQNN
का एक उप-मामला जो पिछले ट्यूटोरियल में पेश किया गया था, का उपयोग करते हुए स्पष्ट करते हैं।
[4]:
# Set up QNN
# Note: we are not providing them explicitly in this examples,
# but TwoLayerQNN requires a feature_map and ansatz to work.
# By default, these parameters are set to ZZFeatureMap
# and RealAmplitudes (respectively).
qnn1 = TwoLayerQNN(num_qubits=num_inputs, quantum_instance=qi)
print(qnn1.operator)
# Set up PyTorch module
# Note: If we don't explicitly declare the initial weights
# they are chosen uniformly at random from [-1, 1].
initial_weights = 0.1 * (2 * algorithm_globals.random.random(qnn1.num_weights) - 1)
model1 = TorchConnector(qnn1, initial_weights=initial_weights)
print("Initial weights: ", initial_weights)
ComposedOp([
OperatorMeasurement(1.0 * ZZ),
CircuitStateFn(
┌──────────────────────────┐»
q_0: ┤0 ├»
│ ZZFeatureMap(x[0],x[1]) │»
q_1: ┤1 ├»
└──────────────────────────┘»
« ┌──────────────────────────────────────────────────────────┐
«q_0: ┤0 ├
« │ RealAmplitudes(θ[0],θ[1],θ[2],θ[3],θ[4],θ[5],θ[6],θ[7]) │
«q_1: ┤1 ├
« └──────────────────────────────────────────────────────────┘
)
])
Initial weights: [-0.01256962 0.06653564 0.04005302 -0.03752667 0.06645196 0.06095287
-0.02250432 -0.04233438]
[5]:
# Test with a single input
model1(X_[0, :])
[5]:
tensor([-0.3285], grad_fn=<_TorchNNFunctionBackward>)
आप्टमाइज़र¶
किसी भी मशीन लर्निंग मॉडल के प्रशिक्षण के लिए अनुकूलक का चुनाव हमारे प्रशिक्षण के परिणाम की सफलता को निर्धारित करने में महत्वपूर्ण हो सकता है। TorchConnector
का उपयोग करते समय, हमें [torch.optim
] पैकेज (link <https://pytorch.org/docs/stable/optim.html> `__)में परिभाषित सभी अनुकूलक एल्गोरिदम तक पहुंच प्राप्त होती है। लोकप्रिय मशीन लर्निंग आर्किटेक्चर में उपयोग किए जाने वाले कुछ सबसे प्रसिद्ध एल्गोरिदम में *Adam*, *SGD*, या *Adagrad* शामिल हैं। हालाँकि, इस ट्यूटोरियल के लिए हम L-BFGS एल्गोरिथम (``torch.optim.LBFGS`) का उपयोग करेंगे, जो संख्यात्मक अनुकूलन के लिए सबसे अच्छी तरह से ज्ञात दूसरे क्रम के अनुकूलन एल्गोरिदम में से एक है।
लॉस फंकशन¶
हानि फ़ंक्शन के लिए, हम torch.nn से PyTorch के पूर्व-निर्धारित मॉड्यूल का भी लाभ उठा सकते हैं, जैसे कि Cross-Entropy या माध्य चुकता त्रुटि हानियाँ।
💡 स्पष्टीकरण: क्लासिकल मशीन लर्निंग में, सामान्य नियम यह है कि वर्गीकरण कार्यों के लिए क्रॉस-एंट्रॉपी हानि, और प्रतिगमन कार्यों के लिए एमएसई हानि को लागू किया जाए। हालांकि, यह सिफारिश इस धारणा के तहत दी गई है कि वर्गीकरण नेटवर्क का आउटपुट [0,1] श्रेणी में एक वर्ग संभाव्यता मान है (आमतौर पर यह सॉफ्टमैक्स परत के माध्यम से प्राप्त किया जाता है)। क्योंकि TwoLayerQNN
के लिए निम्न उदाहरण में ऐसी परत शामिल नहीं है, और हम आउटपुट पर कोई मैपिंग लागू नहीं करते हैं (निम्न अनुभाग ``CircuitQNNs` के साथ समता मानचित्रण के अनुप्रयोग का एक उदाहरण दिखाता है), QNN का आउटपुट [-1,1] की सीमा में कोई भी मान ले सकते हैं। यदि आप सोच रहे थे, यही कारण है कि यह विशेष उदाहरण वर्गीकरण के लिए MSELoss का उपयोग करता है, जबकि यह मानक नहीं है (लेकिन हम आपको विभिन्न हानि कार्यों के साथ प्रयोग करने के लिए प्रोत्साहित करते हैं और देखें कि वे प्रशिक्षण परिणामों को कैसे प्रभावित कर सकते हैं)।
[6]:
# Define optimizer and loss
optimizer = LBFGS(model1.parameters())
f_loss = MSELoss(reduction="sum")
# Start training
model1.train() # set model to training mode
# Note from (https://pytorch.org/docs/stable/optim.html):
# Some optimization algorithms such as LBFGS need to
# reevaluate the function multiple times, so you have to
# pass in a closure that allows them to recompute your model.
# The closure should clear the gradients, compute the loss,
# and return it.
def closure():
optimizer.zero_grad() # Initialize/clear gradients
loss = f_loss(model1(X_), y_) # Evaluate loss function
loss.backward() # Backward pass
print(loss.item()) # Print loss
return loss
# Run optimizer step4
optimizer.step(closure)
25.535646438598633
22.696760177612305
20.039228439331055
19.687908172607422
19.267208099365234
19.025373458862305
18.154708862304688
17.337854385375977
19.082578659057617
17.073287963867188
16.21839141845703
14.992582321166992
14.929339408874512
14.914533615112305
14.907636642456055
14.902364730834961
14.902134895324707
14.90211009979248
14.902111053466797
[6]:
tensor(25.5356, grad_fn=<MseLossBackward0>)
[7]:
# Evaluate model and compute accuracy
y_predict = []
for x, y_target in zip(X, y):
output = model1(Tensor(x))
y_predict += [np.sign(output.detach().numpy())[0]]
print("Accuracy:", sum(y_predict == y) / len(y))
# Plot results
# red == wrongly classified
for x, y_target, y_p in zip(X, y, y_predict):
if y_target == 1:
plt.plot(x[0], x[1], "bo")
else:
plt.plot(x[0], x[1], "go")
if y_target != y_p:
plt.scatter(x[0], x[1], s=200, facecolors="none", edgecolors="r", linewidths=2)
plt.plot([-1, 1], [1, -1], "--", color="black")
plt.show()
Accuracy: 0.8

लाल घेरे गलत रूप से वर्गीकृत डेटा बिंदुओं को दर्शाते हैं।
B. PyTorch और CircuitQNN
के साथ वर्गीकरण¶
एक CircuitQNN
को PyTorch से जोड़ने के लिए OpflowQNN
की तुलना में थोड़ा अधिक ध्यान देने की आवश्यकता है। सही सेटअप के बिना, बैकप्रोपेगेशन संभव नहीं है।
विशेष रूप से, हमें यह सुनिश्चित करना चाहिए कि हम नेटवर्क के फॉरवर्ड पास (sparse=False
) में संभावनाओं की एक सघन सरणी लौटा रहे हैं। यह पैरामीटर डिफ़ॉल्ट रूप से गलत
पर सेट है, इसलिए हमें केवल यह सुनिश्चित करना है कि इसे बदला नहीं गया है।
⚠️ Attention: If we define a custom interpret function ( in the example: parity
), we must remember to explicitly provide the desired output shape ( in the example: 2
). For more info on the initial parameter setup for CircuitQNN
, please check out the official qiskit documentation.
[8]:
# Define feature map and ansatz
feature_map = ZZFeatureMap(num_inputs)
ansatz = RealAmplitudes(num_inputs, entanglement="linear", reps=1)
# Define quantum circuit of num_qubits = input dim
# Append feature map and ansatz
qc = QuantumCircuit(num_inputs)
qc.append(feature_map, range(num_inputs))
qc.append(ansatz, range(num_inputs))
# Define CircuitQNN and initial setup
parity = lambda x: "{:b}".format(x).count("1") % 2 # optional interpret function
output_shape = 2 # parity = 0, 1
qnn2 = CircuitQNN(
qc,
input_params=feature_map.parameters,
weight_params=ansatz.parameters,
interpret=parity,
output_shape=output_shape,
quantum_instance=qi,
)
# Set up PyTorch module
# Reminder: If we don't explicitly declare the initial weights
# they are chosen uniformly at random from [-1, 1].
initial_weights = 0.1 * (2 * algorithm_globals.random.random(qnn2.num_weights) - 1)
print("Initial weights: ", initial_weights)
model2 = TorchConnector(qnn2, initial_weights)
Initial weights: [ 0.0364991 -0.0720495 -0.06001836 -0.09852755]
ऑप्टिमाइज़र और हानि फ़ंक्शन विकल्पों पर अनुस्मारक के लिए, आप इस अनुभाग पर वापस जा सकते हैं।
[9]:
# Define model, optimizer, and loss
optimizer = LBFGS(model2.parameters())
f_loss = CrossEntropyLoss() # Our output will be in the [0,1] range
# Start training
model2.train()
# Define LBFGS closure method (explained in previous section)
def closure():
optimizer.zero_grad(set_to_none=True) # Initialize gradient
loss = f_loss(model2(X_), y01_) # Calculate loss
loss.backward() # Backward pass
print(loss.item()) # Print loss
return loss
# Run optimizer (LBFGS requires closure)
optimizer.step(closure);
0.6925069093704224
0.6881508231163025
0.6516683101654053
0.6485998034477234
0.6394743919372559
0.7057444453239441
0.669085681438446
0.766187310218811
0.7188469171524048
0.7919709086418152
0.7598814964294434
0.7028256058692932
0.7486447095870972
0.6890242695808411
0.7760348916053772
0.7892935276031494
0.7556288242340088
0.7058126330375671
0.7203161716461182
0.7030722498893738
[10]:
# Evaluate model and compute accuracy
y_predict = []
for x in X:
output = model2(Tensor(x))
y_predict += [np.argmax(output.detach().numpy())]
print("Accuracy:", sum(y_predict == y01) / len(y01))
# plot results
# red == wrongly classified
for x, y_target, y_ in zip(X, y01, y_predict):
if y_target == 1:
plt.plot(x[0], x[1], "bo")
else:
plt.plot(x[0], x[1], "go")
if y_target != y_:
plt.scatter(x[0], x[1], s=200, facecolors="none", edgecolors="r", linewidths=2)
plt.plot([-1, 1], [1, -1], "--", color="black")
plt.show()
Accuracy: 0.5

लाल घेरे गलत रूप से वर्गीकृत डेटा बिंदुओं को दर्शाते हैं।
2. प्रतिगमन¶
हम TwoLayerQNN
पर आधारित एक मॉडल का उपयोग यह भी बताने के लिए करते हैं कि प्रतिगमन कार्य कैसे करें। इस मामले में चुना गया डेटासेट एक साइन वेव के बाद बेतरतीब ढंग से उत्पन्न होता है।
[11]:
# Generate random dataset
num_samples = 20
eps = 0.2
lb, ub = -np.pi, np.pi
f = lambda x: np.sin(x)
X = (ub - lb) * algorithm_globals.random.random([num_samples, 1]) + lb
y = f(X) + eps * (2 * algorithm_globals.random.random([num_samples, 1]) - 1)
plt.plot(np.linspace(lb, ub), f(np.linspace(lb, ub)), "r--")
plt.plot(X, y, "bo")
plt.show()

A. PyTorch और OpflowQNN
के साथ प्रतिगमन¶
नेटवर्क परिभाषा और प्रशिक्षण लूप TwoLayerQNN
का उपयोग करने वाले वर्गीकरण कार्य के अनुरूप होंगे। इस मामले में, हम डिफ़ॉल्ट मानों का उपयोग करने के बजाय, अपने स्वयं के फीचर मैप और ansatz को परिभाषित करते हैं।
[12]:
# Construct simple feature map
param_x = Parameter("x")
feature_map = QuantumCircuit(1, name="fm")
feature_map.ry(param_x, 0)
# Construct simple feature map
param_y = Parameter("y")
ansatz = QuantumCircuit(1, name="vf")
ansatz.ry(param_y, 0)
# Construct QNN
qnn3 = TwoLayerQNN(1, feature_map, ansatz, quantum_instance=qi)
print(qnn3.operator)
# Set up PyTorch module
# Reminder: If we don't explicitly declare the initial weights
# they are chosen uniformly at random from [-1, 1].
initial_weights = 0.1 * (2 * algorithm_globals.random.random(qnn3.num_weights) - 1)
model3 = TorchConnector(qnn3, initial_weights)
ComposedOp([
OperatorMeasurement(1.0 * Z),
CircuitStateFn(
┌───────┐┌───────┐
q: ┤ fm(x) ├┤ vf(y) ├
└───────┘└───────┘
)
])
ऑप्टिमाइज़र और हानि फ़ंक्शन विकल्पों पर अनुस्मारक के लिए, आप इस अनुभाग पर वापस जा सकते हैं।
[13]:
# Define optimizer and loss function
optimizer = LBFGS(model3.parameters())
f_loss = MSELoss(reduction="sum")
# Start training
model3.train() # set model to training mode
# Define objective function
def closure():
optimizer.zero_grad(set_to_none=True) # Initialize gradient
loss = f_loss(model3(Tensor(X)), Tensor(y)) # Compute batch loss
loss.backward() # Backward pass
print(loss.item()) # Print loss
return loss
# Run optimizer
optimizer.step(closure)
14.947757720947266
2.948650360107422
8.952412605285645
0.37905153632164
0.24995625019073486
0.2483610212802887
0.24835753440856934
[13]:
tensor(14.9478, grad_fn=<MseLossBackward0>)
[14]:
# Plot target function
plt.plot(np.linspace(lb, ub), f(np.linspace(lb, ub)), "r--")
# Plot data
plt.plot(X, y, "bo")
# Plot fitted line
y_ = []
for x in np.linspace(lb, ub):
output = model3(Tensor([x]))
y_ += [output.detach().numpy()[0]]
plt.plot(np.linspace(lb, ub), y_, "g-")
plt.show()

भाग 2: MNIST वर्गीकरण, हाइब्रिड QNNs¶
इस दूसरे भाग में, हम दिखाते हैं कि MNIST हस्तलिखित अंकों के डेटासेट पर अधिक जटिल छवि वर्गीकरण कार्य करने के लिए ``TorchConnector` का उपयोग करके एक हाइब्रिड क्वांटम-शास्त्रीय तंत्रिका नेटवर्क का लाभ कैसे उठाया जाए।
हाइब्रिड क्वांटम-शास्त्रीय तंत्रिका नेटवर्क पर अधिक विस्तृत (पूर्व-`` टॉर्च कनेक्टर`) स्पष्टीकरण के लिए, आप किस्किट पाठ्यपुस्तक में संबंधित अनुभाग देख सकते हैं।.
[15]:
# Additional torch-related imports
import torch
from torch import cat, no_grad, manual_seed
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import torch.optim as optim
from torch.nn import (
Module,
Conv2d,
Linear,
Dropout2d,
NLLLoss,
MaxPool2d,
Flatten,
Sequential,
ReLU,
)
import torch.nn.functional as F
चरण 1: ट्रेन और परीक्षण के लिए डेटा लोडर को परिभाषित करना¶
हम torchvision
API का लाभ उठाते हुए MNIST डेटासेट <https://en.wikipedia.org/wiki/MNIST_database>`__के सबसेट को सीधे लोड करते हैं और ट्रेन और परीक्षण के लिए मशाल ``DataLoader`s (लिंक) को परिभाषित करें।
[16]:
# Train Dataset
# -------------
# Set train shuffle seed (for reproducibility)
manual_seed(42)
batch_size = 1
n_samples = 100 # We will concentrate on the first 100 samples
# Use pre-defined torchvision function to load MNIST train data
X_train = datasets.MNIST(
root="./data", train=True, download=True, transform=transforms.Compose([transforms.ToTensor()])
)
# Filter out labels (originally 0-9), leaving only labels 0 and 1
idx = np.append(
np.where(X_train.targets == 0)[0][:n_samples], np.where(X_train.targets == 1)[0][:n_samples]
)
X_train.data = X_train.data[idx]
X_train.targets = X_train.targets[idx]
# Define torch dataloader with filtered data
train_loader = DataLoader(X_train, batch_size=batch_size, shuffle=True)
यदि हम एक त्वरित विज़ुअलाइज़ेशन करते हैं तो हम देख सकते हैं कि ट्रेन डेटासेट में हस्तलिखित 0s और 1s की छवियां होती हैं।
[17]:
n_samples_show = 6
data_iter = iter(train_loader)
fig, axes = plt.subplots(nrows=1, ncols=n_samples_show, figsize=(10, 3))
while n_samples_show > 0:
images, targets = data_iter.__next__()
axes[n_samples_show - 1].imshow(images[0, 0].numpy().squeeze(), cmap="gray")
axes[n_samples_show - 1].set_xticks([])
axes[n_samples_show - 1].set_yticks([])
axes[n_samples_show - 1].set_title("Labeled: {}".format(targets[0].item()))
n_samples_show -= 1

[18]:
# Test Dataset
# -------------
# Set test shuffle seed (for reproducibility)
# manual_seed(5)
n_samples = 50
# Use pre-defined torchvision function to load MNIST test data
X_test = datasets.MNIST(
root="./data", train=False, download=True, transform=transforms.Compose([transforms.ToTensor()])
)
# Filter out labels (originally 0-9), leaving only labels 0 and 1
idx = np.append(
np.where(X_test.targets == 0)[0][:n_samples], np.where(X_test.targets == 1)[0][:n_samples]
)
X_test.data = X_test.data[idx]
X_test.targets = X_test.targets[idx]
# Define torch dataloader with filtered data
test_loader = DataLoader(X_test, batch_size=batch_size, shuffle=True)
चरण 2: QNN और हाइब्रिड मॉडल को परिभाषित करना¶
यह दूसरा चरण TorchConnector
की शक्ति को दर्शाता है। हमारे क्वांटम न्यूरल नेटवर्क लेयर (इस मामले में, एक TwoLayerQNN
) को परिभाषित करने के बाद, हम एक टॉर्च कनेक्टर को TorchConnector(qnn)
के रूप में आरंभ करके इसे अपने मशाल मॉड्यूल
में एक परत में एम्बेड कर सकते हैं।
⚠️ ध्यान दें: हाइब्रिड मॉडल में पर्याप्त ग्रेडिएंट बैकप्रोपेगेशन के लिए, हमें qnn इनिशियलाइज़ेशन के दौरान प्रारंभिक पैरामीटर ``input_gradients` को TRUE पर सेट करना होगा।
[19]:
# Define and create QNN
def create_qnn():
feature_map = ZZFeatureMap(2)
ansatz = RealAmplitudes(2, reps=1)
# REMEMBER TO SET input_gradients=True FOR ENABLING HYBRID GRADIENT BACKPROP
qnn = TwoLayerQNN(
2,
feature_map,
ansatz,
input_gradients=True,
exp_val=AerPauliExpectation(),
quantum_instance=qi,
)
return qnn
qnn4 = create_qnn()
print(qnn4.operator)
ComposedOp([
OperatorMeasurement(1.0 * ZZ),
CircuitStateFn(
┌──────────────────────────┐┌──────────────────────────────────────┐
q_0: ┤0 ├┤0 ├
│ ZZFeatureMap(x[0],x[1]) ││ RealAmplitudes(θ[0],θ[1],θ[2],θ[3]) │
q_1: ┤1 ├┤1 ├
└──────────────────────────┘└──────────────────────────────────────┘
)
])
[20]:
# Define torch NN module
class Net(Module):
def __init__(self, qnn):
super().__init__()
self.conv1 = Conv2d(1, 2, kernel_size=5)
self.conv2 = Conv2d(2, 16, kernel_size=5)
self.dropout = Dropout2d()
self.fc1 = Linear(256, 64)
self.fc2 = Linear(64, 2) # 2-dimensional input to QNN
self.qnn = TorchConnector(qnn) # Apply torch connector, weights chosen
# uniformly at random from interval [-1,1].
self.fc3 = Linear(1, 1) # 1-dimensional output from QNN
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2)
x = self.dropout(x)
x = x.view(x.shape[0], -1)
x = F.relu(self.fc1(x))
x = self.fc2(x)
x = self.qnn(x) # apply QNN
x = self.fc3(x)
return cat((x, 1 - x), -1)
model4 = Net(qnn4)
चरण 3: प्रशिक्षण¶
[21]:
# Define model, optimizer, and loss function
optimizer = optim.Adam(model4.parameters(), lr=0.001)
loss_func = NLLLoss()
# Start training
epochs = 10 # Set number of epochs
loss_list = [] # Store loss history
model4.train() # Set model to training mode
for epoch in range(epochs):
total_loss = []
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad(set_to_none=True) # Initialize gradient
output = model4(data) # Forward pass
loss = loss_func(output, target) # Calculate loss
loss.backward() # Backward pass
optimizer.step() # Optimize weights
total_loss.append(loss.item()) # Store loss
loss_list.append(sum(total_loss) / len(total_loss))
print("Training [{:.0f}%]\tLoss: {:.4f}".format(100.0 * (epoch + 1) / epochs, loss_list[-1]))
Training [10%] Loss: -1.1630
Training [20%] Loss: -1.5294
Training [30%] Loss: -1.7855
Training [40%] Loss: -1.9863
Training [50%] Loss: -2.2257
Training [60%] Loss: -2.4513
Training [70%] Loss: -2.6758
Training [80%] Loss: -2.8832
Training [90%] Loss: -3.1006
Training [100%] Loss: -3.3061
[22]:
# Plot loss convergence
plt.plot(loss_list)
plt.title("Hybrid NN Training Convergence")
plt.xlabel("Training Iterations")
plt.ylabel("Neg. Log Likelihood Loss")
plt.show()

Now we’ll save the trained model, just to show how a hybrid model can be saved and re-used later for inference. To save and load hybrid models, when using the TorchConnector, follow the PyTorch recommendations of saving and loading the models.
[23]:
torch.save(model4.state_dict(), "model4.pt")
चरण 4: मूल्यांकन¶
We start from recreating the model and loading the state from the previously saved file. You create a QNN layer using another simulator or a real hardware. So, you can train a model on real hardware available on the cloud and then for inference use a simulator or vice verse. For a sake of simplicity we create a new quantum neural network in the same way as above.
[24]:
qnn5 = create_qnn()
model5 = Net(qnn5)
model5.load_state_dict(torch.load("model4.pt"))
[24]:
<All keys matched successfully>
[25]:
model5.eval() # set model to evaluation mode
with no_grad():
correct = 0
for batch_idx, (data, target) in enumerate(test_loader):
output = model5(data)
if len(output.shape) == 1:
output = output.reshape(1, *output.shape)
pred = output.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()
loss = loss_func(output, target)
total_loss.append(loss.item())
print(
"Performance on test data:\n\tLoss: {:.4f}\n\tAccuracy: {:.1f}%".format(
sum(total_loss) / len(total_loss), correct / len(test_loader) / batch_size * 100
)
)
Performance on test data:
Loss: -3.3585
Accuracy: 100.0%
[26]:
# Plot predicted labels
n_samples_show = 6
count = 0
fig, axes = plt.subplots(nrows=1, ncols=n_samples_show, figsize=(10, 3))
model5.eval()
with no_grad():
for batch_idx, (data, target) in enumerate(test_loader):
if count == n_samples_show:
break
output = model5(data[0:1])
if len(output.shape) == 1:
output = output.reshape(1, *output.shape)
pred = output.argmax(dim=1, keepdim=True)
axes[count].imshow(data[0].numpy().squeeze(), cmap="gray")
axes[count].set_xticks([])
axes[count].set_yticks([])
axes[count].set_title("Predicted {}".format(pred.item()))
count += 1

🎉🎉🎉🎉 अब आप Qiskit Machine Learning का उपयोग करके अपने स्वयं के हाइब्रिड डेटासेट और आर्किटेक्चर के साथ प्रयोग करने में सक्षम हैं। सौभाग्य!
[27]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.20.0 |
qiskit-aer | 0.10.3 |
qiskit-ibmq-provider | 0.18.3 |
qiskit | 0.33.0 |
qiskit-machine-learning | 0.4.0 |
System information | |
Python version | 3.7.9 |
Python compiler | MSC v.1916 64 bit (AMD64) |
Python build | default, Aug 31 2020 17:10:11 |
OS | Windows |
CPUs | 4 |
Memory (Gb) | 31.837730407714844 |
Wed Apr 13 12:19:16 2022 GMT Daylight Time |
This code is a part of Qiskit
© Copyright IBM 2017, 2022.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.