pennylane について
PennyLaneは、量子回路の構築と微分を行うPythonフレームワークです。回路を量子・古典ハイブリッドモデルに組み込み、シミュレーターや実機で量子機械学習、変分アルゴリズム、量子化学の処理を行えます。
主な機能
- 01微分可能な量子回路
- 02勾配による回路最適化
- 03量子・古典ハイブリッドモデル
- 04量子化学ツール
- 05シミュレーターと実機のデバイスインターフェース
活用シーン
- 01量子ニューラルネットワークの学習
- 02VQEやQAOAの実装
- 03微分可能な量子化学計算
- 04デバイス間での量子アルゴリズム評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tondevrel/ scientific-agent-skills --skill pennylaneインストール後、Claude Code で/pennylaneを入力して読み込まれたか確認します。
詳細
PennyLane - 量子機械学習
PennyLane は、量子コンピューターをニューラルネットワークのレイヤーのように扱います。量子回路の勾配を計算することで(パラメーターシフト則またはバックプロパゲーションを使用)、古典・量子ハイブリッドモデルを最適化できます。
使用する場面
- 量子ニューラルネットワーク(QNN)の開発とトレーニング
- 変分量子アルゴリズム(VQE、QAOA)
- 古典・量子ハイブリッド機械学習(例:量子 CNN)
- 微分可能なフレームワークでの量子化学計算
- 異なるハードウェア(IBM、Rigetti、Xanadu、IonQ)での量子アルゴリズムのベンチマーク
- 量子制御パルスの最適化
- バレンプラトーやその他の QML 固有の現象の調査
参考ドキュメント
公式ドキュメント: https://docs.pennylane.ai/
デモ/チュートリアル: https://pennylane.ai/qml/demonstrations.html
検索パターン: qml.qnode、qml.device、qml.expval、qml.grad、qml.templates
基本原則
QNode(量子ノード)
QNode はデバイスに紐付けられた量子回路で、通常の Python 関数のように呼び出すことができます。PennyLane が微分できる基本単位です。
ハードウェア非依存性
PennyLane は統一されたインターフェースを提供します。同じコードを高性能シミュレーター(default.qubit)、GPU アクセラレーション対応バックエンド(lightning.qubit)、または実際の量子ハードウェアで実行できます。
自動微分
PennyLane の量子回路は勾配を「認識」します。標準的なオプティマイザー(Adam、SGD)を使って、回路内の回転角を調整できます。
クイックリファレンス
インストール
pip install pennylane
# For GPU support
pip install pennylane-lightning[gpu]
標準的なインポート
import pennylane as qml
from pennylane import numpy as np # Use PennyLane's wrapped NumPy for gradients
基本パターン - 微分可能な回路
import pennylane as qml
from pennylane import numpy as np
# 1. Define Device
dev = qml.device("default.qubit", wires=2)
# 2. Define QNode (Quantum Node)
@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))
# 3. Calculate Gradient
params = np.array([0.1, 0.2], requires_grad=True)
grad_fn = qml.grad(circuit)
print(f"Gradient: {grad_fn(params)}")
重要なルール
✅ 推奨事項
- qml.numpy を使用する - 微分するパラメーターには、必ず PennyLane がラップした NumPy を使用してください
- テンプレートを使用する - レイヤーを手動で構築する代わりに、効率的な QML アーキテクチャー向けの
qml.templates(StronglyEntanglingLayersなど)を使用してください - requires_grad を設定する - 学習可能なパラメーターには、明示的に
requires_grad=Trueを指定してください - lightning.qubit を優先する - 15 量子ビットを超えるシミュレーションでは、パフォーマンスが大幅に向上する lightning デバイスを使用してください
- ブロードキャストを使用する - 多くのゲートは入力配列へのブロードキャストに対応しており、ループより高速です
- 回路をバッチ処理する - 複数の入力を同時に処理するには、
qml.batch_inputまたはqml.mapを使用してください
❌ 禁止事項
- NumPy のバージョンを混在させない - 学習可能なパラメーターに標準の
import numpy as npを使用すると、自動微分エンジンが動作しなくなります - Ansatz を複雑にしすぎない - 勾配が消失するバレンプラトーを避けるため、シンプルな回路から始めてください
- シミュレーターで量子ビットを使いすぎない - メモリ使用量は 2^N に比例します。30 量子ビットでは、単一の状態ベクトルに約 16GB の RAM が必要です
- ワイヤーのインデックスをハードコードしない - コードの再利用性と拡張性を高めるため、ワイヤーには変数を使用してください
アンチパターン(絶対に避ける)
import pennylane as qml
# ❌ BAD: Standard numpy for trainable parameters
import numpy as np
# ✅ GOOD: PennyLane's wrapped numpy
from pennylane import numpy as np
# ❌ BAD: Creating a device inside a loop
for i in range(100):
dev = qml.device("default.qubit", wires=2) # Expensive initialization
# ✅ GOOD: Define device once
dev = qml.device("default.qubit", wires=2)
# ❌ BAD: Manual parameter shifting
# (shift = 0.5 * pi, calc f(x+s) - f(x-s)...)
# ✅ GOOD: Let PennyLane handle it automatically
grad = qml.grad(circuit)(params)
回路テンプレート(qml.templates)
組み込み QML レイヤー
import pennylane as qml
@qml.qnode(dev)
def qnn_layer(inputs, weights):
# Encoding classical data into quantum state
qml.AngleEmbedding(inputs, wires=range(n_qubits))
# Trainable entangling layer
qml.StronglyEntanglingLayers(weights, wires=range(n_qubits))
return qml.expval(qml.PauliZ(0))
ハイブリッド最適化(PyTorch/TF)
古典フレームワークとの統合
import torch
import pennylane as qml
dev = qml.device("default.qubit", wires=2)
@qml.qnode(dev, interface="torch")
def quantum_layer(phi, theta):
qml.RX(phi, wires=0)
qml.RZ(theta, wires=1)
return qml.expval(qml.PauliZ(0))
# Now this QNode can be used in a Torch Module
phi = torch.tensor(0.1, requires_grad=True)
theta = torch.tensor(0.2, requires_grad=True)
result = quantum_layer(phi, theta)
result.backward()
print(phi.grad)
量子化学(qml.qchem)
VQE ワークフロー
from pennylane import qchem
# 1. Define molecule
symbols = ["H", "H"]
coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614])
# 2. Build Hamiltonian
H, qubits = qchem.molecular_hamiltonian(symbols, coordinates)
# 3. Define VQE circuit
dev = qml.device("default.qubit", wires=qubits)
@qml.qnode(dev)
def vqe_circuit(params):
# Simple Hartree-Fock state + rotations
qml.BasisState(np.array([1, 1, 0, 0]), wires=range(qubits))
qml.DoubleExcitation(params[0], wires=[0, 1, 2, 3])
return qml.expval(H)
測定とオブザーバブル
期待値以外の測定
@qml.qnode(dev)
def multi_measure(params):
qml.RX(params[0], wires=0)
return (
qml.expval(qml.PauliZ(0)), # Expectation value
qml.var(qml.PauliZ(0)), # Variance
qml.probs(wires=[0, 1]), # Probabilities
qml.sample(qml.PauliX(1)) # Raw samples (shots)
)
実践的なワークフロー
1. 量子変分分類器
def variational_classifier(weights, bias, x):
"""A simple QNN classifier."""
return circuit(weights, x) + bias
def cost(weights, bias, X, Y):
predictions = [variational_classifier(weights, bias, x) for x in X]
return square_loss(Y, predictions)
# Optimizer
opt = qml.AdamOptimizer(stepsize=0.1)
# ... loop with opt.step(cost, ...)
2. ハードウェアでの勾配計算(パラメーターシフト)
# When running on real hardware, PennyLane automatically uses
# the parameter-shift rule to calculate gradients via multiple executions.
dev_remote = qml.device("braket.aws.qubit", device_arn="...", wires=2)
@qml.qnode(dev_remote, diff_method="parameter-shift")
def hardware_circuit(params):
qml.RY(params[0], wires=0)
return qml.expval(qml.PauliZ(0))
3. ノイズシミュレーション
dev_noisy = qml.device("default.mixed", wires=2)
@qml.qnode(dev_noisy)
def noisy_circuit(p):
qml.Hadamard(wires=0)
# Apply depolarizing noise to wire 0
qml.DepolarizingChannel(p, wires=0)
return qml.state()
パフォーマンスの最適化
高速化のための JAX 統合
大規模シミュレーションでは、Just-In-Time(JIT)コンパイルにより、JAX が最速のインターフェースとなることがよくあります。
import jax
@qml.qnode(dev, interface="jax")
def fast_circuit(x):
qml.RX(x, wires=0)
return qml.expval(qml.PauliZ(0))
jit_circuit = jax.jit(fast_circuit)
随伴微分
大規模な回路では、diff_method="adjoint" はバックプロパゲーションよりもメモリ効率に優れています。
dev = qml.device("lightning.qubit", wires=20)
@qml.qnode(dev, diff_method="adjoint")
def large_circuit(params):
...
よくある落とし穴と解決策
「勾配消失」(バレンプラトー)
量子ビット数とレイヤー数が増えるにつれ、勾配は指数関数的に小さくなることがよくあります。
# ✅ Solution:
# 1. Use better initialization for weights.
# 2. Use local observables (PauliZ(i)) instead of global ones.
# 3. Use identity-block initialization.
学習対象ではない入力
最適化の対象にしないデータ(画像など)を渡したい場合があります。
# ✅ Solution: Use the 'argnum' in qml.grad or use non-array types
# Or explicitly:
params = np.array(0.1, requires_grad=True)
data = np.array(0.5, requires_grad=False)
出力形状の不一致
qml.probs はサイズ 2^N の配列を返します。
# ❌ Problem: Using probs(wires=[0,1,2]) in a loss function expecting a scalar.
# ✅ Solution: Use expval() for a single scalar or handle the distribution.
PennyLane は量子物理学と人工知能の間の橋渡しをします。量子回路を微分可能にすることで、次世代の科学計算に向けた強力でトレーニング可能なツールへと変えます。