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" 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)
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)
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 _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() # 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() 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 __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_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 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)
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_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_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_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)
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)
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))