Skip to content

Commit 9c171e7

Browse files
committed
update week 16
1 parent 8f8dbb7 commit 9c171e7

File tree

9 files changed

+724
-1262
lines changed

9 files changed

+724
-1262
lines changed

doc/pub/week16/html/week16-bs.html

Lines changed: 108 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@
105105
2,
106106
None,
107107
'implementation-with-pennylane'),
108-
('Kullback-Leibler divergence',
108+
('Summary of steps in PennyLane implementation',
109109
2,
110110
None,
111-
'kullback-leibler-divergence')]}
111+
'summary-of-steps-in-pennylane-implementation')]}
112112
end of tocinfo -->
113113

114114
<body>
@@ -170,7 +170,7 @@
170170
<!-- navigation toc: --> <li><a href="#gibbs-sampling" style="font-size: 80%;">Gibbs sampling</a></li>
171171
<!-- navigation toc: --> <li><a href="#parameter-optimization-and-variational-techniques" style="font-size: 80%;">Parameter Optimization and Variational Techniques</a></li>
172172
<!-- navigation toc: --> <li><a href="#implementation-with-pennylane" style="font-size: 80%;">Implementation with PennyLane</a></li>
173-
<!-- navigation toc: --> <li><a href="#kullback-leibler-divergence" style="font-size: 80%;">Kullback-Leibler divergence</a></li>
173+
<!-- navigation toc: --> <li><a href="#summary-of-steps-in-pennylane-implementation" style="font-size: 80%;">Summary of steps in PennyLane implementation</a></li>
174174

175175
</ul>
176176
</li>
@@ -786,36 +786,69 @@ <h2 id="parameter-optimization-and-variational-techniques" class="anchor">Parame
786786
<!-- !split -->
787787
<h2 id="implementation-with-pennylane" class="anchor">Implementation with PennyLane </h2>
788788

789-
<p>As a concrete example, we outline how to implement an RQBM in
790-
PennyLane. We consider \( n_v \) visible and \( n_h \) hidden qubits. The ansatz
791-
can be, for instance, layers of parameterized single-qubit rotations
792-
and entangling gates that respect the bipartite structure. Below is
793-
illustrative code (in Python) using PennyLane&#8217;s default.qubit
794-
simulator.
789+
<p>Below we sketch a toy example: a two-qubit Quantum Circuit Born Machine
790+
(QCBM), which generates a probability distribution via a parameterized
791+
quantum circuit. While a QCBM is not exactly a QBM (it has no thermal
792+
state), it serves to show how to code a quantum generative model.
795793
</p>
796794

797-
<!-- !bc pycod -->
798795

799-
<!-- !ec -->
796+
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
797+
<div class="cell border-box-sizing code_cell rendered">
798+
<div class="input">
799+
<div class="inner_cell">
800+
<div class="input_area">
801+
<div class="highlight" style="background: #f8f8f8">
802+
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">pennylane</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">qml</span>
803+
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">pennylane</span> <span style="color: #008000; font-weight: bold">import</span> numpy <span style="color: #008000; font-weight: bold">as</span> np
804+
805+
<span style="color: #408080; font-style: italic"># Use a 2-qubit simulator</span>
806+
dev <span style="color: #666666">=</span> qml<span style="color: #666666">.</span>device(<span style="color: #BA2121">&#39;default.qubit&#39;</span>, wires<span style="color: #666666">=2</span>)
807+
808+
<span style="color: #408080; font-style: italic"># Define a simple 2-qubit QCBM circuit</span>
809+
<span style="color: #AA22FF">@qml</span><span style="color: #666666">.</span>qnode(dev)
810+
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">circuit</span>(params):
811+
<span style="color: #408080; font-style: italic"># params = 4 angles</span>
812+
qml<span style="color: #666666">.</span>RX(params[<span style="color: #666666">0</span>], wires<span style="color: #666666">=0</span>)
813+
qml<span style="color: #666666">.</span>RY(params[<span style="color: #666666">1</span>], wires<span style="color: #666666">=1</span>)
814+
qml<span style="color: #666666">.</span>CNOT(wires<span style="color: #666666">=</span>[<span style="color: #666666">0</span>, <span style="color: #666666">1</span>])
815+
qml<span style="color: #666666">.</span>RX(params[<span style="color: #666666">2</span>], wires<span style="color: #666666">=0</span>)
816+
qml<span style="color: #666666">.</span>RY(params[<span style="color: #666666">3</span>], wires<span style="color: #666666">=1</span>)
817+
<span style="color: #008000; font-weight: bold">return</span> qml<span style="color: #666666">.</span>probs(wires<span style="color: #666666">=</span>[<span style="color: #666666">0</span>,<span style="color: #666666">1</span>]) <span style="color: #408080; font-style: italic"># return probabilities of |00&gt;,|01&gt;,|10&gt;,|11&gt;</span>
818+
819+
<span style="color: #408080; font-style: italic"># Initialize random parameters</span>
820+
params <span style="color: #666666">=</span> np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>randn(<span style="color: #666666">4</span>, requires_grad<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">True</span>)
821+
822+
<span style="color: #408080; font-style: italic"># Get the output distribution from the circuit</span>
823+
probs <span style="color: #666666">=</span> circuit(params)
824+
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Probabilities:&quot;</span>, probs)
825+
</pre>
826+
</div>
827+
</div>
828+
</div>
829+
</div>
830+
<div class="output_wrapper">
831+
<div class="output">
832+
<div class="output_area">
833+
<div class="output_subarea output_stream output_stdout output_text">
834+
</div>
835+
</div>
836+
</div>
837+
</div>
838+
</div>
800839

801-
<p>This circuit takes a parameter vector params of length \( n_v+n_h \) and
802-
returns the probabilities \( p_{\Theta}(v) \) of measuring each visible
803-
bitstring \( v \). Notice we measure only the visible wires (the
804-
wires=list(range(n$\_$v)) in qml.probs marginalizes out the hidden
805-
qubit).
840+
<p>In this code, we create a two-qubit variational circuit and return the
841+
probabilities of each basis state. One could train params to match a
842+
target distribution by defining a cost function between
843+
probs and the data distribution, and using PennyLane&#8217;s automatic
844+
differentiation to update params. Though not a true QBM (no
845+
Hamiltonian or Gibbs state), this demonstrates how one might build and
846+
train a small quantum generative model in PennyLane.
806847
</p>
807848

808-
<!-- !split -->
809-
<h2 id="kullback-leibler-divergence" class="anchor">Kullback-Leibler divergence </h2>
810-
811-
<p>Next, we train this model to match a target dataset distribution.
812-
Suppose our data has distribution target = \( [p(00), p(01), p(10),
813-
p(11)] \). We can define the (classical) loss as the Kullback-Leibler
814-
divergence \( D_{\mathrm{KL}}(p_{\mathrm{data}}\vert\vert q_\Theta) \) or simply the
815-
negative log-likelihood. Then we update params by gradient descent.
816-
PennyLane&#8217;s automatic differentiation can compute gradients via the
817-
parameter-shift rule, but we show an explicit parameter-shift
818-
computation for demonstration:
849+
<p>To make it more QBM-like, one could encode the classical visible units
850+
as fixed inputs. For example, to compute the energy of a QBM
851+
Hamiltonian for a given visible bitstring, one might do:
819852
</p>
820853

821854

@@ -825,7 +858,18 @@ <h2 id="kullback-leibler-divergence" class="anchor">Kullback-Leibler divergence
825858
<div class="inner_cell">
826859
<div class="input_area">
827860
<div class="highlight" style="background: #f8f8f8">
828-
<pre style="line-height: 125%;">Initialize parameters <span style="color: #AA22FF; font-weight: bold">and</span> perform a simple gradient descent
861+
<pre style="line-height: 125%;"><span style="color: #408080; font-style: italic"># Example: compute expectation of a simple Hamiltonian for a given state |v&gt;</span>
862+
H <span style="color: #666666">=</span> <span style="color: #666666">1.5</span> <span style="color: #666666">*</span> qml<span style="color: #666666">.</span>PauliZ(<span style="color: #666666">0</span>) <span style="color: #666666">+</span> <span style="color: #666666">0.7</span> <span style="color: #666666">*</span> qml<span style="color: #666666">.</span>PauliZ(<span style="color: #666666">1</span>) <span style="color: #666666">+</span> <span style="color: #666666">0.9</span> <span style="color: #666666">*</span> qml<span style="color: #666666">.</span>PauliZ(<span style="color: #666666">0</span>)<span style="color: #AA22FF">@qml</span><span style="color: #666666">.</span>PauliZ(<span style="color: #666666">1</span>)
863+
864+
<span style="color: #AA22FF">@qml</span><span style="color: #666666">.</span>qnode(dev)
865+
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">energy_of_state</span>():
866+
<span style="color: #408080; font-style: italic"># Prepare visible qubits in state |v&gt; = |01&gt;, say</span>
867+
qml<span style="color: #666666">.</span>PauliX(wires<span style="color: #666666">=1</span>) <span style="color: #408080; font-style: italic"># flips qubit 1 to |1&gt;</span>
868+
<span style="color: #408080; font-style: italic"># No hidden qubits in this simple example</span>
869+
<span style="color: #408080; font-style: italic"># Return expectation of H in this state</span>
870+
<span style="color: #008000; font-weight: bold">return</span> qml<span style="color: #666666">.</span>expval(H)
871+
872+
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Energy of |01&gt; state:&quot;</span>, energy_of_state())
829873
</pre>
830874
</div>
831875
</div>
@@ -841,13 +885,43 @@ <h2 id="kullback-leibler-divergence" class="anchor">Kullback-Leibler divergence
841885
</div>
842886
</div>
843887

844-
<p>This code illustrates the training loop. At each epoch we evaluate
845-
the loss, compute gradients (via two forward passes per parameter),
846-
and update the parameters. In practice one can use qml.grad for
847-
automatic gradients, and more sophisticated optimizers (Adam, natural
848-
gradient, etc.). The above shows that PennyLane can seamlessly
849-
integrate quantum circuit definitions with classical training logic.
888+
<p>Here, we used a two-qubit Hamiltonian
889+
\( H=1.5\sigma_z^0+0.7\sigma_z^1+0.9\sigma_z^0\sigma_z^1 \) and prepared
890+
the state \( \vert v\rangle=\vert 01\rangle \). The <b>expval(H)</b> call returns
891+
</p>
892+
$$
893+
\langle 01 \vert H \vert 01\rangle = -1.5 + 0.7 - 0.9 = -1.7,
894+
$$
895+
896+
<p>(up to sign
897+
conventions). This shows how PennyLane can compute energies of basis
898+
states, which is a key step in evaluating the QBM energy and
899+
probability of data states.
900+
</p>
901+
902+
<p>In practice, training a QBM in PennyLane would involve preparing
903+
quantum states corresponding to the Gibbs distribution. One could use
904+
functions like qml.qaoa.cost.Hamiltonian or custom circuits to
905+
approximate \( \exp{-\beta H} \), and then use PennyLane&#8217;s optimizers. Also,
906+
PennyLane can interface with PyTorch or TensorFlow, enabling hybrid
907+
optimization of quantum circuits with classical parameters (e.g. the
908+
Hamiltonian weights).
850909
</p>
910+
911+
<!-- !split -->
912+
<h2 id="summary-of-steps-in-pennylane-implementation" class="anchor">Summary of steps in PennyLane implementation </h2>
913+
914+
<ol>
915+
<li> Define a quantum device (qml.device) with enough wires for visibles+hidden.</li>
916+
</ol>
917+
<p>0 Construct a parametric quantum circuit (ansatz) that depends on trainable parameters (e.g. angles in rotations and entangling gates).</p>
918+
<ol>
919+
<li> If modeling an RQBM, one might clamp visible qubits (preparing them according to training data) and apply gates only to hidden qubits.</li>
920+
<li> Measure relevant observables: one can return probabilities (probs) or expectation values (expval) of Pauli operators, depending on the chosen loss function.</li>
921+
<li> Define a cost function, such as the negative log-likelihood or a distance between output and target distribution.</li>
922+
</ol>
923+
<p>Use an optimizer (e.g. gradient descent, Adam) with PennyLane&#8217;s gradient calculations to update parameters.</p>
924+
851925
<!-- ------------------- end of main content --------------- -->
852926
</div> <!-- end container -->
853927
<!-- include javascript, jQuery *first* -->

0 commit comments

Comments
 (0)