Closed amandalqy closed 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.
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:
tf.distribute.experimental.MultiWorkerMirroredStrategy()
so if you want to offload your computation onto lots of nodes in a cluster, you can. More hereI'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 ?
@ 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?
@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.
@amandalqy Is this issue resolved or are there still some outstanding questions ?
@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!
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.)
Thanks a lot! It helps me a lot!
Does the tensor network simulator have the decomposition function of CZ gate for a big circuit running on lots of distributed machines?Thank you!
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.
Can quantum work on Large-scale distributed platform?such as several gpus?