From b67c7f8b7fd7334cf1884b061754f60a25e02371 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 28 May 2020 06:22:12 +0000 Subject: [PATCH 01/52] Implement rotosolve optimizers --- tensorflow_quantum/python/optimizers/BUILD | 6 + .../python/optimizers/__init__.py | 22 ++ .../python/optimizers/rotosolve_minimizer.py | 284 ++++++++++++++++++ .../optimizers/rotosolve_minimizer_test.py | 80 +++++ tensorflow_quantum/python/optimizers/utils.py | 103 +++++++ .../python/optimizers/utils_test.py | 57 ++++ 6 files changed, 552 insertions(+) create mode 100755 tensorflow_quantum/python/optimizers/BUILD create mode 100755 tensorflow_quantum/python/optimizers/__init__.py create mode 100755 tensorflow_quantum/python/optimizers/rotosolve_minimizer.py create mode 100755 tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py create mode 100755 tensorflow_quantum/python/optimizers/utils.py create mode 100755 tensorflow_quantum/python/optimizers/utils_test.py diff --git a/tensorflow_quantum/python/optimizers/BUILD b/tensorflow_quantum/python/optimizers/BUILD new file mode 100755 index 000000000..fd4e75c2e --- /dev/null +++ b/tensorflow_quantum/python/optimizers/BUILD @@ -0,0 +1,6 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +# Export for the PIP package. +exports_files(["__init__.py"]) diff --git a/tensorflow_quantum/python/optimizers/__init__.py b/tensorflow_quantum/python/optimizers/__init__.py new file mode 100755 index 000000000..644762ce6 --- /dev/null +++ b/tensorflow_quantum/python/optimizers/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2020 The TensorFlow Quantum Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Module definitions for tensorflow_quantum.python.optimizers.*""" + +# Quantum circuit specific optimizers. +from tensorflow_quantum.python.optimizers.rotosolve_minimizer import ( + minimize as rotosolve_minimize) + +# Utils for optimizers. +from tensorflow_quantum.python.optimizers.utils import (function_factory) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py new file mode 100755 index 000000000..aba90ff65 --- /dev/null +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -0,0 +1,284 @@ +# Copyright 2020 The TensorFlow Quantum Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""The rotosolve minimization algorithm +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import math +import collections +import tensorflow as tf + + +def prefer_static_shape(x): + """Return static shape of tensor `x` if available, + else `tf.shape(x)`. + Args: + x: `Tensor` (already converted). + Returns: + Numpy array (if static shape is obtainable), else `Tensor`. + """ + return prefer_static_value(tf.shape(x)) + + +def prefer_static_value(x): + """Return static value of tensor `x` if available, else `x`. + Args: + x: `Tensor` (already converted). + Returns: + Numpy array (if static value is obtainable), else `Tensor`. + """ + static_x = tf.get_static_value(x) + if static_x is not None: + return static_x + return x + + +RotosolveOptimizerResults = collections.namedtuple( + 'RotosolveOptimizerResults', + [ + 'converged', # Scalar boolean tensor indicating whether the minimum + # was found within tolerance. + 'num_iterations', # The number of iterations of the BFGS update. + # The total number of objective evaluations performed. + 'num_objective_evaluations', + 'position', # A tensor containing the last argument value found + # during the search. If the search converged, then + # this value is the argmin of the objective function. + # A tensor containing the value of the objective from previous iteration + 'last_objective_value', + 'objective_value', # A tensor containing the value of the objective + # function at the `position`. If the search + # converged, then this is the (local) minimum of + # the objective function. + 'tolerance', # Define the stop criteria. Iteration will stop when the + # objective value difference between two iterations is smaller than + # tolerance + 'solve_param_i', # The parameter index where rotosolve is currently + # modifying. Reserved for internal use. + ]) + + +def _get_initial_state(initial_position, tolerance, expectation_value_function): + """Create RotosolveOptimizerResults with initial state of search .""" + init_args = { + "converged": tf.Variable(False), + "num_iterations": tf.Variable(0), + "num_objective_evaluations": expectation_value_function.iter, + "position": tf.Variable(initial_position), + "objective_value": tf.Variable(0.), + "last_objective_value": tf.Variable(0.), + "tolerance": tolerance, + "solve_param_i": tf.Variable(0) + } + return RotosolveOptimizerResults(**init_args) + + +def minimize(expectation_value_function, + initial_position, + tolerance=1e-8, + max_iterations=50, + name=None): + """Applies the rotosolve algorithm to minimize a linear combination + of quantum measurement expectation values. See arXiv:1903.12166, + arXiv:1905.09692 + + ### Usage: + + The following example demonstrates the Rotosolve optimizer attempting + to find the minimum for two qubit ansatz expectation value. + + ```python + + # In this example we train a circuit perform an XOR operation + X = np.asarray([ + [0, 0], + [0, 1], + [1, 0], + [1, 1], + ], dtype=float) + + Y = np.asarray([ + [-1], [1], [1], [-1] + ], dtype=float) + + def convert_to_circuit(input_data): + # Encode into quantum datapoint. + values = np.ndarray.flatten(input_data) + qubits = cirq.GridQubit.rect(1, 2) + circuit = cirq.Circuit() + for i, value in enumerate(values): + if value: + circuit.append(cirq.X(qubits[i])) + return circuit + + x_circ = tfq.convert_to_tensor([convert_to_circuit(x) for x in X]) + + # Create two qubits + q0, q1 = cirq.GridQubit.rect(1, 2) + + # Create an anzatz on these qubits. + a, b = sympy.symbols('a b') # parameters for the circuit + circuit = cirq.Circuit( + cirq.rx(a).on(q0), + cirq.ry(b).on(q1), cirq.CNOT(control=q0, target=q1)) + + # Build the Keras model. + model = tf.keras.Sequential([ + # The input is the data-circuit, encoded as a tf.string + tf.keras.layers.Input(shape=(), dtype=tf.string), + # The PQC layer returns the expected value of the + # readout gate, range [-1,1]. + tfq.layers.PQC(circuit, cirq.Z(q1)), + ]) + + def hinge_loss(y_true, y_pred): + # Here we use hinge loss as the cost function + tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) + + result = rotosolve_minimizer.minimize( + rotosolve_minimizer.function_factory( + model, hinge_loss, x_circ, Y), np.random.rand([2]) + ) # Initial guess of the parameter + + print(result) + ``` + + Args: + expectation_value_function: A Python callable that accepts + a point as a real `Tensor` and returns a tuple of `Tensor`s + of real dtype containing the value of the function and its + gradient at that point. The function to be minimized. The + input is of shape `[..., n]`, where `n` is the size of the + domain of input points, and all others are batching dimensions. + The first component of the return value is a real `Tensor` of + matching shape `[...]`. The second component (the gradient) + is also of shape `[..., n]` like the input value to the function. + This must be a linear combination of quantum measurement + expectation value, otherwise this algorithm cannot work. + initial_position: Real `Tensor` of shape `[..., n]`. The starting + point, or points when using batching dimensions, of the search + procedure. At these points the function value and the gradient + norm should be finite. + tolerance: Scalar `Tensor` of real dtype. Specifies the gradient + tolerance for the procedure. If the supremum norm of the gradient + vector is below this number, the algorithm is stopped. + name: (Optional) Python str. The name prefixed to the ops created + by this function. If not supplied, the default name 'minimize' + is used. + + Returns: + optimizer_results: A RotosolveOptimizerResults object contains the + result of the optimization process. + """ + + with tf.name_scope(name or 'minimize'): + initial_position = tf.convert_to_tensor(initial_position, + name='initial_position', + dtype='float32') + dtype = initial_position.dtype.base_dtype + tolerance = tf.convert_to_tensor(tolerance, + dtype=dtype, + name='grad_tolerance') + max_iterations = tf.convert_to_tensor(max_iterations, + name='max_iterations') + + def _rotosolve_one_parameter_once(state): + """ + Rotosolve a single parameter. + """ + delta_shift = tf.reshape( + tf.cast(tf.sparse.to_dense( + tf.sparse.SparseTensor( + [[state.solve_param_i, 0]], [math.pi / 2], + [prefer_static_shape(state.position)[0], 1])), + dtype=dtype), prefer_static_shape(state.position)) + + # Evaluate three different point for curve fitting + v_l, v_n, v_r = expectation_value_function( + state.position - delta_shift), \ + state.objective_value, \ + expectation_value_function(state.position + delta_shift) + + # Use the analytical solution to find the optimized position + delta_update = -math.pi / 2 - \ + tf.math.atan2(2 * v_n - v_l - v_r, v_r - v_l) + + delta_update_tensor = tf.reshape( + tf.cast(tf.sparse.to_dense( + tf.sparse.SparseTensor( + [[state.solve_param_i, 0]], [delta_update], + [prefer_static_shape(state.position)[0], 1])), + dtype=dtype), prefer_static_shape(state.position)) + + state.solve_param_i.assign_add(1) + state.position.assign( + tf.math.floormod(state.position + delta_update_tensor, + math.pi * 2)) + + state.last_objective_value.assign(state.objective_value) + state.objective_value.assign( + expectation_value_function(state.position)) + + return [state] + + def _rotosolve_all_parameters_once(state): + """ + Loop iterate over all parameters and update each one of them + """ + + def _cond_internal(state_cond): + return state_cond.solve_param_i < \ + prefer_static_shape(state_cond.position)[0] + + return tf.while_loop( + cond=_cond_internal, + body=_rotosolve_one_parameter_once, + loop_vars=[state], + parallel_iterations=1, + ) + + # The `state` here is a `RotosolveOptimizerResults` tuple with + # values for the current state of the algorithm computation. + def _cond(state): + """Continue if iterations remain and stopping condition + is not met.""" + return (state.num_iterations < max_iterations) \ + and (not state.converged) + + def _body(state): + """Main optimization loop.""" + + state.solve_param_i.assign(0) + + _rotosolve_all_parameters_once(state) + + state.num_iterations.assign_add(1) + state.converged.assign( + tf.abs(state.objective_value - + state.last_objective_value) < state.tolerance) + + return [state] + + initial_state = _get_initial_state(initial_position, tolerance, + expectation_value_function) + + initial_state.objective_value.assign( + expectation_value_function(initial_state.position)) + + return tf.while_loop(cond=_cond, + body=_body, + loop_vars=[initial_state], + parallel_iterations=1)[0] diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py new file mode 100755 index 000000000..e9208b4d4 --- /dev/null +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -0,0 +1,80 @@ +# Copyright 2020 The TensorFlow Quantum Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Test module for tfq.python.optimizers.rotosolve_minimizer optimizer.""" +import numpy as np +import tensorflow as tf +from absl.testing import parameterized +import cirq +import sympy + +from tensorflow_quantum.python.layers.high_level import pqc +from tensorflow_quantum.python import util +from tensorflow_quantum.python.optimizers \ + import rotosolve_minimizer, function_factory + + +class RotosolveMinimizerTest(tf.test.TestCase, parameterized.TestCase): + """Tests for the rotosolve optimization algorithm.""" + + def test_optimization(self): + """Optimization test.""" + + x = np.asarray([ + [0, 0], + [0, 1], + [1, 0], + [1, 1], + ], dtype=float) + + y = np.asarray([[-1], [1], [1], [-1]], dtype=float) + + def convert_to_circuit(input_data): + """Encode into quantum datapoint.""" + values = np.ndarray.flatten(input_data) + qubits = cirq.GridQubit.rect(1, 2) + circuit = cirq.Circuit() + for i, value in enumerate(values): + if value: + circuit.append(cirq.X(qubits[i])) + return circuit + + x_circ = util.convert_to_tensor([convert_to_circuit(x) for x in x]) + + # Create two qubits + q0, q1 = cirq.GridQubit.rect(1, 2) + + # Create an anzatz on these qubits. + a, b = sympy.symbols('a b') # parameters for the circuit + circuit = cirq.Circuit( + cirq.rx(a).on(q0), + cirq.ry(b).on(q1), cirq.CNOT(control=q0, target=q1)) + + # Build the Keras model. + model = tf.keras.Sequential([ + # The input is the data-circuit, encoded as a tf.string + tf.keras.layers.Input(shape=(), dtype=tf.string), + # The PQC layer returns the expected value of the + # readout gate, range [-1,1]. + pqc.PQC(circuit, cirq.Z(q1)), + ]) + + def hinge_loss(y_true, y_pred): + # Here we use hinge loss as the cost function + return tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) + + # Initial guess of the parameter from random number + rotosolve_minimizer.minimize( + function_factory(model, hinge_loss, x_circ, y), + np.random.random(2) * 2 * np.pi) diff --git a/tensorflow_quantum/python/optimizers/utils.py b/tensorflow_quantum/python/optimizers/utils.py new file mode 100755 index 000000000..6ab5151ca --- /dev/null +++ b/tensorflow_quantum/python/optimizers/utils.py @@ -0,0 +1,103 @@ +# Copyright 2020 The TensorFlow Quantum Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Utils for tensorflow quantum optimizers +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from operator import mul +from functools import reduce +import tensorflow as tf + + +def function_factory(model, loss, train_x, train_y): + """A factory to create a function required by tfq.optimizer.rotosolve. + This function is originally defined for l-bgfs minimizer for tensorflow + probability package. + + Args: + model : an instance of `tf.keras.Model` or its subclasses. + loss : a function with signature loss_value = loss(pred_y, true_y). + train_x : the input part of training data. + train_y : the output part of training data. + + Returns: + A function that has a signature of: + loss_value = f(model_parameters). + """ + + # obtain the shapes of all trainable parameters in the model + shapes = tf.shape_n(model.trainable_variables) + n_tensors = len(shapes) + + # we'll use tf.dynamic_stitch and tf.dynamic_partition later, so we need to + # prepare required information first + count = 0 + idx = [] # stitch indices + part = [] # partition indices + + for i, shape in enumerate(shapes): + n = reduce(mul, shape) + idx.append(tf.reshape(tf.range(count, count + n, dtype=tf.int32), + shape)) + part.extend([i] * n) + count += n + + part = tf.constant(part) + + @tf.function + def assign_new_model_parameters(params_1d): + """A function updating the model's parameters with a 1D tf.Tensor. + + Args: + params_1d [in]: a 1D tf.Tensor representing the model's + trainable parameters. + """ + + params = tf.dynamic_partition(params_1d, part, n_tensors) + for i, (shape, param) in enumerate(zip(shapes, params)): + model.trainable_variables[i].assign(tf.reshape(param, shape)) + + # now create a function that will be returned by this factory + @tf.function + def exposed_func(params_1d): + """A function that can be used by tfp.optimizer.rotosolve_minimize. + + This function is created by function_factory. + + Args: + params_1d [in]: a 1D tf.Tensor. + + Returns: + A scalar loss and the gradients w.r.t. the `params_1d`. + """ + + # update the parameters in the model + assign_new_model_parameters(params_1d) + # calculate the loss + loss_value = loss(model(train_x, training=True), train_y) + exposed_func.iter.assign_add(1) + + return loss_value + + # store these information as members so we can use them outside the scope + exposed_func.iter = tf.Variable(0) + exposed_func.idx = idx + exposed_func.part = part + exposed_func.shapes = shapes + exposed_func.assign_new_model_parameters = assign_new_model_parameters + + return exposed_func diff --git a/tensorflow_quantum/python/optimizers/utils_test.py b/tensorflow_quantum/python/optimizers/utils_test.py new file mode 100755 index 000000000..fd79bfd64 --- /dev/null +++ b/tensorflow_quantum/python/optimizers/utils_test.py @@ -0,0 +1,57 @@ +# Copyright 2020 The TensorFlow Quantum Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Utils for tensorflow quantum optimizers +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import tensorflow as tf +from absl.testing import parameterized +import numpy as np +from .utils import function_factory + + +class RotosolveMinimizerTest(tf.test.TestCase, parameterized.TestCase): + """Tests for optimizer utils""" + + def test_function_factory(self): + """Test the function_factory""" + + class LinearModel(object): + """ A simple tensorflow linear model""" + + def __init__(self): + self.w = tf.Variable(0.0) + self.b = tf.Variable(0.0) + + def __call__(self, x): + return self.w * x + self.b + + model = LinearModel() + + def loss(target_y, predicted_y): + return tf.reduce_mean(tf.square(target_y - predicted_y)) + + xs = [[1], [2]] + ys = [[9], [14]] # y = x * 5 + 4 + + new_func = function_factory(model, loss, xs, ys) + + loss_1 = new_func(np.asarray([2, 3])) # ys = 5, 7 / loss = 32.5 + loss_2 = new_func(np.asarray([5, 4])) # ys = 9, 14 / loss = 0 + + self.assertNear(loss_1, 32.5, 1e-6) + self.assertNear(loss_2, 0, 1e-6) From a8ea8a7796a9f5fb9380cbf37680186a6d63e6ab Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 06:11:36 +0000 Subject: [PATCH 02/52] Fix import issue --- release/BUILD | 3 ++ scripts/import_test.py | 4 +++ tensorflow_quantum/__init__.py | 3 ++ tensorflow_quantum/python/optimizers/BUILD | 28 +++++++++++++++++++ .../python/optimizers/rotosolve_minimizer.py | 3 +- 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/release/BUILD b/release/BUILD index 6121aaa55..201c15a06 100644 --- a/release/BUILD +++ b/release/BUILD @@ -22,6 +22,7 @@ sh_binary( "//tensorflow_quantum/python/layers/circuit_construction:__init__.py", "//tensorflow_quantum/python/layers/circuit_executors:__init__.py", "//tensorflow_quantum/python/layers/high_level:__init__.py", + "//tensorflow_quantum/python/optimizers:__init__.py", # Datasets module. "//tensorflow_quantum/datasets:__init__.py", @@ -47,5 +48,7 @@ sh_binary( "//tensorflow_quantum/python/layers/high_level:controlled_pqc", "//tensorflow_quantum/python/layers/high_level:pqc", "//tensorflow_quantum/python:util", + "//tensorflow_quantum/python/optimizers:rotosolve_minimizer", + "//tensorflow_quantum/python/optimizers:utils", ], ) diff --git a/scripts/import_test.py b/scripts/import_test.py index e2c895c16..d0526f0fa 100644 --- a/scripts/import_test.py +++ b/scripts/import_test.py @@ -59,6 +59,10 @@ def test_imports(): # Datasets. _ = tfq.datasets.excited_cluster_states + #Optimizers + _ = tfq.optimizers.rotosolve_minimize + _ = tfq.optimizers.function_factory + if __name__ == "__main__": test_imports() diff --git a/tensorflow_quantum/__init__.py b/tensorflow_quantum/__init__.py index de7e18394..48b4835a9 100644 --- a/tensorflow_quantum/__init__.py +++ b/tensorflow_quantum/__init__.py @@ -40,6 +40,9 @@ # Import differentiators. import tensorflow_quantum.python.differentiators as differentiators +# Import optimizers. +import tensorflow_quantum.python.optimizers as optimizers + # Python adds these symbols for resolution of above imports to # work. We get rid of them so that we don't have two paths to # things. For example: tfq.layers and tfq.python.layers diff --git a/tensorflow_quantum/python/optimizers/BUILD b/tensorflow_quantum/python/optimizers/BUILD index fd4e75c2e..ed6a07bac 100755 --- a/tensorflow_quantum/python/optimizers/BUILD +++ b/tensorflow_quantum/python/optimizers/BUILD @@ -4,3 +4,31 @@ licenses(["notice"]) # Export for the PIP package. exports_files(["__init__.py"]) + +py_library( + name = "utils", + srcs = ["utils.py"], +) + +py_test( + name = "utils_test", + srcs = ["utils_test.py"], + python_version = "PY3", + deps = [ + ":utils", + ], +) + +py_library( + name = "rotosolve_minimizer", + srcs = ["rotosolve_minimizer.py"], +) + +py_test( + name = "rotosolve_minimizer_test", + srcs = ["rotosolve_minimizer_test.py"], + python_version = "PY3", + deps = [ + ":rotosolve_minimizer", + ], +) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index aba90ff65..fae7b4fd9 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -12,8 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""The rotosolve minimization algorithm -""" +"""The rotosolve minimization algorithm""" from __future__ import absolute_import from __future__ import division from __future__ import print_function From 37e926f4e1153e502c5c475c36bf379546e3774a Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 06:22:39 +0000 Subject: [PATCH 03/52] Fix comments layout --- .../python/optimizers/rotosolve_minimizer.py | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index fae7b4fd9..22590c029 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -49,24 +49,26 @@ def prefer_static_value(x): 'RotosolveOptimizerResults', [ 'converged', # Scalar boolean tensor indicating whether the minimum - # was found within tolerance. - 'num_iterations', # The number of iterations of the BFGS update. - # The total number of objective evaluations performed. - 'num_objective_evaluations', + # was found within tolerance. + 'num_iterations', # The number of iterations of the rotosolve update. + 'num_objective_evaluations',# The total number of objective + # evaluations performed. 'position', # A tensor containing the last argument value found - # during the search. If the search converged, then - # this value is the argmin of the objective function. - # A tensor containing the value of the objective from previous iteration - 'last_objective_value', + # during the search. If the search converged, then + # this value is the argmin of the objective function. + # A tensor containing the value of the objective from + # previous iteration + 'last_objective_value', # Save the latest evalued value of the + # objective function 'objective_value', # A tensor containing the value of the objective - # function at the `position`. If the search - # converged, then this is the (local) minimum of - # the objective function. + # function at the `position`. If the search + # converged, then this is the (local) minimum of + # the objective function. 'tolerance', # Define the stop criteria. Iteration will stop when the - # objective value difference between two iterations is smaller than - # tolerance + # objective value difference between two iterations is + # smaller than tolerance 'solve_param_i', # The parameter index where rotosolve is currently - # modifying. Reserved for internal use. + # modifying. Reserved for internal use. ]) From 41b3161fc10974521e3223b2bc63a4cd0d6d1a23 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 06:41:28 +0000 Subject: [PATCH 04/52] Modify rotosolve example docstring --- .../python/optimizers/rotosolve_minimizer.py | 167 +++++++++--------- 1 file changed, 88 insertions(+), 79 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 22590c029..c3a44deef 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -49,26 +49,26 @@ def prefer_static_value(x): 'RotosolveOptimizerResults', [ 'converged', # Scalar boolean tensor indicating whether the minimum - # was found within tolerance. + # was found within tolerance. 'num_iterations', # The number of iterations of the rotosolve update. - 'num_objective_evaluations',# The total number of objective - # evaluations performed. + 'num_objective_evaluations', # The total number of objective + # evaluations performed. 'position', # A tensor containing the last argument value found - # during the search. If the search converged, then - # this value is the argmin of the objective function. - # A tensor containing the value of the objective from - # previous iteration - 'last_objective_value', # Save the latest evalued value of the - # objective function + # during the search. If the search converged, then + # this value is the argmin of the objective function. + # A tensor containing the value of the objective from + # previous iteration + 'last_objective_value', # Save the latest evalued value of the + # objective function 'objective_value', # A tensor containing the value of the objective - # function at the `position`. If the search - # converged, then this is the (local) minimum of - # the objective function. + # function at the `position`. If the search + # converged, then this is the (local) minimum of + # the objective function. 'tolerance', # Define the stop criteria. Iteration will stop when the - # objective value difference between two iterations is - # smaller than tolerance + # objective value difference between two iterations is + # smaller than tolerance 'solve_param_i', # The parameter index where rotosolve is currently - # modifying. Reserved for internal use. + # modifying. Reserved for internal use. ]) @@ -101,80 +101,89 @@ def minimize(expectation_value_function, The following example demonstrates the Rotosolve optimizer attempting to find the minimum for two qubit ansatz expectation value. - ```python - - # In this example we train a circuit perform an XOR operation - X = np.asarray([ - [0, 0], - [0, 1], - [1, 0], - [1, 1], - ], dtype=float) - - Y = np.asarray([ - [-1], [1], [1], [-1] - ], dtype=float) - - def convert_to_circuit(input_data): - # Encode into quantum datapoint. - values = np.ndarray.flatten(input_data) - qubits = cirq.GridQubit.rect(1, 2) - circuit = cirq.Circuit() - for i, value in enumerate(values): - if value: - circuit.append(cirq.X(qubits[i])) - return circuit - - x_circ = tfq.convert_to_tensor([convert_to_circuit(x) for x in X]) - - # Create two qubits - q0, q1 = cirq.GridQubit.rect(1, 2) - - # Create an anzatz on these qubits. - a, b = sympy.symbols('a b') # parameters for the circuit - circuit = cirq.Circuit( - cirq.rx(a).on(q0), - cirq.ry(b).on(q1), cirq.CNOT(control=q0, target=q1)) - - # Build the Keras model. - model = tf.keras.Sequential([ - # The input is the data-circuit, encoded as a tf.string - tf.keras.layers.Input(shape=(), dtype=tf.string), - # The PQC layer returns the expected value of the - # readout gate, range [-1,1]. - tfq.layers.PQC(circuit, cirq.Z(q1)), - ]) - - def hinge_loss(y_true, y_pred): - # Here we use hinge loss as the cost function - tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) - - result = rotosolve_minimizer.minimize( - rotosolve_minimizer.function_factory( - model, hinge_loss, x_circ, Y), np.random.rand([2]) - ) # Initial guess of the parameter - - print(result) - ``` + We first start by defining some variables for training dataset. In this + example we train a circuit perform an XOR operation + + >>> X = np.asarray([ + ... [0, 0], + ... [0, 1], + ... [1, 0], + ... [1, 1], + ...], dtype=float) + + >>> Y = np.asarray([ + ... [-1], [1], [1], [-1] + ...], dtype=float) + + While we have classical dataset defined, it needs to be + converted into a quantum data before a quantum circuit + can handle it. We here by encode the data as follow. + + >>> def convert_to_circuit(input_data): + ... # Encode into quantum datapoint. + ... values = np.ndarray.flatten(input_data) + ... qubits = cirq.GridQubit.rect(1, 2) + ... circuit = cirq.Circuit() + ... for i, value in enumerate(values): + ... if value: + ... circuit.append(cirq.X(qubits[i])) + ... return circuit + + >>> x_circ = tfq.convert_to_tensor([convert_to_circuit(x) for x in X]) + + + Now we define our ansatz circuit + + >>> q0, q1 = cirq.GridQubit.rect(1, 2) + >>> a, b = sympy.symbols('a b') # parameters for the circuit + >>> circuit = cirq.Circuit( + ... cirq.rx(a).on(q0), + ... cirq.ry(b).on(q1), cirq.CNOT(control=q0, target=q1)) + + And embed our circuit into a keras model + >>> model = tf.keras.Sequential([ + ... # The input is the data-circuit, encoded as a tf.string + ... tf.keras.layers.Input(shape=(), dtype=tf.string), + ... # The PQC layer returns the expected value of the + ... # readout gate, range [-1,1]. + ... tfq.layers.PQC(circuit, cirq.Z(q1)), + ...]) + + Rotosolve minimizer can only accept linear loss functions. + Here we define the hinge_loss as use it as the loss function. + + >>> def hinge_loss(y_true, y_pred): + ... # Here we use hinge loss as the cost function + ... tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) + + Lastly, we expose the trainable parameter from our model with + `function_factory`, then run the minimize algorithm. The initial + parameter is guessed randomly. + + >>> rotosolve_minimizer.minimize( + ... rotosolve_minimizer.function_factory( + ... model, + ... hinge_loss, + ... x_circ, + ... Y), + ... np.random.rand([2]) + ... ) Args: expectation_value_function: A Python callable that accepts a point as a real `Tensor` and returns a tuple of `Tensor`s - of real dtype containing the value of the function and its - gradient at that point. The function to be minimized. The - input is of shape `[..., n]`, where `n` is the size of the - domain of input points, and all others are batching dimensions. - The first component of the return value is a real `Tensor` of - matching shape `[...]`. The second component (the gradient) - is also of shape `[..., n]` like the input value to the function. + of real dtype containing the value of the function. + The function to be minimized. The input is of shape `[..., n]`, + where `n` is the size of the domain of input points. + The return value is a real `Tensor` of matching shape `[...]`. This must be a linear combination of quantum measurement expectation value, otherwise this algorithm cannot work. initial_position: Real `Tensor` of shape `[..., n]`. The starting point, or points when using batching dimensions, of the search procedure. At these points the function value and the gradient norm should be finite. - tolerance: Scalar `Tensor` of real dtype. Specifies the gradient - tolerance for the procedure. If the supremum norm of the gradient + tolerance: Scalar `Tensor` of real dtype. Specifies the tolerance + for the procedure. If the supremum norm between two iteration vector is below this number, the algorithm is stopped. name: (Optional) Python str. The name prefixed to the ops created by this function. If not supplied, the default name 'minimize' From 564256fa0316a94cc5fc82a6285ebe64285afab8 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 06:51:29 +0000 Subject: [PATCH 05/52] Remove meaningless whitespaces --- .../python/optimizers/rotosolve_minimizer.py | 30 +++++++++---------- .../python/optimizers/utils_test.py | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index c3a44deef..d46a5b2ac 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -51,14 +51,14 @@ def prefer_static_value(x): 'converged', # Scalar boolean tensor indicating whether the minimum # was found within tolerance. 'num_iterations', # The number of iterations of the rotosolve update. - 'num_objective_evaluations', # The total number of objective + 'num_objective_evaluations', # The total number of objective # evaluations performed. 'position', # A tensor containing the last argument value found # during the search. If the search converged, then # this value is the argmin of the objective function. # A tensor containing the value of the objective from # previous iteration - 'last_objective_value', # Save the latest evalued value of the + 'last_objective_value', # Save the latest evalued value of the # objective function 'objective_value', # A tensor containing the value of the objective # function at the `position`. If the search @@ -73,7 +73,7 @@ def prefer_static_value(x): def _get_initial_state(initial_position, tolerance, expectation_value_function): - """Create RotosolveOptimizerResults with initial state of search .""" + """Create RotosolveOptimizerResults with initial state of search.""" init_args = { "converged": tf.Variable(False), "num_iterations": tf.Variable(0), @@ -101,8 +101,8 @@ def minimize(expectation_value_function, The following example demonstrates the Rotosolve optimizer attempting to find the minimum for two qubit ansatz expectation value. - We first start by defining some variables for training dataset. In this - example we train a circuit perform an XOR operation + We first start by defining some variables for training dataset. In this + example we train a circuit perform an XOR operation >>> X = np.asarray([ ... [0, 0], @@ -115,8 +115,8 @@ def minimize(expectation_value_function, ... [-1], [1], [1], [-1] ...], dtype=float) - While we have classical dataset defined, it needs to be - converted into a quantum data before a quantum circuit + While we have classical dataset defined, it needs to be + converted into a quantum data before a quantum circuit can handle it. We here by encode the data as follow. >>> def convert_to_circuit(input_data): @@ -156,18 +156,18 @@ def minimize(expectation_value_function, ... # Here we use hinge loss as the cost function ... tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) - Lastly, we expose the trainable parameter from our model with + Lastly, we expose the trainable parameter from our model with `function_factory`, then run the minimize algorithm. The initial parameter is guessed randomly. >>> rotosolve_minimizer.minimize( ... rotosolve_minimizer.function_factory( - ... model, - ... hinge_loss, - ... x_circ, - ... Y), + ... model, + ... hinge_loss, + ... x_circ, + ... Y), ... np.random.rand([2]) - ... ) + ... ) Args: expectation_value_function: A Python callable that accepts @@ -175,7 +175,7 @@ def minimize(expectation_value_function, of real dtype containing the value of the function. The function to be minimized. The input is of shape `[..., n]`, where `n` is the size of the domain of input points. - The return value is a real `Tensor` of matching shape `[...]`. + The return value is a real `Tensor` of matching shape `[...]`. This must be a linear combination of quantum measurement expectation value, otherwise this algorithm cannot work. initial_position: Real `Tensor` of shape `[..., n]`. The starting @@ -183,7 +183,7 @@ def minimize(expectation_value_function, procedure. At these points the function value and the gradient norm should be finite. tolerance: Scalar `Tensor` of real dtype. Specifies the tolerance - for the procedure. If the supremum norm between two iteration + for the procedure. If the supremum norm between two iteration vector is below this number, the algorithm is stopped. name: (Optional) Python str. The name prefixed to the ops created by this function. If not supplied, the default name 'minimize' diff --git a/tensorflow_quantum/python/optimizers/utils_test.py b/tensorflow_quantum/python/optimizers/utils_test.py index fd79bfd64..f19d6db36 100755 --- a/tensorflow_quantum/python/optimizers/utils_test.py +++ b/tensorflow_quantum/python/optimizers/utils_test.py @@ -31,7 +31,7 @@ def test_function_factory(self): """Test the function_factory""" class LinearModel(object): - """ A simple tensorflow linear model""" + """A simple tensorflow linear model""" def __init__(self): self.w = tf.Variable(0.0) From 25a75df2f6c70559080182fcc5f2945585479b8d Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 06:54:27 +0000 Subject: [PATCH 06/52] Correct types in docstring --- .../python/optimizers/rotosolve_minimizer.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index d46a5b2ac..d6c53565f 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -25,9 +25,9 @@ def prefer_static_shape(x): """Return static shape of tensor `x` if available, else `tf.shape(x)`. Args: - x: `Tensor` (already converted). + x: `tf.Tensor` (already converted). Returns: - Numpy array (if static shape is obtainable), else `Tensor`. + Numpy array (if static shape is obtainable), else `tf.Tensor`. """ return prefer_static_value(tf.shape(x)) @@ -35,9 +35,9 @@ def prefer_static_shape(x): def prefer_static_value(x): """Return static value of tensor `x` if available, else `x`. Args: - x: `Tensor` (already converted). + x: `tf.Tensor` (already converted). Returns: - Numpy array (if static value is obtainable), else `Tensor`. + Numpy array (if static value is obtainable), else `tf.Tensor`. """ static_x = tf.get_static_value(x) if static_x is not None: @@ -171,21 +171,21 @@ def minimize(expectation_value_function, Args: expectation_value_function: A Python callable that accepts - a point as a real `Tensor` and returns a tuple of `Tensor`s + a point as a real `tf.Tensor` and returns a `tf.Tensor`s of real dtype containing the value of the function. The function to be minimized. The input is of shape `[..., n]`, where `n` is the size of the domain of input points. - The return value is a real `Tensor` of matching shape `[...]`. + The return value is a real `tf.Tensor` of matching shape `[...]`. This must be a linear combination of quantum measurement expectation value, otherwise this algorithm cannot work. - initial_position: Real `Tensor` of shape `[..., n]`. The starting + initial_position: Real `tf.Tensor` of shape `[..., n]`. The starting point, or points when using batching dimensions, of the search procedure. At these points the function value and the gradient norm should be finite. - tolerance: Scalar `Tensor` of real dtype. Specifies the tolerance + tolerance: Scalar `tf.Tensor` of real dtype. Specifies the tolerance for the procedure. If the supremum norm between two iteration vector is below this number, the algorithm is stopped. - name: (Optional) Python str. The name prefixed to the ops created + name: (Optional) Python `str`. The name prefixed to the ops created by this function. If not supplied, the default name 'minimize' is used. From 112400e847d6d98588c1708517aed5b7b7aeeb43 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 07:14:16 +0000 Subject: [PATCH 07/52] Change docstring indents --- .../python/optimizers/rotosolve_minimizer.py | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index d6c53565f..d5f6683ac 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -23,11 +23,12 @@ def prefer_static_shape(x): """Return static shape of tensor `x` if available, - else `tf.shape(x)`. + else `tf.shape(x)`. + Args: - x: `tf.Tensor` (already converted). + x: `tf.Tensor` (already converted). Returns: - Numpy array (if static shape is obtainable), else `tf.Tensor`. + Numpy array (if static shape is obtainable), else `tf.Tensor`. """ return prefer_static_value(tf.shape(x)) @@ -35,9 +36,9 @@ def prefer_static_shape(x): def prefer_static_value(x): """Return static value of tensor `x` if available, else `x`. Args: - x: `tf.Tensor` (already converted). + x: `tf.Tensor` (already converted). Returns: - Numpy array (if static value is obtainable), else `tf.Tensor`. + Numpy array (if static value is obtainable), else `tf.Tensor`. """ static_x = tf.get_static_value(x) if static_x is not None: @@ -170,28 +171,28 @@ def minimize(expectation_value_function, ... ) Args: - expectation_value_function: A Python callable that accepts - a point as a real `tf.Tensor` and returns a `tf.Tensor`s - of real dtype containing the value of the function. - The function to be minimized. The input is of shape `[..., n]`, - where `n` is the size of the domain of input points. - The return value is a real `tf.Tensor` of matching shape `[...]`. - This must be a linear combination of quantum measurement - expectation value, otherwise this algorithm cannot work. - initial_position: Real `tf.Tensor` of shape `[..., n]`. The starting - point, or points when using batching dimensions, of the search - procedure. At these points the function value and the gradient - norm should be finite. - tolerance: Scalar `tf.Tensor` of real dtype. Specifies the tolerance - for the procedure. If the supremum norm between two iteration - vector is below this number, the algorithm is stopped. - name: (Optional) Python `str`. The name prefixed to the ops created - by this function. If not supplied, the default name 'minimize' - is used. + expectation_value_function: A Python callable that accepts + a point as a real `tf.Tensor` and returns a `tf.Tensor`s + of real dtype containing the value of the function. + The function to be minimized. The input is of shape `[..., n]`, + where `n` is the size of the domain of input points. + The return value is a real `tf.Tensor` of matching shape `[...]`. + This must be a linear combination of quantum measurement + expectation value, otherwise this algorithm cannot work. + initial_position: Real `tf.Tensor` of shape `[..., n]`. The starting + point, or points when using batching dimensions, of the search + procedure. At these points the function value and the gradient + norm should be finite. + tolerance: Scalar `tf.Tensor` of real dtype. Specifies the tolerance + for the procedure. If the supremum norm between two iteration + vector is below this number, the algorithm is stopped. + name: (Optional) Python `str`. The name prefixed to the ops created + by this function. If not supplied, the default name 'minimize' + is used. Returns: - optimizer_results: A RotosolveOptimizerResults object contains the - result of the optimization process. + optimizer_results: A RotosolveOptimizerResults object contains the + result of the optimization process. """ with tf.name_scope(name or 'minimize'): From 26403bd7ec83bc152c069d2bf7ff836b3597d3d1 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 07:41:07 +0000 Subject: [PATCH 08/52] Trying to fix pytest faliure --- tensorflow_quantum/python/optimizers/BUILD | 2 ++ tensorflow_quantum/python/optimizers/utils_test.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/BUILD b/tensorflow_quantum/python/optimizers/BUILD index ed6a07bac..002718c59 100755 --- a/tensorflow_quantum/python/optimizers/BUILD +++ b/tensorflow_quantum/python/optimizers/BUILD @@ -30,5 +30,7 @@ py_test( python_version = "PY3", deps = [ ":rotosolve_minimizer", + "//tensorflow_quantum/python/layers/high_level:pqc", + "//tensorflow_quantum/core/ops:tfq_ps_util_ops_py" ], ) diff --git a/tensorflow_quantum/python/optimizers/utils_test.py b/tensorflow_quantum/python/optimizers/utils_test.py index f19d6db36..49a2f84ae 100755 --- a/tensorflow_quantum/python/optimizers/utils_test.py +++ b/tensorflow_quantum/python/optimizers/utils_test.py @@ -21,7 +21,7 @@ import tensorflow as tf from absl.testing import parameterized import numpy as np -from .utils import function_factory +from tensorflow_quantum.python.optimizers.utils import function_factory class RotosolveMinimizerTest(tf.test.TestCase, parameterized.TestCase): From 7f8bfb40be4c6cd24439320b942af83e1a0490e0 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 08:14:19 +0000 Subject: [PATCH 09/52] Remove extra spances and change docstring layout --- tensorflow_quantum/python/optimizers/utils.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/utils.py b/tensorflow_quantum/python/optimizers/utils.py index 6ab5151ca..77d2a5e7d 100755 --- a/tensorflow_quantum/python/optimizers/utils.py +++ b/tensorflow_quantum/python/optimizers/utils.py @@ -12,8 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Utils for tensorflow quantum optimizers -""" +"""Utils for tensorflow quantum optimizers""" from __future__ import absolute_import from __future__ import division @@ -25,14 +24,16 @@ def function_factory(model, loss, train_x, train_y): """A factory to create a function required by tfq.optimizer.rotosolve. + This function is originally defined for l-bgfs minimizer for tensorflow + probability package. Args: - model : an instance of `tf.keras.Model` or its subclasses. - loss : a function with signature loss_value = loss(pred_y, true_y). - train_x : the input part of training data. - train_y : the output part of training data. + model: an instance of `tf.keras.Model` or its subclasses. + loss: a function with signature loss_value = loss(pred_y, true_y). + train_x: the input part of training data. + train_y: the output part of training data. Returns: A function that has a signature of: From 490331ff397fdc36b3178c43ee47b04c113392ee Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 08:17:16 +0000 Subject: [PATCH 10/52] Fix typo in utils_test.py --- tensorflow_quantum/python/optimizers/utils_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/utils_test.py b/tensorflow_quantum/python/optimizers/utils_test.py index 49a2f84ae..0789aaa24 100755 --- a/tensorflow_quantum/python/optimizers/utils_test.py +++ b/tensorflow_quantum/python/optimizers/utils_test.py @@ -12,8 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Utils for tensorflow quantum optimizers -""" +"""Util tests for tensorflow quantum optimizers""" from __future__ import absolute_import from __future__ import division From f2b15d449ea0ddd1870b903ee914a92a001e5dc2 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 08:24:56 +0000 Subject: [PATCH 11/52] Check the input / output shape requirement for rotosolve expectation value function --- .../python/optimizers/rotosolve_minimizer.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index d5f6683ac..20f28eb95 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -174,12 +174,13 @@ def minimize(expectation_value_function, expectation_value_function: A Python callable that accepts a point as a real `tf.Tensor` and returns a `tf.Tensor`s of real dtype containing the value of the function. - The function to be minimized. The input is of shape `[..., n]`, - where `n` is the size of the domain of input points. - The return value is a real `tf.Tensor` of matching shape `[...]`. - This must be a linear combination of quantum measurement - expectation value, otherwise this algorithm cannot work. - initial_position: Real `tf.Tensor` of shape `[..., n]`. The starting + The function to be minimized. The input is of shape `[n]`, + where `n` is the size of the trainable parameters. + The return value is a real `tf.Tensor` scala (matching shape + `[1]`). This must be a linear combination of quantum + measurement expectation value, otherwise this algorithm cannot + work. + initial_position: Real `tf.Tensor` of shape `[n]`. The starting point, or points when using batching dimensions, of the search procedure. At these points the function value and the gradient norm should be finite. From 64f76c59d428d1501648637c7f1cc3af399cc7ed Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 08:33:02 +0000 Subject: [PATCH 12/52] Add docstring for internal functions --- .../python/optimizers/rotosolve_minimizer.py | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 20f28eb95..1c0335f87 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -208,8 +208,14 @@ def minimize(expectation_value_function, name='max_iterations') def _rotosolve_one_parameter_once(state): - """ - Rotosolve a single parameter. + """Rotosolve a single parameter once. + + Args: + state: A RotosolveOptimizerResults object stores the + current state of the minimizer. + + Returns: + states: A list which the first element is the new state """ delta_shift = tf.reshape( tf.cast(tf.sparse.to_dense( @@ -247,10 +253,17 @@ def _rotosolve_one_parameter_once(state): return [state] def _rotosolve_all_parameters_once(state): - """ - Loop iterate over all parameters and update each one of them - """ + """Iterate over all parameters and rotosolve each single + + of them once. + + Args: + state: A RotosolveOptimizerResults object stores the + current state of the minimizer. + Returns: + states: A list which the first element is the new state + """ def _cond_internal(state_cond): return state_cond.solve_param_i < \ prefer_static_shape(state_cond.position)[0] From f8ec7fec881951926261ada644c2e48082bfc59a Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 08:46:41 +0000 Subject: [PATCH 13/52] Fix formats --- .../python/optimizers/rotosolve_minimizer.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 1c0335f87..ffe21452e 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -176,9 +176,9 @@ def minimize(expectation_value_function, of real dtype containing the value of the function. The function to be minimized. The input is of shape `[n]`, where `n` is the size of the trainable parameters. - The return value is a real `tf.Tensor` scala (matching shape - `[1]`). This must be a linear combination of quantum - measurement expectation value, otherwise this algorithm cannot + The return value is a real `tf.Tensor` scala (matching shape + `[1]`). This must be a linear combination of quantum + measurement expectation value, otherwise this algorithm cannot work. initial_position: Real `tf.Tensor` of shape `[n]`. The starting point, or points when using batching dimensions, of the search @@ -210,7 +210,7 @@ def minimize(expectation_value_function, def _rotosolve_one_parameter_once(state): """Rotosolve a single parameter once. - Args: + Args: state: A RotosolveOptimizerResults object stores the current state of the minimizer. @@ -253,17 +253,18 @@ def _rotosolve_one_parameter_once(state): return [state] def _rotosolve_all_parameters_once(state): - """Iterate over all parameters and rotosolve each single - + """Iterate over all parameters and rotosolve each single + of them once. - Args: + Args: state: A RotosolveOptimizerResults object stores the current state of the minimizer. Returns: states: A list which the first element is the new state """ + def _cond_internal(state_cond): return state_cond.solve_param_i < \ prefer_static_shape(state_cond.position)[0] From 5f5508cb8b0f1886d16ce97c5a070fa890068ceb Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 10:38:15 +0000 Subject: [PATCH 14/52] Fix dependency --- tensorflow_quantum/python/optimizers/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow_quantum/python/optimizers/BUILD b/tensorflow_quantum/python/optimizers/BUILD index 002718c59..b39cbafc9 100755 --- a/tensorflow_quantum/python/optimizers/BUILD +++ b/tensorflow_quantum/python/optimizers/BUILD @@ -30,6 +30,7 @@ py_test( python_version = "PY3", deps = [ ":rotosolve_minimizer", + ":utils", "//tensorflow_quantum/python/layers/high_level:pqc", "//tensorflow_quantum/core/ops:tfq_ps_util_ops_py" ], From 62105dc2f97d08ce12fadf8f720d8ed9c1a62793 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Sun, 31 May 2020 11:42:28 +0000 Subject: [PATCH 15/52] Fix import --- .../python/optimizers/rotosolve_minimizer_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index e9208b4d4..80a5f14a2 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -21,8 +21,8 @@ from tensorflow_quantum.python.layers.high_level import pqc from tensorflow_quantum.python import util -from tensorflow_quantum.python.optimizers \ - import rotosolve_minimizer, function_factory +from tensorflow_quantum.python.optimizers import rotosolve_minimizer +from tensorflow_quantum.python.optimizers.utils import function_factory class RotosolveMinimizerTest(tf.test.TestCase, parameterized.TestCase): From aa74043911ba6b96c814457a607b7c5c87b257f6 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Mon, 1 Jun 2020 04:22:53 +0000 Subject: [PATCH 16/52] Modify docstring layout --- .../python/optimizers/rotosolve_minimizer.py | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index ffe21452e..3ec50ae51 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -23,6 +23,7 @@ def prefer_static_shape(x): """Return static shape of tensor `x` if available, + else `tf.shape(x)`. Args: @@ -35,6 +36,7 @@ def prefer_static_shape(x): def prefer_static_value(x): """Return static value of tensor `x` if available, else `x`. + Args: x: `tf.Tensor` (already converted). Returns: @@ -50,26 +52,26 @@ def prefer_static_value(x): 'RotosolveOptimizerResults', [ 'converged', # Scalar boolean tensor indicating whether the minimum - # was found within tolerance. + # was found within tolerance. 'num_iterations', # The number of iterations of the rotosolve update. 'num_objective_evaluations', # The total number of objective - # evaluations performed. + # evaluations performed. 'position', # A tensor containing the last argument value found - # during the search. If the search converged, then - # this value is the argmin of the objective function. - # A tensor containing the value of the objective from - # previous iteration + # during the search. If the search converged, then + # this value is the argmin of the objective function. + # A tensor containing the value of the objective from + # previous iteration 'last_objective_value', # Save the latest evalued value of the - # objective function + # objective function 'objective_value', # A tensor containing the value of the objective - # function at the `position`. If the search - # converged, then this is the (local) minimum of - # the objective function. + # function at the `position`. If the search + # converged, then this is the (local) minimum of + # the objective function. 'tolerance', # Define the stop criteria. Iteration will stop when the - # objective value difference between two iterations is - # smaller than tolerance + # objective value difference between two iterations is + # smaller than tolerance 'solve_param_i', # The parameter index where rotosolve is currently - # modifying. Reserved for internal use. + # modifying. Reserved for internal use. ]) @@ -94,7 +96,9 @@ def minimize(expectation_value_function, max_iterations=50, name=None): """Applies the rotosolve algorithm to minimize a linear combination + of quantum measurement expectation values. See arXiv:1903.12166, + arXiv:1905.09692 ### Usage: From 056c72c39a1087dee43c3340b653ae052d63b461 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Wed, 3 Jun 2020 02:27:24 +0000 Subject: [PATCH 17/52] Fix format --- .../python/optimizers/rotosolve_minimizer.py | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 3ec50ae51..5126bf26a 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -51,27 +51,35 @@ def prefer_static_value(x): RotosolveOptimizerResults = collections.namedtuple( 'RotosolveOptimizerResults', [ - 'converged', # Scalar boolean tensor indicating whether the minimum - # was found within tolerance. - 'num_iterations', # The number of iterations of the rotosolve update. - 'num_objective_evaluations', # The total number of objective - # evaluations performed. - 'position', # A tensor containing the last argument value found - # during the search. If the search converged, then - # this value is the argmin of the objective function. - # A tensor containing the value of the objective from - # previous iteration - 'last_objective_value', # Save the latest evalued value of the - # objective function - 'objective_value', # A tensor containing the value of the objective - # function at the `position`. If the search - # converged, then this is the (local) minimum of - # the objective function. - 'tolerance', # Define the stop criteria. Iteration will stop when the - # objective value difference between two iterations is - # smaller than tolerance - 'solve_param_i', # The parameter index where rotosolve is currently - # modifying. Reserved for internal use. + 'converged', + # Scalar boolean tensor indicating whether the minimum + # was found within tolerance. + 'num_iterations', + # The number of iterations of the rotosolve update. + 'num_objective_evaluations', + # The total number of objective + # evaluations performed. + 'position', + # A tensor containing the last argument value found + # during the search. If the search converged, then + # this value is the argmin of the objective function. + # A tensor containing the value of the objective from + # previous iteration + 'last_objective_value', + # Save the latest evalued value of the + # objective function + 'objective_value', + # A tensor containing the value of the objective + # function at the `position`. If the search + # converged, then this is the (local) minimum of + # the objective function. + 'tolerance', + # Define the stop criteria. Iteration will stop when the + # objective value difference between two iterations is + # smaller than tolerance + 'solve_param_i', + # The parameter index where rotosolve is currently + # modifying. Reserved for internal use. ]) From 21345edf49312fe9e6b415b7aa2fec8f8c193431 Mon Sep 17 00:00:00 2001 From: Sachin Date: Thu, 16 Jul 2020 17:38:48 +0800 Subject: [PATCH 18/52] Remove function factory (#1) Remove function factory. --- scripts/import_test.py | 1 - .../python/optimizers/__init__.py | 2 - .../python/optimizers/rotosolve_minimizer.py | 8 +- .../optimizers/rotosolve_minimizer_test.py | 53 ++++++++- tensorflow_quantum/python/optimizers/utils.py | 104 ------------------ .../python/optimizers/utils_test.py | 56 ---------- 6 files changed, 56 insertions(+), 168 deletions(-) delete mode 100755 tensorflow_quantum/python/optimizers/utils.py delete mode 100755 tensorflow_quantum/python/optimizers/utils_test.py diff --git a/scripts/import_test.py b/scripts/import_test.py index 9a48a377f..e8c1d01c5 100644 --- a/scripts/import_test.py +++ b/scripts/import_test.py @@ -62,7 +62,6 @@ def test_imports(): #Optimizers _ = tfq.optimizers.rotosolve_minimize - _ = tfq.optimizers.function_factory if __name__ == "__main__": diff --git a/tensorflow_quantum/python/optimizers/__init__.py b/tensorflow_quantum/python/optimizers/__init__.py index 644762ce6..58968d6b9 100755 --- a/tensorflow_quantum/python/optimizers/__init__.py +++ b/tensorflow_quantum/python/optimizers/__init__.py @@ -18,5 +18,3 @@ from tensorflow_quantum.python.optimizers.rotosolve_minimizer import ( minimize as rotosolve_minimize) -# Utils for optimizers. -from tensorflow_quantum.python.optimizers.utils import (function_factory) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 5126bf26a..fcc4cb5ed 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -170,11 +170,13 @@ def minimize(expectation_value_function, ... tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) Lastly, we expose the trainable parameter from our model with - `function_factory`, then run the minimize algorithm. The initial - parameter is guessed randomly. + `function_factory`[https://pychao.com/2019/11/02/optimize-\ + tensorflow-keras-models-with-l-bfgs-from-tensorflow-probability/], + then run the minimize algorithm. The initial parameter is + guessed randomly. >>> rotosolve_minimizer.minimize( - ... rotosolve_minimizer.function_factory( + ... function_factory( ... model, ... hinge_loss, ... x_circ, diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 80a5f14a2..21822ca52 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -22,7 +22,56 @@ from tensorflow_quantum.python.layers.high_level import pqc from tensorflow_quantum.python import util from tensorflow_quantum.python.optimizers import rotosolve_minimizer -from tensorflow_quantum.python.optimizers.utils import function_factory + +def loss_function_with_model_parameters(model, loss, train_x, train_y): + """Create a new function that assign the model parameter to the model + and evaluate its value. + + Args: + model : an instance of `tf.keras.Model` or its subclasses. + loss : a function with signature loss_value = loss(pred_y, true_y). + train_x : the input part of training data. + train_y : the output part of training data. + + Returns: + A function that has a signature of: + loss_value = f(model_parameters). + """ + + # obtain the shapes of all trainable parameters in the model + shapes = tf.shape_n(model.trainable_variables) + count = 0 + sizes = [] + + # Record the shape of each parameter + for shape in shapes: + n = reduce(mul, shape) + sizes.append(n) + count += n + + # Function accept the parameter and evaluate model + @tf.function + def func(params): + """A function that can be used by tfq.optimizer.rotosolve_minimize. + + Args: + params [in]: a 1D tf.Tensor. + + Returns: + Loss function value + """ + + # update the parameters of the model + start = 0 + for i, size in enumerate(sizes): + model.trainable_variables[i].assign(tf.reshape(params[start:start + size], shape)) + start += size + + # evaluate the loss + loss_value = loss(model(train_x, training=True), train_y) + return loss_value + + return func class RotosolveMinimizerTest(tf.test.TestCase, parameterized.TestCase): @@ -76,5 +125,5 @@ def hinge_loss(y_true, y_pred): # Initial guess of the parameter from random number rotosolve_minimizer.minimize( - function_factory(model, hinge_loss, x_circ, y), + loss_function_with_model_parameters(model, hinge_loss, x_circ, y), np.random.random(2) * 2 * np.pi) diff --git a/tensorflow_quantum/python/optimizers/utils.py b/tensorflow_quantum/python/optimizers/utils.py deleted file mode 100755 index 77d2a5e7d..000000000 --- a/tensorflow_quantum/python/optimizers/utils.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2020 The TensorFlow Quantum Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================== -"""Utils for tensorflow quantum optimizers""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from operator import mul -from functools import reduce -import tensorflow as tf - - -def function_factory(model, loss, train_x, train_y): - """A factory to create a function required by tfq.optimizer.rotosolve. - - This function is originally defined for l-bgfs minimizer for tensorflow - - probability package. - - Args: - model: an instance of `tf.keras.Model` or its subclasses. - loss: a function with signature loss_value = loss(pred_y, true_y). - train_x: the input part of training data. - train_y: the output part of training data. - - Returns: - A function that has a signature of: - loss_value = f(model_parameters). - """ - - # obtain the shapes of all trainable parameters in the model - shapes = tf.shape_n(model.trainable_variables) - n_tensors = len(shapes) - - # we'll use tf.dynamic_stitch and tf.dynamic_partition later, so we need to - # prepare required information first - count = 0 - idx = [] # stitch indices - part = [] # partition indices - - for i, shape in enumerate(shapes): - n = reduce(mul, shape) - idx.append(tf.reshape(tf.range(count, count + n, dtype=tf.int32), - shape)) - part.extend([i] * n) - count += n - - part = tf.constant(part) - - @tf.function - def assign_new_model_parameters(params_1d): - """A function updating the model's parameters with a 1D tf.Tensor. - - Args: - params_1d [in]: a 1D tf.Tensor representing the model's - trainable parameters. - """ - - params = tf.dynamic_partition(params_1d, part, n_tensors) - for i, (shape, param) in enumerate(zip(shapes, params)): - model.trainable_variables[i].assign(tf.reshape(param, shape)) - - # now create a function that will be returned by this factory - @tf.function - def exposed_func(params_1d): - """A function that can be used by tfp.optimizer.rotosolve_minimize. - - This function is created by function_factory. - - Args: - params_1d [in]: a 1D tf.Tensor. - - Returns: - A scalar loss and the gradients w.r.t. the `params_1d`. - """ - - # update the parameters in the model - assign_new_model_parameters(params_1d) - # calculate the loss - loss_value = loss(model(train_x, training=True), train_y) - exposed_func.iter.assign_add(1) - - return loss_value - - # store these information as members so we can use them outside the scope - exposed_func.iter = tf.Variable(0) - exposed_func.idx = idx - exposed_func.part = part - exposed_func.shapes = shapes - exposed_func.assign_new_model_parameters = assign_new_model_parameters - - return exposed_func diff --git a/tensorflow_quantum/python/optimizers/utils_test.py b/tensorflow_quantum/python/optimizers/utils_test.py deleted file mode 100755 index 0789aaa24..000000000 --- a/tensorflow_quantum/python/optimizers/utils_test.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2020 The TensorFlow Quantum Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================== -"""Util tests for tensorflow quantum optimizers""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -import tensorflow as tf -from absl.testing import parameterized -import numpy as np -from tensorflow_quantum.python.optimizers.utils import function_factory - - -class RotosolveMinimizerTest(tf.test.TestCase, parameterized.TestCase): - """Tests for optimizer utils""" - - def test_function_factory(self): - """Test the function_factory""" - - class LinearModel(object): - """A simple tensorflow linear model""" - - def __init__(self): - self.w = tf.Variable(0.0) - self.b = tf.Variable(0.0) - - def __call__(self, x): - return self.w * x + self.b - - model = LinearModel() - - def loss(target_y, predicted_y): - return tf.reduce_mean(tf.square(target_y - predicted_y)) - - xs = [[1], [2]] - ys = [[9], [14]] # y = x * 5 + 4 - - new_func = function_factory(model, loss, xs, ys) - - loss_1 = new_func(np.asarray([2, 3])) # ys = 5, 7 / loss = 32.5 - loss_2 = new_func(np.asarray([5, 4])) # ys = 9, 14 / loss = 0 - - self.assertNear(loss_1, 32.5, 1e-6) - self.assertNear(loss_2, 0, 1e-6) From 90a5b933ac1cee4cdd4f8a5143962c12f7aef832 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 16 Jul 2020 09:42:55 +0000 Subject: [PATCH 19/52] Fix format --- tensorflow_quantum/python/optimizers/__init__.py | 1 - .../python/optimizers/rotosolve_minimizer_test.py | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/__init__.py b/tensorflow_quantum/python/optimizers/__init__.py index 58968d6b9..21a9d08fc 100755 --- a/tensorflow_quantum/python/optimizers/__init__.py +++ b/tensorflow_quantum/python/optimizers/__init__.py @@ -17,4 +17,3 @@ # Quantum circuit specific optimizers. from tensorflow_quantum.python.optimizers.rotosolve_minimizer import ( minimize as rotosolve_minimize) - diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 21822ca52..42903fcb3 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -23,6 +23,7 @@ from tensorflow_quantum.python import util from tensorflow_quantum.python.optimizers import rotosolve_minimizer + def loss_function_with_model_parameters(model, loss, train_x, train_y): """Create a new function that assign the model parameter to the model and evaluate its value. @@ -64,7 +65,8 @@ def func(params): # update the parameters of the model start = 0 for i, size in enumerate(sizes): - model.trainable_variables[i].assign(tf.reshape(params[start:start + size], shape)) + model.trainable_variables[i].assign( + tf.reshape(params[start:start + size], shape)) start += size # evaluate the loss From 0e51e5c21964ecd66427611d3f018c4b67fbda8f Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 16 Jul 2020 09:48:38 +0000 Subject: [PATCH 20/52] Fix lint --- .../python/optimizers/rotosolve_minimizer_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 42903fcb3..a890083e6 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -13,12 +13,13 @@ # limitations under the License. # ============================================================================== """Test module for tfq.python.optimizers.rotosolve_minimizer optimizer.""" +from operator import mul +from functools import reduce import numpy as np import tensorflow as tf from absl.testing import parameterized import cirq import sympy - from tensorflow_quantum.python.layers.high_level import pqc from tensorflow_quantum.python import util from tensorflow_quantum.python.optimizers import rotosolve_minimizer From a19595fee2067fb2d9277ff0802af28399972136 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 16 Jul 2020 09:56:30 +0000 Subject: [PATCH 21/52] Fix tests --- tensorflow_quantum/python/optimizers/BUILD | 1 - 1 file changed, 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/BUILD b/tensorflow_quantum/python/optimizers/BUILD index b39cbafc9..002718c59 100755 --- a/tensorflow_quantum/python/optimizers/BUILD +++ b/tensorflow_quantum/python/optimizers/BUILD @@ -30,7 +30,6 @@ py_test( python_version = "PY3", deps = [ ":rotosolve_minimizer", - ":utils", "//tensorflow_quantum/python/layers/high_level:pqc", "//tensorflow_quantum/core/ops:tfq_ps_util_ops_py" ], From c0e3ab6cd9b2a0dd89155acbe8e7133df2396d66 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 16 Jul 2020 10:10:09 +0000 Subject: [PATCH 22/52] Remove utils --- tensorflow_quantum/python/optimizers/BUILD | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/BUILD b/tensorflow_quantum/python/optimizers/BUILD index 002718c59..18e875a60 100755 --- a/tensorflow_quantum/python/optimizers/BUILD +++ b/tensorflow_quantum/python/optimizers/BUILD @@ -5,20 +5,6 @@ licenses(["notice"]) # Export for the PIP package. exports_files(["__init__.py"]) -py_library( - name = "utils", - srcs = ["utils.py"], -) - -py_test( - name = "utils_test", - srcs = ["utils_test.py"], - python_version = "PY3", - deps = [ - ":utils", - ], -) - py_library( name = "rotosolve_minimizer", srcs = ["rotosolve_minimizer.py"], From 150e6b3730221ebfb084b8c2a70740522b084ac7 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 16 Jul 2020 10:12:15 +0000 Subject: [PATCH 23/52] Remove utils --- release/BUILD | 1 - 1 file changed, 1 deletion(-) diff --git a/release/BUILD b/release/BUILD index 6e08ac5b4..c5c764c50 100644 --- a/release/BUILD +++ b/release/BUILD @@ -50,6 +50,5 @@ sh_binary( "//tensorflow_quantum/python/layers/high_level:pqc", "//tensorflow_quantum/python:util", "//tensorflow_quantum/python/optimizers:rotosolve_minimizer", - "//tensorflow_quantum/python/optimizers:utils", ], ) From 5d0d1f492fff018a0c5d92a0ed11fd5a7462e9f4 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 30 Jul 2020 02:42:59 +0000 Subject: [PATCH 24/52] Fix format and typos --- release/BUILD | 4 +-- tensorflow_quantum/python/optimizers/BUILD | 4 +-- .../python/optimizers/rotosolve_minimizer.py | 26 ++++++++++--------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/release/BUILD b/release/BUILD index c5c764c50..e2a98baa8 100644 --- a/release/BUILD +++ b/release/BUILD @@ -22,7 +22,7 @@ sh_binary( "//tensorflow_quantum/python/layers/circuit_construction:__init__.py", "//tensorflow_quantum/python/layers/circuit_executors:__init__.py", "//tensorflow_quantum/python/layers/high_level:__init__.py", - "//tensorflow_quantum/python/optimizers:__init__.py", + "//tensorflow_quantum/python/optimizers:__init__.py", # Datasets module. "//tensorflow_quantum/datasets:__init__.py", @@ -49,6 +49,6 @@ sh_binary( "//tensorflow_quantum/python/layers/high_level:controlled_pqc", "//tensorflow_quantum/python/layers/high_level:pqc", "//tensorflow_quantum/python:util", - "//tensorflow_quantum/python/optimizers:rotosolve_minimizer", + "//tensorflow_quantum/python/optimizers:rotosolve_minimizer", ], ) diff --git a/tensorflow_quantum/python/optimizers/BUILD b/tensorflow_quantum/python/optimizers/BUILD index 18e875a60..c6dca3ce3 100755 --- a/tensorflow_quantum/python/optimizers/BUILD +++ b/tensorflow_quantum/python/optimizers/BUILD @@ -16,7 +16,7 @@ py_test( python_version = "PY3", deps = [ ":rotosolve_minimizer", - "//tensorflow_quantum/python/layers/high_level:pqc", - "//tensorflow_quantum/core/ops:tfq_ps_util_ops_py" + "//tensorflow_quantum/python/layers/high_level:pqc", + "//tensorflow_quantum/core/ops:tfq_ps_util_ops_py" ], ) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index fcc4cb5ed..5d436e4fd 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -103,11 +103,14 @@ def minimize(expectation_value_function, tolerance=1e-8, max_iterations=50, name=None): - """Applies the rotosolve algorithm to minimize a linear combination + """Applies the rotosolve algorithm. + + The rotosolve algorithm can be used to minimize a linear combination - of quantum measurement expectation values. See arXiv:1903.12166, - - arXiv:1905.09692 + of quantum measurement expectation values. See the following paper: + + [arXiv:1903.12166](https://arxiv.org/abs/1903.12166), Ken M. Nakanishi. + [arXiv:1905.09692](https://arxiv.org/abs/1905.09692), Mateusz Ostaszewski. ### Usage: @@ -115,7 +118,7 @@ def minimize(expectation_value_function, to find the minimum for two qubit ansatz expectation value. We first start by defining some variables for training dataset. In this - example we train a circuit perform an XOR operation + example you train a circuit perform an XOR operation >>> X = np.asarray([ ... [0, 0], @@ -128,13 +131,12 @@ def minimize(expectation_value_function, ... [-1], [1], [1], [-1] ...], dtype=float) - While we have classical dataset defined, it needs to be + While you have classical dataset defined, it needs to be converted into a quantum data before a quantum circuit can handle it. We here by encode the data as follow. >>> def convert_to_circuit(input_data): ... # Encode into quantum datapoint. - ... values = np.ndarray.flatten(input_data) ... qubits = cirq.GridQubit.rect(1, 2) ... circuit = cirq.Circuit() ... for i, value in enumerate(values): @@ -145,7 +147,7 @@ def minimize(expectation_value_function, >>> x_circ = tfq.convert_to_tensor([convert_to_circuit(x) for x in X]) - Now we define our ansatz circuit + Now you define our ansatz circuit >>> q0, q1 = cirq.GridQubit.rect(1, 2) >>> a, b = sympy.symbols('a b') # parameters for the circuit @@ -163,13 +165,13 @@ def minimize(expectation_value_function, ...]) Rotosolve minimizer can only accept linear loss functions. - Here we define the hinge_loss as use it as the loss function. + Here you define the hinge_loss as use it as the loss function. >>> def hinge_loss(y_true, y_pred): - ... # Here we use hinge loss as the cost function + ... # Here you use hinge loss as the cost function ... tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) - Lastly, we expose the trainable parameter from our model with + Lastly, you expose the trainable parameter from our model with `function_factory`[https://pychao.com/2019/11/02/optimize-\ tensorflow-keras-models-with-l-bfgs-from-tensorflow-probability/], then run the minimize algorithm. The initial parameter is @@ -190,7 +192,7 @@ def minimize(expectation_value_function, of real dtype containing the value of the function. The function to be minimized. The input is of shape `[n]`, where `n` is the size of the trainable parameters. - The return value is a real `tf.Tensor` scala (matching shape + The return value is a real `tf.Tensor` Scala (matching shape `[1]`). This must be a linear combination of quantum measurement expectation value, otherwise this algorithm cannot work. From ca2237431cc738545c1a2c119690cd3748e39203 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 30 Jul 2020 03:06:48 +0000 Subject: [PATCH 25/52] Update examples --- .../python/optimizers/rotosolve_minimizer.py | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 5d436e4fd..f00440c82 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -131,9 +131,9 @@ def minimize(expectation_value_function, ... [-1], [1], [1], [-1] ...], dtype=float) - While you have classical dataset defined, it needs to be - converted into a quantum data before a quantum circuit - can handle it. We here by encode the data as follow. + Using the classical data you defined above, it's now time to make + quantum circuit representations of the data. You can use the encoding + scheme below to convert the datapoints into circuits. >>> def convert_to_circuit(input_data): ... # Encode into quantum datapoint. @@ -171,20 +171,36 @@ def minimize(expectation_value_function, ... # Here you use hinge loss as the cost function ... tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) - Lastly, you expose the trainable parameter from our model with - `function_factory`[https://pychao.com/2019/11/02/optimize-\ - tensorflow-keras-models-with-l-bfgs-from-tensorflow-probability/], - then run the minimize algorithm. The initial parameter is + Now you need to expose the trainable parameter from our model. + First obtain the shapes of all trainable parameters in the model. + + >>> shapes = tf.shape_n(model.trainable_variables) + >>> count = 0 + >>> sizes = [] + >>> for shape in shapes: + ... n = reduce(mul, shape) + ... sizes.append(n) + ... count += n + + Then create a function which accepts the parameter and evaluate the model. + + >>> @tf.function + ... def model_func(params): + ... # update the parameters of the model + ... start = 0 + ... for i, size in enumerate(sizes): + ... model.trainable_variables[i].assign( + ... tf.reshape(params[start:start + size], shape)) + ... start += size + ... + ... # evaluate the loss + ... loss_value = hinge_loss(model(x_circ, training=True), Y) + ... return loss_value + + Last you can run the minimize algorithm. The initial parameter is guessed randomly. - >>> rotosolve_minimizer.minimize( - ... function_factory( - ... model, - ... hinge_loss, - ... x_circ, - ... Y), - ... np.random.rand([2]) - ... ) + >>> rotosolve_minimizer.minimize(model_func,np.random.rand([2])) Args: expectation_value_function: A Python callable that accepts From 846753893f5f9fbf8990965ac56cecbe345a0c09 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 30 Jul 2020 03:09:59 +0000 Subject: [PATCH 26/52] Fix lint --- .../python/optimizers/rotosolve_minimizer.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index f00440c82..e6ffe68b6 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -104,11 +104,11 @@ def minimize(expectation_value_function, max_iterations=50, name=None): """Applies the rotosolve algorithm. - + The rotosolve algorithm can be used to minimize a linear combination of quantum measurement expectation values. See the following paper: - + [arXiv:1903.12166](https://arxiv.org/abs/1903.12166), Ken M. Nakanishi. [arXiv:1905.09692](https://arxiv.org/abs/1905.09692), Mateusz Ostaszewski. @@ -131,7 +131,7 @@ def minimize(expectation_value_function, ... [-1], [1], [1], [-1] ...], dtype=float) - Using the classical data you defined above, it's now time to make + Using the classical data you defined above, it's now time to make quantum circuit representations of the data. You can use the encoding scheme below to convert the datapoints into circuits. @@ -173,7 +173,7 @@ def minimize(expectation_value_function, Now you need to expose the trainable parameter from our model. First obtain the shapes of all trainable parameters in the model. - + >>> shapes = tf.shape_n(model.trainable_variables) >>> count = 0 >>> sizes = [] @@ -181,9 +181,9 @@ def minimize(expectation_value_function, ... n = reduce(mul, shape) ... sizes.append(n) ... count += n - + Then create a function which accepts the parameter and evaluate the model. - + >>> @tf.function ... def model_func(params): ... # update the parameters of the model @@ -197,7 +197,7 @@ def minimize(expectation_value_function, ... loss_value = hinge_loss(model(x_circ, training=True), Y) ... return loss_value - Last you can run the minimize algorithm. The initial parameter is + Last you can run the minimize algorithm. The initial parameter is guessed randomly. >>> rotosolve_minimizer.minimize(model_func,np.random.rand([2])) From 18070871b8e2ee7642fcfe154f73ebd4170c754e Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Tue, 4 Aug 2020 03:55:14 +0000 Subject: [PATCH 27/52] Fix typo --- tensorflow_quantum/python/optimizers/rotosolve_minimizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index e6ffe68b6..7ab599001 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -208,7 +208,7 @@ def minimize(expectation_value_function, of real dtype containing the value of the function. The function to be minimized. The input is of shape `[n]`, where `n` is the size of the trainable parameters. - The return value is a real `tf.Tensor` Scala (matching shape + The return value is a real `tf.Tensor` Scalar (matching shape `[1]`). This must be a linear combination of quantum measurement expectation value, otherwise this algorithm cannot work. From 8aee2e6bc4ab3bfdd1edb41f184fb669e023d01f Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 27 Aug 2020 11:27:30 +0800 Subject: [PATCH 28/52] Switch to scatter_nd --- .../python/optimizers/rotosolve_minimizer.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 7ab599001..d613e458f 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -249,12 +249,9 @@ def _rotosolve_one_parameter_once(state): Returns: states: A list which the first element is the new state """ - delta_shift = tf.reshape( - tf.cast(tf.sparse.to_dense( - tf.sparse.SparseTensor( - [[state.solve_param_i, 0]], [math.pi / 2], - [prefer_static_shape(state.position)[0], 1])), - dtype=dtype), prefer_static_shape(state.position)) + delta_shift = tf.scatter_nd(tf.constant([[state.solve_param_i]]), + [tf.constant(math.pi / 2,dtype=dtype)], + prefer_static_shape(state.position)) # Evaluate three different point for curve fitting v_l, v_n, v_r = expectation_value_function( @@ -266,12 +263,16 @@ def _rotosolve_one_parameter_once(state): delta_update = -math.pi / 2 - \ tf.math.atan2(2 * v_n - v_l - v_r, v_r - v_l) - delta_update_tensor = tf.reshape( - tf.cast(tf.sparse.to_dense( - tf.sparse.SparseTensor( - [[state.solve_param_i, 0]], [delta_update], - [prefer_static_shape(state.position)[0], 1])), - dtype=dtype), prefer_static_shape(state.position)) + #delta_update_tensor = tf.reshape( + # tf.cast(tf.sparse.to_dense( + # tf.sparse.SparseTensor( + # [[state.solve_param_i, 0]], [delta_update], + # [prefer_static_shape(state.position)[0], 1])), + # dtype=dtype), prefer_static_shape(state.position)) + + delta_update_tensor = tf.scatter_nd(tf.constant([[state.solve_param_i]]), + [delta_update], + prefer_static_shape(state.position)) state.solve_param_i.assign_add(1) state.position.assign( From a5f0b7617b211811d437e5b277ba7f4dd5a097d0 Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 27 Aug 2020 12:26:02 +0800 Subject: [PATCH 29/52] Update rotosolve test --- .../optimizers/rotosolve_minimizer_test.py | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index a890083e6..4e1ebb6ab 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -80,8 +80,27 @@ def func(params): class RotosolveMinimizerTest(tf.test.TestCase, parameterized.TestCase): """Tests for the rotosolve optimization algorithm.""" - def test_optimization(self): - """Optimization test.""" + def test_function_optimization(self): + """Optimize a simple sinusoid function.""" + + n = 10 # Number of parameters to be optimized + coefficient = tf.random.uniform(shape=[n]) + min_value = -tf.sum(tf.abs(coefficient)) + + def func(x): + """The sinusoid function to optimize""" + return tf.sum(tf.sin(x) * coefficient) + + result = rotosolve_minimizer.minimize( + func, + np.random.random(n)) + + self.assertAlmostEqual(func(result['position']), min_value) + self.assertAlmostEqual(result['objective_value'], min_value) + self.assertTrue(result['converged']) + + def test_keras_model_optimization(self): + """Optimizate a PQC based keras model.""" x = np.asarray([ [0, 0], @@ -127,6 +146,9 @@ def hinge_loss(y_true, y_pred): return tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) # Initial guess of the parameter from random number - rotosolve_minimizer.minimize( + result = rotosolve_minimizer.minimize( loss_function_with_model_parameters(model, hinge_loss, x_circ, y), np.random.random(2) * 2 * np.pi) + + self.assertAlmostEqual(result['objective_value'], 0) + self.assertTrue(result['converged']) From 93ffa533a50ea38e8f6b7df3568d854ddc50ccb6 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 27 Aug 2020 04:28:12 +0000 Subject: [PATCH 30/52] Reformat code --- .../python/optimizers/rotosolve_minimizer.py | 8 ++++---- .../python/optimizers/rotosolve_minimizer_test.py | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index d613e458f..c124c0a14 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -250,7 +250,7 @@ def _rotosolve_one_parameter_once(state): states: A list which the first element is the new state """ delta_shift = tf.scatter_nd(tf.constant([[state.solve_param_i]]), - [tf.constant(math.pi / 2,dtype=dtype)], + [tf.constant(math.pi / 2, dtype=dtype)], prefer_static_shape(state.position)) # Evaluate three different point for curve fitting @@ -270,9 +270,9 @@ def _rotosolve_one_parameter_once(state): # [prefer_static_shape(state.position)[0], 1])), # dtype=dtype), prefer_static_shape(state.position)) - delta_update_tensor = tf.scatter_nd(tf.constant([[state.solve_param_i]]), - [delta_update], - prefer_static_shape(state.position)) + delta_update_tensor = tf.scatter_nd( + tf.constant([[state.solve_param_i]]), [delta_update], + prefer_static_shape(state.position)) state.solve_param_i.assign_add(1) state.position.assign( diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 4e1ebb6ab..f69bffcc6 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -91,9 +91,7 @@ def func(x): """The sinusoid function to optimize""" return tf.sum(tf.sin(x) * coefficient) - result = rotosolve_minimizer.minimize( - func, - np.random.random(n)) + result = rotosolve_minimizer.minimize(func, np.random.random(n)) self.assertAlmostEqual(func(result['position']), min_value) self.assertAlmostEqual(result['objective_value'], min_value) From a559b54aadda15e790c22fda207dbb9a72c7f176 Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 27 Aug 2020 13:25:12 +0800 Subject: [PATCH 31/52] Update tests and comments --- .../python/optimizers/rotosolve_minimizer.py | 93 ++----------------- .../optimizers/rotosolve_minimizer_test.py | 4 +- 2 files changed, 10 insertions(+), 87 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index c124c0a14..980cbfac1 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -117,90 +117,15 @@ def minimize(expectation_value_function, The following example demonstrates the Rotosolve optimizer attempting to find the minimum for two qubit ansatz expectation value. - We first start by defining some variables for training dataset. In this - example you train a circuit perform an XOR operation - - >>> X = np.asarray([ - ... [0, 0], - ... [0, 1], - ... [1, 0], - ... [1, 1], - ...], dtype=float) - - >>> Y = np.asarray([ - ... [-1], [1], [1], [-1] - ...], dtype=float) - - Using the classical data you defined above, it's now time to make - quantum circuit representations of the data. You can use the encoding - scheme below to convert the datapoints into circuits. - - >>> def convert_to_circuit(input_data): - ... # Encode into quantum datapoint. - ... qubits = cirq.GridQubit.rect(1, 2) - ... circuit = cirq.Circuit() - ... for i, value in enumerate(values): - ... if value: - ... circuit.append(cirq.X(qubits[i])) - ... return circuit - - >>> x_circ = tfq.convert_to_tensor([convert_to_circuit(x) for x in X]) - - - Now you define our ansatz circuit - - >>> q0, q1 = cirq.GridQubit.rect(1, 2) - >>> a, b = sympy.symbols('a b') # parameters for the circuit - >>> circuit = cirq.Circuit( - ... cirq.rx(a).on(q0), - ... cirq.ry(b).on(q1), cirq.CNOT(control=q0, target=q1)) - - And embed our circuit into a keras model - >>> model = tf.keras.Sequential([ - ... # The input is the data-circuit, encoded as a tf.string - ... tf.keras.layers.Input(shape=(), dtype=tf.string), - ... # The PQC layer returns the expected value of the - ... # readout gate, range [-1,1]. - ... tfq.layers.PQC(circuit, cirq.Z(q1)), - ...]) - - Rotosolve minimizer can only accept linear loss functions. - Here you define the hinge_loss as use it as the loss function. - - >>> def hinge_loss(y_true, y_pred): - ... # Here you use hinge loss as the cost function - ... tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) - - Now you need to expose the trainable parameter from our model. - First obtain the shapes of all trainable parameters in the model. - - >>> shapes = tf.shape_n(model.trainable_variables) - >>> count = 0 - >>> sizes = [] - >>> for shape in shapes: - ... n = reduce(mul, shape) - ... sizes.append(n) - ... count += n - - Then create a function which accepts the parameter and evaluate the model. - - >>> @tf.function - ... def model_func(params): - ... # update the parameters of the model - ... start = 0 - ... for i, size in enumerate(sizes): - ... model.trainable_variables[i].assign( - ... tf.reshape(params[start:start + size], shape)) - ... start += size - ... - ... # evaluate the loss - ... loss_value = hinge_loss(model(x_circ, training=True), Y) - ... return loss_value - - Last you can run the minimize algorithm. The initial parameter is - guessed randomly. - - >>> rotosolve_minimizer.minimize(model_func,np.random.rand([2])) + Here we show an example of optimize a function which consists summation of + a few sinusoids. + + >>> n = 10 # Number of sinusoids + >>> coefficient = tf.random.uniform(shape=[n]) # Coefficents for each sinusoids + >>> min_value = -tf.sum(tf.abs(coefficient)) # The min value + >>> func = lambda x:tf.sum(tf.sin(x) * coefficient) # Define the function + >>> # Optimize the function with rotosolve, start with random parameters + >>> result = rotosolve_minimizer.minimize(func, np.random.random(n)) # Get the result Args: expectation_value_function: A Python callable that accepts diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index f69bffcc6..f55e2445a 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -87,9 +87,7 @@ def test_function_optimization(self): coefficient = tf.random.uniform(shape=[n]) min_value = -tf.sum(tf.abs(coefficient)) - def func(x): - """The sinusoid function to optimize""" - return tf.sum(tf.sin(x) * coefficient) + func = lambda x:tf.sum(tf.sin(x) * coefficient) result = rotosolve_minimizer.minimize(func, np.random.random(n)) From c0ab8e811d4916ac74fd4b5fd05e1c7850ceabb9 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 27 Aug 2020 05:31:01 +0000 Subject: [PATCH 32/52] Update test --- .../python/optimizers/rotosolve_minimizer_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index f55e2445a..2d42de293 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -87,7 +87,7 @@ def test_function_optimization(self): coefficient = tf.random.uniform(shape=[n]) min_value = -tf.sum(tf.abs(coefficient)) - func = lambda x:tf.sum(tf.sin(x) * coefficient) + func = lambda x: tf.sum(tf.sin(x) * coefficient) result = rotosolve_minimizer.minimize(func, np.random.random(n)) From 223d5978f1da74a3dbe63fe28a6670451a46ce0e Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 27 Aug 2020 05:48:51 +0000 Subject: [PATCH 33/52] Fix lint --- .../python/optimizers/rotosolve_minimizer.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 980cbfac1..4e4e891a1 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -121,11 +121,11 @@ def minimize(expectation_value_function, a few sinusoids. >>> n = 10 # Number of sinusoids - >>> coefficient = tf.random.uniform(shape=[n]) # Coefficents for each sinusoids + >>> coefficient = tf.random.uniform(shape=[n]) >>> min_value = -tf.sum(tf.abs(coefficient)) # The min value >>> func = lambda x:tf.sum(tf.sin(x) * coefficient) # Define the function >>> # Optimize the function with rotosolve, start with random parameters - >>> result = rotosolve_minimizer.minimize(func, np.random.random(n)) # Get the result + >>> result = rotosolve_minimizer.minimize(func, np.random.random(n)) Args: expectation_value_function: A Python callable that accepts @@ -188,13 +188,6 @@ def _rotosolve_one_parameter_once(state): delta_update = -math.pi / 2 - \ tf.math.atan2(2 * v_n - v_l - v_r, v_r - v_l) - #delta_update_tensor = tf.reshape( - # tf.cast(tf.sparse.to_dense( - # tf.sparse.SparseTensor( - # [[state.solve_param_i, 0]], [delta_update], - # [prefer_static_shape(state.position)[0], 1])), - # dtype=dtype), prefer_static_shape(state.position)) - delta_update_tensor = tf.scatter_nd( tf.constant([[state.solve_param_i]]), [delta_update], prefer_static_shape(state.position)) From 163a156312fc62fbec9e659fa3139cc1ee702aac Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 27 Aug 2020 05:55:38 +0000 Subject: [PATCH 34/52] fix lint --- tensorflow_quantum/python/optimizers/rotosolve_minimizer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 4e4e891a1..54deb2cb8 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -121,11 +121,11 @@ def minimize(expectation_value_function, a few sinusoids. >>> n = 10 # Number of sinusoids - >>> coefficient = tf.random.uniform(shape=[n]) + >>> coefficient = tf.random.uniform(shape=[n]) >>> min_value = -tf.sum(tf.abs(coefficient)) # The min value >>> func = lambda x:tf.sum(tf.sin(x) * coefficient) # Define the function >>> # Optimize the function with rotosolve, start with random parameters - >>> result = rotosolve_minimizer.minimize(func, np.random.random(n)) + >>> result = rotosolve_minimizer.minimize(func, np.random.random(n)) Args: expectation_value_function: A Python callable that accepts From 4053d7442db733859fdbbe8fa0e9ccfaa6ce1d09 Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 3 Sep 2020 18:56:29 +0800 Subject: [PATCH 35/52] Modify build docs, modify comments, change test to use built-in hinge loss --- scripts/build_docs.py | 1 + .../python/optimizers/rotosolve_minimizer.py | 4 ++-- .../python/optimizers/rotosolve_minimizer_test.py | 7 ++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/scripts/build_docs.py b/scripts/build_docs.py index 80af0d0d3..d306f4502 100644 --- a/scripts/build_docs.py +++ b/scripts/build_docs.py @@ -68,6 +68,7 @@ def main(unused_argv): "stochastic_differentiator_util", "adjoint" ], "tfq.datasets": ["cluster_state"], + "tfq.optimizers":["rotosolve_minimizer"], "tfq.util": [ "from_tensor", "convert_to_tensor", "exp_identity", "check_commutability", "kwargs_cartesian_product", diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 54deb2cb8..806e9874a 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -100,7 +100,7 @@ def _get_initial_state(initial_position, tolerance, expectation_value_function): def minimize(expectation_value_function, initial_position, - tolerance=1e-8, + tolerance=1e-5, max_iterations=50, name=None): """Applies the rotosolve algorithm. @@ -117,7 +117,7 @@ def minimize(expectation_value_function, The following example demonstrates the Rotosolve optimizer attempting to find the minimum for two qubit ansatz expectation value. - Here we show an example of optimize a function which consists summation of + Here is an example of optimize a function which consists summation of a few sinusoids. >>> n = 10 # Number of sinusoids diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 2d42de293..06e7a42a8 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -137,13 +137,10 @@ def convert_to_circuit(input_data): pqc.PQC(circuit, cirq.Z(q1)), ]) - def hinge_loss(y_true, y_pred): - # Here we use hinge loss as the cost function - return tf.reduce_mean(tf.cast(1 - y_true * y_pred, tf.float32)) - # Initial guess of the parameter from random number result = rotosolve_minimizer.minimize( - loss_function_with_model_parameters(model, hinge_loss, x_circ, y), + loss_function_with_model_parameters(model, tf.keras.losses.hinge, + x_circ, y), np.random.random(2) * 2 * np.pi) self.assertAlmostEqual(result['objective_value'], 0) From 01714d31556a1b91c5fb956535a471ddd8a0bfed Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 3 Sep 2020 19:48:46 +0800 Subject: [PATCH 36/52] Fix format of build_docs.py --- scripts/build_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build_docs.py b/scripts/build_docs.py index d306f4502..6a006d3ea 100644 --- a/scripts/build_docs.py +++ b/scripts/build_docs.py @@ -68,7 +68,7 @@ def main(unused_argv): "stochastic_differentiator_util", "adjoint" ], "tfq.datasets": ["cluster_state"], - "tfq.optimizers":["rotosolve_minimizer"], + "tfq.optimizers": ["rotosolve_minimizer"], "tfq.util": [ "from_tensor", "convert_to_tensor", "exp_identity", "check_commutability", "kwargs_cartesian_product", From 10cee943f2930c71d29f903764bb67f937d7687c Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 3 Sep 2020 21:03:10 +0800 Subject: [PATCH 37/52] Change name of object value from previous iteration --- .../python/optimizers/rotosolve_minimizer.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 806e9874a..f341db6ed 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -65,9 +65,9 @@ def prefer_static_value(x): # this value is the argmin of the objective function. # A tensor containing the value of the objective from # previous iteration - 'last_objective_value', - # Save the latest evalued value of the - # objective function + 'objective_value_previous_iteration', + # Save the evaluated value of the objective function + # from the previous iteration 'objective_value', # A tensor containing the value of the objective # function at the `position`. If the search @@ -91,7 +91,7 @@ def _get_initial_state(initial_position, tolerance, expectation_value_function): "num_objective_evaluations": expectation_value_function.iter, "position": tf.Variable(initial_position), "objective_value": tf.Variable(0.), - "last_objective_value": tf.Variable(0.), + "objective_value_previous_iteration": tf.Variable(0.), "tolerance": tolerance, "solve_param_i": tf.Variable(0) } @@ -197,7 +197,8 @@ def _rotosolve_one_parameter_once(state): tf.math.floormod(state.position + delta_update_tensor, math.pi * 2)) - state.last_objective_value.assign(state.objective_value) + state.objective_value_previous_iteration.assign( + state.objective_value) state.objective_value.assign( expectation_value_function(state.position)) @@ -245,7 +246,8 @@ def _body(state): state.num_iterations.assign_add(1) state.converged.assign( tf.abs(state.objective_value - - state.last_objective_value) < state.tolerance) + state.objective_value_previous_iteration) < + state.tolerance) return [state] From 25ecc76a0a29c6dc9ee815d847c54478ebc5998c Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 3 Sep 2020 22:51:02 +0800 Subject: [PATCH 38/52] Fix comments examples --- .../python/optimizers/rotosolve_minimizer.py | 21 +++++++++++++------ .../optimizers/rotosolve_minimizer_test.py | 4 ++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index f341db6ed..92e321ed2 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -88,7 +88,7 @@ def _get_initial_state(initial_position, tolerance, expectation_value_function): init_args = { "converged": tf.Variable(False), "num_iterations": tf.Variable(0), - "num_objective_evaluations": expectation_value_function.iter, + "num_objective_evaluations": tf.Variable(0), "position": tf.Variable(initial_position), "objective_value": tf.Variable(0.), "objective_value_previous_iteration": tf.Variable(0.), @@ -120,12 +120,19 @@ def minimize(expectation_value_function, Here is an example of optimize a function which consists summation of a few sinusoids. + >>> import tensorflow_quantum as tfq + >>> import numpy as np + >>> import tensorflow as tf >>> n = 10 # Number of sinusoids >>> coefficient = tf.random.uniform(shape=[n]) - >>> min_value = -tf.sum(tf.abs(coefficient)) # The min value - >>> func = lambda x:tf.sum(tf.sin(x) * coefficient) # Define the function + >>> min_value = -tf.math.reduce_sum(tf.abs(coefficient)) # The min value + >>> func = lambda x:tf.math.reduce_sum(tf.sin(x) * coefficient) # Define the function >>> # Optimize the function with rotosolve, start with random parameters - >>> result = rotosolve_minimizer.minimize(func, np.random.random(n)) + >>> result = tfq.optimizers.rotosolve_minimizer.minimize(func, np.random.random(n)) + >>> print(result.converged) + tf.Tensor(True, shape=(), dtype=bool) + >>> print(result.objective_value) + tf.Tensor(-4.7045116, shape=(), dtype=float32) Args: expectation_value_function: A Python callable that accepts @@ -174,7 +181,7 @@ def _rotosolve_one_parameter_once(state): Returns: states: A list which the first element is the new state """ - delta_shift = tf.scatter_nd(tf.constant([[state.solve_param_i]]), + delta_shift = tf.scatter_nd([[state.solve_param_i]], [tf.constant(math.pi / 2, dtype=dtype)], prefer_static_shape(state.position)) @@ -189,7 +196,7 @@ def _rotosolve_one_parameter_once(state): tf.math.atan2(2 * v_n - v_l - v_r, v_r - v_l) delta_update_tensor = tf.scatter_nd( - tf.constant([[state.solve_param_i]]), [delta_update], + [[state.solve_param_i]], [delta_update], prefer_static_shape(state.position)) state.solve_param_i.assign_add(1) @@ -221,6 +228,8 @@ def _cond_internal(state_cond): return state_cond.solve_param_i < \ prefer_static_shape(state_cond.position)[0] + state.num_objective_evaluations.assign_add(1) + return tf.while_loop( cond=_cond_internal, body=_rotosolve_one_parameter_once, diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 06e7a42a8..4eea55228 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -85,9 +85,9 @@ def test_function_optimization(self): n = 10 # Number of parameters to be optimized coefficient = tf.random.uniform(shape=[n]) - min_value = -tf.sum(tf.abs(coefficient)) + min_value = -tf.math.reduce_sum(tf.abs(coefficient)) - func = lambda x: tf.sum(tf.sin(x) * coefficient) + func = lambda x: tf.math.reduce_sum(tf.sin(x) * coefficient) result = rotosolve_minimizer.minimize(func, np.random.random(n)) From 8813c350433a28a96d636c9a303990c51b2de7dd Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 3 Sep 2020 23:13:03 +0800 Subject: [PATCH 39/52] Fix lint --- .../python/optimizers/rotosolve_minimizer_test.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 4eea55228..2f04932df 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -94,6 +94,21 @@ def test_function_optimization(self): self.assertAlmostEqual(func(result['position']), min_value) self.assertAlmostEqual(result['objective_value'], min_value) self.assertTrue(result['converged']) + self.assertLessEqual(result['num_iterations'], + 50) # 50 is the default max iteration + + def test_nonlinear_function_optimization(self): + """Optimize a non-linear function. + A non-linear function which cannot be optimized by rotosolve and can never con + never converge + """ + func = lambda x: x**2 + + result = rotosolve_minimizer.minimize(func, np.random.random(1)) + + self.assertFalse(result['converged']) + self.assertEqual(result['num_iterations'], + 50) # 50 is the default max iteration def test_keras_model_optimization(self): """Optimizate a PQC based keras model.""" From e4ea224485b6329cb6efdfe2ff3d487883816f45 Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 3 Sep 2020 23:16:59 +0800 Subject: [PATCH 40/52] Fix lint --- .../python/optimizers/rotosolve_minimizer.py | 7 ++++--- .../python/optimizers/rotosolve_minimizer_test.py | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 92e321ed2..a8ee9a105 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -125,10 +125,11 @@ def minimize(expectation_value_function, >>> import tensorflow as tf >>> n = 10 # Number of sinusoids >>> coefficient = tf.random.uniform(shape=[n]) - >>> min_value = -tf.math.reduce_sum(tf.abs(coefficient)) # The min value - >>> func = lambda x:tf.math.reduce_sum(tf.sin(x) * coefficient) # Define the function + >>> min_value = -tf.math.reduce_sum(tf.abs(coefficient)) + >>> func = lambda x:tf.math.reduce_sum(tf.sin(x) * coefficient) >>> # Optimize the function with rotosolve, start with random parameters - >>> result = tfq.optimizers.rotosolve_minimizer.minimize(func, np.random.random(n)) + >>> result = tfq.optimizers.rotosolve_minimizer.minimize( \ + ... func, np.random.random(n)) >>> print(result.converged) tf.Tensor(True, shape=(), dtype=bool) >>> print(result.objective_value) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 2f04932df..7d7be97f4 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -99,8 +99,8 @@ def test_function_optimization(self): def test_nonlinear_function_optimization(self): """Optimize a non-linear function. - A non-linear function which cannot be optimized by rotosolve and can never con - never converge + A non-linear function which cannot be optimized by rotosolve + and can never con never converge """ func = lambda x: x**2 From 5535067a94044b8fb1cc1a8ef641c05c8c00f6b5 Mon Sep 17 00:00:00 2001 From: Coxious Date: Mon, 7 Sep 2020 22:36:35 +0800 Subject: [PATCH 41/52] Test tolerance criteria --- .../python/optimizers/rotosolve_minimizer_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 7d7be97f4..a51fe1ada 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -94,7 +94,7 @@ def test_function_optimization(self): self.assertAlmostEqual(func(result['position']), min_value) self.assertAlmostEqual(result['objective_value'], min_value) self.assertTrue(result['converged']) - self.assertLessEqual(result['num_iterations'], + self.assertLess(result['num_iterations'], 50) # 50 is the default max iteration def test_nonlinear_function_optimization(self): From 3ba151cfc27fa5db8f75ea5ddb15e1d3567f5b8d Mon Sep 17 00:00:00 2001 From: Coxious Date: Tue, 8 Sep 2020 10:47:31 +0800 Subject: [PATCH 42/52] Fix format --- .../python/optimizers/rotosolve_minimizer_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index a51fe1ada..fe63f40f2 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -95,7 +95,7 @@ def test_function_optimization(self): self.assertAlmostEqual(result['objective_value'], min_value) self.assertTrue(result['converged']) self.assertLess(result['num_iterations'], - 50) # 50 is the default max iteration + 50) # 50 is the default max iteration def test_nonlinear_function_optimization(self): """Optimize a non-linear function. From 3bc4bf2a507a9d86d8cd5c1198c8d7da1bfd40dd Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 10 Sep 2020 16:47:10 +0800 Subject: [PATCH 43/52] Fix tests --- .../python/optimizers/rotosolve_minimizer_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index fe63f40f2..8c28d927f 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -160,3 +160,6 @@ def convert_to_circuit(input_data): self.assertAlmostEqual(result['objective_value'], 0) self.assertTrue(result['converged']) + +if __name__ == "__main__": + tf.test.main() From 5004e923defe92310f2b755731a9e6d5294ef386 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 10 Sep 2020 08:52:50 +0000 Subject: [PATCH 44/52] Fix format --- tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 8c28d927f..703abb032 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -161,5 +161,6 @@ def convert_to_circuit(input_data): self.assertAlmostEqual(result['objective_value'], 0) self.assertTrue(result['converged']) + if __name__ == "__main__": tf.test.main() From 52984cad8b00b18456e3a0b284d9cf6014408cad Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 10 Sep 2020 16:56:54 +0800 Subject: [PATCH 45/52] Fix format --- .../python/optimizers/rotosolve_minimizer_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 8c28d927f..24b59af4d 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -104,7 +104,7 @@ def test_nonlinear_function_optimization(self): """ func = lambda x: x**2 - result = rotosolve_minimizer.minimize(func, np.random.random(1)) + result = rotosolve_minimizer.minimize(func, [np.random.random(1)]) self.assertFalse(result['converged']) self.assertEqual(result['num_iterations'], From f4ddd7d6d5ad0b04d49b453cff8eac4ee524ea11 Mon Sep 17 00:00:00 2001 From: Coxious Date: Thu, 10 Sep 2020 17:00:49 +0800 Subject: [PATCH 46/52] Change test --- .../python/optimizers/rotosolve_minimizer_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index ee0c274e5..6b02d532d 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -102,9 +102,10 @@ def test_nonlinear_function_optimization(self): A non-linear function which cannot be optimized by rotosolve and can never con never converge """ - func = lambda x: x**2 + func = lambda x: x[0]**2 + x[1]**2 - result = rotosolve_minimizer.minimize(func, [np.random.random(1)]) + result = rotosolve_minimizer.minimize(func, + tf.random.uniform(shape=[2])) self.assertFalse(result['converged']) self.assertEqual(result['num_iterations'], From 25c1f659fc7d2b4acb2eb91e93702338d2b88837 Mon Sep 17 00:00:00 2001 From: Shuxiang Cao Date: Thu, 10 Sep 2020 09:17:41 +0000 Subject: [PATCH 47/52] Fix tests --- .../optimizers/rotosolve_minimizer_test.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 6b02d532d..8f390d2cc 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -91,10 +91,10 @@ def test_function_optimization(self): result = rotosolve_minimizer.minimize(func, np.random.random(n)) - self.assertAlmostEqual(func(result['position']), min_value) - self.assertAlmostEqual(result['objective_value'], min_value) - self.assertTrue(result['converged']) - self.assertLess(result['num_iterations'], + self.assertAlmostEqual(func(result.position), min_value) + self.assertAlmostEqual(result.objective_value, min_value) + self.assertTrue(result.converged) + self.assertLess(result.num_iterations, 50) # 50 is the default max iteration def test_nonlinear_function_optimization(self): @@ -107,8 +107,8 @@ def test_nonlinear_function_optimization(self): result = rotosolve_minimizer.minimize(func, tf.random.uniform(shape=[2])) - self.assertFalse(result['converged']) - self.assertEqual(result['num_iterations'], + self.assertFalse(result.converged) + self.assertEqual(result.num_iterations, 50) # 50 is the default max iteration def test_keras_model_optimization(self): @@ -121,7 +121,7 @@ def test_keras_model_optimization(self): [1, 1], ], dtype=float) - y = np.asarray([[-1], [1], [1], [-1]], dtype=float) + y = np.asarray([[-1], [1], [1], [-1]], dtype=np.float32) def convert_to_circuit(input_data): """Encode into quantum datapoint.""" @@ -155,12 +155,12 @@ def convert_to_circuit(input_data): # Initial guess of the parameter from random number result = rotosolve_minimizer.minimize( - loss_function_with_model_parameters(model, tf.keras.losses.hinge, + loss_function_with_model_parameters(model, tf.keras.losses.Hinge(), x_circ, y), - np.random.random(2) * 2 * np.pi) + tf.random.uniform(shape=[2]) * 2 * np.pi) - self.assertAlmostEqual(result['objective_value'], 0) - self.assertTrue(result['converged']) + self.assertAlmostEqual(result.objective_value, 0) + self.assertTrue(result.converged) if __name__ == "__main__": From 2a425e73a6abbba99c21c3e1a0ebd7065e53c87d Mon Sep 17 00:00:00 2001 From: Coxious Date: Fri, 11 Sep 2020 01:24:19 +0800 Subject: [PATCH 48/52] Fix typo in comment --- .../python/optimizers/rotosolve_minimizer_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py index 8f390d2cc..2631f9606 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer_test.py @@ -98,9 +98,9 @@ def test_function_optimization(self): 50) # 50 is the default max iteration def test_nonlinear_function_optimization(self): - """Optimize a non-linear function. - A non-linear function which cannot be optimized by rotosolve - and can never con never converge + """Test to optimize a non-linear function. + A non-linear function cannot be optimized by rotosolve, + therefore the optimization must never converge. """ func = lambda x: x[0]**2 + x[1]**2 From e9da877e4b3be1d187164f92a2fcf6aba0def909 Mon Sep 17 00:00:00 2001 From: Coxious Date: Sun, 13 Sep 2020 12:03:27 +0800 Subject: [PATCH 49/52] Fix minor problems --- .../python/optimizers/rotosolve_minimizer.py | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index a8ee9a105..d4cc1d7a6 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -16,7 +16,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import math +import numpy as np import collections import tensorflow as tf @@ -114,25 +114,18 @@ def minimize(expectation_value_function, ### Usage: - The following example demonstrates the Rotosolve optimizer attempting - to find the minimum for two qubit ansatz expectation value. - Here is an example of optimize a function which consists summation of a few sinusoids. - >>> import tensorflow_quantum as tfq - >>> import numpy as np - >>> import tensorflow as tf >>> n = 10 # Number of sinusoids >>> coefficient = tf.random.uniform(shape=[n]) >>> min_value = -tf.math.reduce_sum(tf.abs(coefficient)) >>> func = lambda x:tf.math.reduce_sum(tf.sin(x) * coefficient) >>> # Optimize the function with rotosolve, start with random parameters - >>> result = tfq.optimizers.rotosolve_minimizer.minimize( \ - ... func, np.random.random(n)) - >>> print(result.converged) + >>> result = tfq.optimizers.rotosolve_minimize(func, np.random.random(n)) + >>> result.converged tf.Tensor(True, shape=(), dtype=bool) - >>> print(result.objective_value) + >>> result.objective_value tf.Tensor(-4.7045116, shape=(), dtype=float32) Args: @@ -183,7 +176,7 @@ def _rotosolve_one_parameter_once(state): states: A list which the first element is the new state """ delta_shift = tf.scatter_nd([[state.solve_param_i]], - [tf.constant(math.pi / 2, dtype=dtype)], + [tf.constant(np.pi / 2, dtype=dtype)], prefer_static_shape(state.position)) # Evaluate three different point for curve fitting @@ -193,7 +186,7 @@ def _rotosolve_one_parameter_once(state): expectation_value_function(state.position + delta_shift) # Use the analytical solution to find the optimized position - delta_update = -math.pi / 2 - \ + delta_update = -np.pi / 2 - \ tf.math.atan2(2 * v_n - v_l - v_r, v_r - v_l) delta_update_tensor = tf.scatter_nd( @@ -203,7 +196,7 @@ def _rotosolve_one_parameter_once(state): state.solve_param_i.assign_add(1) state.position.assign( tf.math.floormod(state.position + delta_update_tensor, - math.pi * 2)) + np.pi * 2)) state.objective_value_previous_iteration.assign( state.objective_value) From fef587c97b738734abec336d741a29510f6ef258 Mon Sep 17 00:00:00 2001 From: Coxious Date: Sun, 13 Sep 2020 12:08:23 +0800 Subject: [PATCH 50/52] Fix lint --- tensorflow_quantum/python/optimizers/rotosolve_minimizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index d4cc1d7a6..36e051a42 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -16,8 +16,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import numpy as np import collections +import numpy as np import tensorflow as tf From baf5e998405aa2f219c476595655b7edc21319e3 Mon Sep 17 00:00:00 2001 From: Coxious Date: Sun, 13 Sep 2020 12:09:50 +0800 Subject: [PATCH 51/52] Remove unused input --- tensorflow_quantum/python/optimizers/rotosolve_minimizer.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index 36e051a42..e1563356e 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -13,9 +13,6 @@ # limitations under the License. # ============================================================================== """The rotosolve minimization algorithm""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function import collections import numpy as np import tensorflow as tf From 5217868fd42a9b3edd283ba07b575ff8f82a69c2 Mon Sep 17 00:00:00 2001 From: Coxious Date: Sun, 13 Sep 2020 12:12:13 +0800 Subject: [PATCH 52/52] Update comment --- tensorflow_quantum/python/optimizers/rotosolve_minimizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py index e1563356e..bd1270068 100755 --- a/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py +++ b/tensorflow_quantum/python/optimizers/rotosolve_minimizer.py @@ -109,7 +109,7 @@ def minimize(expectation_value_function, [arXiv:1903.12166](https://arxiv.org/abs/1903.12166), Ken M. Nakanishi. [arXiv:1905.09692](https://arxiv.org/abs/1905.09692), Mateusz Ostaszewski. - ### Usage: + Usage: Here is an example of optimize a function which consists summation of a few sinusoids.