Russian
Языки
English
Bengali
French
Hindi
Italian
Japanese
Korean
Malayalam
Russian
Spanish
Tamil
Turkish
Vietnamese
Shortcuts

Примечание

Страница создана на основе docs/tutorials/05_torch_connector.ipynb.

Torch Connector и гибридные QNN

Этот учебный материал представляет класс TorchConnector из Qiskit и демонстрирует, как TorchConnector позволяет интегрировать любую NeuralNetwork из Qiskit Machine Learning в рабочий процесс PyTorch. TorchConnector принимает Qiskit NeuralNetwork и делает его доступным как Module PyTorch. Результирующий модуль можно легко интегрировать в классические архитектуры PyTorch и обучать без дополнительных сложностей, открывая возможность разработки и тестирования гибридных квантово-классических архитектур машинного обучения.

Содержание:

Часть 1: Простая классификация и регрессия

Первая часть этого урока показывает, как квантовые нейронные сети могут быть обучены с помощью механизма автоматического дифференцирования PyTorch (torch.autograd, ``ссылка <https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html>`__) для простых задач классификации и регрессии.

  1. Классификация

    1. Классификация с PyTorch и OpflowQNN

    2. Классификация с PyTorch и CircuitQNN

  2. Регрессия

    1. Регрессия с PyTorch и OpflowQNN

Часть 2: Классификация MNIST, гибридные QNNs

Вторая часть этого урока показывает, как встроить (квантовую) NeuralNetwork в целевой рабочий процесс PyTorch (в данном случае, типичную архитектуру CNN) для классификации данных MNIST гибридным квантово-классическим способом.


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

# declare quantum instance
qi = QuantumInstance(Aer.get_backend('aer_simulator_statevector'))

Часть 1: Простая классификация и регрессия

1. Классификация

Сначала мы покажем, как TorchConnector'' позволяет обучить Quantum ``NeuralNetwork для решения задач классификации с помощью механизма автоматического дифференцирования PyTorch. Чтобы проиллюстрировать это, мы выполним бинарную классификацию на случайно сгенерированном наборе данных.

[2]:
# Generate random dataset

# Set seed for random dataset
np.random.seed(5)

# 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*np.random.rand(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_4_0.png

A. Классификация с PyTorch и OpflowQNN

Привязать OpflowQNN к PyTorch относительно просто. Здесь мы проиллюстрируем это на примере TwoLayerQNN, подслучая OpflowQNN, представленного в предыдущих уроках.

[3]:
# 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].
np.random.seed(10)
initial_weights = 0.1*(2*np.random.rand(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                   ├┤0                                                 ├
       │  nlocal(x[0],x[1]) ││  nlocal(θ[0],θ[1],θ[2],θ[3],θ[4],θ[5],θ[6],θ[7]) │
  q_1: ┤1                   ├┤1                                                 ├
       └────────────────────┘└──────────────────────────────────────────────────┘
  )
])
Initial weights:  [ 0.05426413 -0.09584961  0.02672965  0.04976078 -0.0002986  -0.05504067
 -0.06038743  0.05210614]
[4]:
# Test with a single input
model1(X_[0, :])
[4]:
tensor([-0.0547], grad_fn=<_TorchNNFunctionBackward>)
Оптимизатор

Выбор оптимизатора для обучения любой модели машинного обучения может иметь решающее значение для определения успеха нашего обучения. При использовании TorchConnector, мы получаем доступ ко всем алгоритмам оптимизатора, определенным в пакете [torch.optim] (ссылка на источник). Некоторые наиболее известные алгоритмы, используемые в популярных архитектурах машинного обучения, включают Adam, SGD, или Adagrad. Однако, для этого урока мы будем использовать алгоритм L-BFGS (torch.optim.LBFGS), один из наиболее известных алгоритмов оптимизации второго порядка для числовой оптимизации.

Функция потерь

Что касается функции потерь, то мы также можем воспользоваться предопределенными модулями PyTorch с torch.nn, например, Cross-Entropy или Mean Squared Error.

💡 Уточнение : В процессе классического обучения общим правилом большого пальца является применение Cross-Entropy loss к задачам классификации, и MSE loss в регрессионных задачах. Однако, эта рекомендация приводится исходя из предположения о том, что результатом работы системы классификации является значение вероятности в диапазоне [0, 1] (обычно это достигается через слой Softmax). Поскольку следующий пример TwoLayerQN не включает такой слой, и мы не применяем никакие сопоставления с результатами (следующий раздел показывает пример приложения с parity mapping для CircuitQNs), вывод QNN может принимать любое значение в диапазоне [-1,1]. Именно поэтому в данном примере используется MSELoss для классификации, несмотря на то, что она не является нормой (но мы рекомендуем вам экспериментировать с различными функциями потерь и посмотреть, как они могут повлиять на результаты обучения).

[5]:
# 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)
29.08934783935547
22.97238540649414
16.25204849243164
29.874549865722656
15.212966918945312
15.903762817382812
14.69144058227539
15.069099426269531
14.648868560791016
14.838859558105469
14.472648620605469
17.432323455810547
17.68243408203125
22.356327056884766
15.594417572021484
35.22927474975586
35.516239166259766
29.633190155029297
31.025428771972656
19.802261352539062
[5]:
tensor(29.0893, grad_fn=<MseLossBackward>)
[6]:
# 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.55
../_images/tutorials_05_torch_connector_10_1.png

Красными кружками отмечены неверно классифицированные данные.

B. Классификация с PyTorch и CircuitQNN

Связание CircuitQNNN с PyTorch требует немного больше внимания, чем OpflowQNN. Без правильной настройки использование метода обратного распространения ошибки (backpropagation) невозможно.

В частности, мы должны убедиться, что мы возвращаем плотный массив вероятностей при прямом прохождении сети (sparse=False). Этот параметр имеет значение False по умолчанию, поэтому мы просто должны убедиться, что он не был изменен.

⚠️ Внимание: Если мы определим пользовательскую функцию интерпретации (в примере - parity), мы должны явно предоставить желаемую форму вывода (в примере - 2). Для получения дополнительной информации о начальной настройке параметра CircuitQNN, ознакомьтесь с официальной документацией qiskit.

[7]:
# 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].
np.random.seed(9)
initial_weights = 0.1*(2*np.random.rand(qnn2.num_weights) - 1)
print("Initial weights: ", initial_weights)
model2 = TorchConnector(qnn2, initial_weights)
Initial weights:  [-0.09792517  0.00037492 -0.00084534 -0.07323409]

Для выбора оптимизатора и функции потерь вы можете вернуться к этому разделу.

[8]:
# 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.6603068709373474
0.6486624479293823
0.5996587872505188
0.589975893497467
0.5881412029266357
0.5867496728897095
0.5887688398361206
0.5896384119987488
0.5888267159461975
0.5813128352165222
0.5787640810012817
0.7018635272979736
0.7185250520706177
0.7709338665008545
0.7072550058364868
0.7725899815559387
0.6697829365730286
0.7946376800537109
0.6232572793960571
0.6820956468582153
[9]:
# 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.75
../_images/tutorials_05_torch_connector_16_1.png

Красными кружками отмечены неверно классифицированные данные.

2. Регрессия

Чтобы продемонстрировать выполнение задачи регрессии, мы также используем модель на основе TwoLayerQNN. Выбранный набор данных в данном случае является случайно сгенерированным и имеет форму синусоидальной волны.

[10]:
# Generate random dataset

np.random.seed(0)
num_samples = 20
eps = 0.2
lb, ub = -np.pi, np.pi
f = lambda x: np.sin(x)

X = (ub - lb)*np.random.rand(num_samples, 1) + lb
y = f(X) + eps*(2*np.random.rand(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_19_0.png

A. Регрессия с PyTorch OpflowQNN

При использовании TwoLayerQNN определение сети и цикл обучения будут аналогичны задачам классификации. В этом случае мы определяем собственную карту признаков и анзац, а не используем значения по умолчанию.

[11]:
# 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].
# Set seed for random dataset
np.random.seed(7)
initial_weights = 0.1*(2*np.random.rand(qnn3.num_weights) - 1)
model3 = TorchConnector(qnn3, initial_weights)
ComposedOp([
  OperatorMeasurement(1.0 * Z),
  CircuitStateFn(
       ┌───────┐┌───────┐
  q_0: ┤ fm(x) ├┤ vf(y) ├
       └───────┘└───────┘
  )
])

Для выбора оптимизатора и функции потерь вы можете вернуться к этому разделу.

[12]:
# 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)
21.348440170288086
3.375812292098999
21.63526153564453
2.7181315422058105
30.3101806640625
9.999582290649414
19.066198348999023
1.8251923322677612
10.245695114135742
0.30168071389198303
0.3217697739601135
0.2346433401107788
0.2989022135734558
0.24148759245872498
0.19600583612918854
0.23429127037525177
0.3245868384838104
0.23837639391422272
0.2259863168001175
0.296633780002594
[12]:
tensor(21.3484, grad_fn=<MseLossBackward>)
[13]:
# 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_25_0.png

Часть 2: Классификация MNIST, гибридные QNN

В этой второй части мы показываем, как использовать гибридно-классическую нейронную сеть с помощью TorchConnector для выполнения более сложной задачи по классификации изображений на наборе данных с рукописными буквами MNIST.

Для более подробного (до TorchConnector) объяснения гибридных кванто-классических нейронных сетей вы можете посмотреть соответствующий раздел в Qiskit Textbook.

[14]:
# Additional torch-related imports
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 и определения DataLoader (link) для обучения и тестирования.

[15]:
# Train Dataset
# -------------

# Set train shuffle seed (for reproducibility)
manual_seed(1)

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)

Если мы выполним быструю визуализацию, то станет видно, что набор данных для обучения состоит из изображений написанных вручную цифр 0 и 1.

[16]:
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_32_0.png
[17]:
# 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. После определения нашего квантового слоя нейросети (в данном случае TwoLayerQN), мы можем встроить его в наш Module, инициализируя его как TorchConnector(qnn).

⚠️ Внимание: Для правильного использования метода обратного распространения ошибки (backpropagation) для градиента в гибридных моделях, НЕОБХОДИМО установить начальный параметр input_gradients в значение TRUE во время инициализации qnn.

[18]:
# Define QNN
feature_map = ZZFeatureMap(2)
ansatz = RealAmplitudes(2, reps=1)
# REMEMBER TO SET input_gradients=True FOR ENABLING HYBRID GRADIENT BACKPROP
qnn4 = TwoLayerQNN(2, feature_map, ansatz, input_gradients=True, exp_val=AerPauliExpectation(), quantum_instance=qi)
print(qnn4.operator)
ComposedOp([
  OperatorMeasurement(1.0 * ZZ),
  CircuitStateFn(
       ┌────────────────────┐┌──────────────────────────────┐
  q_0: ┤0                   ├┤0                             ├
       │  nlocal(x[0],x[1]) ││  nlocal(θ[0],θ[1],θ[2],θ[3]) │
  q_1: ┤1                   ├┤1                             ├
       └────────────────────┘└──────────────────────────────┘
  )
])
[19]:
# Define torch NN module

class Net(Module):

    def __init__(self):
        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(qnn4)  # 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()

Шаг 3: Обучение

[20]:
# 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. * (epoch + 1) / epochs, loss_list[-1]))
Training [10%]  Loss: -0.7126
Training [20%]  Loss: -0.9233
Training [30%]  Loss: -1.1075
Training [40%]  Loss: -1.2774
Training [50%]  Loss: -1.4991
Training [60%]  Loss: -1.5984
Training [70%]  Loss: -1.8882
Training [80%]  Loss: -2.0387
Training [90%]  Loss: -2.2595
Training [100%] Loss: -2.4982
[21]:
# 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_40_0.png

Шаг 4: Оценка

[22]:
model4.eval()  # set model to evaluation mode
with no_grad():

    correct = 0
    for batch_idx, (data, target) in enumerate(test_loader):
        output = model4(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: -2.5128
        Accuracy: 98.0%
[23]:
# Plot predicted labels

n_samples_show = 6
count = 0
fig, axes = plt.subplots(nrows=1, ncols=n_samples_show, figsize=(10, 3))

model4.eval()
with no_grad():
    for batch_idx, (data, target) in enumerate(test_loader):
        if count == n_samples_show:
            break
        output = model4(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_43_0.png

🎉🎉🎉🎉 Теперь вы можете экспериментировать с собственными гибридными наборами данных и архитектурами, используя Qiskit Machine Learning. Удачи!

[24]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
QiskitNone
Terra0.17.4
Aer0.8.2
IgnisNone
AquaNone
IBM Q ProviderNone
System information
Python3.9.6 (default, Jun 29 2021, 05:25:02) [Clang 12.0.5 (clang-1205.0.22.9)]
OSDarwin
CPUs8
Memory (Gb)64.0
Wed Jul 07 09:47:11 2021 JST

This code is a part of Qiskit

© Copyright IBM 2017, 2021.

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.