def test_circuit_qnn_without_parameters(self):
        """Tests CircuitQNN without parameters."""
        quantum_instance = self._sv_quantum_instance
        qc = QuantumCircuit(2)
        param_y = Parameter("y")
        qc.ry(param_y, range(2))

        qnn = CircuitQNN(
            circuit=qc,
            input_params=[param_y],
            sparse=False,
            quantum_instance=quantum_instance,
            input_gradients=True,
        )
        model = TorchConnector(qnn)
        self._validate_backward_pass(model)

        qnn = CircuitQNN(
            circuit=qc,
            weight_params=[param_y],
            sparse=False,
            quantum_instance=quantum_instance,
            input_gradients=True,
        )
        model = TorchConnector(qnn)
        self._validate_backward_pass(model)
    def _get_qnn(self, sparse, sampling, quantum_instance_type, interpret_id):
        """Construct QNN from configuration."""

        # get quantum instance
        if quantum_instance_type == STATEVECTOR:
            quantum_instance = self.quantum_instance_sv
        elif quantum_instance_type == QASM:
            quantum_instance = self.quantum_instance_qasm
        elif quantum_instance_type == CUSTOM_PASS_MANAGERS:
            quantum_instance = self.quantum_instance_pm
        else:
            quantum_instance = None

        # get interpret setting
        interpret = None
        output_shape = None
        if interpret_id == 1:
            interpret = self.interpret_1d
            output_shape = self.output_shape_1d
        elif interpret_id == 2:
            interpret = self.interpret_2d
            output_shape = self.output_shape_2d

        # construct QNN
        qnn = CircuitQNN(
            self.qc,
            self.input_params,
            self.weight_params,
            sparse=sparse,
            sampling=sampling,
            interpret=interpret,
            output_shape=output_shape,
            quantum_instance=quantum_instance,
        )
        return qnn
    def get_qnn(self, sparse, sampling, statevector, interpret_id):
        """ Construct QNN from configuration. """

        # get quantum instance
        if statevector:
            quantum_instance = self.quantum_instance_sv
        else:
            quantum_instance = self.quantum_instance_qasm

        # get interpret setting
        interpret = None
        output_shape = None
        if interpret_id == 1:
            interpret = self.interpret_1d
            output_shape = self.output_shape_1d
        elif interpret_id == 2:
            interpret = self.interpret_2d
            output_shape = self.output_shape_2d

        # construct QNN
        qnn = CircuitQNN(self.qc, self.input_params, self.weight_params,
                         sparse=sparse, sampling=sampling,
                         interpret=interpret, output_shape=output_shape,
                         quantum_instance=quantum_instance)
        return qnn
Ejemplo n.º 4
0
    def __init__(self, h, w, outputs):
        super(DQN, self).__init__()

        qi = QuantumInstance(Aer.get_backend('statevector_simulator'))

        num_inputs=4

        feature_map = ZZFeatureMap(num_inputs)
        ansatz = RealAmplitudes(num_inputs, entanglement='linear', reps=1)

        qc = QuantumCircuit(num_inputs)
        qc.append(feature_map, range(num_inputs))
        qc.append(ansatz, range(num_inputs))

        parity = lambda x: '{:b}'.format(x).count('1') % num_inputs
        output_shape =num_inputs # parity = 0, 1

        qnn = CircuitQNN(qc, input_params=feature_map.parameters, weight_params=ansatz.parameters,
                interpret=parity, output_shape=output_shape, quantum_instance=qi)

        #set up PyTorch Module
        initial_weights = 0.1*(2*np.random.rand(qnn.num_weights) - 1)

        # Our final network choice. It is wide enough to capture a lot of detail but not too
        # large to have problems with vanishing gradients on such a small sample size
        self.conv1 = nn.Conv2d(1, 256, kernel_size=2, stride=1, padding=1)
        self.bn1 = nn.BatchNorm2d(256)
        self.fcl1 = nn.Linear(20736,10000)
        self.fcl2 = nn.Linear(10000, num_inputs)
        self.qnn = TorchConnector(qnn, initial_weights)
Ejemplo n.º 5
0
    def test_circuit_qnn_sampling(self, interpret):
        """Test Torch Connector + Circuit QNN for sampling."""

        qc = QuantumCircuit(2)

        # construct simple feature map
        param_x1, param_x2 = Parameter('x1'), Parameter('x2')
        qc.ry(param_x1, range(2))
        qc.ry(param_x2, range(2))

        # construct simple feature map
        param_y = Parameter('y')
        qc.ry(param_y, range(2))

        qnn = CircuitQNN(qc, [param_x1, param_x2], [param_y],
                         sparse=False,
                         sampling=True,
                         interpret=interpret,
                         output_shape=None,
                         quantum_instance=self.qasm_quantum_instance)
        model = TorchConnector(qnn)

        test_data = [Tensor([2, 2]), Tensor([[1, 1], [2, 2]])]
        for i, x in enumerate(test_data):
            if i == 0:
                self.assertEqual(model(x).shape, qnn.output_shape)
            else:
                shape = model(x).shape
                self.assertEqual(shape, (len(x), *qnn.output_shape))
    def _create_circuit_qnn(self, quantum_instance: QuantumInstance) -> Tuple[CircuitQNN, int, int]:
        num_inputs = 2
        feature_map = ZZFeatureMap(num_inputs)
        ansatz = RealAmplitudes(num_inputs, reps=1)

        # construct circuit
        qc = QuantumCircuit(num_inputs)
        qc.append(feature_map, range(2))
        qc.append(ansatz, range(2))

        # construct qnn
        def parity(x):
            return f"{x:b}".count("1") % 2

        output_shape = 2
        qnn = CircuitQNN(
            qc,
            input_params=feature_map.parameters,
            weight_params=ansatz.parameters,
            sparse=False,
            interpret=parity,
            output_shape=output_shape,
            quantum_instance=quantum_instance,
        )

        return qnn, num_inputs, ansatz.num_parameters
    def test_classifier_with_circuit_qnn_and_cross_entropy(self, config):
        """ Test Neural Network Classifier with Circuit QNN and Cross Entropy loss."""

        opt, q_i = config

        if q_i == 'statevector':
            quantum_instance = self.sv_quantum_instance
        else:
            quantum_instance = self.qasm_quantum_instance

        if opt == 'bfgs':
            optimizer = L_BFGS_B(maxiter=5)
        else:
            optimizer = COBYLA(maxiter=25)

        loss = CrossEntropyLoss()

        num_inputs = 2
        feature_map = ZZFeatureMap(num_inputs)
        ansatz = RealAmplitudes(num_inputs, reps=1)

        # construct circuit
        qc = QuantumCircuit(num_inputs)
        qc.append(feature_map, range(2))
        qc.append(ansatz, range(2))

        # construct qnn
        def parity(x):
            return '{:b}'.format(x).count('1') % 2

        output_shape = 2
        qnn = CircuitQNN(qc,
                         input_params=feature_map.parameters,
                         weight_params=ansatz.parameters,
                         sparse=False,
                         interpret=parity,
                         output_shape=output_shape,
                         quantum_instance=quantum_instance)

        # construct classifier - note: CrossEntropy requires eval_probabilities=True!
        classifier = NeuralNetworkClassifier(qnn,
                                             optimizer=optimizer,
                                             loss=loss,
                                             one_hot=True)

        # construct data
        num_samples = 5
        X = np.random.rand(num_samples, num_inputs)  # pylint: disable=invalid-name
        y = 1.0 * (np.sum(X, axis=1) <= 1)
        y = np.array([y, 1 - y]).transpose()

        # fit to data
        classifier.fit(X, y)

        # score
        score = classifier.score(X, y)
        self.assertGreater(score, 0.5)
    def test_circuit_qnn_2_4(self, config):
        """Torch Connector + Circuit QNN with no interpret, dense output,
        and input/output shape 1/8 ."""
        from torch import Tensor

        interpret, output_shape, sparse, q_i = config
        if sparse and not _optionals.HAS_SPARSE:
            self.skipTest("sparse library is required to run this test")
            return
        if q_i == "sv":
            quantum_instance = self._sv_quantum_instance
        else:
            quantum_instance = self._qasm_quantum_instance

        qc = QuantumCircuit(2)

        # construct simple feature map
        param_x_1, param_x_2 = Parameter("x1"), Parameter("x2")
        qc.ry(param_x_1, range(2))
        qc.ry(param_x_2, range(2))

        # construct simple feature map
        param_y = Parameter("y")
        qc.ry(param_y, range(2))

        qnn = CircuitQNN(
            qc,
            [param_x_1, param_x_2],
            [param_y],
            sparse=sparse,
            sampling=False,
            interpret=interpret,
            output_shape=output_shape,
            quantum_instance=quantum_instance,
            input_gradients=True,
        )
        model = TorchConnector(qnn)

        test_data = [
            Tensor([1]),
            Tensor([1, 2]),
            Tensor([[1], [2]]),
            Tensor([[1, 2], [3, 4]]),
            Tensor([[[1], [2]], [[3], [4]]]),
        ]

        # test model
        self._validate_output_shape(model, test_data)
        if q_i == "sv":
            self._validate_backward_pass(model)
    def test_warning1_circuit_qnn(self, config):
        """Circuit QNN with no sampling and input/output shape 1/1 ."""

        interpret, output_shape, sparse, q_i = config
        if sparse and not _optionals.HAS_SPARSE:
            self.skipTest("sparse library is required to run this test")
            return

        if q_i == "sv":
            quantum_instance = self.quantum_instance_sv
        elif q_i == "qasm":
            quantum_instance = self.quantum_instance_qasm
        else:
            raise ValueError("Unsupported quantum instance")

        qc = QuantumCircuit(1)

        # construct simple feature map
        param_x = Parameter("x")
        qc.ry(param_x, 0)

        # construct simple feature map
        param_y = Parameter("y")
        qc.ry(param_y, 0)

        # check warning when output_shape defined without interpret
        with self.assertLogs(level="WARNING") as w_1:
            CircuitQNN(
                qc,
                [param_x],
                [param_y],
                sparse=sparse,
                sampling=False,
                interpret=interpret,
                output_shape=output_shape,
                quantum_instance=quantum_instance,
                input_gradients=True,
            )
            self.assertEqual(
                w_1.output,
                [
                    "WARNING:qiskit_machine_learning.neural_networks.circuit_qnn:No "
                    "interpret function given, output_shape will be automatically "
                    "determined as 2^num_qubits."
                ],
            )
Ejemplo n.º 10
0
    def test_circuit_qnn_2_4(self, config):
        """Torch Connector + Circuit QNN with no interpret, dense output,
        and input/output shape 1/8 ."""

        interpret, output_shape, sparse, q_i = config
        if q_i == 'sv':
            quantum_instance = self.sv_quantum_instance
        else:
            quantum_instance = self.qasm_quantum_instance

        qc = QuantumCircuit(2)

        # construct simple feature map
        param_x_1, param_x_2 = Parameter('x1'), Parameter('x2')
        qc.ry(param_x_1, range(2))
        qc.ry(param_x_2, range(2))

        # construct simple feature map
        param_y = Parameter('y')
        qc.ry(param_y, range(2))

        qnn = CircuitQNN(qc, [param_x_1, param_x_2], [param_y],
                         sparse=sparse,
                         sampling=False,
                         interpret=interpret,
                         output_shape=output_shape,
                         quantum_instance=quantum_instance)
        try:
            model = TorchConnector(qnn)

            test_data = [
                Tensor(1),
                Tensor([1, 2]),
                Tensor([[1], [2]]),
                Tensor([[1, 2], [3, 4]]),
                Tensor([[[1], [2]], [[3], [4]]])
            ]

            # test model
            self.validate_output_shape(model, test_data)
            if q_i == 'sv':
                self.validate_backward_pass(model)
        except MissingOptionalLibraryError as ex:
            self.skipTest(str(ex))
    def test_warning2_circuit_qnn(self, config):
        """Torch Connector + Circuit QNN with sampling and input/output shape 1/1 ."""

        interpret, output_shape, sparse, q_i = config
        if q_i == "sv":
            quantum_instance = self.quantum_instance_sv
        elif q_i == "qasm":
            quantum_instance = self.quantum_instance_qasm
        else:
            raise ValueError("Unsupported quantum instance")

        qc = QuantumCircuit(2)

        # construct simple feature map
        param_x = Parameter("x")
        qc.ry(param_x, 0)

        # construct simple feature map
        param_y = Parameter("y")
        qc.ry(param_y, 0)

        # check warning when sampling true
        with self.assertLogs(level="WARNING") as w_2:
            CircuitQNN(
                qc,
                [param_x],
                [param_y],
                sparse=sparse,
                sampling=True,
                interpret=interpret,
                output_shape=output_shape,
                quantum_instance=quantum_instance,
                input_gradients=True,
            )

            self.assertEqual(
                w_2.output,
                [
                    "WARNING:qiskit_machine_learning.neural_networks.circuit_qnn:"
                    "In sampling mode, output_shape will be automatically inferred "
                    "from the number of samples and interpret function, if provided."
                ],
            )
Ejemplo n.º 12
0
    def _create_circuit_qnn(self) -> CircuitQNN:
        output_shape, interpret = 2, lambda x: f"{x:b}".count("1") % 2
        num_inputs = 2

        feature_map = ZZFeatureMap(num_inputs)
        ansatz = RealAmplitudes(num_inputs, entanglement="linear", reps=1)

        qc = QuantumCircuit(num_inputs)
        qc.append(feature_map, range(num_inputs))
        qc.append(ansatz, range(num_inputs))

        qnn = CircuitQNN(
            qc,
            input_params=feature_map.parameters,
            weight_params=ansatz.parameters,
            input_gradients=True,  # for hybrid qnn
            interpret=interpret,
            output_shape=output_shape,
            quantum_instance=self._sv_quantum_instance,
        )
        return qnn
Ejemplo n.º 13
0
    def test_circuit_qnn_1_8(self, config):
        """Torch Connector + Circuit QNN with no interpret, dense output,
        and input/output shape 1/8 ."""

        interpret, output_shape, sparse, q_i = config
        if q_i == 'sv':
            quantum_instance = self.sv_quantum_instance
        else:
            quantum_instance = self.qasm_quantum_instance

        qc = QuantumCircuit(3)

        # construct simple feature map
        param_x = Parameter('x')
        qc.ry(param_x, range(3))

        # construct simple feature map
        param_y = Parameter('y')
        qc.ry(param_y, range(3))

        qnn = CircuitQNN(qc, [param_x], [param_y],
                         sparse=sparse,
                         sampling=False,
                         interpret=interpret,
                         output_shape=output_shape,
                         quantum_instance=quantum_instance)
        model = TorchConnector(qnn)

        test_data = [
            Tensor(1),
            Tensor([1, 2]),
            Tensor([[1], [2]]),
            Tensor([[[1], [2]], [[3], [4]]])
        ]

        # test model
        self.validate_output_shape(model, test_data)
        if q_i == 'sv':
            self.validate_backward_pass(model)
def main(args):

    # Load the data
    data, __ = titanic()
    X_train, y_train, X_test, y_test = parse_data_train_vqc(
        data, split_ratio=args.split_ratio)

    quantum_instance = QuantumInstance(
        Aer.get_backend('statevector_simulator'), shots=100)
    optimizer = COBYLA(maxiter=100)
    feature_map = ZZFeatureMap(feature_dimension=X_train.shape[1], reps=1)
    ansatz = RealAmplitudes(num_qubits=feature_map._num_qubits, reps=1)

    qc = QuantumCircuit(feature_map._num_qubits)
    qc.compose(feature_map, inplace=True)
    qc.compose(ansatz, inplace=True)

    qnn = CircuitQNN(circuit=qc,
                     input_params=feature_map.parameters,
                     weight_params=ansatz.parameters,
                     sparse=False,
                     sampling=False,
                     interpret=parity,
                     output_shape=len(np.unique(y_train, axis=0)),
                     gradient=None,
                     quantum_instance=quantum_instance)

    cc = NeuralNetworkClassifier(neural_network=qnn, optimizer=optimizer)

    # Train the model
    cc.fit(X_train, y_train)

    # Model accuracy
    acc_train = cc.score(X_train, y_train)
    acc_test = cc.score(X_test, y_test)
    print("Accuracy on training dataset: {}.".format(acc_train))
    print("Accuracy on testing dataset: {}.".format(acc_test))
    def _verify_qnn(
        self,
        qnn: CircuitQNN,
        quantum_instance_type: str,
        batch_size: int,
    ) -> None:
        """
        Verifies that a QNN functions correctly

        Args:
            qnn: a QNN to check
            quantum_instance_type:
            batch_size:

        Returns:
            None.
        """
        # pylint: disable=import-error
        from sparse import SparseArray

        input_data = np.zeros((batch_size, qnn.num_inputs))
        weights = np.zeros(qnn.num_weights)

        # if sampling and statevector, make sure it fails
        if quantum_instance_type == STATEVECTOR and qnn.sampling:
            with self.assertRaises(QiskitMachineLearningError):
                qnn.forward(input_data, weights)
        else:
            # evaluate QNN forward pass
            result = qnn.forward(input_data, weights)

            # make sure forward result is sparse if it should be
            if qnn.sparse and not qnn.sampling:
                self.assertTrue(isinstance(result, SparseArray))
            else:
                self.assertTrue(isinstance(result, np.ndarray))

            # check forward result shape
            self.assertEqual(result.shape, (batch_size, *qnn.output_shape))

            input_grad, weights_grad = qnn.backward(input_data, weights)
            if qnn.sampling:
                self.assertIsNone(input_grad)
                self.assertIsNone(weights_grad)
            else:
                self.assertIsNone(input_grad)
                self.assertEqual(
                    weights_grad.shape,
                    (batch_size, *qnn.output_shape, qnn.num_weights))

            # verify that input gradients are None if turned off
            qnn.input_gradients = True
            input_grad, weights_grad = qnn.backward(input_data, weights)
            if qnn.sampling:
                self.assertIsNone(input_grad)
                self.assertIsNone(weights_grad)
            else:
                self.assertEqual(
                    input_grad.shape,
                    (batch_size, *qnn.output_shape, qnn.num_inputs))
                self.assertEqual(
                    weights_grad.shape,
                    (batch_size, *qnn.output_shape, qnn.num_weights))
    def test_circuit_qnn_batch_gradients(self, config):
        """Test batch gradient computation of CircuitQNN gives the same result as the sum of
        individual gradients."""
        import torch
        from torch.nn import MSELoss
        from torch.optim import SGD

        output_shape, interpret = config
        num_inputs = 2

        feature_map = ZZFeatureMap(num_inputs)
        ansatz = RealAmplitudes(num_inputs, entanglement="linear", reps=1)

        qc = QuantumCircuit(num_inputs)
        qc.append(feature_map, range(num_inputs))
        qc.append(ansatz, range(num_inputs))

        qnn = CircuitQNN(
            qc,
            input_params=feature_map.parameters,
            weight_params=ansatz.parameters,
            interpret=interpret,
            output_shape=output_shape,
            quantum_instance=self._sv_quantum_instance,
        )

        # set up PyTorch module
        initial_weights = np.array([0.1] * qnn.num_weights)
        model = TorchConnector(qnn, initial_weights)
        model.to(self._device)

        # random data set
        x = torch.rand(5, 2)
        y = torch.rand(5, output_shape)

        # define optimizer and loss
        optimizer = SGD(model.parameters(), lr=0.1)
        f_loss = MSELoss(reduction="sum")

        sum_of_individual_losses = 0.0
        for x_i, y_i in zip(x, y):
            x_i = x_i.to(self._device)
            y_i = y_i.to(self._device)
            output = model(x_i)
            sum_of_individual_losses += f_loss(output, y_i)
        optimizer.zero_grad()
        sum_of_individual_losses.backward()
        sum_of_individual_gradients = model.weight.grad.detach().cpu()

        x = x.to(self._device)
        y = y.to(self._device)
        output = model(x)
        batch_loss = f_loss(output, y)
        optimizer.zero_grad()
        batch_loss.backward()
        batch_gradients = model.weight.grad.detach().cpu()

        self.assertAlmostEqual(np.linalg.norm(sum_of_individual_gradients -
                                              batch_gradients),
                               0.0,
                               places=4)

        self.assertAlmostEqual(
            sum_of_individual_losses.detach().cpu().numpy(),
            batch_loss.detach().cpu().numpy(),
            places=4,
        )
Ejemplo n.º 17
0
    def setUp(self):
        super().setUp()

        algorithm_globals.random_seed = 1234
        qi_sv = QuantumInstance(
            Aer.get_backend("aer_simulator_statevector"),
            seed_simulator=algorithm_globals.random_seed,
            seed_transpiler=algorithm_globals.random_seed,
        )

        # set up quantum neural networks
        num_qubits = 3
        feature_map = ZFeatureMap(feature_dimension=num_qubits, reps=1)
        ansatz = RealAmplitudes(num_qubits, reps=1)

        # CircuitQNNs
        qc = QuantumCircuit(num_qubits)
        qc.append(feature_map, range(num_qubits))
        qc.append(ansatz, range(num_qubits))

        def parity(x):
            return f"{x:b}".count("1") % 2

        circuit_qnn_1 = CircuitQNN(
            qc,
            input_params=feature_map.parameters,
            weight_params=ansatz.parameters,
            interpret=parity,
            output_shape=2,
            sparse=False,
            quantum_instance=qi_sv,
        )

        # qnn2 for checking result without parity
        circuit_qnn_2 = CircuitQNN(
            qc,
            input_params=feature_map.parameters,
            weight_params=ansatz.parameters,
            sparse=False,
            quantum_instance=qi_sv,
        )

        # OpflowQNN
        observable = PauliSumOp.from_list([("Z" * num_qubits, 1)])
        opflow_qnn = TwoLayerQNN(
            num_qubits,
            feature_map=feature_map,
            ansatz=ansatz,
            observable=observable,
            quantum_instance=qi_sv,
        )

        self.qnns = {
            "circuit1": circuit_qnn_1,
            "circuit2": circuit_qnn_2,
            "opflow": opflow_qnn
        }

        # define sample numbers
        self.n_list = [
            5000, 8000, 10000, 40000, 60000, 100000, 150000, 200000, 500000,
            1000000
        ]
        self.n = 5000