Repository: XanaduAI/quantum-neural-networks Branch: master Commit: d28e68b2faa8 Files: 17 Total size: 70.2 KB Directory structure: gitextract_p7of1u1r/ ├── .gitignore ├── LICENSE ├── README.md ├── fraud_detection/ │ ├── README.md │ ├── data_processor.py │ ├── fraud_detection.py │ ├── plot_confusion_matrix.py │ ├── roc.py │ └── testing.py ├── function_fitting/ │ ├── function_fitting.py │ ├── sine_outputs.npy │ ├── sine_test_data.npy │ └── sine_train_data.npy ├── requirements.txt ├── tetrominos_learning/ │ ├── plot_images.py │ └── tetrominos_learning.py └── version_check.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ creditcard* outputs* roc.pdf confusion.pdf ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: README.md ================================================ # Continuous-variable quantum neural networks This repository contains the source code used to produce the results presented in [*"Continuous-variable quantum neural networks"*](https://doi.org/10.1103/PhysRevResearch.1.033063).
## Requirements To construct and optimize the variational quantum circuits, these scripts and notebooks use the TensorFlow backend of [Strawberry Fields](https://github.com/XanaduAI/strawberryfields). In addition, matplotlib is required for generating output plots. **Due to subsequent interface upgrades, these scripts will work only with the following configuration** - Strawberry Fields version 0.10.0 - TensorFlow version 1.3 - Python version 3.5 or 3.6 Your version of Python can be checked by running `python --version`. The correct versions of StrawberryFields and TensorFlow can be installed by running `pip install -r requirements.txt` from the main directory of this repository. ## Contents * **Function fitting**: The folder `function_fitting` contains the Python script `function_fitting.py`, which automates the process of fitting classical functions using continuous-variable (CV) variational quantum circuits. Simply specify the function you would like to fit, along with other hyperparameters, and this script automatically constructs and optimizes the CV quantum neural network. In addition, training data is also provided. * **Quantum autoencoder**: coming soon. * **Quantum fraud detection**: The folder `fraud_detection` contains the Python script `fraud_detection.py`, which builds and trains a hybrid classical/quantum model for fraud detection. Additional scripts are provided for visualizing the results. * **Tetrominos learning**: The folder `tetrominos_learning` contains the Python script `tetrominos_learning.py`, which trains a continuous-variable (CV) quantum neural network. The task of the network is to encode 7 different 4X4 images, representing the (L,O,T,I,S,J,Z) [tetrominos](https://en.wikipedia.org/wiki/Tetromino), in the photon number distribution of two light modes. Once the training phase is completed, the script `plot_images.py` can be executed in order to generate a `.png` figure representing the final results. ## Using the scripts To use the scripts, simply set the input data, output data, and hyperparametersby modifying the scripts directly - and then enter the subdirectory and run the script using Python 3: ```bash python3 script_name.py ``` The outputs of the simulations will be saved in the subdirectory. To access any saved data, the file can be loaded using NumPy: ```python results = np.load('simulation_results.npz') ``` ## Authors Nathan Killoran, Thomas R. Bromley, Juan Miguel Arrazola, Maria Schuld, Nicolás Quesada, and Seth Lloyd. If you are doing any research using this source code and Strawberry Fields, please cite the following two papers: > Nathan Killoran, Thomas R. Bromley, Juan Miguel Arrazola, Maria Schuld, Nicolás Quesada, and Seth Lloyd. Continuous-variable quantum neural networks. [Physical Review Research, 1(3), 033063](https://doi.org/10.1103/PhysRevResearch.1.033063) (2019). > Nathan Killoran, Josh Izaac, Nicolás Quesada, Ville Bergholm, Matthew Amy, and Christian Weedbrook. Strawberry Fields: A Software Platform for Photonic Quantum Computing. arXiv, 2018. [Quantum, 3, 129](https://quantum-journal.org/papers/q-2019-03-11-129/) (2019). ## License This source code is free and open source, released under the Apache License, Version 2.0. ================================================ FILE: fraud_detection/README.md ================================================ # Fraud detection This folder provides the source code used in Experiment B in *"Continuous-variable quantum neural networks"* [arXiv:1806.06871](https://arxiv.org/abs/1806.06871). ## Getting the data The raw data is sourced from the [Credit Card Fraud Detection](https://www.kaggle.com/mlg-ulb/creditcardfraud) dataset on Kaggle. The `creditcard.csv` file should be downloaded and placed in this folder. The user can then run: ```bash python3 data_processor.py ``` This script creates two datasets for training and testing. ## Training and testing the model The model is a hybrid classical-quantum classifier, with a number of input classical layers that control the parameters of an input layer in a two-mode CV quantum neural network. The model is trained so that it outputs a photon in one mode for a genuine credit card transaction, and outputs a photon in the other mode for a fraudulent transaction. Training can be performed with: ```bash python3 fraud_detection.py ``` | WARNING: this script can take a long time to run. On a typical PC, it may take hours to arrive at a well-trained model. | | --- | The model is periodically saved during training, and progress can be monitored by launching TensorBoard in the terminal: ```bash tensorboard --logdir=outputs/tensorboard/simulation_label ``` where `simulation_label` is the name used to refer to a particular run of the script `fraud_detection.py` (this is specified within the file itself; the default is `1`). Testing can be performed with: ```bash python3 testing.py ``` | WARNING: this script can take a long time to run| | --- | Here, the user must edit `testing.py` to point to the simulation label and checkpoint of the model which is to be tested. These are specified under the variables `simulation_label` and `ckpt_val` in `testing.py`. The output of testing is a confusion table, which can be found as a numpy array in `outputs/confusion/simulation_label`. The confusion table is given for multiple threshold probabilities for a transaction to be considered as genuine. ## Visualizing the results The performance of the trained model can be investigated with: ```bash python3 roc.py ``` which outputs the receiver operating characteristic (ROC) curve and confusion matrix for the optimal threshold probability. ================================================ FILE: fraud_detection/data_processor.py ================================================ # Copyright 2018 Xanadu Quantum Technologies Inc. # 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. """For processing data from https://www.kaggle.com/mlg-ulb/creditcardfraud""" import csv import numpy as np import random # creditcard.csv downloaded from https://www.kaggle.com/mlg-ulb/creditcardfraud with open('creditcard.csv', 'r') as csv_file: csv_reader = csv.reader(csv_file, delimiter=',') data = list(csv_reader) data = data[1:] data_genuine = [] data_fraudulent = [] # Splitting genuine and fraudulent data for i in range(len(data)): if int(data[i][30]) == 0: data_genuine.append([float(i) for i in data[i]]) if int(data[i][30]) == 1: data_fraudulent.append([float(i) for i in data[i]]) fraudulent_data_points = len(data_fraudulent) # We want the genuine data points to be 3x the fraudulent ones undersampling_ratio = 3 genuine_data_points = fraudulent_data_points * undersampling_ratio random.shuffle(data_genuine) random.shuffle(data_fraudulent) # Fraudulent and genuine transactions are split into two datasets for cross validation data_fraudulent_1 = data_fraudulent[:int(fraudulent_data_points / 2)] data_fraudulent_2 = data_fraudulent[int(fraudulent_data_points / 2):] data_genuine_1 = data_genuine[:int(genuine_data_points / 2)] data_genuine_2 = data_genuine[int(genuine_data_points / 2):genuine_data_points] data_genuine_remaining = data_genuine[genuine_data_points:] random.shuffle(data_fraudulent_1) random.shuffle(data_fraudulent_2) random.shuffle(data_genuine_1) random.shuffle(data_genuine_2) np.savetxt('creditcard_genuine_1.csv', data_genuine_1, delimiter=',') np.savetxt('creditcard_genuine_2.csv', data_genuine_2, delimiter=',') np.savetxt('creditcard_fraudulent_1.csv', data_fraudulent_1, delimiter=',') np.savetxt('creditcard_fraudulent_2.csv', data_fraudulent_2, delimiter=',') # Larger datasets are used for testing, including genuine transactions unseen in training np.savetxt('creditcard_combined_1_big.csv', data_fraudulent_1 + data_genuine_1 + data_genuine_remaining, delimiter=',') np.savetxt('creditcard_combined_2_big.csv', data_fraudulent_2 + data_genuine_2 + data_genuine_remaining, delimiter=',') ================================================ FILE: fraud_detection/fraud_detection.py ================================================ # Copyright 2018 Xanadu Quantum Technologies Inc. # 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. """Fraud detection fitting script""" import numpy as np import os import tensorflow as tf import strawberryfields as sf from strawberryfields.ops import Dgate, BSgate, Kgate, Sgate, Rgate import sys sys.path.append("..") import version_check # =================================================================================== # Hyperparameters # =================================================================================== # Two modes required: one for "genuine" transactions and one for "fradulent" mode_number = 2 # Number of photonic quantum layers depth = 4 # Fock basis truncation cutoff = 10 # Number of batches in optimization reps = 30000 # Label for simulation simulation_label = 1 # Number of batches to use in the optimization batch_size = 24 # Random initialization of gate parameters sdev_photon = 0.1 sdev = 1 # Variable clipping values disp_clip = 5 sq_clip = 5 kerr_clip = 1 # If loading from checkpoint, previous batch number reached ckpt_val = 0 # Number of repetitions between each output to TensorBoard tb_reps = 100 # Number of repetitions between each model save savr_reps = 1000 model_string = str(simulation_label) # Target location of output folder_locator = './outputs/' # Locations of TensorBoard and model save outputs board_string = folder_locator + 'tensorboard/' + model_string + '/' checkpoint_string = folder_locator + 'models/' + model_string + '/' # =================================================================================== # Loading the training data # =================================================================================== # Data outputted from data_processor.py data_genuine = np.loadtxt('creditcard_genuine_1.csv', delimiter=',') data_fraudulent = np.loadtxt('creditcard_fraudulent_1.csv', delimiter=',') # Combining genuine and fraudulent data data_combined = np.append(data_genuine, data_fraudulent, axis=0) data_points = len(data_combined) # =================================================================================== # Setting up the classical NN input # =================================================================================== # Input neurons input_neurons = 10 # Widths of hidden layers nn_architecture = [10, 10] # Output neurons of classical part output_neurons = 14 # Defining classical network parameters input_classical_layer = tf.placeholder(tf.float32, shape=[batch_size, input_neurons]) layer_matrix_1 = tf.Variable(tf.random_normal(shape=[input_neurons, nn_architecture[0]])) offset_1 = tf.Variable(tf.random_normal(shape=[nn_architecture[0]])) layer_matrix_2 = tf.Variable(tf.random_normal(shape=[nn_architecture[0], nn_architecture[1]])) offset_2 = tf.Variable(tf.random_normal(shape=[nn_architecture[1]])) layer_matrix_3 = tf.Variable(tf.random_normal(shape=[nn_architecture[1], output_neurons])) offset_3 = tf.Variable(tf.random_normal(shape=[output_neurons])) # Creating hidden layers and output layer_1 = tf.nn.elu(tf.matmul(input_classical_layer, layer_matrix_1) + offset_1) layer_2 = tf.nn.elu(tf.matmul(layer_1, layer_matrix_2) + offset_2) output_layer = tf.nn.elu(tf.matmul(layer_2, layer_matrix_3) + offset_3) # =================================================================================== # Defining QNN parameters # =================================================================================== # Number of beamsplitters in interferometer bs_in_interferometer = int(1.0 * mode_number * (mode_number - 1) / 2) with tf.name_scope('variables'): bs_variables = tf.Variable(tf.random_normal(shape=[depth, bs_in_interferometer, 2, 2] , stddev=sdev)) phase_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number, 2], stddev=sdev)) sq_magnitude_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number] , stddev=sdev_photon)) sq_phase_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number] , stddev=sdev)) disp_magnitude_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number] , stddev=sdev_photon)) disp_phase_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number] , stddev=sdev)) kerr_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number], stddev=sdev_photon)) parameters = [layer_matrix_1, offset_1, layer_matrix_2, offset_2, layer_matrix_3, offset_3, bs_variables, phase_variables, sq_magnitude_variables, sq_phase_variables, disp_magnitude_variables, disp_phase_variables, kerr_variables] # =================================================================================== # Constructing quantum layers # =================================================================================== # Defining input QNN layer, whose parameters are set by the outputs of the classical network def input_qnn_layer(): with tf.name_scope('inputlayer'): Sgate(tf.clip_by_value(output_layer[:, 0], -sq_clip, sq_clip), output_layer[:, 1]) | q[0] Sgate(tf.clip_by_value(output_layer[:, 2], -sq_clip, sq_clip), output_layer[:, 3]) | q[1] BSgate(output_layer[:, 4], output_layer[:, 5]) | (q[0], q[1]) Rgate(output_layer[:, 6]) | q[0] Rgate(output_layer[:, 7]) | q[1] Dgate(tf.clip_by_value(output_layer[:, 8], -disp_clip, disp_clip), output_layer[:, 9]) \ | q[0] Dgate(tf.clip_by_value(output_layer[:, 10], -disp_clip, disp_clip), output_layer[:, 11]) \ | q[1] Kgate(tf.clip_by_value(output_layer[:, 12], -kerr_clip, kerr_clip)) | q[0] Kgate(tf.clip_by_value(output_layer[:, 13], -kerr_clip, kerr_clip)) | q[1] # Defining standard QNN layers def qnn_layer(layer_number): with tf.name_scope('layer_{}'.format(layer_number)): BSgate(bs_variables[layer_number, 0, 0, 0], bs_variables[layer_number, 0, 0, 1]) \ | (q[0], q[1]) for i in range(mode_number): Rgate(phase_variables[layer_number, i, 0]) | q[i] for i in range(mode_number): Sgate(tf.clip_by_value(sq_magnitude_variables[layer_number, i], -sq_clip, sq_clip), sq_phase_variables[layer_number, i]) | q[i] BSgate(bs_variables[layer_number, 0, 1, 0], bs_variables[layer_number, 0, 1, 1]) \ | (q[0], q[1]) for i in range(mode_number): Rgate(phase_variables[layer_number, i, 1]) | q[i] for i in range(mode_number): Dgate(tf.clip_by_value(disp_magnitude_variables[layer_number, i], -disp_clip, disp_clip), disp_phase_variables[layer_number, i]) | q[i] for i in range(mode_number): Kgate(tf.clip_by_value(kerr_variables[layer_number, i], -kerr_clip, kerr_clip)) | q[i] # =================================================================================== # Defining QNN # =================================================================================== # construct the two-mode Strawberry Fields engine eng, q = sf.Engine(mode_number) # construct the circuit with eng: input_qnn_layer() for i in range(depth): qnn_layer(i) # run the engine (in batch mode) state = eng.run("tf", cutoff_dim=cutoff, eval=False, batch_size=batch_size) # extract the state ket = state.ket() # =================================================================================== # Setting up cost function # =================================================================================== # Classifications for whole batch: rows act as data points in the batch and columns # are the one-hot classifications classification = tf.placeholder(shape=[batch_size, 2], dtype=tf.int32) func_to_minimise = 0 # Building up the function to minimize by looping through batch for i in range(batch_size): # Probabilities corresponding to a single photon in either mode prob = tf.abs(ket[i, classification[i, 0], classification[i, 1]]) ** 2 # These probabilities should be optimised to 1 func_to_minimise += (1.0 / batch_size) * (prob - 1) ** 2 # Defining the cost function cost_func = func_to_minimise tf.summary.scalar('Cost', cost_func) # =================================================================================== # Training # =================================================================================== # We choose the Adam optimizer optimiser = tf.train.AdamOptimizer() training = optimiser.minimize(cost_func) # Saver/Loader for outputting model saver = tf.train.Saver(parameters) session = tf.Session() session.run(tf.global_variables_initializer()) # Load previous model if non-zero ckpt_val is specified if ckpt_val != 0: saver.restore(session, checkpoint_string + 'sess.ckpt-' + str(ckpt_val)) # TensorBoard writer writer = tf.summary.FileWriter(board_string) merge = tf.summary.merge_all() counter = ckpt_val # Tracks optimum value found (set high so first iteration encodes value) opt_val = 1e20 # Batch number in which optimum value occurs opt_position = 0 # Flag to detect if new optimum occured in last batch new_opt = False while counter <= reps: # Shuffles data to create new epoch np.random.shuffle(data_combined) # Splits data into batches split_data = np.split(data_combined, data_points / batch_size) for batch in split_data: if counter > reps: break # Input data (provided as principal components) data_points_principal_components = batch[:, 1:input_neurons + 1] # Data classes classes = batch[:, -1] # Encoding classes into one-hot form one_hot_input = np.zeros((batch_size, 2)) for i in range(batch_size): if int(classes[i]) == 0: # Encoded such that genuine transactions should be outputted as a photon in the first mode one_hot_input[i] = [1, 0] else: one_hot_input[i] = [0, 1] # Output to TensorBoard if counter % tb_reps == 0: [summary, training_run, func_to_minimise_run] = session.run([merge, training, func_to_minimise], feed_dict={ input_classical_layer: data_points_principal_components, classification: one_hot_input}) writer.add_summary(summary, counter) else: # Standard run of training [training_run, func_to_minimise_run] = session.run([training, func_to_minimise], feed_dict={ input_classical_layer: data_points_principal_components, classification: one_hot_input}) # Ensures cost function is well behaved if np.isnan(func_to_minimise_run): compute_grads = session.run(optimiser.compute_gradients(cost_func), feed_dict={input_classical_layer: data_points_principal_components, classification: one_hot_input}) if not os.path.exists(checkpoint_string): os.makedirs(checkpoint_string) # If cost function becomes NaN, output value of gradients for investigation np.save(checkpoint_string + 'NaN.npy', compute_grads) print('NaNs outputted - leaving at step ' + str(counter)) raise SystemExit # Test to see if new optimum found in current batch if func_to_minimise_run < opt_val: opt_val = func_to_minimise_run opt_position = counter new_opt = True # Save model every fixed number of batches, provided a new optimum value has occurred if (counter % savr_reps == 0) and (i != 0) and new_opt and (not np.isnan(func_to_minimise_run)): if not os.path.exists(checkpoint_string): os.makedirs(checkpoint_string) saver.save(session, checkpoint_string + 'sess.ckpt', global_step=counter) # Saves position of optimum and corresponding value of cost function np.savetxt(checkpoint_string + 'optimum.txt', [opt_position, opt_val]) counter += 1 ================================================ FILE: fraud_detection/plot_confusion_matrix.py ================================================ # Code adapted from scikit-learn: https://scikit-learn.org/stable/_downloads/plot_confusion_matrix.py """ New BSD License Copyright (c) 2007-2019 The scikit-learn developers. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: a. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. b. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. c. Neither the name of the Scikit-learn Developers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================ Confusion matrix ================ Example of confusion matrix usage to evaluate the quality of the output of a classifier on the iris data set. The diagonal elements represent the number of points for which the predicted label is equal to the true label, while off-diagonal elements are those that are mislabeled by the classifier. The higher the diagonal values of the confusion matrix the better, indicating many correct predictions. The figures show the confusion matrix with and without normalization by class support size (number of elements in each class). This kind of normalization can be interesting in case of class imbalance to have a more visual interpretation of which class is being misclassified. Here the results are not as good as they could be as our choice for the regularization parameter C was not the best. In real life applications this parameter is usually chosen using :ref:`grid_search`. """ import numpy as np import matplotlib.pyplot as plt def plot_confusion_matrix(cm, classes, title=None, cmap=plt.cm.Blues): """ This function prints and plots the confusion matrix. Normalization can be applied by setting `normalize=True`. """ fig, ax = plt.subplots() im = ax.imshow(cm, interpolation='nearest', cmap=cmap) # We want to show all ticks... ax.set(xticks=np.arange(cm.shape[1]), yticks=np.arange(cm.shape[0]), # ... and label them with the respective list entries xticklabels=classes, yticklabels=classes, ylabel='True label', xlabel='Predicted label') # Rotate the tick labels and set their alignment. plt.setp(ax.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor") # Loop over data dimensions and create text annotations. fmt = '.2f' thresh = cm.max() / 2. for i in range(cm.shape[0]): for j in range(cm.shape[1]): ax.text(j, i, format(cm[i, j], fmt), ha="center", va="center", color="white" if cm[i, j] > thresh else "black") fig.tight_layout() return ax ================================================ FILE: fraud_detection/roc.py ================================================ # Copyright 2018 Xanadu Quantum Technologies Inc. # 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. """Script for creating Plots""" import numpy as np import matplotlib.pyplot as plt import plot_confusion_matrix plt.switch_backend('agg') # Label for simulation simulation_label = 1 # Loading confusion table confusion_table = np.load('./outputs/confusion/' + str(simulation_label) + '/confusion_table.npy') # Defining array of thresholds from 0 to 1 to consider in the ROC curve thresholds_points = 101 thresholds = np.linspace(0, 1, num=thresholds_points) # false/true positive/negative rates fp_rate = [] tp_rate = [] fn_rate = [] tn_rate = [] # Creating rates for i in range(thresholds_points): fp_rate.append(confusion_table[i, 0, 1] / (confusion_table[i, 0, 1] + confusion_table[i, 0, 0])) tp_rate.append(confusion_table[i, 1, 1] / (confusion_table[i, 1, 1] + confusion_table[i, 1, 0])) fn_rate.append(confusion_table[i, 1, 0] / (confusion_table[i, 1, 1] + confusion_table[i, 1, 0])) tn_rate.append(confusion_table[i, 0, 0] / (confusion_table[i, 0, 0] + confusion_table[i, 0, 1])) # Distance of each threshold from ideal point at (0, 1) distance_from_ideal = (np.array(tn_rate) - 1)**2 + (np.array(fn_rate) - 0)**2 # Threshold closest to (0, 1) closest_threshold = np.argmin(distance_from_ideal) # Area under ROC curve area_under_curve = np.trapz(np.sort(tn_rate), x=np.sort(fn_rate)) print("Area under ROC curve: " + str(area_under_curve)) print("Closest threshold to optimal ROC: " + str(thresholds[closest_threshold])) # Plotting ROC curve straight_line = np.linspace(0, 1, 1001) plt.gcf().subplots_adjust(bottom=0.15) plt.rc('text', usetex=True) plt.rc('font', family='serif') plt.rc('font', serif='New Century Schoolbook') plt.gcf().subplots_adjust(bottom=0.15) plt.plot(fn_rate, tn_rate, color='#056eee', linewidth=2.2) plt.plot(straight_line, straight_line, color='#070d0d', linewidth=1.5, dashes=[6, 2]) plt.plot(0.0, 1.0, 'ko') plt.plot(fn_rate[closest_threshold], tn_rate[closest_threshold], 'k^') plt.ylim(-0.05, 1.05) plt.xlim(-0.05, 1.05) plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) plt.xlabel('False negative rate', fontsize=15) plt.ylabel('True negative rate', fontsize=15) plt.tick_params(axis='both', which='major', labelsize=14, length=6, width=1) plt.tick_params(axis='both', which='minor', labelsize=14, length=6, width=1) plt.savefig('./roc.pdf') plt.close() # Selecting ideal confusion table and plotting confusion_table_ideal = confusion_table[closest_threshold] plt.figure() plot_confusion_matrix.plot_confusion_matrix(confusion_table_ideal, classes=['Genuine', 'Fraudulent'], title='') plt.savefig('./confusion.pdf') ================================================ FILE: fraud_detection/testing.py ================================================ # Copyright 2018 Xanadu Quantum Technologies Inc. # 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. """Fraud detection fitting script""" import numpy as np import os import tensorflow as tf import strawberryfields as sf from strawberryfields.ops import Dgate, BSgate, Kgate, Sgate, Rgate import sys sys.path.append("..") import version_check # =================================================================================== # Hyperparameters # =================================================================================== # Two modes required: one for "genuine" transactions and one for "fradulent" mode_number = 2 # Number of photonic quantum layers depth = 4 # Fock basis truncation cutoff = 10 # Label for simulation simulation_label = 1 # Random initialization of gate parameters sdev_photon = 0.1 sdev = 1 # Variable clipping values disp_clip = 5 sq_clip = 5 kerr_clip = 1 # If loading from checkpoint, previous batch number reached ckpt_val = 30000 model_string = str(simulation_label) # Target location of output folder_locator = './outputs/' # Locations of model saves and where confusion matrix will be saved checkpoint_string = folder_locator + 'models/' + model_string + '/' confusion_string = folder_locator + 'confusion/' + model_string + '/' # =================================================================================== # Loading the testing data # =================================================================================== # Loading combined dataset with extra genuine datapoints unseen in training data_combined = np.loadtxt('./creditcard_combined_2_big.csv', delimiter=',') # Set to a size so that the data can be equally split up with no remainder batch_size = 29 data_combined_points = len(data_combined) # =================================================================================== # Setting up the classical NN input # =================================================================================== # Input neurons input_neurons = 10 # Widths of hidden layers nn_architecture = [10, 10] # Output neurons of classical part output_neurons = 14 # Defining classical network parameters input_classical_layer = tf.placeholder(tf.float32, shape=[batch_size, input_neurons]) layer_matrix_1 = tf.Variable(tf.random_normal(shape=[input_neurons, nn_architecture[0]])) offset_1 = tf.Variable(tf.random_normal(shape=[nn_architecture[0]])) layer_matrix_2 = tf.Variable(tf.random_normal(shape=[nn_architecture[0], nn_architecture[1]])) offset_2 = tf.Variable(tf.random_normal(shape=[nn_architecture[1]])) layer_matrix_3 = tf.Variable(tf.random_normal(shape=[nn_architecture[1], output_neurons])) offset_3 = tf.Variable(tf.random_normal(shape=[output_neurons])) # Creating hidden layers and output layer_1 = tf.nn.elu(tf.matmul(input_classical_layer, layer_matrix_1) + offset_1) layer_2 = tf.nn.elu(tf.matmul(layer_1, layer_matrix_2) + offset_2) output_layer = tf.nn.elu(tf.matmul(layer_2, layer_matrix_3) + offset_3) # =================================================================================== # Defining QNN parameters # =================================================================================== # Number of beamsplitters in interferometer bs_in_interferometer = int(1.0 * mode_number * (mode_number - 1) / 2) with tf.name_scope('variables'): bs_variables = tf.Variable(tf.random_normal(shape=[depth, bs_in_interferometer, 2, 2] , stddev=sdev)) phase_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number, 2], stddev=sdev)) sq_magnitude_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number] , stddev=sdev_photon)) sq_phase_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number] , stddev=sdev)) disp_magnitude_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number] , stddev=sdev_photon)) disp_phase_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number] , stddev=sdev)) kerr_variables = tf.Variable(tf.random_normal(shape=[depth, mode_number], stddev=sdev_photon)) parameters = [layer_matrix_1, offset_1, layer_matrix_2, offset_2, layer_matrix_3, offset_3, bs_variables, phase_variables, sq_magnitude_variables, sq_phase_variables, disp_magnitude_variables, disp_phase_variables, kerr_variables] # =================================================================================== # Constructing quantum layers # =================================================================================== # Defining input QNN layer, whose parameters are set by the outputs of the classical network def input_qnn_layer(): with tf.name_scope('inputlayer'): Sgate(tf.clip_by_value(output_layer[:, 0], -sq_clip, sq_clip), output_layer[:, 1]) | q[0] Sgate(tf.clip_by_value(output_layer[:, 2], -sq_clip, sq_clip), output_layer[:, 3]) | q[1] BSgate(output_layer[:, 4], output_layer[:, 5]) | (q[0], q[1]) Rgate(output_layer[:, 6]) | q[0] Rgate(output_layer[:, 7]) | q[1] Dgate(tf.clip_by_value(output_layer[:, 8], -disp_clip, disp_clip), output_layer[:, 9]) \ | q[0] Dgate(tf.clip_by_value(output_layer[:, 10], -disp_clip, disp_clip), output_layer[:, 11]) \ | q[1] Kgate(tf.clip_by_value(output_layer[:, 12], -kerr_clip, kerr_clip)) | q[0] Kgate(tf.clip_by_value(output_layer[:, 13], -kerr_clip, kerr_clip)) | q[1] # Defining standard QNN layers def qnn_layer(layer_number): with tf.name_scope('layer_{}'.format(layer_number)): BSgate(bs_variables[layer_number, 0, 0, 0], bs_variables[layer_number, 0, 0, 1]) \ | (q[0], q[1]) for i in range(mode_number): Rgate(phase_variables[layer_number, i, 0]) | q[i] for i in range(mode_number): Sgate(tf.clip_by_value(sq_magnitude_variables[layer_number, i], -sq_clip, sq_clip), sq_phase_variables[layer_number, i]) | q[i] BSgate(bs_variables[layer_number, 0, 1, 0], bs_variables[layer_number, 0, 1, 1]) \ | (q[0], q[1]) for i in range(mode_number): Rgate(phase_variables[layer_number, i, 1]) | q[i] for i in range(mode_number): Dgate(tf.clip_by_value(disp_magnitude_variables[layer_number, i], -disp_clip, disp_clip), disp_phase_variables[layer_number, i]) | q[i] for i in range(mode_number): Kgate(tf.clip_by_value(kerr_variables[layer_number, i], -kerr_clip, kerr_clip)) | q[i] # =================================================================================== # Defining QNN # =================================================================================== # construct the two-mode Strawberry Fields engine eng, q = sf.Engine(mode_number) # construct the circuit with eng: input_qnn_layer() for i in range(depth): qnn_layer(i) # run the engine (in batch mode) state = eng.run("tf", cutoff_dim=cutoff, eval=False, batch_size=batch_size) # extract the state ket = state.ket() # =================================================================================== # Extracting probabilities # =================================================================================== # Classifications for whole batch: rows act as data points in the batch and columns # are the one-hot classifications classification = tf.placeholder(shape=[batch_size, 2], dtype=tf.int32) prob = [] for i in range(batch_size): # Finds the probability of a photon being in either mode prob.append([tf.abs(ket[i, 1, 0]) ** 2, tf.abs(ket[i, 0, 1]) ** 2]) # =================================================================================== # Testing performance # =================================================================================== # Defining array of thresholds from 0 to 1 to consider in the ROC curve thresholds_points = 101 thresholds = np.linspace(0, 1, num=thresholds_points) # Saver/Loader for outputting model saver = tf.train.Saver(parameters) session = tf.Session() session.run(tf.global_variables_initializer()) saver.restore(session, checkpoint_string + 'sess.ckpt-' + str(ckpt_val)) # Split up data to process in batches data_split = np.split(data_combined, data_combined_points / batch_size) # Defining confusion table confusion_table = np.zeros((thresholds_points, 2, 2)) for batch in data_split: # Input data (provided as principal components) data_points_principal_components = batch[:, 1:input_neurons + 1] # Data classes classes = batch[:, -1] # Probabilities outputted from circuit prob_run = session.run(prob, feed_dict={input_classical_layer: data_points_principal_components}) for i in range(batch_size): # Calculate probabilities of photon coming out of either mode p = prob_run[i] # Normalize to these two events (i.e. ignore all other outputs) p = p / np.sum(p) # Predicted class is a list corresponding to threshold probabilities predicted_class = [] for j in range(thresholds_points): # If probability of a photon exiting first mode is larger than threshold, attribute as genuine if p[0] > thresholds[j]: predicted_class.append(0) else: predicted_class.append(1) actual_class = classes[i] # Constructing confusion table for j in range(2): for k in range(2): for l in range(thresholds_points): if actual_class == j and predicted_class[l] == k: confusion_table[l, j, k] += 1 # Renormalizing confusion table for i in range(thresholds_points): confusion_table[i] = confusion_table[i] / data_combined_points * 100 if not os.path.exists(confusion_string): os.makedirs(confusion_string) # Save as numpy array np.save(confusion_string + 'confusion_table.npy', confusion_table) ================================================ FILE: function_fitting/function_fitting.py ================================================ # Copyright 2018 Xanadu Quantum Technologies Inc. # 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. """Function fitting script""" import os import time import numpy as np import matplotlib.pyplot as plt from matplotlib import rcParams import tensorflow as tf import strawberryfields as sf from strawberryfields.ops import * import sys sys.path.append("..") import version_check # =================================================================================== # Hyperparameters # =================================================================================== # Fock basis truncation cutoff = 10 # domain [-xmax, xmax] to perform the function fitting over xmax = 1 # Number of batches to use in the optimization # Each batch corresponds to a different input-output relation batch_size = 50 # Number of photonic quantum layers depth = 6 # variable clipping values disp_clip = 100 sq_clip = 50 kerr_clip = 50 # number of optimization steps reps = 1000 # regularization regularization = 0.0 reg_variance = 0.0 # =================================================================================== # Functions # =================================================================================== # This section contains various function we may wish to fit using our quantum # neural network. def f1(x, eps=0.0): """The function f(x)=|x|+noise""" return np.abs(x) + eps * np.random.normal(size=x.shape) def f2(x, eps=0.0): """The function f(x)=sin(pi*x)/(pi*x)+noise""" return np.sin(x*pi)/(pi*x) + eps * np.random.normal(size=x.shape) def f3(x, eps=0.0): """The function f(x)=sin(pi*x)+noise""" return 1.0*(np.sin(1.0 * x * np.pi) + eps * np.random.normal(size=x.shape)) def f4(x, eps=0.0): """The function f(x)=exp(x)+noise""" return np.exp(x) + eps * np.random.normal(size=x.shape) def f5(x, eps=0.0): """The function f(x)=tanh(4x)+noise""" return np.tanh(4*x) + eps * np.random.normal(size=x.shape) def f6(x, eps=0.0): """The function f(x)=x^3+noise""" return x**3 + eps * np.random.normal(size=x.shape) # =================================================================================== # Training data # =================================================================================== # load the training data from the provided files train_data = np.load('sine_train_data.npy') test_data = np.load('sine_test_data.npy') data_y = np.load('sine_outputs.npy') # =================================================================================== # Construct the quantum neural network # =================================================================================== # Random initialization of gate parameters sdev = 0.05 with tf.name_scope('variables'): d_r = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) d_phi = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) r1 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) sq_r = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) sq_phi = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) r2 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) kappa1 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) # construct the one-mode Strawberry Fields engine eng, q = sf.Engine(1) def layer(i): """This function generates the ith layer of the quantum neural network. Note: it must be executed within a Strawberry Fields engine context. Args: i (int): the layer number. """ with tf.name_scope('layer_{}'.format(i)): # displacement gate Dgate(tf.clip_by_value(d_r[i], -disp_clip, disp_clip), d_phi[i]) | q[0] # rotation gate Rgate(r1[i]) | q[0] # squeeze gate Sgate(tf.clip_by_value(sq_r[i], -sq_clip, sq_clip), sq_phi[i]) | q[0] # rotation gate Rgate(r2[i]) | q[0] # Kerr gate Kgate(tf.clip_by_value(kappa1[i], -kerr_clip, kerr_clip)) | q[0] # Use a TensorFlow placeholder to store the input data input_data = tf.placeholder(tf.float32, shape=[batch_size]) # construct the circuit with eng: # the input data is encoded as displacement in the phase space Dgate(input_data) | q[0] for k in range(depth): # apply layers to the required depth layer(k) # run the engine state = eng.run('tf', cutoff_dim=cutoff, eval=False, batch_size=batch_size) # =================================================================================== # Define the loss function # =================================================================================== # First, we calculate the x-quadrature expectation value ket = state.ket() mean_x, svd_x = state.quad_expectation(0) errors_y = tf.sqrt(svd_x) # the loss function is defined as mean(|[batch_num] - data[batch_num]|^2) output_data = tf.placeholder(tf.float32, shape=[batch_size]) loss = tf.reduce_mean(tf.abs(mean_x - output_data) ** 2) var = tf.reduce_mean(errors_y) # when constructing the cost function, we ensure that the norm of the state # remains close to 1, and that the variance in the error do not grow. state_norm = tf.abs(tf.reduce_mean(state.trace())) cost = loss + regularization * (tf.abs(state_norm - 1) ** 2) + reg_variance*var tf.summary.scalar('cost', cost) # =================================================================================== # Perform the optimization # =================================================================================== # we choose the Adam optimizer optimiser = tf.train.AdamOptimizer() min_op = optimiser.minimize(cost) session = tf.Session() session.run(tf.global_variables_initializer()) print('Beginning optimization') loss_vals = [] error_vals = [] # start time start_time = time.time() for i in range(reps+1): loss_, predictions, errors, mean_error, ket_norm, _ = session.run( [loss, mean_x, errors_y, var, state_norm, min_op], feed_dict={input_data: train_data, output_data: data_y}) loss_vals.append(loss_) error_vals.append(mean_error) if i % 100 == 0: print('Step: {} Loss: {}'.format(i, loss_)) end_time = time.time() # =================================================================================== # Analyze the results # =================================================================================== test_predictions = session.run(mean_x, feed_dict={input_data: test_data}) np.save('sine_test_predictions', test_predictions) print("Elapsed time is {} seconds".format(np.round(end_time - start_time))) x = np.linspace(-xmax, xmax, 200) # set plotting options rcParams['font.family'] = 'serif' rcParams['font.sans-serif'] = ['Computer Modern Roman'] fig, ax = plt.subplots(1,1) # plot the function to be fitted, in green ax.plot(x, f3(x), color='#3f9b0b', zorder=1, linewidth=2) # plot the training data, in red ax.scatter(train_data, data_y, color='#fb2943', marker='o', zorder=2, s=75) # plot the test predictions, in blue ax.scatter(test_data, test_predictions, color='#0165fc', marker='x', zorder=3, s=75) ax.set_xlabel('Input', fontsize=18) ax.set_ylabel('Output', fontsize=18) ax.tick_params(axis='both', which='minor', labelsize=16) fig.savefig('result.pdf', format='pdf', bbox_inches='tight') ================================================ FILE: requirements.txt ================================================ strawberryfields==0.10 tensorflow==1.3 matplotlib ================================================ FILE: tetrominos_learning/plot_images.py ================================================ # Copyright 2018 Xanadu Quantum Technologies Inc. # 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. """ This scripts converts Tetris numpy images into a .png figure.""" import numpy as np import matplotlib.pyplot as plt import os ##################### set local directories ######## # Model name model_string = 'tetris' # Output folder folder_locator = './outputs/' # Locations of saved data and output figure save_string = folder_locator + 'models/' + model_string + '/' # Loading of images images_out = np.load(save_string + 'images_out.npy') images_out_big = np.load(save_string + 'images_out_big.npy') num_labels = 7 plot_scale = 1 # Plotting of the final image. fig_images, axs = plt.subplots( nrows=2, ncols=num_labels, figsize=(num_labels * plot_scale, 2 * plot_scale) ) all_images = [images_out, images_out_big] for i in range(2): for lable in range(num_labels): ax = axs[i][lable] ax.imshow(all_images[i][lable], cmap='gray') ax.axis('off') ax.set_xticklabels([]) ax.set_yticklabels([]) plt.tight_layout() fig_images.savefig(save_string + 'fig_images.png') ================================================ FILE: tetrominos_learning/tetrominos_learning.py ================================================ # Copyright 2018 Xanadu Quantum Technologies Inc. # 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. """ This script trains a quantum network for encoding Tetris images in the quantum state of two bosonic modes.""" import strawberryfields as sf from strawberryfields.ops import Dgate, BSgate, Kgate, Sgate, Rgate import tensorflow as tf import numpy as np import time import os import sys sys.path.append("..") import version_check os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' os.environ['OMP_NUM_THREADS'] = '1' os.environ['CUDA_VISIBLE_DEVICES'] = '1' # ============================================= # Settings and hyperparameters # ============================================= # Model name model_string = 'tetris' # Output folder folder_locator = './outputs/' # Locations of TensorBoard and model saving outputs board_string = folder_locator + 'tensorboard/' + model_string + '/' save_string = folder_locator + 'models/' + model_string + '/' # Record initial time init_time = time.time() # Set seed for random generator tf.set_random_seed(1) # Depth of the quantum network (suggested: 25) depth = 25 # Fock basis truncation cutoff = 11 # suggested value: 11 # Image size (im_dim X im_dim) im_dim = 4 # Number of optimization steps (suggested: 50000) reps = 20000 # Number of steps between data logging/saving. partial_reps = 1000 # Number of images to encode (suggested: 7) num_images = 7 # Clipping of training parameters disp_clip = 5 sq_clip = 5 kerr_clip = 1 # Weight for quantum state normalization norm_weight = 100.0 # ==================================================== # Manual definition of target images # ==================================================== train_images = np.zeros((num_images, im_dim, im_dim)) # Target images: L,O,T,I,S,J,Z tetrominos. L, O, T, I, S, J, Z = np.zeros((num_images, im_dim, im_dim)) L[0, 0] = L[1, 0] = L[2, 0] = L[2, 1] = 1 / np.sqrt(4) O[0, 0] = O[1, 1] = O[0, 1] = O[1, 0] = 1 / np.sqrt(4) T[0, 0] = T[0, 1] = T[0, 2] = T[1, 1] = 1 / np.sqrt(4) I[0, 0] = I[1, 0] = I[2, 0] = I[3, 0] = 1 / np.sqrt(4) S[1, 0] = S[1, 1] = S[0, 1] = S[0, 2] = 1 / np.sqrt(4) J[0, 1] = J[1, 1] = J[2, 1] = J[2, 0] = 1 / np.sqrt(4) Z[0, 0] = Z[0, 1] = Z[1, 1] = Z[1, 2] = 1 / np.sqrt(4) train_images = [L, O, T, I, S, J, Z] # ==================================================== # Initialization of TensorFlow variables # ==================================================== print('Initializing TensorFlow graph...') # Initial standard deviation of parameters sdev = 0.1 # Coherent state amplitude alpha = 1.4 # Combinations of two-mode amplitudes corresponding to different final images disps_alpha = tf.constant( [alpha, -alpha, alpha, -alpha, 1.0j * alpha, -1.0j * alpha, 1.0j * alpha] ) disps_beta = tf.constant( [alpha, alpha, -alpha, -alpha, 1.0j * alpha, 1.0j * alpha, -1.0j * alpha] ) # Trainable weights of the quantum network. with tf.name_scope('variables'): r1 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) r2 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) theta1 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) phi1 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) theta2 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) phi2 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) sqr1 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) sqphi1 = tf.Variable(tf.random_normal(shape=[depth])) sqr2 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) sqphi2 = tf.Variable(tf.random_normal(shape=[depth])) dr1 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) dphi1 = tf.Variable(tf.random_normal(shape=[depth])) dr2 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) dphi2 = tf.Variable(tf.random_normal(shape=[depth])) kappa1 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) kappa2 = tf.Variable(tf.random_normal(shape=[depth], stddev=sdev)) # List of all the weights parameters = [ r1, r2, theta1, phi1, theta2, phi2, sqr1, sqphi1, sqr2, sqphi2, dr1, dphi1, dr2, dphi2, kappa1, kappa2, ] # ==================================================== # Definition of the quantum neural network # ==================================================== # Single quantum variational layer def layer(l): with tf.name_scope('layer_{}'.format(l)): BSgate(theta1[l], phi1[l]) | (q[0], q[1]) Rgate(r1[l]) | q[0] Sgate(tf.clip_by_value(sqr1[l], -sq_clip, sq_clip), sqphi1[l]) | q[0] Sgate(tf.clip_by_value(sqr2[l], -sq_clip, sq_clip), sqphi2[l]) | q[1] BSgate(theta2[l], phi2[l]) | (q[0], q[1]) Rgate(r2[l]) | q[0] Dgate(tf.clip_by_value(dr1[l], -disp_clip, disp_clip), dphi1[l]) | q[0] Dgate(tf.clip_by_value(dr2[l], -disp_clip, disp_clip), dphi2[l]) | q[1] Kgate(tf.clip_by_value(kappa1[l], -kerr_clip, kerr_clip)) | q[0] Kgate(tf.clip_by_value(kappa2[l], -kerr_clip, kerr_clip)) | q[1] # StrawberryFields quantum simulator of 2 optical modes engine, q = sf.Engine(num_subsystems=2) # Definition of the CV quantum network with engine: # State preparation Dgate(disps_alpha) | q[0] Dgate(disps_beta) | q[1] # Sequence of variational layers for i in range(depth): layer(i) # Symbolic evaluation of the output state state = engine.run('tf', cutoff_dim=cutoff, eval=False, batch_size=num_images) ket = state.ket() trace = tf.abs(state.trace()) # Projection on the subspace of up to im_dim-1 photons for each mode. ket_reduced = ket[:, :im_dim, :im_dim] norm = tf.sqrt(tf.abs(tf.reduce_sum(tf.conj(ket_reduced) * ket_reduced, axis=[1, 2]))) # Since norm has shape [num_images] while ket_reduced has shape [num_images,im_dim,im_dim] # we need to add 2 extra dimensions to the norm tensor. norm_extended = tf.reshape(norm, [num_images, 1, 1]) ket_processed = ket_reduced / tf.cast(norm_extended, dtype=tf.complex64) # ==================================================== # Definition of the loss function # ==================================================== # Target images data_states = tf.placeholder(tf.complex64, shape=[num_images, im_dim, im_dim]) # Overlaps with target images overlaps = tf.abs(tf.reduce_sum(tf.conj(ket_processed) * data_states, axis=[1, 2])) ** 2 # Overlap cost function overlap_cost = tf.reduce_mean((overlaps - 1) ** 2) # State norm cost function norm_cost = tf.reduce_sum((trace - 1) ** 2) cost = overlap_cost + norm_weight * norm_cost # ==================================================== # TensorBoard logging of cost functions and images # ==================================================== tf.summary.scalar('Cost', cost) tf.summary.scalar('Norm cost', norm_cost) tf.summary.scalar('Overlap cost', overlap_cost) # Output images with and without subspace projection. images_out = tf.abs(ket_processed) ** 2 images_out_big = tf.abs(ket) ** 2 tf.summary.image( 'image_out', tf.expand_dims(images_out, axis=3), max_outputs=num_images ) tf.summary.image( 'image_out_big', tf.expand_dims(images_out_big, axis=3), max_outputs=num_images ) # TensorBoard writer and summary writer = tf.summary.FileWriter(board_string) merge = tf.summary.merge_all() # ==================================================== # Training # ==================================================== # Optimization algorithm (Adam optimizer) optim = tf.train.AdamOptimizer() training = optim.minimize(cost) print('Graph building time: {:3f}'.format(time.time() - init_time)) # TensorFlow session with tf.Session() as session: session.run(tf.global_variables_initializer()) start_time = time.time() for i in range(reps): rep_time = time.time() # make an optimization step _training = session.run(training, feed_dict={data_states: train_images}) if (i + 1) % partial_reps == 0: # evaluate tensors for saving and logging [summary, params_numpy, _images_out, _images_out_big] = session.run( [merge, tf.squeeze(parameters), images_out, images_out_big], feed_dict={data_states: train_images}, ) # save tensorboard data writer.add_summary(summary, i + 1) # save trained weights os.makedirs(save_string, exist_ok=True) np.save(save_string + 'trained_params.npy', params_numpy) # save output images as numpy arrays np.save(save_string + 'images_out.npy', _images_out) np.save(save_string + 'images_out_big.npy', _images_out_big) print( 'Iteration: {:d} Single iteration time {:.3f}'.format( i + 1, time.time() - rep_time ) ) print('Script completed. Total time: {:3f}'.format(time.time() - init_time)) ================================================ FILE: version_check.py ================================================ """Script for checking the correct versions of Python, StrawberryFields and TensorFlow are being used.""" import sys import strawberryfields as sf import tensorflow as tf python_version = sys.version_info sf_version = sf.__version__ tf_version = tf.__version__.split(".") if python_version < (3, 5) or python_version > (3, 6): raise SystemError("Your version of python is {}.{}. You must have Python 3.5 or 3.6 installed " "to run this script.".format(python_version.major, python_version.minor)) if sf_version != "0.10.0": raise ImportError("An incompatible version of StrawberryFields is installed. You must have " "StrawberryFields version 0.10 to run this script. To install the correct " "version, run:\n >>> pip install strawberryfields==0.10") if not(tf_version[0] == "1" and tf_version[1] == "3"): raise ImportError("An incompatible version of TensorFlow is installed. You must have " "TensorFlow version 1.3 to run this script. To install the correct " "version, run:\n >>> pip install tensorflow==1.3")