Korean
언어
English
Bengali
French
Hindi
Italian
Japanese
Korean
Malayalam
Russian
Spanish
Tamil
Turkish
Vietnamese
Shortcuts

참고

이 페이지는 docs/tutorials/01_neural_networks.ipynb 에서 생성되었다.

양자 신경망

이 노트북은 Qiskit Machine Learning에서 제공하는 여러 가지 QNN (일반적인 양자 신경망)을 시연한다. 네트워크는 애플리케이션에 구애받지 않는 컴퓨터적인 단위로써 다양한 예제에 사용될 수 있다 . 애플리케이션에 따라 특정 유형의 네트워크가 더 적합하거나 적합하지 않을 수 있으며, 경우에 따라 네트워크를 특별한 방식으로 설정해야 할 수도 있다. 이제 다음과 같은 다른 사용 가능한 신경망을 자세히 설명한다.

  1. NeuralNetwork : 신경망을 위한 인터페이스.

  2. OpflowQNN : 양자역학적 관측 수행을 기반으로 한 네트워크.

  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 은 학습 가능한 가중치를 저장하지 않는다. 다음은 이 인터페이스의 다양한 구현 예제가 소개한다.

NeuralNetworknn 이라 부르자. 그러면 nn.forward(input, weights) 경로는 데이터의 입력과 가중치를 nn.num_inputsnn.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\(n\) 큐비트에 작용하는 특별한 종류의 OpflowQNN 으로서 두 가지 요소로 구성되어 있다. 첫 번째는 데이터를 삽입하기 위한 feature map이고 두 번째는 훈련된 ansatz이다. 기본 관측값은 \(Z^{\otimes n}\), 즉 parity이다.

[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 에 기반으로 한다. 이것은 가중치뿐만 아니라 입력을 취할 수 있고, 측정을 통해 샘플을 생성할 수 있다. 샘플들은 비트열에 대응하는 정수 인덱스를 측정하는 확률 또는 이진 출력의 배치(batch) 로서 직접적으로 해석될 수 있다. 확률의 경우 기울기는 효율적으로 추정될 수 있고, CircuitQNN 은 역방향 경로 또한 제공된다. 샘플의 경우에는 미분이 가능하지 않으며 역방향 경로는 (None, None) 을 반환한다.

또한, CircuitQNN 은 샘플들을 후처리하기 위한 interpret 함수를 설정할 수 있다. 이것은 비트열에서 측정된 정수를 가져와 새로운 인덱스 (예를 들면, 음이 아닌 정수)에 mapping 하게 된다. 이 경우, 출력 형태가 제공되어야 하며 이에 따라 확률이 집계되어야 한다.

CircuitQNN 은 밀집 확률 벡터뿐만 아니라, 희소 확률 벡터를 반환하도록 조정될 수 있다. interpret 함수가 사용되지 않는 경우, 확률 벡터의 차원은 큐비트의 수에 지수적으로 비례하고, 보통 희소 방식이 권장된다. interpret 함수의 경우, 이는 기대되는 출력값에 의존한다. 예를 들어, 만약 index가 해당 비트열의 패리티에 mapping되었을 경우 (예를 들면 0 or 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.2 출력: 조밀한 패리티 확률

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

[ ]: