Performance
MerLin quantum layers can run as PyTorch modules on either CPU or GPU. The
following results measure QuantumLayer execution on an NVIDIA H100 PCIe
GPU with 80 GB of memory.
GPU benchmark
The benchmark constructs an MZI entangling circuit with angle encoding and two
trainable variational layers. It measures graph-building time, forward time,
backward time, and PyTorch CUDA allocated-memory deltas. Results use
float32, two warmup steps, and five measured repetitions. The main sweep
uses batch sizes 1, 8, 32, and 64, mode counts 8, 12, 16, 20, and 24, and both
FOCK and UNBUNCHED computation spaces. Cases above 3,000,000 basis
states are skipped.
The benchmark was run with Python 3.12.3 and PyTorch 2.11.0+cu128. The plots
below were generated from
benchmarks/gpu_benchmark/gpu_memory.json using
benchmarks/gpu_benchmark/plot_gpu_memory_results.py. Photon-count plots
use batch size 8. Memory is the larger forward/backward peak allocated delta.
How to read these results
The computation space determines how many quantum amplitudes the layer must
store and update. FOCK uses photon-number occupation states, whose count
for n_modes modes and n_photons photons is
comb(n_modes + n_photons - 1, n_photons). UNBUNCHED uses states with at
most one photon per mode, whose count is comb(n_modes, n_photons).
Consequently, basis-state
counts—not mode count alone—are the most useful first indicator of memory and
execution cost. The count is the size of one quantum state; a batch requires
the corresponding work and storage for every item in the batch.
The timings describe different phases of using a layer:
Graph-building time is the one-time cost of constructing the computational graph. It is not included in the forward or backward timings.
Forward time is one evaluation of the layer for a batch.
Backward time is the gradient evaluation for that same batch.
The reported memory value is the largest increase in memory allocated by the PyTorch CUDA allocator during either measured pass. It is an incremental pressure estimate, not the total GPU memory used by the process, and it does not include memory held by other processes or necessarily all allocator reservations. The measurements use the configured batch size and are therefore not directly comparable across rows with different batches.
These are single-GPU reference measurements, not hardware-independent limits. They include framework, driver, circuit-construction, and measurement overheads, and should be used to compare scaling trends or reproduce the benchmark rather than to predict an exact runtime on another system. The representative rows below intentionally cover different spaces and system sizes; they are examples, not a ranking of the two computation spaces.
At batch size 8, representative results are:
Space |
Modes |
Photons |
Basis states |
Forward |
Backward |
|---|---|---|---|---|---|
|
16 |
8 |
490,314 |
63.6 ms |
133.8 ms |
|
24 |
6 |
475,020 |
143.1 ms |
253.1 ms |
|
20 |
10 |
184,756 |
99.8 ms |
202.5 ms |
|
24 |
12 |
2,704,156 |
193.7 ms |
1,135.5 ms |
The largest measured memory delta is 20,739.1 MiB for 24 modes and 12 photons
in UNBUNCHED space at batch size 8. In FOCK space, 16 modes and 8
photons reaches 927.5 MiB at the same batch size; larger Fock-space cases were
outside the configured basis-size limit.
Memory scaling
Timing scaling
Graph-building time grows substantially with basis size. For example, at
batch size 8, building the 24-mode, 12-photon UNBUNCHED layer takes
193.6 seconds, while its forward and backward passes take 193.7 ms and
1,135.5 ms respectively.
NoiseModel overhead
A smaller FOCK sweep compares a noiseless layer with a NoiseModel using
source indistinguishability 0.9 and transmittance 0.95. At batch size 8, the
noise model increases the 12-mode, 6-photon case from 36.3 ms to 912.0 ms in
the forward pass and from 59.7 ms to 1,090.0 ms in the backward pass. The
corresponding peak allocated delta increases from 18.2 MiB to 1,108.1 MiB.
Reproducing the benchmark
From the repository root, run the benchmark and generate its plots with:
PYTHONPATH=$PWD PCVL_PERSISTENT_PATH=.pcvl_home \
python benchmarks/gpu_benchmark/benchmark_gpu_memory.py \
--json-out benchmarks/gpu_benchmark/gpu_memory.json
PYTHONPATH=$PWD python benchmarks/gpu_benchmark/plot_gpu_memory_results.py \
--json benchmarks/gpu_benchmark/gpu_memory.json \
--output-dir docs/source/_static/performance/h100-perf-2607 \
--noise
The benchmark requires CUDA, PyTorch, and Perceval. See
benchmarks/gpu_benchmark/benchmark_gpu_memory.py for the complete set of
options and the configured sweep limits.