Tutorials
qcr:2606.92305.1

Building Noise Models on Amazon Braket

Accurately modeling the noise of real quantum hardware is essential for predicting how circuits will behave and for developing error-mitigation and error-correction strategies, and this Amazon Braket notebook introduces Braket's noise modeling tools. A noise model is a specification of which error channels act on which operations, and the notebook shows how to build one from the ground up: instantiating individual noise channels such as bit-flip, phase-flip, depolarizing, amplitude damping, and two-qubit correlated noise, and attaching them to gates, qubits, or the whole circuit according to flexible criteria. It then demonstrates applying a constructed noise model to a circuit and running it on Braket's density-matrix simulator, which tracks the full mixed state, so the resulting measurement statistics reflect the modeled imperfections. The notebook also shows how a realistic noise model can be assembled from a device's published calibration data, so simulations can be tuned to mimic a specific QPU. By making noise construction explicit and composable, the example equips researchers to study how errors propagate through their circuits and to benchmark mitigation techniques, all within the Amazon Braket SDK.
QEM
Qubit
Circuit-based
Uploaded 1 day ago
33
Views
GitHub582
Citing this entry? Use this QCR ID
Uploaded by
QL
QCR Librarian

Overview

amazon-braket/amazon-braket-examples
582261
In [ ]:
# --- Setup cell added by QCR (not part of the original tutorial) ---
# Source: amazon-braket/amazon-braket-examples @ 0c0818f315479aab9deebed7e7ed7533ac581923, Apache License 2.0.
# Installs the example's dependencies. If a later cell still reports a missing
# package, restart the runtime/kernel and run again from the top.
%pip install -q amazon-braket-sdk==1.117.3

Noise models on Amazon Braket

This notebook introduces noise models on Amazon Braket. We show how to create noise models containing different types of noise and instructions for how to apply the noise to a circuit. In the next notebooks, we will show how to construct a noise model from device calibration data for real quantum processing units (QPUs).

Before you begin: We recommend being familiar with noise channels in Braket. For an introduction see Simulating Noise On Amazon Braket. Additionally, users should be familiar with Running quantum circuits on QPU devices

Table of Contents

  • What is a noise model?
  • Introduction to Noise Models
    • Adding noise to a noise model
    • Applying noise models to circuits
    • Qubit noise
    • Readout noise
    • Filtering noise models
    • Saving and loading noise models

What is a noise model?

Quantum devices and QPUs are subject noise on qubits and gate operations due to imperfect control. The presence of noise deteriorates the quality of a quantum computation, especially when creating highly-entangled states. Understanding the source and magnitude of this noise is essential to debugging and improving quantum computers.

The general noise on a quantum device is modelled as a noise channel (see Simulating Noise On Amazon Braket). The size of the full noise channel for a QPU scales exponentially with the number of qubits. Accordingly, it is essential to place assumptions on the noise channel to make it practical to simulate and debug circuits of interest.

A noise model encapsulates the assumptions on quantum noise channels and how they act on a given circuit. Simulating this noisy circuit gives information about much the noise impacts the results of the quantum computation. By incrementally adjusting the noise model, the impact of noise can be understood on a variety of quantum algorithms.

Finding realistic and accurate noise models for quantum devices is a active field of research. While simple models that treat each qubit or gate independently are useful, the effects of non-local crosstalk are often the most important when using multi-qubit devices.

Introduction to noise models

Noise models are contained in the Amazon Braket SDK, within the circuits module. The following lines of code import the required features:

In [1]:
from braket.circuits import Circuit, Gate, Observable
from braket.circuits.noise_model import GateCriteria, NoiseModel, ObservableCriteria
from braket.circuits.noises import AmplitudeDamping, BitFlip, Depolarizing, PauliChannel, PhaseFlip

Adding noise to a noise model

A noise model consists of a list of noise model instructions. Similar to circuits, we can add NoiseModelInstructions to model. First, we start we an empty noise model:

In [2]:
noise_model = NoiseModel()

A NoiseModelInstruction consists of two pieces of information: (1) what noise channel to apply, and (2) when to apply it. Common noise channels are available in the Braket noise module (see Simulating Noise On Amazon Braket). The information about when to apply the noise is contained a Criteria object. Criteria can depend on qubits, gates, or measured observables.

For example, consider applying depolarizing noise with probability noise after every Hadamard gate (Gate.H). The depolarizing channel maps a state to the maximal mixed state with probability , i.e. . In Braket, we denote this as Depolarizing(0.1). The condition to apply the noise only depends on the gate, so it is created with GateCriteria(Gate.H). The default behavior for gate criteria is to apply to all qubits, which is specified by setting qubits=None. We can specify only a subset of qubits with GateCriteria(gates=Gate.H, qubits=[0,1]) which will only apply noise to qubits 0 and 1. Similarly, we can apply the same noise channel to a set of gates with GateCriteria(gates=[Gate.H, Gate.S], qubits=[0]) which applies noise to both the Hadamard and phase gate on qubit 0.

In [3]:
noise_model = NoiseModel()
noise_model.add_noise(Depolarizing(0.1), GateCriteria(Gate.H))
print(noise_model)
Gate Noise:
  Depolarizing(0.1), GateCriteria({'H'}, None)

Great! We added depolarizing noise on gate to the noise model.

Note: Be careful adding noise to the model. If we repeat the noise_model.add_noise() twice with the same noise and criteria, we will get two entries in the noise model!

Similar to a circuit with instructions, we can see the list of noise model instructions with:

In [4]:
noise_model.instructions
[NoiseModelInstruction(noise=Depolarizing(0.1), criteria=GateCriteria({'H'}, None))]

Here, we only have one instruction which applies depolarizing noise after every gate.

Applying noise models to circuits

Noise models encapsulate all the information about the noise we wish to apply to circuits. This lets us apply noise channels across different circuits with minimal repetition.

For example, consider the circuit:

In [5]:
circ = Circuit().h(0).s(1).h(2).y(0).x(1).z(2)
print(circ)
T  : |0|1|
          
q0 : -H-Y-
          
q1 : -S-X-
          
q2 : -H-Z-

T  : |0|1|

We can apply the noise model to the circuit with noise_model.apply(circ) to produce the noisy circuit.

In [6]:
noisy_circ = noise_model.apply(circ)
print(noisy_circ)
T  : |     0     |1|
                    
q0 : -H-DEPO(0.1)-Y-
                    
q1 : -S-----------X-
                    
q2 : -H-DEPO(0.1)-Z-

T  : |     0     |1|

Notice how depolarizing noise is applied after every Hadamard gate, just like it was specified in the noise model.

We can also apply multiple noise models to a circuit. For example,

In [7]:
noise_model_2 = NoiseModel().add_noise(BitFlip(0.2), criteria=GateCriteria(Gate.H, 0))

noisy_circ_2 = noise_model_2.apply(noisy_circ)

print(noisy_circ_2)
T  : |          0          |1|
                              
q0 : -H-BF(0.2)---DEPO(0.1)-Y-
                              
q1 : -S---------------------X-
                              
q2 : -H-DEPO(0.1)-----------Z-

T  : |          0          |1|

Notice that the most recently applied noise model inserts noise directly after the target gate(s).

Modeling qubit decoherence by gate noise

Let's add a few more types of noise to the model. This time we will add amplitude dampening noise after every single-qubit gate, but only on qubit . This is intended to mimic the effect of the |1⟩ state decaying into the ground state |0⟩.

In [8]:
noise_model.add_noise(AmplitudeDamping(0.1), GateCriteria(qubits=0))
print(noise_model)
Gate Noise:
  Depolarizing(0.1), GateCriteria({'H'}, None)
  AmplitudeDamping(0.1), GateCriteria(None, {0})

Let's also add a highly-specific type of noise. Consider adding a Pauli channel noise after the X gate only on qubit 1.

In [9]:
noise_model.add_noise(PauliChannel(0.1, 0.2, 0.3), GateCriteria(gates=Gate.X, qubits=1))
print(noise_model)
Gate Noise:
  Depolarizing(0.1), GateCriteria({'H'}, None)
  AmplitudeDamping(0.1), GateCriteria(None, {0})
  PauliChannel(0.1, 0.2, 0.3), GateCriteria({'X'}, {1})

Now we have a noise model containing three terms.

  • depolarizing(0.1) after every Hadamard gate
  • amplitude dampening(0.1) after every gate on qubit 0.
  • Pauli channel(0.1, 0.2, 0.3) after an -gate on qubit 1.

Let' apply it to previous circuit:

In [10]:
print(noise_model.apply(circ))
T  : |         0         |        1        |
                                            
q0 : -H-DEPO(0.1)-AD(0.1)-Y-AD(0.1)---------
                                            
q1 : -S-------------------X-PC(0.1,0.2,0.3)-
                                            
q2 : -H-DEPO(0.1)---------Z-----------------

T  : |         0         |        1        |

Take a minute to double check that this is correct.

Note: If two or more criteria apply to the same gate and target qubits, then the order of the noise instructions in the noise model matters. In the above example, the Hadamard gate on qubit 0 has two types of noise applied after the gate. Since depolarizing noise appeared first in the noise model, it was applied first. The next criteria had amplitude dampening, so it was applied after the depolarizing noise.

Readout noise

Similarly, we can also add readout noise to circuits. By default, circuits at the end of a Braket circuit are measured in the -basis.

Let's add a bit flip readout noise with probability on qubits 0 and 1.

In [11]:
noise_model = NoiseModel()
noise_model.add_noise(BitFlip(0.01), ObservableCriteria(qubits=[1, 2]))
print(noise_model)
Readout Noise:
  BitFlip(0.01), ObservableCriteria(None, {1, 2})
In [12]:
print(noise_model.apply(circ))
T  : |0|1|
          
q0 : -H-Y-
          
q1 : -S-X-
          
q2 : -H-Z-

T  : |0|1|

Observable Criteria

Readout noise can also depend on the measurement basis. For single-qubit measurements, those would be measuring the in , , or basis. In Braket, measurements in other basis are defined with observables at the end of a circuit (see Braket result types).

For example, lets' measure on qubit 0, and on qubit 1.

In [13]:
circ.sample(Observable.X(), target=0)
circ.sample(Observable.Z(), target=1)
print(circ)
T  : |0|1|Result Types|
                     
q0 : -H-Y-Sample(X)----
                     
q1 : -S-X-Sample(Z)----
                     
q2 : -H-Z--------------

T  : |0|1|Result Types|

Noise models can also contain instructions based on which observable is present.

For example, let's add a phase flip error on qubit 0 when we measure in the -basis. Let's also add a bit flip channel when measuring in the -basis.

In [14]:
noise_model = NoiseModel()
noise_model.add_noise(PhaseFlip(0.02), ObservableCriteria(Observable.X, 0))
noise_model.add_noise(BitFlip(0.01), ObservableCriteria(Observable.Z, 1))
print(noise_model)
Readout Noise:
  PhaseFlip(0.02), ObservableCriteria({'X'}, {0})
  BitFlip(0.01), ObservableCriteria({'Z'}, {1})

Let's apply this noise model to a circuit. The circuit is the same as above, but this time we measure Observable.X on qubit 0.

In [15]:
noisy_circ = noise_model.apply(circ)
print(noisy_circ)
T  : |0|    1     |Result Types|
                              
q0 : -H-Y-PF(0.02)-Sample(X)----
                              
q1 : -S-X-BF(0.01)-Sample(Z)----
                              
q2 : -H-Z-----------------------

T  : |0|    1     |Result Types|

Take a minute to double check that all the terms in the noise model are applied in the correct place in the circuit.

Filtering noise models

We can reduce the size of the noise model by selecting only noise and criteria relevant to our interest. For instance, we might only care about noise affecting qubit 0.

Let's start with a large noise model:

In [16]:
noise_model = NoiseModel()
noise_model.add_noise(Depolarizing(0.1), GateCriteria(Gate.H))
noise_model.add_noise(Depolarizing(0.1), GateCriteria())

noise_model.add_noise(AmplitudeDamping(0.1), GateCriteria(qubits=0))
noise_model.add_noise(PauliChannel(0.1, 0.2, 0.3), GateCriteria(Gate.X, qubits=0))
noise_model.add_noise(PhaseFlip(0.02), ObservableCriteria(Observable.X, 0))
noise_model.add_noise(BitFlip(0.01), ObservableCriteria(Observable.Z, 1))
print(noise_model)
Gate Noise:
  Depolarizing(0.1), GateCriteria({'H'}, None)
  Depolarizing(0.1), GateCriteria(None, None)
  AmplitudeDamping(0.1), GateCriteria(None, {0})
  PauliChannel(0.1, 0.2, 0.3), GateCriteria({'X'}, {0})
Readout Noise:
  PhaseFlip(0.02), ObservableCriteria({'X'}, {0})
  BitFlip(0.01), ObservableCriteria({'Z'}, {1})

Now we filter the noise model by qubit=0 which returns a new noise model with only the noise affecting qubit 0.

In [17]:
reduced_noise_model = noise_model.from_filter(qubit=0)
print(reduced_noise_model)
Gate Noise:
  Depolarizing(0.1), GateCriteria({'H'}, None)
  Depolarizing(0.1), GateCriteria(None, None)
  AmplitudeDamping(0.1), GateCriteria(None, {0})
  PauliChannel(0.1, 0.2, 0.3), GateCriteria({'X'}, {0})
Readout Noise:
  PhaseFlip(0.02), ObservableCriteria({'X'}, {0})

Likewise, we can scope the noise model to only include noise that references a specific gate. Below, we filter by gate = Gate.H. Notice that qubit criteria, which doesn't depend on gate, is also included.

In [18]:
reduced_noise_model = noise_model.from_filter(gate=Gate.H)
print(reduced_noise_model)
Gate Noise:
  Depolarizing(0.1), GateCriteria({'H'}, None)
  Depolarizing(0.1), GateCriteria(None, None)
  AmplitudeDamping(0.1), GateCriteria(None, {0})

Similarly we can also filter by the type of noise, for instance to get only bit flip channels, we do:

In [19]:
reduced_noise_model = noise_model.from_filter(noise=BitFlip)
print(reduced_noise_model)
Readout Noise:
  BitFlip(0.01), ObservableCriteria({'Z'}, {1})

We can also combine filters to get more specific reductions.

In [20]:
reduced_noise_model = noise_model.from_filter(gate=Gate.H, qubit=1)
print(reduced_noise_model)
Gate Noise:
  Depolarizing(0.1), GateCriteria({'H'}, None)
  Depolarizing(0.1), GateCriteria(None, None)

If we don't filter by anything, the returned model will be the same as the original.

Saving and loading noise models

Noise models can be converted to Python dictionaries. This makes it easy to save and load models.

In [21]:
noise_model.to_dict()
{'instructions': [{'noise': {'__class__': 'Depolarizing',
    'probability': 0.1,
    'qubit_count': 1,
    'ascii_symbols': ('DEPO(0.1)',)},
   'criteria': {'__class__': 'GateCriteria', 'gates': ['H'], 'qubits': None}},
  {'noise': {'__class__': 'Depolarizing',
    'probability': 0.1,
    'qubit_count': 1,
    'ascii_symbols': ('DEPO(0.1)',)},
   'criteria': {'__class__': 'GateCriteria', 'gates': None, 'qubits': None}},
  {'noise': {'__class__': 'AmplitudeDamping',
    'gamma': 0.1,
    'qubit_count': 1,
    'ascii_symbols': ('AD(0.1)',)},
   'criteria': {'__class__': 'GateCriteria', 'gates': None, 'qubits': [0]}},
  {'noise': {'__class__': 'PauliChannel',
    'probX': 0.1,
    'probY': 0.2,
    'probZ': 0.3,
    'qubit_count': 1,
    'ascii_symbols': ('PC(0.1,0.2,0.3)',)},
   'criteria': {'__class__': 'GateCriteria', 'gates': ['X'], 'qubits': [0]}},
  {'noise': {'__class__': 'PhaseFlip',
    'probability': 0.02,
    'qubit_count': 1,
    'ascii_symbols': ('PF(0.02)',)},
   'criteria': {'__class__': 'ObservableCriteria',
    'observables': ['X'],
    'qubits': [0]}},
  {'noise': {'__class__': 'BitFlip',
    'probability': 0.01,
    'qubit_count': 1,
    'ascii_symbols': ('BF(0.01)',)},
   'criteria': {'__class__': 'ObservableCriteria',
    'observables': ['Z'],
    'qubits': [1]}}]}

To save the Python dictionary as a json file in a local directory, we use the json package.

In [22]:
import json

# save to local file
json.dump(noise_model.to_dict(), open("model_dict.json", "w"))

# Load from local file:
model_dict = json.load(open("model_dict.json"))
In [23]:
print(NoiseModel().from_dict(model_dict))
Gate Noise:
  Depolarizing(0.1), GateCriteria({'H'}, None)
  Depolarizing(0.1), GateCriteria(None, None)
  AmplitudeDamping(0.1), GateCriteria(None, {0})
  PauliChannel(0.1, 0.2, 0.3), GateCriteria({'X'}, {0})
Readout Noise:
  PhaseFlip(0.02), ObservableCriteria({'X'}, {0})
  BitFlip(0.01), ObservableCriteria({'Z'}, {1})

Summary

In this section, we showed how to construct custom noise models in Braket containing qubit, gate, and readout noise. We showed how to apply noise models to circuits, construct smaller noise models by filtering, and how to save/load models.

Join the Discussion

Comments (0)

No comments yet. Be the first to share your thoughts!

Indexed by QCR Librarian

This entry was created automatically from publicly available records. QCR links to public sources and only stores repository content where the license permits redistribution.

Versions

v1 Latest
Jun 17, 2026
qcr:2606.92305.1

Cite all versions? Use the base QCR ID to always reference the latest version of this entry.

Tools used

Amazon Braket SDK

Keywords

noise-model
density-matrix
error-channels
braket
simulation

You may also like5