class TestTwoLayerQNN(QiskitMachineLearningTestCase):
    """Two Layer QNN Tests."""
    def setUp(self):
        super().setUp()

        # specify "run configuration"
        backend = Aer.get_backend('statevector_simulator')
        quantum_instance = QuantumInstance(backend)

        # define QNN
        feature_map = ZZFeatureMap(2)
        var_form = RealAmplitudes(2, reps=1)
        self.qnn = TwoLayerQNN(2,
                               feature_map=feature_map,
                               var_form=var_form,
                               quantum_instance=quantum_instance)

    def test_two_layer_qnn1(self):
        """ Opflow QNN Test """

        input_data = np.zeros(self.qnn.num_inputs)
        weights = np.zeros(self.qnn.num_weights)

        # test forward pass
        result = self.qnn.forward(input_data, weights)
        self.assertEqual(result.shape, (1, *self.qnn.output_shape))

        # test backward pass
        result = self.qnn.backward(input_data, weights)
        self.assertEqual(result[0].shape,
                         (1, *self.qnn.output_shape, self.qnn.num_inputs))
        self.assertEqual(result[1].shape,
                         (1, *self.qnn.output_shape, self.qnn.num_weights))
Esempio n. 2
0
    def __init__(self,
                 input_size: int,
                 hidden_size: int,
                 n_qubits: int = 4,
                 n_qlayers: int = 1,
                 batch_first=True,
                 backend='statevector_simulator'):
        super(QLSTM, self).__init__()

        self.input_size = input_size
        self.hidden_size = hidden_size
        self.concat_size = input_size + hidden_size
        self.n_qubits = n_qubits
        self.n_qlayers = n_qlayers
        self.batch_first = batch_first

        self.clayer_in = nn.Linear(self.concat_size, n_qubits)
        self.clayer_out = nn.Linear(self.n_qubits, self.hidden_size)

        self.qi = QuantumInstance(Aer.get_backend('statevector_simulator'))
        feature_map = ZZFeatureMap(self.n_qubits)
        ansatz = RealAmplitudes(self.n_qubits, reps=self.n_qlayers)

        self.qnn1 = TwoLayerQNN(self.n_qubits,
                                feature_map,
                                ansatz,
                                exp_val=AerPauliExpectation(),
                                quantum_instance=self.qi)
        self.qnn2 = TwoLayerQNN(self.n_qubits,
                                feature_map,
                                ansatz,
                                exp_val=AerPauliExpectation(),
                                quantum_instance=self.qi)
        self.qnn3 = TwoLayerQNN(self.n_qubits,
                                feature_map,
                                ansatz,
                                exp_val=AerPauliExpectation(),
                                quantum_instance=self.qi)
        self.qnn4 = TwoLayerQNN(self.n_qubits,
                                feature_map,
                                ansatz,
                                exp_val=AerPauliExpectation(),
                                quantum_instance=self.qi)

        self.qlayer = {
            'forget': TorchConnector(self.qnn1),
            'input': TorchConnector(self.qnn2),
            'update': TorchConnector(self.qnn3),
            'output': TorchConnector(self.qnn4)
        }
    def setUp(self):
        super().setUp()

        # specify "run configuration"
        backend = Aer.get_backend('statevector_simulator')
        quantum_instance = QuantumInstance(backend)

        # define QNN
        feature_map = ZZFeatureMap(2)
        var_form = RealAmplitudes(2, reps=1)
        self.qnn = TwoLayerQNN(2,
                               feature_map=feature_map,
                               var_form=var_form,
                               quantum_instance=quantum_instance)
    def setUp(self):
        super().setUp()

        # specify "run configuration"
        quantum_instance = QuantumInstance(StatevectorSimulator())

        # define QNN
        num_qubits = 2
        feature_map = ZZFeatureMap(num_qubits)
        ansatz = RealAmplitudes(num_qubits, reps=1)
        self.qnn = TwoLayerQNN(num_qubits, feature_map=feature_map,
                               ansatz=ansatz, quantum_instance=quantum_instance)

        self.qnn_no_qi = TwoLayerQNN(num_qubits, feature_map=feature_map,
                                     ansatz=ansatz)
Esempio n. 5
0
    def test_opflow_qnn_2_1(self, q_i):
        """ Test Torch Connector + Opflow QNN with input/output dimension 2/1."""

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

        # construct QNN
        qnn = TwoLayerQNN(2, quantum_instance=quantum_instance)
        try:
            model = TorchConnector(qnn)

            test_data = [
                Tensor(1),
                Tensor([1, 2]),
                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)
        except MissingOptionalLibraryError as ex:
            self.skipTest(str(ex))
    def test_opflow_qnn_2_1(self, q_i):
        """Test Torch Connector + Opflow QNN with input/output dimension 2/1."""
        from torch import Tensor

        if q_i == "sv":
            quantum_instance = self._sv_quantum_instance
        else:
            quantum_instance = self._qasm_quantum_instance

        # construct QNN
        qnn = TwoLayerQNN(2,
                          quantum_instance=quantum_instance,
                          input_gradients=True)
        model = TorchConnector(qnn)

        test_data = [
            Tensor([1]),
            Tensor([1, 2]),
            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 test_classifier_with_opflow_qnn(self, opt, loss, q_i, cb_flag):
        """Test Neural Network Classifier with Opflow QNN (Two Layer QNN)."""

        quantum_instance = self._create_quantum_instance(q_i)
        optimizer = self._create_optimizer(opt)
        callback, history = self._create_callback(cb_flag)

        num_inputs = 2
        ansatz = RealAmplitudes(num_inputs, reps=1)
        qnn = TwoLayerQNN(num_inputs, ansatz=ansatz, quantum_instance=quantum_instance)

        classifier = self._create_classifier(qnn, ansatz.num_parameters, optimizer, loss, callback)

        # construct data
        num_samples = 6
        X = algorithm_globals.random.random(  # pylint: disable=invalid-name
            (num_samples, num_inputs)
        )
        y = 2.0 * (np.sum(X, axis=1) <= 1) - 1.0

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

        # score
        score = classifier.score(X, y)
        self.assertGreater(score, 0.5)

        self._verify_callback_values(callback, history, qnn.num_weights)
Esempio n. 8
0
    def _create_opflow_qnn(self) -> TwoLayerQNN:
        num_inputs = 2

        # set up QNN
        qnn = TwoLayerQNN(
            num_qubits=num_inputs,
            quantum_instance=self._sv_quantum_instance,
            input_gradients=True,  # for hybrid qnn
        )
        return qnn
 def setUp(self):
     super().setUp()
     self._trainer_provider = FakeTorchTrainerRuntimeProvider()
     self._infer_provider = FakeTorchInferRuntimeProvider()
     self._backend = QasmSimulatorPy()
     # construct a simple qnn for unit tests
     param_x = Parameter("x")
     feature_map = QuantumCircuit(1, name="fm")
     feature_map.ry(param_x, 0)
     param_y = Parameter("y")
     ansatz = QuantumCircuit(1, name="vf")
     ansatz.ry(param_y, 0)
     self._qnn = TwoLayerQNN(1, feature_map, ansatz)
    def setUp(self):
        super().setUp()
        algorithm_globals.random_seed = 12345
        # specify "run configuration"
        quantum_instance = QuantumInstance(
            Aer.get_backend("aer_simulator_statevector"),
            seed_simulator=algorithm_globals.random_seed,
            seed_transpiler=algorithm_globals.random_seed,
        )

        # define QNN
        num_qubits = 2
        feature_map = ZZFeatureMap(num_qubits)
        ansatz = RealAmplitudes(num_qubits, reps=1)
        self.qnn = TwoLayerQNN(
            num_qubits,
            feature_map=feature_map,
            ansatz=ansatz,
            quantum_instance=quantum_instance,
        )

        self.qnn_no_qi = TwoLayerQNN(num_qubits,
                                     feature_map=feature_map,
                                     ansatz=ansatz)
    def test_save_load(self, qnn_type):
        """Tests save and load models."""
        features = np.array([[0, 0], [0.1, 0.2], [1, 1], [0.9, 0.8]])

        if qnn_type == "opflow":
            labels = np.array([-1, -1, 1, 1])

            num_qubits = 2
            ansatz = RealAmplitudes(num_qubits, reps=1)
            qnn = TwoLayerQNN(
                num_qubits, ansatz=ansatz, quantum_instance=self.qasm_quantum_instance
            )
            num_parameters = ansatz.num_parameters
        elif qnn_type == "circuit_qnn":
            labels = np.array([0, 0, 1, 1])
            qnn, _, num_parameters = self._create_circuit_qnn(self.qasm_quantum_instance)
        else:
            raise ValueError(f"Unsupported QNN type: {qnn_type}")

        classifier = self._create_classifier(
            qnn, num_parameters=num_parameters, optimizer=COBYLA(), loss="squared_error"
        )
        classifier.fit(features, labels)

        # predicted labels from the newly trained model
        test_features = np.array([[0.2, 0.1], [0.8, 0.9]])
        original_predicts = classifier.predict(test_features)

        # save/load, change the quantum instance and check if predicted values are the same
        with tempfile.TemporaryDirectory() as dir_name:
            file_name = os.path.join(dir_name, "classifier.model")
            classifier.save(file_name)

            classifier_load = NeuralNetworkClassifier.load(file_name)
            loaded_model_predicts = classifier_load.predict(test_features)

            np.testing.assert_array_almost_equal(original_predicts, loaded_model_predicts)

            # test loading warning
            class FakeModel(SerializableModelMixin):
                """Fake model class for test purposes."""

                pass

            with self.assertRaises(TypeError):
                FakeModel.load(file_name)
    def __init__(self, h, w, outputs):
        super(DQN, self).__init__()
        # We did a lot of experimentation with model sizes and types, so we decided to leave some
        # of our attempts here
        #1
        # self.conv1 = nn.Conv2d(1, 16, kernel_size=5, stride=2)
        # self.bn1 = nn.BatchNorm2d(16)
        # self.conv2 = nn.Conv2d(16, 32, kernel_size=5, stride=2)
        # self.bn2 = nn.BatchNorm2d(32)
        # self.conv3 = nn.Conv2d(32, 32, kernel_size=5, stride=2)
        # self.bn3 = nn.BatchNorm2d(32)

        #2
        # # Number of Linear input connections depends on output of conv2d layers
        # # and therefore the input image size, so compute it.
        # def conv2d_size_out(size, kernel_size = 5, stride = 2):
        #     return (size - (kernel_size - 1) - 1) // stride  + 1
        # convw = conv2d_size_out(conv2d_size_out(conv2d_size_out(w)))
        # convh = conv2d_size_out(conv2d_size_out(conv2d_size_out(h)))
        # linear_input_size = convw * convh * 32

        #3
        # self.conv1 = nn.Conv2d(1, 128, kernel_size=2, stride=1, padding=1)
        # self.bn1 = nn.BatchNorm2d(128)
        # self.conv2 = nn.Conv2d(128, 256, kernel_size=5, stride=1, padding=1)
        # self.bn2 = nn.BatchNorm2d(256)
        # self.fcl1 = nn.Linear(12544,5000)
        # self.fcl2 = nn.Linear(5000, 64)
        qi = QuantumInstance(Aer.get_backend('statevector_simulator'))

        feature_map = ZZFeatureMap(4)
        ansatz = RealAmplitudes(4, reps=1)
        qnn = TwoLayerQNN(4,
                          feature_map,
                          ansatz,
                          exp_val=AerPauliExpectation(),
                          quantum_instance=qi)

        #4
        # 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, 4)
        self.qnn = TorchConnector(qnn)
    def test_regressor_with_opflow_qnn(self, config):
        """ Test Neural Network Regressor with Opflow QNN (Two Layer QNN)."""
        opt, q_i = config

        num_qubits = 1
        # construct simple feature map
        param_x = Parameter('x')
        feature_map = QuantumCircuit(num_qubits, name='fm')
        feature_map.ry(param_x, 0)

        # construct simple feature map
        param_y = Parameter('y')
        var_form = QuantumCircuit(num_qubits, name='vf')
        var_form.ry(param_y, 0)

        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)

        # construct QNN
        regression_opflow_qnn = TwoLayerQNN(num_qubits,
                                            feature_map,
                                            var_form,
                                            quantum_instance=quantum_instance)

        # construct the regressor from the neural network
        regressor = NeuralNetworkRegressor(
            neural_network=regression_opflow_qnn,
            loss='l2',
            optimizer=optimizer)

        # fit to data
        regressor.fit(self.X, self.y)

        # score the result
        score = regressor.score(self.X, self.y)
        self.assertGreater(score, 0.5)
Esempio n. 14
0
    def test_opflow_qnn_1_1(self, q_i):
        """ Test Torch Connector + Opflow QNN with input/output dimension 1/1."""

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

        # 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 with statevector simulator
        qnn = TwoLayerQNN(1,
                          feature_map,
                          ansatz,
                          quantum_instance=quantum_instance)
        try:
            model = TorchConnector(qnn)

            test_data = [
                Tensor(1),
                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)
        except MissingOptionalLibraryError as ex:
            self.skipTest(str(ex))
    def test_opflow_qnn_1_1(self, q_i):
        """Test Torch Connector + Opflow QNN with input/output dimension 1/1."""
        from torch import Tensor

        if q_i == "sv":
            quantum_instance = self._sv_quantum_instance
        else:
            quantum_instance = self._qasm_quantum_instance

        # 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 with statevector simulator
        qnn = TwoLayerQNN(1,
                          feature_map,
                          ansatz,
                          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]]]),
        ]

        # test model
        self._validate_output_shape(model, test_data)
        if q_i == "sv":
            self._validate_backward_pass(model)
    def test_save_load(self):
        """Tests save and load models."""
        features = np.array([[0, 0], [0.1, 0.1], [0.4, 0.4], [1, 1]])
        labels = np.array([0, 0.1, 0.4, 1])
        num_inputs = 2
        qnn = TwoLayerQNN(
            num_inputs,
            feature_map=ZZFeatureMap(num_inputs),
            ansatz=RealAmplitudes(num_inputs),
            observable=PauliSumOp.from_list([("Z" * num_inputs, 1)]),
            quantum_instance=self.qasm_quantum_instance,
        )
        regressor = NeuralNetworkRegressor(qnn, optimizer=COBYLA())
        regressor.fit(features, labels)

        # predicted labels from the newly trained model
        test_features = np.array([[0.5, 0.5]])
        original_predicts = regressor.predict(test_features)

        # save/load, change the quantum instance and check if predicted values are the same
        with tempfile.TemporaryDirectory() as dir_name:
            file_name = os.path.join(dir_name, "regressor.model")
            regressor.save(file_name)

            regressor_load = NeuralNetworkRegressor.load(file_name)
            loaded_model_predicts = regressor_load.predict(test_features)

            np.testing.assert_array_almost_equal(original_predicts,
                                                 loaded_model_predicts)

            # test loading warning
            class FakeModel(SerializableModelMixin):
                """Fake model class for test purposes."""

                pass

            with self.assertRaises(TypeError):
                FakeModel.load(file_name)
    def test_classifier_with_opflow_qnn(self, config):
        """ Test Neural Network Classifier with Opflow QNN (Two Layer QNN)."""

        opt, loss, 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)

        num_inputs = 2
        ansatz = RealAmplitudes(num_inputs, reps=1)
        qnn = TwoLayerQNN(num_inputs,
                          ansatz=ansatz,
                          quantum_instance=quantum_instance)

        classifier = NeuralNetworkClassifier(qnn,
                                             optimizer=optimizer,
                                             loss=loss)

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

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

        # score
        score = classifier.score(X, y)
        self.assertGreater(score, 0.5)
Esempio n. 18
0
    def test_batch_gradients(self):
        """Test backward pass for batch input."""

        # construct random data set
        num_inputs = 2
        num_samples = 10
        x = np.random.rand(num_samples, num_inputs)

        # set up QNN
        qnn = TwoLayerQNN(num_qubits=num_inputs,
                          quantum_instance=self.sv_quantum_instance)

        # set up PyTorch module
        initial_weights = np.random.rand(qnn.num_weights)
        model = TorchConnector(qnn, initial_weights=initial_weights)

        # test single gradient
        w = model.weights.detach().numpy()
        res_qnn = qnn.forward(x[0, :], w)

        # construct finite difference gradient for weights
        eps = 1e-4
        grad = np.zeros(w.shape)
        for k in range(len(w)):
            delta = np.zeros(w.shape)
            delta[k] += eps

            f_1 = qnn.forward(x[0, :], w + delta)
            f_2 = qnn.forward(x[0, :], w - delta)

            grad[k] = (f_1 - f_2) / (2 * eps)

        grad_qnn = qnn.backward(x[0, :], w)[1][0, 0, :]
        self.assertAlmostEqual(np.linalg.norm(grad - grad_qnn), 0.0, places=4)

        model.zero_grad()
        res_model = model(Tensor(x[0, :]))
        self.assertAlmostEqual(np.linalg.norm(res_model.detach().numpy() -
                                              res_qnn[0]),
                               0.0,
                               places=4)
        res_model.backward()
        grad_model = model.weights.grad
        self.assertAlmostEqual(np.linalg.norm(grad_model.detach().numpy() -
                                              grad_qnn),
                               0.0,
                               places=4)

        # test batch input
        batch_grad = np.zeros((*w.shape, num_samples, 1))
        for k in range(len(w)):
            delta = np.zeros(w.shape)
            delta[k] += eps

            f_1 = qnn.forward(x, w + delta)
            f_2 = qnn.forward(x, w - delta)

            batch_grad[k] = (f_1 - f_2) / (2 * eps)

        batch_grad = np.sum(batch_grad, axis=1)
        batch_grad_qnn = np.sum(qnn.backward(x, w)[1], axis=0)
        self.assertAlmostEqual(np.linalg.norm(batch_grad -
                                              batch_grad_qnn.transpose()),
                               0.0,
                               places=4)

        model.zero_grad()
        batch_res_model = sum(model(Tensor(x)))
        batch_res_model.backward()
        self.assertAlmostEqual(np.linalg.norm(model.weights.grad.numpy() -
                                              batch_grad.transpose()[0]),
                               0.0,
                               places=4)
Esempio n. 19
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
    def test_regressor_with_opflow_qnn(self, config):
        """Test Neural Network Regressor with Opflow QNN (Two Layer QNN)."""
        opt, q_i, cb_flag = config

        num_qubits = 1
        # construct simple feature map
        param_x = Parameter("x")
        feature_map = QuantumCircuit(num_qubits, name="fm")
        feature_map.ry(param_x, 0)

        # construct simple feature map
        param_y = Parameter("y")
        ansatz = QuantumCircuit(num_qubits, name="vf")
        ansatz.ry(param_y, 0)

        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)
        elif opt == "cobyla":
            optimizer = COBYLA(maxiter=25)
        else:
            optimizer = None

        if cb_flag is True:
            history = {"weights": [], "values": []}

            def callback(objective_weights, objective_value):
                history["weights"].append(objective_weights)
                history["values"].append(objective_value)

        else:
            callback = None

        # construct QNN
        regression_opflow_qnn = TwoLayerQNN(num_qubits,
                                            feature_map,
                                            ansatz,
                                            quantum_instance=quantum_instance)

        initial_point = np.zeros(ansatz.num_parameters)

        # construct the regressor from the neural network
        regressor = NeuralNetworkRegressor(
            neural_network=regression_opflow_qnn,
            loss="squared_error",
            optimizer=optimizer,
            initial_point=initial_point,
            callback=callback,
        )

        # fit to data
        regressor.fit(self.X, self.y)

        # score the result
        score = regressor.score(self.X, self.y)
        self.assertGreater(score, 0.5)

        # callback
        if callback is not None:
            self.assertTrue(
                all(isinstance(value, float) for value in history["values"]))
            for weights in history["weights"]:
                self.assertEqual(len(weights),
                                 regression_opflow_qnn.num_weights)
                self.assertTrue(
                    all(isinstance(weight, float) for weight in weights))
class TestTwoLayerQNN(QiskitMachineLearningTestCase):
    """Two Layer QNN Tests."""

    def setUp(self):
        super().setUp()

        # specify "run configuration"
        quantum_instance = QuantumInstance(StatevectorSimulator())

        # define QNN
        num_qubits = 2
        feature_map = ZZFeatureMap(num_qubits)
        ansatz = RealAmplitudes(num_qubits, reps=1)
        self.qnn = TwoLayerQNN(num_qubits, feature_map=feature_map,
                               ansatz=ansatz, quantum_instance=quantum_instance)

        self.qnn_no_qi = TwoLayerQNN(num_qubits, feature_map=feature_map,
                                     ansatz=ansatz)

    @data(
        "qi",
        "no_qi"
    )
    def test_qnn_simple_new(self, qnn_type: str):
        """Simple Opflow QNN Test for a specified neural network."""

        input_data = np.zeros(self.qnn.num_inputs)
        weights = np.zeros(self.qnn.num_weights)

        if qnn_type == "qi":
            qnn = self.qnn
        else:
            qnn = self.qnn_no_qi

        # test forward pass
        result = qnn.forward(input_data, weights)
        self.assertEqual(result.shape, (1, *self.qnn.output_shape))

        # test backward pass
        result = self.qnn.backward(input_data, weights)
        # batch dimension of 1
        self.assertEqual(result[0].shape, (1, *self.qnn.output_shape, self.qnn.num_inputs))
        self.assertEqual(result[1].shape, (1, *self.qnn.output_shape, self.qnn.num_weights))

    @data(
        "qi",
        "no_qi"
    )
    def _test_qnn_batch(self, qnn_type: str):
        """Batched Opflow QNN Test for the specified network."""
        batch_size = 10

        input_data = np.arange(batch_size * self.qnn.num_inputs)\
            .reshape((batch_size, self.qnn.num_inputs))
        weights = np.zeros(self.qnn.num_weights)

        if qnn_type == "qi":
            qnn = self.qnn
        else:
            qnn = self.qnn_no_qi

        # test forward pass
        result = qnn.forward(input_data, weights)
        self.assertEqual(result.shape, (batch_size, *self.qnn.output_shape))

        # test backward pass
        result = self.qnn.backward(input_data, weights)
        self.assertEqual(result[0].shape,
                         (batch_size, *self.qnn.output_shape, self.qnn.num_inputs))
        self.assertEqual(result[1].shape,
                         (batch_size, *self.qnn.output_shape, self.qnn.num_weights))