tensorflow / quantum

Hybrid Quantum-Classical Machine Learning in TensorFlow
https://www.tensorflow.org/quantum
Apache License 2.0
1.78k stars 571 forks source link

Can quantum work on Large-scale distributed platform? #193

Closed amandalqy closed 4 years ago

amandalqy commented 4 years ago

Can quantum work on Large-scale distributed platform?such as several gpus?

swastiknath commented 4 years ago

A quantum computer works with bits which can be superimposed called the Qubits. Classical Hardware like GPU's or CPU's won't work with the computations those are powered by the Quantum Mechanics, although after the computation is ended a classical computer understandable response is generated. However Quantum Computers , which can be used to implement quantum logic gates can be distributed can each of these discrete Quantum Computers can be connected together using Quantum Networks. However Quantum Computing can help large distributed platforms to work as they exhibit a great property called Entanglement, which performs the classical distributed task like leader election with a great efficiency.

MichaelBroughton commented 4 years ago

If you are interested in the scaling capabilities of TensorFlow Quantum when it is being used for circuit simulation (not real quantum hardware) I can also mention this:

  1. TFQ works with things like tf.distribute.experimental.MultiWorkerMirroredStrategy() so if you want to offload your computation onto lots of nodes in a cluster, you can. More here
  2. TFQ currently doesn't support simulation on single or multiple GPUs. It is a tricky problem to tackle for a number of reasons, most importantly memory and communication bandwidth (especially on older GPUs). We are looking into adding GPU support, but it may be a while.

I've also quickly modified the QCNN tutorial to work on multiple nodes and parallelize over data (This isn't a very exciting use of multiple nodes, but it is a nice first example of using TFQ with multiple nodes once you get a network setup).

from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
import cirq
import sympy
import tensorflow_quantum as tfq
import numpy as np

strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy()

def generate_data(qubits):
    """Generate training and testing data."""
    n_rounds = 20  # Produces n_rounds * n_qubits datapoints.
    excitations = []
    labels = []
    for n in range(n_rounds):
        for bit in qubits:
            rng = np.random.uniform(-np.pi, np.pi)
            excitations.append(cirq.Circuit(cirq.Rx(rng)(bit)))
            labels.append(1 if (-np.pi / 2) <= rng <= (np.pi / 2) else -1)

    split_ind = int(len(excitations) * 0.7)
    train_excitations = excitations[:split_ind]
    test_excitations = excitations[split_ind:]

    train_labels = labels[:split_ind]
    test_labels = labels[split_ind:]

    return tfq.convert_to_tensor(train_excitations), np.array(train_labels), \
        tfq.convert_to_tensor(test_excitations), np.array(test_labels)

def cluster_state_circuit(bits):
    """Return a cluster state on the qubits in `bits`."""
    circuit = cirq.Circuit()
    circuit.append(cirq.H.on_each(bits))
    for this_bit, next_bit in zip(bits, bits[1:] + [bits[0]]):
        circuit.append(cirq.CZ(this_bit, next_bit))
    return circuit

def one_qubit_unitary(bit, symbols):
    """Make a Cirq circuit enacting a rotation of the bloch sphere about the X,
    Y and Z axis, that depends on the values in `symbols`.
    """
    return cirq.Circuit(
        cirq.X(bit)**symbols[0],
        cirq.Y(bit)**symbols[1],
        cirq.Z(bit)**symbols[2])

def two_qubit_unitary(bits, symbols):
    """Make a Cirq circuit that creates an arbitrary two qubit unitary."""
    circuit = cirq.Circuit()
    circuit += one_qubit_unitary(bits[0], symbols[0:3])
    circuit += one_qubit_unitary(bits[1], symbols[3:6])
    circuit += [cirq.ZZ(*bits)**symbols[7]]
    circuit += [cirq.YY(*bits)**symbols[8]]
    circuit += [cirq.XX(*bits)**symbols[9]]
    circuit += one_qubit_unitary(bits[0], symbols[9:12])
    circuit += one_qubit_unitary(bits[1], symbols[12:])
    return circuit

def two_qubit_pool(source_qubit, sink_qubit, symbols):
    """Make a Cirq circuit to do a parameterized 'pooling' operation, which
    attempts to reduce entanglement down from two qubits to just one."""
    pool_circuit = cirq.Circuit()
    sink_basis_selector = one_qubit_unitary(sink_qubit, symbols[0:3])
    source_basis_selector = one_qubit_unitary(source_qubit, symbols[3:6])
    pool_circuit.append(sink_basis_selector)
    pool_circuit.append(source_basis_selector)
    pool_circuit.append(cirq.CNOT(control=source_qubit, target=sink_qubit))
    pool_circuit.append(sink_basis_selector**-1)
    return pool_circuit

def quantum_conv_circuit(bits, symbols):
    """Quantum Convolution Layer following the above diagram.
    Return a Cirq circuit with the cascade of `two_qubit_unitary` applied
    to all pairs of qubits in `bits` as in the diagram above.
    """
    circuit = cirq.Circuit()
    for first, second in zip(bits[0::2], bits[1::2]):
        circuit += two_qubit_unitary([first, second], symbols)
    for first, second in zip(bits[1::2], bits[2::2] + [bits[0]]):
        circuit += two_qubit_unitary([first, second], symbols)
    return circuit

def quantum_pool_circuit(source_bits, sink_bits, symbols):
    """A layer that specifies a quantum pooling operation.
    A Quantum pool tries to learn to pool the relevant information from two
    qubits onto 1.
    """
    circuit = cirq.Circuit()
    for source, sink in zip(source_bits, sink_bits):
        circuit += two_qubit_pool(source, sink, symbols)
    return circuit

def create_model_circuit(qubits):
    """Create sequence of alternating convolution and pooling operators 
    which gradually shrink over time."""
    model_circuit = cirq.Circuit()
    symbols = sympy.symbols('qconv0:63')
    # Cirq uses sympy.Symbols to map learnable variables. TensorFlow Quantum
    # scans incoming circuits and replaces these with TensorFlow variables.
    model_circuit += quantum_conv_circuit(qubits, symbols[0:15])
    model_circuit += quantum_pool_circuit(qubits[:4], qubits[4:],
                                          symbols[15:21])
    model_circuit += quantum_conv_circuit(qubits[4:], symbols[21:36])
    model_circuit += quantum_pool_circuit(qubits[4:6], qubits[6:],
                                          symbols[36:42])
    model_circuit += quantum_conv_circuit(qubits[6:], symbols[42:57])
    model_circuit += quantum_pool_circuit([qubits[6]], [qubits[7]],
                                          symbols[57:63])
    return model_circuit

# Create our qubits and readout operators in Cirq.
cluster_state_bits = cirq.GridQubit.rect(1, 8)
readout_operators = cirq.Z(cluster_state_bits[-1])

# Generate some training data.
train_excitations, train_labels, test_excitations, test_labels = generate_data(
    cluster_state_bits)

# Build a sequential model enacting the logic in 1.3 of this notebook.
# Here you are making the static cluster state prep as a part of the AddCircuit and the
# "quantum datapoints" are coming in the form of excitation

opt = tf.keras.optimizers.Adam(learning_rate=0.02)
excitation_input = tf.keras.Input(shape=(), dtype=tf.dtypes.string)

with strategy.scope():    
    cluster_state = tfq.layers.AddCircuit()(
        excitation_input, prepend=cluster_state_circuit(cluster_state_bits))

    quantum_model = tfq.layers.PQC(create_model_circuit(cluster_state_bits),
                                   readout_operators)(cluster_state)

    qcnn_model = tf.keras.Model(inputs=[excitation_input], outputs=[quantum_model])
    qcnn_model.compile(optimizer=opt,
                       loss=tf.losses.mse)

history = qcnn_model.fit(x=train_excitations,
                         y=train_labels,
                         batch_size=32,
                         epochs=25,
                         verbose=1)

Does this answer your question ?

amandalqy commented 4 years ago

@ MichaelBroughton @ swastiknath Thank you for your reply! I want to make use of TFQ for quantum circuit simulation on multiple GPUs or CPUs . Does tf.distribute.experimental.MultiWorkerMirroredStrategy() allow quantum circuit simulation to run on several CPUS? In the sentence"so if you want to offload your computation onto lots of nodes in a cluster",what does "cluster"mean? Does it mean cluster_state_bit(quantum data)? Or does it mean CPU?

swastiknath commented 4 years ago

@amandalqy You cannot use distributed GPU's to offload the circuit simulation. It only works on CPUs as paralleling these workload into discrete GPU's will create much overhead which tf.distribute.experimental.MultiWorkerMirroredStrategy() cannot handle as of now, but collaborators are working. It can work with multiple CPUs. Cluster means you can rather than using a single device can connect many CPU powered devices to offload your workload while using the simulation.

MichaelBroughton commented 4 years ago

@amandalqy Is this issue resolved or are there still some outstanding questions ?

amandalqy commented 4 years ago

@MichaelBroughton @ swastiknath Thank you for your reply! Can the available simulator run on several computers that share a LAN or in the same cloud? How many qubits can the tensorflow quantum simulator support at most? Thank you!

MichaelBroughton commented 4 years ago

So the simulator tensorflow quantum uses runs one circuit on one machine. In TensorFlow Quantum I might have a batch of 30 different circuits. TFQ lets me do things like: simulate 15 of those circuits on one computer over LAN (or cloud) and 15 on another in parallel. We use full state vector simulation so we can comfortably do a little over 30 qubits.

From a simulation perspective, one way to think of things is like this:

TFQ lets you use lots of distributed compute resources to simulate lots and lots of moderately sized circuits.

A Tensor network simulator (Like the one used here: https://arxiv.org/pdf/1710.05867.pdf ) lets you use lots of distributed compute resources to simulate one really big circuit (usually with limited depth and precision etc.)

amandalqy commented 4 years ago

Thanks a lot! It helps me a lot!

amandalqy commented 4 years ago

Does the tensor network simulator have the decomposition function of CZ gate for a big circuit running on lots of distributed machines?Thank you!

MichaelBroughton commented 4 years ago

I don't really understand what you are asking, but I will say this:

Many simulation efforts that want to push the number of qubits up into the 35+ range past what is possible with just state vector simulation do so by trading the exponential cost in qubit count for an exponential cost in circuit depth (Tensor networks can do this, but there are other ways). In certain situations a heuristic that can be used in simulation to greatly improve the runtime is to identify subsystems in the circuit that have few gates crossing between them (CZ is nice because it has a low Schmidt rank), with a little extra bookkeeping you can simulate the subsystems nearly independently of one another in order to simulate sampling from the original system. If you are still interested I would recommend reading more papers that experiment with different techniques for high qubit count simulation, they will do a better job explaining things than I will.

To re-iterate we do NOT use tensor network simulation in TFQ. We use full state vector simulation. Our goal isn't big circuits it's many moderately sized circuits.

Going to close this issue since Tensor network simulation is getting off topic.