python v0.7

TensorFlow Quantum

Google's framework for hybrid quantum-classical machine learning with Keras integration

Quick install

pip install tensorflow-quantum

Background and History

TensorFlow Quantum (TFQ) was developed by a collaboration between Google Quantum AI and the University of Waterloo, with the project publicly announced and released in March 2020. The lead authors of the accompanying paper included Michael Broughton, Guillaume Verdon, Trevor McCourt, and other members of Google’s quantum computing and TensorFlow teams. TFQ was created to provide a native integration between quantum circuits and TensorFlow’s machine learning infrastructure, enabling researchers to train quantum models using the same Keras workflows and optimizers used for classical deep learning.

The timing of TFQ’s release coincided with a period of intense interest in quantum machine learning (QML). Researchers were exploring whether parameterized quantum circuits could serve as trainable models with advantages over classical neural networks for certain tasks. TFQ made this experimentation accessible by representing Cirq circuits as TensorFlow tensor types and computing gradients through the parameter-shift rule, all within the standard model.compile() and model.fit() Keras training loop.

TFQ reached version 0.7 and remained compatible with TensorFlow 2.11 and specific Cirq versions. However, development activity slowed notably after 2022. The project’s coupling to specific TensorFlow and Cirq version combinations made installation increasingly fragile as both dependencies evolved. Meanwhile, PennyLane, which launched at a similar time with a similar QML focus, gained broader adoption by supporting multiple classical ML frameworks (PyTorch, JAX, and TensorFlow) and multiple quantum backends (not just Cirq).

As of 2025, TFQ’s GitHub repository receives limited maintenance updates. The library remains functional for its supported version combinations and continues to be referenced in quantum machine learning literature. However, new QML projects more commonly choose PennyLane or build custom integrations with JAX and Cirq directly. TFQ’s legacy is significant: it helped establish quantum machine learning as a concrete research direction and demonstrated how quantum circuits could integrate with production ML infrastructure. For teams already committed to the TensorFlow/Cirq stack, it remains a viable tool, but prospective users should evaluate its maintenance status before adopting it for new projects.

Overview

TensorFlow Quantum sits at the intersection of two Google projects: Cirq (quantum circuit construction) and TensorFlow/Keras (classical machine learning). In TFQ, a parameterized quantum circuit becomes a layer in a Keras model. Gradients flow through the quantum circuit using the parameter-shift rule, which enables end-to-end training with standard optimizers such as Adam or SGD.

The primary use cases are quantum neural networks (QNNs), quantum kernel methods, and hybrid models that combine classical preprocessing with a quantum layer.

Installation

pip install tensorflow tensorflow-quantum

TFQ requires a compatible TensorFlow version. As of TFQ 0.7, TensorFlow 2.11 is supported. Check the compatibility table before installing.

Key Imports

import tensorflow as tf
import tensorflow_quantum as tfq
import cirq
import sympy

Core Concepts

Parameterized Circuits with Sympy

Gates in Cirq accept sympy.Symbol objects as parameters. TFQ treats these symbols as trainable variables.

import cirq
import sympy

qubit = cirq.GridQubit(0, 0)
theta = sympy.Symbol('theta')
phi   = sympy.Symbol('phi')

# Parameterized single-qubit rotations
circuit = cirq.Circuit([
    cirq.ry(theta)(qubit),
    cirq.rz(phi)(qubit),
])
print(circuit)
# 0: ---Ry(theta)---Rz(phi)---

Converting Circuits to Tensors

TFQ represents circuits as serialized string tensors. Use tfq.convert_to_tensor to convert Cirq circuits for use as model inputs.

import tensorflow_quantum as tfq

circuit_tensor = tfq.convert_to_tensor([circuit])
print(circuit_tensor.shape)  # (1,) - one circuit

PQC Layer

tfq.layers.PQC wraps a parameterized circuit and an observable into a Keras layer. It computes expectation values and supports backpropagation.

import tensorflow as tf
import tensorflow_quantum as tfq
import cirq
import sympy

qubit = cirq.GridQubit(0, 0)
theta = sympy.Symbol('theta')

circuit  = cirq.Circuit(cirq.ry(theta)(qubit))
readout  = cirq.Z(qubit)  # measure expectation of Pauli-Z

model = tf.keras.Sequential([
    tf.keras.layers.Input(shape=(), dtype=tf.string),
    tfq.layers.PQC(circuit, readout),
])

# Input: a batch of circuit tensors
circuit_tensor = tfq.convert_to_tensor([circuit])
output = model(circuit_tensor)
print(output)  # [[expectation_value]] - shape (1, 1)

Expectation Layer

tfq.layers.Expectation is lower-level than PQC. It takes circuits and symbol values separately, useful when input circuits vary per sample or when you want explicit control over symbol injection.

Training a Quantum Model

import tensorflow as tf
import tensorflow_quantum as tfq
import cirq
import sympy
import numpy as np

qubit = cirq.GridQubit(0, 0)
theta = sympy.Symbol('theta')

# Parameterized circuit
circuit = cirq.Circuit(cirq.ry(theta)(qubit))
readout = cirq.Z(qubit)

# Keras model with PQC layer
model = tf.keras.Sequential([
    tf.keras.layers.Input(shape=(), dtype=tf.string),
    tfq.layers.PQC(circuit, readout),
])

model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=0.1),
    loss=tf.keras.losses.MeanSquaredError(),
)

# Training data: same circuit input, target expectation value of -1.0
x_train = tfq.convert_to_tensor([circuit] * 20)
y_train = np.full((20, 1), -1.0, dtype=np.float32)

history = model.fit(x_train, y_train, epochs=30, verbose=0)
print(f"Final loss: {history.history['loss'][-1]:.4f}")
# theta trains toward π, where <Z> = -1

Differentiators

Differentiators control how gradients are computed through the quantum circuit.

DifferentiatorDescription
ParameterShiftExact gradient; two circuit evaluations per parameter
LinearCombinationApproximation; faster for many parameters
AdjointSimulator-only; efficient for statevector backends
# Use parameter-shift explicitly
differentiator = tfq.differentiators.ParameterShift()
pqc_layer = tfq.layers.PQC(circuit, readout, differentiator=differentiator)

Observables

Any Cirq PauliSum works as an observable.

# Single Pauli
obs_z = cirq.Z(qubit)

# Multi-qubit observable
q0, q1 = cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)
obs_zz = cirq.Z(q0) * cirq.Z(q1)   # ZZ correlation

# Sum of Paulis
obs_sum = cirq.X(q0) + 0.5 * cirq.Z(q1)

Relationship to Cirq

TFQ uses Cirq for all circuit construction. You must build circuits in Cirq before passing them to TFQ. Knowing Cirq’s gate notation, qubit types (GridQubit, LineQubit), and circuit structure is a prerequisite. TFQ does not support Qiskit or other circuit formats.

TFQ vs PennyLane for QML

AspectTFQPennyLane
BackendCirq onlyQiskit, Cirq, Braket, and others
Classical ML integrationTensorFlow/Keras nativePyTorch, TF, JAX, NumPy
Maintenance activityLower (as of 2024)More active
Community resourcesModerateLarger
Best fitAlready in TF ecosystemFramework-agnostic QML

Limitations

TFQ requires a specific TensorFlow version and the installation can be fragile across Python environments. Development has slowed relative to PennyLane, which has a larger active community and broader hardware backend support. TFQ only works with Cirq circuits, so any existing Qiskit or Braket code must be rewritten. Simulation speed is limited compared to native Cirq for classical tasks, since TFQ adds serialization overhead.