Vietnamese
Ngôn ngữ
English
Bengali
French
Hindi
Italian
Japanese
Korean
Malayalam
Russian
Spanish
Tamil
Turkish
Vietnamese
Shortcuts

Ghi chú

Trang này được tạo từ docs/tutorials/05_torch_connector.ipynb.

Torch Connector và Hybrid QNNs

Hướng dẫn này giới thiệu lớp TorchConnector của Qiskit và trình bày cách TorchConnector cho phép tích hợp tự nhiên bất kỳ NeuralNetwork nào từ Qiskit Machine Learning vào một quy trình làm việc PyTorch. TorchConnector sử dụng Qiskit NeuralNetwork và cung cấp nó dưới dạng Module PyTorch. Module kết quả có thể được tích hợp liền mạch vào các kiến trúc cổ điển PyTorch và được đào tạo chung mà không cần cân nhắc thêm, cho phép phát triển và thử nghiệm các kiến trúc học máy lai lượng tử-cổ điển mới.

Nội dung:

Phần 1: Phân loại đơn giản & Hồi quy

Phần đầu tiên của hướng dẫn này cho thấy cách mạng neural lượng tử có thể được đào tạo bằng cách sử dụng công cụ phân biệt tự động của PyTorch (torch.autograd, link) cho các nhiệm vụ phân loại và hồi quy đơn giản.

  1. Phân loại

    1. Phân loại với PyTorch và OpflowQNN

    2. Phân loại với PyTorch và CircuitQNN

  2. Hồi quy

    1. Hồi quy với PyTorch và OpflowQNN

Part 2: Phân loại MNIST, Hybrid QNNs

Phần thứ hai của hướng dẫn này minh họa cách nhúng một NeuralNetwork (Lượng tử) vào một quy trình làm việc PyTorch mục tiêu (trong trường hợp này là kiến trúc CNN điển hình) để phân loại dữ liệu MNIST theo cách lai cổ điển-lượng tử.


[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"))

Phần 1: Phân loại đơn giản và Hồi quy

1. Phân loại

Đầu tiên, chúng tôi chỉ ra cách mà TorchConnector cho phép đào tạo một NeuralNetwork lượng tử để giải quyết các nhiệm vụ phân loại bằng cách sử dụng công cụ phân biệt tự động của PyTorch. Để minh họa cho điều này, chúng tôi sẽ thực hiện phân loại nhị phân trên một tập dữ liệu được tạo ngẫu nhiên.

[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()
../_images/tutorials_05_torch_connector_5_0.png

A. Phân loại với PyTorch và OpflowQNN

Liên kết một OpflowQNN với PyTorch tương đối đơn giản. Ở đây chúng tôi minh họa điều này bằng cách sử dụng TwoLayerQNN, một trường hợp con của `` OpflowQNN '' đã được giới thiệu trong các hướng dẫn trước.

[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>)
Trình tối ưu

Việc lựa chọn trình tối ưu hóa để đào tạo bất kỳ mô hình học máy nào có thể rất quan trọng trong việc xác định sự thành công của kết quả đào tạo. Khi sử dụng TorchConnector, chúng tôi có quyền truy cập vào tất cả các thuật toán của trình tối ưu hóa được xác định trong gói [torch.optim] (link). Một số thuật toán nổi tiếng nhất được sử dụng trong kiến trúc học máy thông dụng bao gồm Adam, SGD, hoặc Adagrad. Tuy nhiên, đối với hướng dẫn này, chúng tôi sẽ sử dụng thuật toán L-BFGS (torch.optim.LBFGS), một trong những thuật toán tối ưu hóa bậc hai được biết đến nhiều nhất để tối ưu hóa số.

Hàm mất mát

Đối với loss function (hàm mất mát), chúng tôi cũng có thể tận dụng các module được xác định trước của PyTorch từ torch.nn, chẳng hạn như Cross-Entropy hoặc Mean Squared Error.

** 💡 Làm rõ: ** Trong học máy cổ điển, nguyên tắc chung là áp dụng tổn thất Cross-Entropy cho các tác vụ phân loại và tổn thất MSE cho các tác vụ hồi quy. Tuy nhiên, lời khuyên này được đưa ra với giả định rằng đầu ra của mạng phân loại là một giá trị xác suất lớp trong phạm vi [0,1] (thường điều này đạt được thông qua một lớp Softmax). Vì ví dụ sau cho TwoLayerQNN không bao gồm lớp như vậy và chúng tôi không áp dụng bất kỳ ánh xạ nào cho đầu ra (phần sau trình bày một ví dụ về ứng dụng của ánh xạ chẵn lẻ với CircuitQNNs), đầu ra của QNN có thể nhận bất kỳ giá trị nào trong khoảng [-1,1]. Trong trường hợp bạn thắc mắc, đây là lý do tại sao ví dụ cụ thể này sử dụng MSELoss để phân loại mặc dù nó không phải là chuẩn (nhưng chúng tôi khuyến khích bạn thử nghiệm với các hàm mất mát khác nhau và xem chúng có thể tác động như thế nào đến kết quả đào tạo).

[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
../_images/tutorials_05_torch_connector_11_1.png

Vòng tròn màu đỏ biểu thị các điểm dữ liệu bị phân loại sai.

B. Phân loại với PyTorch và CircuitQNN

Việc liên kết một CircuitQNN với PyTorch cần chú ý hơn một chút so với OpflowQNN. Nếu không có thiết lập chính xác, giải thuật lan truyền ngược là không thể.

Đặc biệt, chúng tôi phải đảm bảo rằng chúng tôi đang trả về một mảng dày đặc các xác suất trong tính toán trực tiếp của mạng (sparse=False). Tham số này được thiết lập mặc định thành False`, vì vậy chúng tôi chỉ cần đảm bảo rằng nó không bị thay đổi.

⚠️ Chú ý: Nếu chúng ta xác định một hàm thông dịch tùy chỉnh (trong ví dụ: parity), chúng ta phải nhớ cung cấp rõ ràng hình dạng đầu ra mong muốn (trong ví dụ: 2). Để biết thêm thông tin về thiết lập tham số ban đầu cho CircuitQNN, vui lòng xem tài liệu qiskit chính thức.

[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]

Để có lời nhắc về các lựa chọn trình tối ưu hóa và hàm mất mát, bạn có thể quay lại phần này.

[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
../_images/tutorials_05_torch_connector_17_1.png

Vòng tròn màu đỏ biểu thị các điểm dữ liệu bị phân loại sai.

2. Hồi quy

Chúng tôi sử dụng mô hình dựa trên TwoLayerQNN để minh họa cách thực hiện tác vụ hồi quy. Tập dữ liệu đã chọn trong trường hợp này được tạo ngẫu nhiên theo sóng sin.

[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()
../_images/tutorials_05_torch_connector_20_0.png

A. Hồi quy với PyTorch và OpflowQNN

Định nghĩa mạng và vòng lặp đào tạo sẽ tương tự với các định nghĩa của tác vụ phân loại bằng sử dụng TwoLayerQNN. Trong trường hợp này, chúng tôi xác định bản đồ tính năng và ansatz của riêng mình, thay vì sử dụng các giá trị mặc định.

[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) ├
     └───────┘└───────┘
  )
])

Để có lời nhắc về các lựa chọn trình tối ưu hóa và hàm mất mát, bạn có thể quay lại phần nà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()
../_images/tutorials_05_torch_connector_26_0.png

Phần 2: Phân loại MNIST, các QNN lai

Trong phần thứ hai này, chúng tôi chỉ ra cách tận dụng một neural network cổ điển-lượng tử lai bằng cách sử dụng TorchConnector, để thực hiện nhiệm vụ phân loại hình ảnh phức tạp hơn trên tập dữ liệu chữ số viết tay MNIST.

Để có giải thích chi tiết hơn (trước TorchConnector) về neural network cổ điển-lượng tử lai, bạn có thể xem phần tương ứng trong Qiskit Textbook.

[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

Bước 1: Xác định Bộ tải dữ liệu cho đào tạo và kiểm tra

Chúng tôi tận dụng torchvision API để tải trực tiếp một tập con của Tập dữ liệu MNIST và xác định torch DataLoaders (link) để đào tạo và kiểm tra.

[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)

Nếu chúng ta thực hiện một hiển thị nhanh, chúng ta có thể thấy rằng tập dữ liệu đào tạo bao gồm các hình ảnh của các số 0 và 1 được viết tay.

[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
../_images/tutorials_05_torch_connector_33_0.png
[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)

Bước 2: Xác định QNN và Hybrid Model (mô hình lai)

Bước thứ hai này cho thấy sức mạnh của TorchConnector. Sau khi xác định lớp neural network lượng tử của chúng tôi (trong trường hợp này là một TwoLayerQNN), chúng tôi có thể nhúng nó vào một lớp trong Module torch bằng cách khởi tạo một đầu nối torch TorchConnector(qnn).

⚠️ Chú ý: Để có sự lan truyền ngược gradient đầy đủ trong các mô hình kết hợp, chúng ta PHẢI đặt tham số ban đầu input_gradients thành TRUE trong quá trình khởi tạo qnn.

[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)

Bước 3: Đào tạo

[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()
../_images/tutorials_05_torch_connector_41_0.png

Bây giờ, chúng ta sẽ lưu lại mô hình đã đào tạo, chỉ để cho biết cách một mô hình lai có thể lưu và sử dụng lại cho những suy luận sau này. Để lưu và tải các mô hình lai, khi sử dụng TorchConnector, nên tuân theo các khuyến nghị PyTorch của việc lưu và tải các mô hình.

[23]:
torch.save(model4.state_dict(), "model4.pt")

Bước 4: Đánh giá

Chúng ta bắt đầu tạo lại mô hình và tải các trạng thái từ tập tin đã lưu trước đó. Bạn cần tạo một lớp QNN sử dụng một trình giả lập khác hoặc phần cứng thực. Vì vậy, bạn có thể thực tập một mô hình trên phần cứng thực có sẵn trên đám mây và sau đó sử dụng cho việc suy luận hoặc mô phỏng và ngược lại. Để đơn giản hơn, chúng ta tạo một mạng lưới thần kinh lượng tử mới theo cách tương tự như trên.

[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
../_images/tutorials_05_torch_connector_48_0.png

🎉🎉🎉🎉 Bây giờ bạn có thể thử nghiệm với kiến trúc và bộ dữ liệu lai của riêng bạn bằng cách sử dụng Qiskit Machine Learning. Chúc may mắn!

[27]:
import qiskit.tools.jupyter

%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.20.0
qiskit-aer0.10.3
qiskit-ibmq-provider0.18.3
qiskit0.33.0
qiskit-machine-learning0.4.0
System information
Python version3.7.9
Python compilerMSC v.1916 64 bit (AMD64)
Python builddefault, Aug 31 2020 17:10:11
OSWindows
CPUs4
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.