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

Примечание

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

Квантовые нейронные сети

Этот блокнот демонстрирует различные общие реализации квантовых нейронных сетей (QNN), предоставляемые в Qiskit Machine Learning. Сети предназначены для использования в качестве вычислительных единиц, не зависящих от области применения, которые могут быть использованы для множества различных случаев. В зависимости от задачи, конкретный тип сети может быть более или менее подходящим и может потребовать определенной настройки. Ниже будут более подробно рассмотрены различные доступные нейронные сети:

  1. ` ` NeuralNetwork ` `: Интерфейс для нейронных сетей.

  2. OpflowQN: Сеть, основанная на оценке квантово-механических наблюдений.

  3. TwoLayerQNN: Специальная реализация OpflowQNN для удобства.

  4. » CircuitQNN ` `: сеть, основанная на образцах, полученных в результате измерения квантовой цепи.

[1]:
import numpy as np

from qiskit import Aer, QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.circuit.library import RealAmplitudes, ZZFeatureMap
from qiskit.opflow import StateFn, PauliSumOp, AerPauliExpectation, ListOp, Gradient
from qiskit.utils import QuantumInstance
[2]:
# set method to calculcate expected values
expval = AerPauliExpectation()

# define gradient method
gradient = Gradient()

# define quantum instances (statevector and sample based)
qi_sv = QuantumInstance(Aer.get_backend('aer_simulator_statevector'))

# we set shots to 10 as this will determine the number of samples later on.
qi_qasm = QuantumInstance(Aer.get_backend('aer_simulator'), shots=10)

1. ` ` NeuralNetwork ` `

NeuralNetwork это интерфейс для всех нейронных сетей, доступных в Qiskit Machine Learning. Он предоставляет собой прямой и обратный проход, принимающий на вход образцы данных и обучаемые веса. NeuralNetwork не содержит никаких возможностей для обучения, они предоставляются конкретными алгоритмами / приложениями. Таким образом, NeuralNetwork также не хранит значения обучаемых весов. Далее будут представлены различные реализации этих интерфейсов.

Предположим, что NeuralNetwork называется nn. Затем проход nn.forward(input, weights) принимает либо одинаковые входные значения для данных и весов размера nn. um_inputs и nn.num_weights, соответственно. NeuralNetwork поддерживает группировку входных данных и возвращает набор выходных данных соответствующей формы.

2. ` ` OpflowQNN ` `

Функция OpflowQNN принимает (параметризованный) оператор из Qiskit и использует градиентную схему Qiskit для обеспечения обратного прохода. Таким оператором может быть, например, математическое ожидание квантово-механической наблюдаемой величины относительно параметризованного квантового состояния. Параметры могут быть использованы для загрузки классических данных, а также для представления обучаемых весов. В OpflowQNN также допускаются списки операторов и более сложные структуры для построения более сложных QNN.

[3]:
from qiskit_machine_learning.neural_networks import OpflowQNN
[4]:
# construct parametrized circuit
params1 = [Parameter('input1'), Parameter('weight1')]
qc1 = QuantumCircuit(1)
qc1.h(0)
qc1.ry(params1[0], 0)
qc1.rx(params1[1], 0)
qc_sfn1 = StateFn(qc1)

# construct cost operator
H1 = StateFn(PauliSumOp.from_list([('Z', 1.0), ('X', 1.0)]))

# combine operator and circuit to objective function
op1 = ~H1 @ qc_sfn1
print(op1)
ComposedOp([
  OperatorMeasurement(1.0 * Z
  + 1.0 * X),
  CircuitStateFn(
       ┌───┐┌────────────┐┌─────────────┐
  q_0: ┤ H ├┤ RY(input1) ├┤ RX(weight1) ├
       └───┘└────────────┘└─────────────┘
  )
])
[5]:
# construct OpflowQNN with the operator, the input parameters, the weight parameters,
# the expected value, gradient, and quantum instance.
qnn1 = OpflowQNN(op1, [params1[0]], [params1[1]], expval, gradient, qi_sv)
[6]:
# define (random) input and weights
input1 = np.random.rand(qnn1.num_inputs)
weights1 = np.random.rand(qnn1.num_weights)
[7]:
# QNN forward pass
qnn1.forward(input1, weights1)
[7]:
array([[0.81422018]])
[8]:
# QNN batched forward pass
qnn1.forward([input1, input1], weights1)
[8]:
array([[0.81422018],
       [0.81422018]])
[9]:
# QNN backward pass
qnn1.backward(input1, weights1)
[9]:
(array([[[-1.15629599]]]), array([[[0.0008565]]]))
[10]:
# QNN batched backward pass
qnn1.backward([input1, input1], weights1)
[10]:
(array([[[-1.15629599]],

        [[-1.15629599]]]),
 array([[[0.0008565]],

        [[0.0008565]]]))

Объединение нескольких наблюдаемых в ListOp также позволяет создавать более сложные QNN

[11]:
op2 = ListOp([op1, op1])
qnn2 = OpflowQNN(op2, [params1[0]], [params1[1]], expval, gradient, qi_sv)
[12]:
# QNN forward pass
qnn2.forward(input1, weights1)
[12]:
array([[0.81422018, 0.81422018]])
[13]:
# QNN backward pass
qnn2.backward(input1, weights1)
[13]:
(array([[[-1.15629599],
         [-1.15629599]]]),
 array([[[0.0008565],
         [0.0008565]]]))

3. ` ` TwoLayerQNN ` `

TwoLayerQNN` - это специальная ``OpflowQNN на \(n\) кубитах, которая состоит из: (1) карты признаков для вставки данных и (2) анзаца, который обучается. Наблюдаемой по умолчанию является \(Z^{\otimes n}\), т.е. четность.

[14]:
from qiskit_machine_learning.neural_networks import TwoLayerQNN
[15]:
# specify the number of qubits
num_qubits = 3
[16]:
# specify the feature map
fm = ZZFeatureMap(num_qubits, reps=2)
fm.draw(output='mpl')
[16]:
../_images/tutorials_01_neural_networks_20_0.png
[17]:
# specify the ansatz
ansatz = RealAmplitudes(num_qubits, reps=1)
ansatz.draw(output='mpl')
[17]:
../_images/tutorials_01_neural_networks_21_0.png
[18]:
# specify the observable
observable = PauliSumOp.from_list([('Z'*num_qubits, 1)])
print(observable)
1.0 * ZZZ
[19]:
# define two layer QNN
qnn3 = TwoLayerQNN(num_qubits,
                   feature_map=fm,
                   ansatz=ansatz,
                   observable=observable, quantum_instance=qi_sv)
[20]:
# define (random) input and weights
input3 = np.random.rand(qnn3.num_inputs)
weights3 = np.random.rand(qnn3.num_weights)
[21]:
# QNN forward pass
qnn3.forward(input3, weights3)
[21]:
array([[0.28520667]])
[22]:
# QNN backward pass
qnn3.backward(input3, weights3)
[22]:
(array([[[-0.2933431 , -0.78565729,  0.5416021 ]]]),
 array([[[-0.09093077,  0.02802006, -0.13559047,  0.1814619 ,
           0.11644461, -0.4073129 ]]]))

4. ` ` CircuitQNN ` `

В основе CircuitQNN лежит (параметризованная) QuantumCircuit. Она может принимать как входные, так и весовые параметры и производит выборки из измерений. Выборки могут быть интерпретированы как вероятности измерения целочисленного индекса, соответствующего битовой строке, или непосредственно как пакет двоичного вывода. В случае вероятностей градиенты могут быть оценены эффективно, а CircuitQNN обеспечивает также обратный проход. В случае выборок дифференцирование невозможно, и обратный проход возвращает (None, None).

Более того, CircuitQNN позволяет указать interpret (интерпретирующую) функцию для последующей обработки выборки. Предполагается, что она будет принимать измеренное целое число (из битовой строки) и преобразовывать его в новый индекс, т.е. неотрицательное целое число. В этом случае необходимо указать форму выходных данных, и вероятности будут распределены соответствующим образом.

CircuitQNN может быть настроен на возврат как разреженных, так и плотных векторов вероятности. Если не используется функция ``interpret““, размерность вектора вероятности экспоненциально растет с числом кубитов, поэтому обычно рекомендуется использовать разреженную рекомендацию. В случае ``interpret““ (интерпретирующей) функции это зависит от ожидаемого результата. Если, например, индекс сопоставляется с четностью соответствующей битовой строки, т.е. с 0 или 1, то имеет смысл плотный вывод, и результатом будет вектор вероятностей длины 2.

[23]:
from qiskit_machine_learning.neural_networks import CircuitQNN
[24]:
qc = RealAmplitudes(num_qubits, entanglement='linear', reps=1)
qc.draw(output='mpl')
[24]:
../_images/tutorials_01_neural_networks_29_0.png

4.1 Выходные данные: разреженные целочисленные вероятности

[25]:
# specify circuit QNN
qnn4 = CircuitQNN(qc, [], qc.parameters, sparse=True, quantum_instance=qi_qasm)
[26]:
# define (random) input and weights
input4 = np.random.rand(qnn4.num_inputs)
weights4 = np.random.rand(qnn4.num_weights)
[27]:
# QNN forward pass
qnn4.forward(input4, weights4).todense()  # returned as a sparse matrix
[27]:
array([[0.5, 0. , 0. , 0. , 0.3, 0. , 0. , 0.2]])
[28]:
# QNN backward pass, returns a tuple of sparse matrices
qnn4.backward(input4, weights4)
[28]:
(<COO: shape=(1, 8, 0), dtype=float64, nnz=0, fill_value=0.0>,
 <COO: shape=(1, 8, 6), dtype=float64, nnz=22, fill_value=0.0>)

4.1 Выходные данные: плотные четные вероятности

[29]:
# specify circuit QNN
parity = lambda x: '{:b}'.format(x).count('1') % 2
output_shape = 2  # this is required in case of a callable with dense output
qnn6 = CircuitQNN(qc, [], qc.parameters, sparse=False, interpret=parity, output_shape=output_shape,
                  quantum_instance=qi_qasm)
[30]:
# define (random) input and weights
input6 = np.random.rand(qnn6.num_inputs)
weights6 = np.random.rand(qnn6.num_weights)
[31]:
# QNN forward pass
qnn6.forward(input6, weights6)
[31]:
array([[0.8, 0.2]])
[32]:
# QNN backward pass
qnn6.backward(input6, weights6)
[32]:
(array([], shape=(1, 2, 0), dtype=float64),
 array([[[-1.00000000e-01,  5.55111512e-17, -5.00000000e-02,
           1.38777878e-17, -2.00000000e-01,  5.00000000e-02],
         [ 1.00000000e-01,  0.00000000e+00,  5.00000000e-02,
          -5.55111512e-17,  2.00000000e-01, -5.00000000e-02]]]))

4.3 Выходные данные: выборки

[33]:
# specify circuit QNN
qnn7 = CircuitQNN(qc, [], qc.parameters, sampling=True,
                  quantum_instance=qi_qasm)
[34]:
# define (random) input and weights
input7 = np.random.rand(qnn7.num_inputs)
weights7 = np.random.rand(qnn7.num_weights)
[35]:
# QNN forward pass, results in samples of measured bit strings mapped to integers
qnn7.forward(input7, weights7)
[35]:
array([[[4.],
        [4.],
        [7.],
        [1.],
        [7.],
        [4.],
        [4.],
        [4.],
        [0.],
        [0.]]])
[36]:
# QNN backward pass
qnn7.backward(input7, weights7)
[36]:
(None, None)

4.4 Выходные данные: четные выборки

[37]:
# specify circuit QNN
qnn8 = CircuitQNN(qc, [], qc.parameters, sampling=True, interpret=parity,
                  quantum_instance=qi_qasm)
[38]:
# define (random) input and weights
input8 = np.random.rand(qnn8.num_inputs)
weights8 = np.random.rand(qnn8.num_weights)
[39]:
# QNN forward pass, results in samples of measured bit strings
qnn8.forward(input8, weights8)
[39]:
array([[[1.],
        [0.],
        [1.],
        [0.],
        [0.],
        [0.],
        [0.],
        [0.],
        [0.],
        [0.]]])
[40]:
# QNN backward pass
qnn8.backward(input8, weights8)
[40]:
(None, None)
[41]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
QiskitNone
Terra0.17.0.dev0+346ffa8
Aer0.8.0
Ignis0.6.0.dev0+d6f1ad7
AquaNone
IBM Q Provider0.13.0.dev0+10f19e0
System information
Python3.8.8 (default, Feb 24 2021, 13:46:16) [Clang 10.0.0 ]
OSDarwin
CPUs6
Memory (Gb)16.0
Wed Mar 31 23:25:48 2021 CEST

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.

[ ]: