Combining PennyLane with Amazon Braket
Overview
# --- 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 pennylane==0.45.0 amazon-braket-pennylane-plugin==1.34.1 matplotlib
Combining PennyLane with Amazon Braket

PennyLane integrates with Amazon Braket to add additional features for quantum machine learning and optimization. This introductory tutorial walks you through how to train a quantum circuit using Amazon Braket simulators and PennyLane's automatic differentiation capabilities.
Setup
PennyLane is already installed on Braket notebook instances. On a local machine, PennyLane can be installed by following these instructions. It can then be imported with:
import pennylane as qml
from pennylane import numpy as npTo use Braket as a backend in PennyLane, we have to create a PennyLane device. Here we will first create a device that uses the local Braket simulator that runs on your local laptop (or on the server that hosts this notebook).
wires = 2 # Number of qubits
dev = qml.device("braket.local.qubit", wires=wires)Below we will also show you how to scale out simulations to the AWS cloud.
Defining a circuit
We will choose a simple two-qubit circuit with two controllable rotations and a CNOT gate.
@qml.qnode(dev)
def circuit(params):
qml.RX(params[0], wires=0)
qml.RY(params[1], wires=1)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(1))The qml.qnode(dev) decorator binds the circuit to the local Braket device. Now, every time that circuit() is called, the quantum computation defined in the function above will be executed with Braket.
@qml.qnode(dev, interface="<interface>").
Evaluating the circuit and accessing its gradient
Let's set some values for our controllable parameters:
params = np.array([0.1, 0.2], requires_grad=True)The circuit can be evaluated with these parameters using
print("Expectation value of circuit:", circuit(params))Expectation value of circuit: 0.9751703272018161
print("Drawing of circuit:\n")
print(qml.draw(circuit)(params))Drawing of circuit: 0: ──RX(0.10)─╭●─┤ 1: ──RY(0.20)─╰X─┤ <Z>
A crucial element of machine learning and optimization is accessing the gradient of a model with respect to its parameters. This functionality is built into PennyLane:
dcircuit = qml.grad(circuit)Here, dcircuit is a callable function that evaluates the gradient of the circuit, i.e., its partial derivatives with respect to the controllable parameters.
dcircuit(params)array([-0.0978434 , -0.19767681])
Training the circuit
Suppose we now want to minimize the output of the circuit by updating its parameters. This can be done using gradient-based optimization.
First, an optimizer is fixed:
opt = qml.GradientDescentOptimizer(stepsize=0.1)The next step is to run the optimizer for a chosen number of iterations:
import matplotlib.pyplot as plt
iterations = 20
costs = []
for i in range(iterations):
params, cost = opt.step_and_cost(circuit, params)
costs.append(cost)
# Visualize results
costs.append(circuit(params))
plt.plot(costs, "-o")
plt.xlabel("Iterations")
plt.ylabel("Cost")
print("Minimized circuit output:", circuit(params))
print("Optimized parameters:", params)Minimized circuit output: 0.37261070647126565 Optimized parameters: [0.4839502 1.13630274]
Running circuits on Braket's on-demand simulator, SV1
So far we have used the local Braket simulator. This is a great choice for quick prototyping, but it is not suitable for large circuits with many qubits and does not provide a connection to quantum hardware.
Amazon Braket also provides access to on-demand, high-performance simulators and quantum processing units (QPUs) from different providers. These devices can be accessed through PennyLane by changing a single line of code, unlocking the potential for machine learning and optimization on quantum hardware and high performance simulators!

# Use Braket SDK Cost Tracking to estimate the cost to run this example
from braket.tracking import Tracker
braket_tasks_cost = Tracker().start()Each remote Braket device can be selected through its ARN. The supported devices on Braket are listed here. For now, we will pick the on-demand SV1 simulator.
In PennyLane, all remote Braket devices are then accessed through a single PennyLane device named braket.aws.qubit.
from braket.devices import Devices
dev = qml.device("braket.aws.qubit", device_arn=Devices.Amazon.SV1, wires=2)A follow up tutorial shows you how to use the remote device to run multiple circuits in parallel, while the QAOA tutorial takes a deeper dive into graph optimization, including using SV1 to optimize a 20-node graph.
Let's execute our circuit on SV1, as well as calculating the gradient:
@qml.qnode(dev)
def circuit(params):
qml.RX(params[0], wires=0)
qml.RY(params[1], wires=1)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(1))
dcircuit = qml.grad(circuit)
print("Result of circuit run on SV1:", circuit(params))
print("Result of gradient calculation on SV1:", dcircuit(params))Result of circuit run on SV1: 0.37261070647126565 Result of gradient calculation on SV1: [-0.19585986 -0.80291741]
print("Quantum Task Summary")
print(braket_tasks_cost.quantum_tasks_statistics())
print(
"Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage. Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits, and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2).",
)
print(
f"Estimated cost to run this example: {braket_tasks_cost.qpu_tasks_cost() + braket_tasks_cost.simulator_tasks_cost():.3f} USD",
)Quantum Task Summary
{<_Amazon.SV1: 'arn:aws:braket:::device/quantum-simulator/amazon/sv1'>: {'shots': 0, 'tasks': {'COMPLETED': 2}, 'execution_duration': datetime.timedelta(microseconds=6000), 'billed_execution_duration': datetime.timedelta(seconds=6)}}
Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage. Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits, and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2).
Estimated cost to run this example: 0.008 USD
Running on a QPU with Amazon Braket Hybrid Jobs
In this notebook, the classical part of the algorithm was running locally. For longer-running algorithms or those requiring more intensive compute resources, it's recommended to dispatch the algorithm to Amazon Braket Hybrid Jobs, which fully manages the classical infrastructure, allowing you to focus on the algorithm. For example, you can train a larger circuit or increase the number of iterations.
The second benefit of running the algorithm as a hybrid job is that for iterative algorithms that require repeated calls to a QPU, you retain priority for that QPU. Once your quantum tasks are created in the hybrid job, they run ahead of other tasks waiting in the regular quantum task queue. This is because hybrid jobs have a separate queue from standalone tasks, ensuring that only a single hybrid job can run on a QPU at a time. This means your algorithm will not be interrupted by other quantum tasks, so it will run more efficiently and predictably. However, hybrid jobs have a separate queue from standalone tasks, so only a single hybrid job can run on a QPU at a time. For a single quantum circuit or a batch of circuits, it's recommended to create quantum tasks instead of hybrid jobs. Only iterative algorithms benefit from QPU priority queuing.
Note that hybrid jobs have at least a one-minute startup time since they create a containerized environment on Amazon EC2. So for very short workloads, there is likely no need to create a hybrid job.
You can run your local Python code as an Amazon Braket hybrid job by annotating your code with the `@hybrid_job`` decorator, as shown in the following code example. Only Python 3.12 is supported by default. For custom Python versions, you can choose to use a custom container from Amazon Elastic Container Registry (ECR) (see BYOC).
In the following code, we create a hybrid job for 10 iterations targeting Rigetti Cepheus-1-108Q. Since we specified Cepheus-1-108Q as the device, this job will run once Cepheus-1-108Q is available and has no jobs running ahead of it.
from braket.jobs import hybrid_job
from braket.jobs.metrics import log_metric
device_arn = Devices.Amazon.SV1
# device_arn = Devices.Rigetti.Cepheus1108Q # <-- uncomment this line to actually use Cepheus-1-108Q, it will cost about 120 USD
@hybrid_job(device=device_arn, data_format="pickle") # set priority QPU
def qubit_rotation(stepsize=0.1, iterations=5):
task_tracker = Tracker().start() # track Braket quantum tasks costs
dev = qml.device("braket.aws.qubit", device_arn=device_arn.value, wires=2, shots=1_000)
params = np.array([0.1, 0.2])
@qml.qnode(dev)
def circuit(params):
qml.RX(params[0], wires=0)
qml.RY(params[1], wires=1)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(1))
opt = qml.GradientDescentOptimizer(stepsize)
costs = []
for i in range(iterations):
params, cost = opt.step_and_cost(circuit, params)
costs.append(cost)
# Record the value of the cost function with each iteration
log_metric(metric_name="cost_function", value=cost, iteration_number=i)
# Additionally, keep track of cost in USD for Braket tasks
braket_task_cost = float(
task_tracker.qpu_tasks_cost() + task_tracker.simulator_tasks_cost(),
)
log_metric(metric_name="braket_cost", value=braket_task_cost, iteration_number=i)
return {"params": params, "costs": costs, "braket_tasks_cost": braket_task_cost}How long will it take the hybrid job to run?
Let's first check if the device is currently available with AwsDevice(device_arn).is_available().
from braket.aws import AwsDevice
AwsDevice(device_arn).is_availableTrue
Next, we check the hybrid job queue depth with AwsDevice(device_arn).queue_depth().jobs.
AwsDevice(device_arn).queue_depth().jobs'0 (1 prioritized hybrid job running)'
If the device is available and there are no hybrid jobs currently running, then it should take about 5 minutes to complete.
job = qubit_rotation(stepsize=0.2, iterations=20)
print(job)AwsQuantumJob('arn':'arn:aws:braket:us-west-1:606892779558:job/d6234c47-fad4-4cda-bf9a-95b1ed20857b')
Once the hybrid job has completed, we can retrieve the results with job.results().
%%time
results = job.result(allow_pickle=True)
print(results){'params': tensor([0.7454, 1.9814], requires_grad=True), 'costs': [array(0.928), array(0.904), array(0.9), array(0.91), array(0.886), array(0.852), array(0.812), array(0.778), array(0.744), array(0.664), array(0.596), array(0.486), array(0.35), array(0.258), array(0.278), array(0.104), array(0.062), array(-0.056), array(-0.096), array(-0.212)], 'braket_tasks_cost': 120.0}
CPU times: user 675 ms, sys: 51.8 ms, total: 727 ms
Wall time: 14min 6s
plt.plot(results["costs"], "o-")
plt.xlabel("Iterations")
plt.ylabel("Cost")
print("Minimized circuit output:", circuit(params))
print("Optimized parameters:", params)Minimized circuit output: 0.37261070647126565 Optimized parameters: [0.4839502 1.13630274]
job_cost = job.result(allow_pickle=True)["braket_tasks_cost"]
sv1_cost = float(braket_tasks_cost.simulator_tasks_cost())
print(
"Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage. Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits, and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2).",
)
print(f"Estimated cost to run this example: {job_cost + sv1_cost:.3f} USD")Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage. Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits, and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2). Estimated cost to run this example: 120.011 USD
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
Cite all versions? Use the base QCR ID to always reference the latest version of this entry.
Join the Discussion
Comments (0)
No comments yet. Be the first to share your thoughts!