ewdlop / ewdlop/NLPNote

Conceptual quantum machinear learning code implment in Qiskit and Q#

Open
#201 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Jupyter Notebook
Stars
2
Forks
0
PR merge metrics
No merged PRs in 30d

Description

ChatGPTA: 好的,下面給你各 2 段「能跑」的最小可行範例:一段 **Qiskit(Python)**,一段 **Q#(含 C# host)**。兩者都展示了典型 QML 流程:**資料嵌入(feature map)→ 參數化量子電路(PQC/ansatz)→ 以期望值當作可微損失做訓練(用 parameter-shift 做數值梯度)**。我用最小 XOR 類資料做二分類示範,模型輸出是測量 $Z$ 期望,映成 $[0,1]$ 機率。

---

# Qiskit:PQC 二分類(XOR),手刻 parameter-shift

```python
# pip install qiskit numpy
import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit.quantum_info import SparsePauliOp
from qiskit.primitives import Estimator

# ----- 1) Toy 資料(XOR) -----
X = np.array([[0.,0.],[0.,1.],[1.,0.],[1.,1.]]) # 兩維特徵
y = np.array([0,1,1,0]) # 標籤 {0,1}
# 簡單角度縮放,映到 [0, 2π)
scale = 2*np.pi
Xang = X * scale

# ----- 2) 量子特徵映射(Ry 角度編碼 + CNOT糾纏) -----
def feature_map(x):
qc = QuantumCircuit(2)
qc.ry(x[0], 0)
qc.ry(x[1], 1)
qc.cx(0, 1)
return qc

# ----- 3) Ansatz(兩層 Ry + CX) -----
def make_ansatz():
theta = ParameterVector("θ", 4) # 4 個可訓參數
qc = QuantumCircuit(2)
# layer 1
qc.ry(theta[0], 0)
qc.ry(theta[1], 1)
qc.cx(0, 1)
# layer 2
qc.ry(theta[2], 0)
qc.ry(theta[3], 1)
return qc, theta

ansatz, theta = make_ansatz()

# 觀測算符:Z ⊗ I(看第一顆量子位的 Z 期望)
observable = SparsePauliOp.from_list([("ZI", 1.0)])
estimator = Estimator() # 走本地模擬後端(如 Statevector/backends 由環境決定)

# ----- 4) 前向:給定 (θ, x),回傳 -----
def expval(theta_vals, x):
qc = QuantumCircuit(2)
qc.compose(feature_map(x), inplace=True)
qc.compose(ansatz, inplace=True)
# 用 Estimator 評估期望值
job = estimator.run([qc], [observable], [dict(zip(theta, theta_vals))])
return job.result().values[0].real # ∈ [-1, 1]

# sigmoid,把期望值映成 [0,1] 機率
def model_prob(theta_vals, x):
z = expval(theta_vals, x) # [-1,1]
p1 = (z + 1)/2 # 當作預測「類別=1」的機率
return np.clip(p1, 1e-6, 1-1e-6)

# 二元交叉熵
def loss(theta_vals):
ps = np.array([model_prob(theta_vals, x) for x in Xang])
ce = -(y*np.log(ps) + (1-y)*np.log(1-ps))
return float(np.mean(ce))

# ----- 5) parameter-shift 梯度 -----
def grad(theta_vals, shift=np.pi/2):
g = np.zeros_like(theta_vals, dtype=float)
for j in range(len(theta_vals)):
tp = theta_vals.copy(); tm = theta_vals.copy()
tp[j] += shift; tm[j] -= shift
g[j] = (loss(tp) - loss(tm)) / 2.0
return g

# ----- 6) 簡單 SGD -----
np.random.seed(0)
theta_vals = np.random.uniform(0, 2*np.pi, len(theta))
lr = 0.2
for it in range(60):
L = loss(theta_vals)
g = grad(theta_vals)
theta_vals -= lr * g
if (it+1) % 10 == 0:
preds = (np.array([model_prob(theta_vals, x) for x in Xang]) > 0.5).astype(int)
acc = (preds == y).mean()
print(f"iter {it+1:02d} | loss={L:.4f} | acc={acc:.2f}")

print("θ* =", theta_vals)
print("pred probs =", [round(model_prob(theta_vals, x), 3) for x in Xang])
```

重點:

* **Ry 角度編碼 + CX** 即為一個簡單 feature map;你也能換成 Qiskit 內建 `PauliFeatureMap`/`ZZFeatureMap`。
* 期望值用 **`Estimator` 原語**算 $\langle Z\otimes I\rangle$,再做 **parameter-shift** 的 $\pm \pi/2$ 數值梯度來更新參數。

---

# Q#:同樣概念的 PQC + C# host 做訓練

**Q# 檔(VariationalClassifier.qs)**
(以 Ry 角度編碼 + CX 糾纏,量測第 0 qubit 的 $Z$ 期望)

```qsharp
namespace QMLDemo {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Measurement;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Math;

operation FeatureMap(x : Double[], qs : Qubit[]) : Unit is Adj + Ctl {
// Ry encoding
Ry(x[0], qs[0]);
Ry(x[1], qs[1]);
CNOT(qs[0], qs[1]);
}

operation Ansatz(theta : Double[], qs : Qubit[]) : Unit is Adj + Ctl {
// layer 1
Ry(theta[0], qs[0]);
Ry(theta[1], qs[1]);
CNOT(qs[0], qs[1]);
// layer 2
Ry(theta[2], qs[0]);
Ry(theta[3], qs[1]);
}

// 以多次 shots 估計 Z⊗I 的期望值,輸出落在 [-1,1]
operation ExpZGivenParams(x : Double[], theta : Double[], shots : Int) : Double {
use qs = Qubit[2];
mutable plusCount = 0;
for _ in 1..shots {
// |00>
ResetAll(qs);
// prepare circuit
FeatureMap(x, qs);
Ansatz(theta, qs);

// 測量 Z on qubit 0
let r = M(qs[0]);
if (r == Zero) { set plusCount += 1; }

// 清場
ResetAll(qs);
}

// p0 - p1 =
let p0 = IntAsDouble(plusCount) / IntAsDouble(shots);
return 2.0 * p0 - 1.0;
}
}
```

**C# host(Program.cs)**
(簡單 SGD + parameter-shift)

```csharp
// dotnet add package Microsoft.Quantum.Development.Kit
// dotnet add package Microsoft.Quantum.Standard
using System;
using System.Linq;
using Microsoft.Quantum.Simulation.Simulators;
using QMLDemo;

class Program {
static double Sigmoid(double z) => 1.0 / (1.0 + Math.Exp(-z));
static double ProbFromZ(double z) => Math.Clamp((z + 1.0)/2.0, 1e-6, 1-1e-6);

static void Main() {
// XOR toy data
double[][] X = {
new double[]{0.0,0.0},
new double[]{0.0,1.0},
new double[]{1.0,0.0},
new double[]{1.0,1.0}
};
int[] y = {0,1,1,0};
double scale = 2*Math.PI;
double[][] Xang = X.Select(v => v.Select(t => t*scale).ToArray()).ToArray();

double[] theta = Enumerable.Range(0,4).Select(_ => 2*Math.PI*new Random().NextDouble()).ToArray();
double lr = 0.2;
int shots = 2000;
double shift = Math.PI/2;

using var sim = new QuantumSimulator();

Func Loss = th => {
double ce = 0.0;
for (int i=0;i 0.5 ? 1 : 0;
if (pred==y[i]) correct++;
}
Console.WriteLine($"iter {it+1:00} | loss={L:F4} | acc={(double)correct/Xang.Length:F2}");
}
}
Console.WriteLine("theta* = ["+string.Join(", ", theta.Select(v=>v.ToString("F3")))+"]");
}
}
```

---

## 補充

* 以上兩個版本都用 **Ry 角度編碼** 當作量子特徵映射;你可以替換成 Qiskit 內建的 `PauliFeatureMap / ZZFeatureMap`,或在 Q# 中自行加入 `Rz`、更多糾纏層。
* 若要走 **kernel 方法**:在 Qiskit 可用 `Statevector` 直接模擬兩個嵌入電路的內積 $|\langle\phi(x)|\phi(x')\rangle|^2$ 來做 Gram 矩陣(之後丟到 SVM)。

---

## 來源(官方文件 / 教學)

* Qiskit `Statevector` 與內積 API(可用來做核的內積或期望值輔助),IBM 官方文件。 ([[quantum.cloud.ibm.com](https://quantum.cloud.ibm.com/docs/api/qiskit/qiskit.quantum_info.Statevector?utm_source=chatgpt.com)][1])
* Qiskit 入門:**Primitives(Estimator / Sampler)** 範例與指南(本例用 Estimator 取期望值)。 ([[quantum.cloud.ibm.com](https://quantum.cloud.ibm.com/docs/guides/primitives-examples?utm_source=chatgpt.com)][2])
* Qiskit 資料編碼與常見 **Feature Map**(含 Z/ZZ/PauliFeatureMap 的設計理念)。 ([[quantum.cloud.ibm.com](https://quantum.cloud.ibm.com/learning/en/courses/quantum-machine-learning/data-encoding?utm_source=chatgpt.com)][3], [[Quantum Computing Stack Exchange](https://quantumcomputing.stackexchange.com/questions/22121/how-does-the-zz-feature-map-influence-the-measurement?utm_source=chatgpt.com)][4])
* 單量子位 **RY** 旋轉 gate 資料(矩陣與在電路中的使用)。 ([[quantum.cloud.ibm.com](https://quantum.cloud.ibm.com/docs/api/qiskit/qiskit.circuit.library.RYGate?utm_source=chatgpt.com)][5])
* Q# 量子運算與旋轉/量測的基礎說明(Ry/測量在 Q# 流程中的位置,含官方與社群討論導引)。 ([[Quantum Computing Stack Exchange](https://quantumcomputing.stackexchange.com/questions/4223/how-to-measure-in-an-arbitrary-basis-in-q?utm_source=chatgpt.com)][6])

如果你想,我可以把 Qiskit 版本改成 **量子核 SVM** 或 **VQE/QAOA** 的模板;或把 Q# 版本換成 **以期望值 API** 的更高效實作(減少 shots 抖動)。你偏好哪一條線?

[1]: https://quantum.cloud.ibm.com/docs/api/qiskit/qiskit.quantum_info.Statevector?utm_source=chatgpt.com "Statevector (latest version) | IBM Quantum Documentation"
[2]: https://quantum.cloud.ibm.com/docs/guides/primitives-examples?utm_source=chatgpt.com "Primitives examples | IBM Quantum Documentation"
[3]: https://quantum.cloud.ibm.com/learning/en/courses/quantum-machine-learning/data-encoding?utm_source=chatgpt.com "Data encoding | IBM Quantum Learning"
[4]: https://quantumcomputing.stackexchange.com/questions/22121/how-does-the-zz-feature-map-influence-the-measurement?utm_source=chatgpt.com "How does the ZZ Feature Map influence the measurement?"
[5]: https://quantum.cloud.ibm.com/docs/api/qiskit/qiskit.circuit.library.RYGate?utm_source=chatgpt.com "RYGate (latest version) | IBM Quantum Documentation"
[6]: https://quantumcomputing.stackexchange.com/questions/4223/how-to-measure-in-an-arbitrary-basis-in-q?utm_source=chatgpt.com "How to measure in an arbitrary basis in Q"

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.