def test_tf_conversion(self, qnode, tol): """Tests that the to_tf() function ignores QNodes that already have the TF interface.""" converted_qnode = to_tf(qnode) assert converted_qnode is qnode x = tf.Variable(0.4) with tf.GradientTape() as tape: res = converted_qnode(x) assert np.allclose(res, tf.cos(x), atol=tol, rtol=0) grad = tape.gradient(res, x) assert np.allclose(grad, -tf.sin(x), atol=tol, rtol=0)
def test_other_conversion(self, qnode, tol): """Tests that the to_tf() function correctly converts both torch and autograd qnodes and QNodes with no interface.""" converted_qnode = to_tf(qnode) assert converted_qnode is not qnode assert converted_qnode._qnode is getattr(qnode, "_qnode", qnode) x = tf.Variable(0.4) with tf.GradientTape() as tape: res = converted_qnode(x) assert np.allclose(res, tf.cos(x), atol=tol, rtol=0) grad = tape.gradient(res, x) assert np.allclose(grad, -tf.sin(x), atol=tol, rtol=0)
def __init__(self, qnode, weight_shapes: dict, output_dim: Iterable, weight_specs: Optional[dict] = None, *args, **kwargs): if not CORRECT_TF_VERSION: raise ImportError( "Quanv2D requires TensorFlow version 2 or above. The latest " "version of TensorFlow can be installed using:\n" "pip install tensorflow --upgrade\nAlternatively, visit " "https://www.tensorflow.org/install for detailed instructions." ) self.weight_shapes = { weight: (tuple(size) if isinstance(size, Iterable) else (size, ) if size > 1 else ()) for weight, size in weight_shapes.items() } if qml.tape_mode_active(): self._signature_validation_tape_mode(qnode, weight_shapes) self.qnode = qnode dtype = tf.float32 if tf.keras.backend.floatx( ) == tf.float32 else tf.float64 if self.qnode.diff_method != "backprop": self.qnode.to_tf(dtype=dtype) else: self._signature_validation(qnode, weight_shapes) self.qnode = to_tf(qnode, dtype=tf.keras.backend.floatx()) # Output dim must be an iterable with at least 2 dimensions (possibly a third for channels) TODO check this if len(output_dim) != 3: raise ValueError( "Output must have three dimensions (the 2 image dimensions and one for the channels)" ) else: self.output_dim = output_dim self.weight_specs = weight_specs if weight_specs is not None else {} self.qnode_weights = {} super().__init__(dynamic=True, *args, **kwargs)
def __init__(self, qnode, weight_shapes: dict, output_dim, weight_specs: Optional[dict] = None, **kwargs): if not CORRECT_TF_VERSION: raise ImportError( "KerasLayer requires TensorFlow version 2 or above. The latest " "version of TensorFlow can be installed using:\n" "pip install tensorflow --upgrade\nAlternatively, visit " "https://www.tensorflow.org/install for detailed instructions." ) self.weight_shapes = { weight: (tuple(size) if isinstance(size, Iterable) else (size, ) if size > 1 else ()) for weight, size in weight_shapes.items() } if qml.tape_mode_active(): self._signature_validation_tape_mode(qnode, weight_shapes) self.qnode = qnode dtype = tf.float32 if tf.keras.backend.floatx( ) == tf.float32 else tf.float64 if self.qnode.diff_method != "backprop": self.qnode.to_tf(dtype=dtype) else: self._signature_validation(qnode, weight_shapes) self.qnode = to_tf(qnode, dtype=tf.keras.backend.floatx()) # Allows output_dim to be specified as an int, e.g., 5, or as a length-1 tuple, e.g., (5,) self.output_dim = output_dim[0] if isinstance(output_dim, Iterable) else output_dim self.weight_specs = weight_specs if weight_specs is not None else {} self.qnode_weights = {} super().__init__(dynamic=True, **kwargs)
def __init__(self, qnode, weight_shapes: dict, output_dim, weight_specs: Optional[dict] = None, **kwargs): if not CORRECT_TF_VERSION: raise ImportError( "KerasLayer requires TensorFlow version 2 or above. The latest " "version of TensorFlow can be installed using:\n" "pip install tensorflow --upgrade\nAlternatively, visit " "https://www.tensorflow.org/install for detailed instructions." ) self.sig = qnode.func.sig if self.input_arg not in self.sig: raise TypeError( "QNode must include an argument with name {} for inputting data" .format(self.input_arg)) if self.input_arg in set(weight_shapes.keys()): raise ValueError( "{} argument should not have its dimension specified in " "weight_shapes".format(self.input_arg)) if set(weight_shapes.keys()) | {self.input_arg} != set( self.sig.keys()): raise ValueError( "Must specify a shape for every non-input parameter in the QNode" ) if qnode.func.var_pos: raise TypeError( "Cannot have a variable number of positional arguments") if qnode.func.var_keyword: raise TypeError( "Cannot have a variable number of keyword arguments") self.qnode = to_tf(qnode, dtype=tf.keras.backend.floatx()) self.weight_shapes = { weight: (tuple(size) if isinstance(size, Iterable) else (size, ) if size > 1 else ()) for weight, size in weight_shapes.items() } # Allows output_dim to be specified as an int, e.g., 5, or as a length-1 tuple, e.g., (5,) self.output_dim = output_dim[0] if isinstance(output_dim, Iterable) else output_dim defaults = { name for name, sig in self.sig.items() if sig.par.default != inspect.Parameter.empty } self.input_is_default = self.input_arg in defaults if defaults - {self.input_arg} != set(): raise TypeError( "Only the argument {} is permitted to have a default".format( self.input_arg)) self.weight_specs = weight_specs if weight_specs is not None else {} self.qnode_weights = {} super().__init__(dynamic=True, **kwargs)