In [ ]:
Copied!
# 导入必要的库
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from qibo import Circuit, gates
# 设置图形
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
print("量子分类器教程")
print(f"环境已准备就绪")
# 导入必要的库
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from qibo import Circuit, gates
# 设置图形
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
print("量子分类器教程")
print(f"环境已准备就绪")
In [ ]:
Copied!
# 定义简单的量子分类器
class SimpleQuantumClassifier:
"""
简单的变分量子分类器
适用于二分类问题
"""
def __init__(self, nqubits, nlayers=3):
self.nqubits = nqubits
self.nlayers = nlayers
self.nparams = 2 * nqubits * nlayers + nqubits
self.params = np.random.randn(self.nparams)
self.circuit = self._create_circuit()
def _create_circuit(self):
"""创建变分电路"""
c = Circuit(self.nqubits)
for l in range(self.nlayers):
# RY 层
for q in range(self.nqubits):
c.add(gates.RY(q, theta=0))
# CZ 纠缠层
for q in range(self.nqubits - 1):
c.add(gates.CZ(q, q + 1))
return c
def encode_data(self, x):
"""将数据编码到量子态
使用角度编码:将每个特征映射到旋转角度
"""
# 归一化数据到 [0, π]
x_norm = (x - x.min()) / (x.max() - x.min()) * np.pi
return x_norm
def predict(self, x):
"""对单个样本进行预测
返回值:-1 或 1(二分类)
"""
# 编码数据
x_encoded = self.encode_data(x)
# 将数据和参数结合
combined_params = []
param_idx = 0
for l in range(self.nlayers):
for q in range(self.nqubits):
# 数据和参数共同决定旋转角度
combined_params.append(self.params[param_idx] * x_encoded[q % len(x_encoded)])
param_idx += 1
# 设置参数并执行
self.circuit.set_parameters(combined_params)
result = self.circuit()
# 计算期望值
state = result.state()
# 测量第一个量子比特
prob_0 = np.abs(state[0])**2 + np.abs(state[1])**2
return 1 if prob_0 > 0.5 else -1
def train(self, X, y, maxiter=100):
"""训练分类器
使用简单的梯度下降优化
"""
from scipy.optimize import minimize
def loss_function(params):
self.params = params
total_loss = 0
for x_i, y_i in zip(X, y):
pred = self.predict(x_i)
total_loss += (pred - y_i) ** 2
return total_loss / len(X)
result = minimize(loss_function, self.params, method='Powell',
options={'maxiter': maxiter, 'disp': True})
self.params = result.x
return result.fun
# 创建分类器
nqubits = 4
nlayers = 2
qcl = SimpleQuantumClassifier(nqubits, nlayers)
print(f"量子分类器创建完成")
print(f"量子比特数:{nqubits}")
print(f"电路层数:{nlayers}")
print(f"参数数量:{qcl.nparams}")
# 定义简单的量子分类器
class SimpleQuantumClassifier:
"""
简单的变分量子分类器
适用于二分类问题
"""
def __init__(self, nqubits, nlayers=3):
self.nqubits = nqubits
self.nlayers = nlayers
self.nparams = 2 * nqubits * nlayers + nqubits
self.params = np.random.randn(self.nparams)
self.circuit = self._create_circuit()
def _create_circuit(self):
"""创建变分电路"""
c = Circuit(self.nqubits)
for l in range(self.nlayers):
# RY 层
for q in range(self.nqubits):
c.add(gates.RY(q, theta=0))
# CZ 纠缠层
for q in range(self.nqubits - 1):
c.add(gates.CZ(q, q + 1))
return c
def encode_data(self, x):
"""将数据编码到量子态
使用角度编码:将每个特征映射到旋转角度
"""
# 归一化数据到 [0, π]
x_norm = (x - x.min()) / (x.max() - x.min()) * np.pi
return x_norm
def predict(self, x):
"""对单个样本进行预测
返回值:-1 或 1(二分类)
"""
# 编码数据
x_encoded = self.encode_data(x)
# 将数据和参数结合
combined_params = []
param_idx = 0
for l in range(self.nlayers):
for q in range(self.nqubits):
# 数据和参数共同决定旋转角度
combined_params.append(self.params[param_idx] * x_encoded[q % len(x_encoded)])
param_idx += 1
# 设置参数并执行
self.circuit.set_parameters(combined_params)
result = self.circuit()
# 计算期望值
state = result.state()
# 测量第一个量子比特
prob_0 = np.abs(state[0])**2 + np.abs(state[1])**2
return 1 if prob_0 > 0.5 else -1
def train(self, X, y, maxiter=100):
"""训练分类器
使用简单的梯度下降优化
"""
from scipy.optimize import minimize
def loss_function(params):
self.params = params
total_loss = 0
for x_i, y_i in zip(X, y):
pred = self.predict(x_i)
total_loss += (pred - y_i) ** 2
return total_loss / len(X)
result = minimize(loss_function, self.params, method='Powell',
options={'maxiter': maxiter, 'disp': True})
self.params = result.x
return result.fun
# 创建分类器
nqubits = 4
nlayers = 2
qcl = SimpleQuantumClassifier(nqubits, nlayers)
print(f"量子分类器创建完成")
print(f"量子比特数:{nqubits}")
print(f"电路层数:{nlayers}")
print(f"参数数量:{qcl.nparams}")
In [ ]:
Copied!
# 加载鸢尾花数据集
iris = load_iris()
X = iris.data[:, :2] # 只使用前两个特征(为了可视化)
y = iris.target
# 只保留两类(setosa 和 versicolor)
mask = y < 2
X = X[mask]
y = y[mask]
# 转换标签为 -1 和 1
y = np.where(y == 0, -1, 1)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)
# 标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
print(f"数据集信息:")
print(f"特征数量:{X.shape[1]}")
print(f"样本总数:{X.shape[0]}")
print(f"训练集大小:{X_train.shape[0]}")
print(f"测试集大小:{X_test.shape[0]}")
print(f"类别:{-1, 1}")
# 加载鸢尾花数据集
iris = load_iris()
X = iris.data[:, :2] # 只使用前两个特征(为了可视化)
y = iris.target
# 只保留两类(setosa 和 versicolor)
mask = y < 2
X = X[mask]
y = y[mask]
# 转换标签为 -1 和 1
y = np.where(y == 0, -1, 1)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)
# 标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
print(f"数据集信息:")
print(f"特征数量:{X.shape[1]}")
print(f"样本总数:{X.shape[0]}")
print(f"训练集大小:{X_train.shape[0]}")
print(f"测试集大小:{X_test.shape[0]}")
print(f"类别:{-1, 1}")
In [ ]:
Copied!
# 可视化数据
plt.figure(figsize=(10, 6))
# 绘制训练集
plt.scatter(X_train[y_train == -1, 0], X_train[y_train == -1, 1],
c='blue', label='类别 -1', s=50, alpha=0.6)
plt.scatter(X_train[y_train == 1, 0], X_train[y_train == 1, 1],
c='red', label='类别 1', s=50, alpha=0.6)
# 绘制测试集
plt.scatter(X_test[:, 0], X_test[:, 1], c='green',
marker='x', s=100, label='测试集', linewidths=2)
plt.xlabel('特征 1(标准化)', fontsize=12)
plt.ylabel('特征 2(标准化)', fontsize=12)
plt.title('鸢尾花数据集可视化', fontsize=14)
plt.legend(fontsize=11)
plt.grid(alpha=0.3)
plt.show()
print("数据可视化完成")
# 可视化数据
plt.figure(figsize=(10, 6))
# 绘制训练集
plt.scatter(X_train[y_train == -1, 0], X_train[y_train == -1, 1],
c='blue', label='类别 -1', s=50, alpha=0.6)
plt.scatter(X_train[y_train == 1, 0], X_train[y_train == 1, 1],
c='red', label='类别 1', s=50, alpha=0.6)
# 绘制测试集
plt.scatter(X_test[:, 0], X_test[:, 1], c='green',
marker='x', s=100, label='测试集', linewidths=2)
plt.xlabel('特征 1(标准化)', fontsize=12)
plt.ylabel('特征 2(标准化)', fontsize=12)
plt.title('鸢尾花数据集可视化', fontsize=14)
plt.legend(fontsize=11)
plt.grid(alpha=0.3)
plt.show()
print("数据可视化完成")
In [ ]:
Copied!
# 训练量子分类器
# 注意:实际运行需要时间
# 使用少量样本演示
n_samples_train = 20
X_train_small = X_train[:n_samples_train]
y_train_small = y_train[:n_samples_train]
print(f"使用 {n_samples_train} 个样本训练量子分类器")
print("\n训练中(实际运行时取消注释):")
print("""
# loss = qcl.train(X_train_small, y_train_small, maxiter=50)
# print(f"\n训练完成!")
# print(f"最终损失:{loss:.4f}")
""")
# 训练量子分类器
# 注意:实际运行需要时间
# 使用少量样本演示
n_samples_train = 20
X_train_small = X_train[:n_samples_train]
y_train_small = y_train[:n_samples_train]
print(f"使用 {n_samples_train} 个样本训练量子分类器")
print("\n训练中(实际运行时取消注释):")
print("""
# loss = qcl.train(X_train_small, y_train_small, maxiter=50)
# print(f"\n训练完成!")
# print(f"最终损失:{loss:.4f}")
""")
In [ ]:
Copied!
# 评估分类器
def evaluate_classifier(classifier, X, y):
"""评估分类器性能"""
predictions = []
for x_i in X:
pred = classifier.predict(x_i)
predictions.append(pred)
predictions = np.array(predictions)
accuracy = np.mean(predictions == y)
return accuracy, predictions
# 评估(假设已训练)
print("评估函数已定义")
print("\n使用方法:")
print("accuracy, predictions = evaluate_classifier(qcl, X_test, y_test)")
# 评估分类器
def evaluate_classifier(classifier, X, y):
"""评估分类器性能"""
predictions = []
for x_i in X:
pred = classifier.predict(x_i)
predictions.append(pred)
predictions = np.array(predictions)
accuracy = np.mean(predictions == y)
return accuracy, predictions
# 评估(假设已训练)
print("评估函数已定义")
print("\n使用方法:")
print("accuracy, predictions = evaluate_classifier(qcl, X_test, y_test)")
In [ ]:
Copied!
# 定义简单的 QCNN 层
def quantum_convolutional_layer(circuit, qubits):
"""
量子卷积层
对相邻量子比特对应用双量子比特旋转门
"""
for i in range(0, len(qubits) - 1, 2):
# RXX, RYY, RZZ 门组合
circuit.add(gates.RZ(qubits[i], theta=0))
circuit.add(gates.RZ(qubits[i + 1], theta=0))
circuit.add(gates.RY(qubits[i], theta=0))
circuit.add(gates.RY(qubits[i + 1], theta=0))
circuit.add(gates.RXX(qubits[i], qubits[i + 1], theta=0))
def quantum_pooling_layer(circuit, qubits):
"""
量子池化层
使用 CNOT 门将两个量子比特的信息压缩到一个
"""
for i in range(0, len(qubits) - 1, 2):
circuit.add(gates.CNOT(qubits[i], qubits[i + 1]))
# 创建 4 量子比特 QCNN
def create_qcnn(nqubits=4):
"""
创建简单的 QCNN
"""
circuit = Circuit(nqubits)
# 初始 Hadamard 层
circuit.add([gates.H(i) for i in range(nqubits)])
# 第一层:卷积 + 池化
quantum_convolutional_layer(circuit, range(nqubits))
quantum_pooling_layer(circuit, range(nqubits))
# 第二层:卷积 + 池化(对剩余的 2 个量子比特)
# 这里简化处理
return circuit
qcnn = create_qcnn(4)
print(f"QCNN 电路创建完成")
print(f"量子比特数:{qcnn.nqubits}")
print(f"门数量:{len(qcnn.queue)}")
# 定义简单的 QCNN 层
def quantum_convolutional_layer(circuit, qubits):
"""
量子卷积层
对相邻量子比特对应用双量子比特旋转门
"""
for i in range(0, len(qubits) - 1, 2):
# RXX, RYY, RZZ 门组合
circuit.add(gates.RZ(qubits[i], theta=0))
circuit.add(gates.RZ(qubits[i + 1], theta=0))
circuit.add(gates.RY(qubits[i], theta=0))
circuit.add(gates.RY(qubits[i + 1], theta=0))
circuit.add(gates.RXX(qubits[i], qubits[i + 1], theta=0))
def quantum_pooling_layer(circuit, qubits):
"""
量子池化层
使用 CNOT 门将两个量子比特的信息压缩到一个
"""
for i in range(0, len(qubits) - 1, 2):
circuit.add(gates.CNOT(qubits[i], qubits[i + 1]))
# 创建 4 量子比特 QCNN
def create_qcnn(nqubits=4):
"""
创建简单的 QCNN
"""
circuit = Circuit(nqubits)
# 初始 Hadamard 层
circuit.add([gates.H(i) for i in range(nqubits)])
# 第一层:卷积 + 池化
quantum_convolutional_layer(circuit, range(nqubits))
quantum_pooling_layer(circuit, range(nqubits))
# 第二层:卷积 + 池化(对剩余的 2 个量子比特)
# 这里简化处理
return circuit
qcnn = create_qcnn(4)
print(f"QCNN 电路创建完成")
print(f"量子比特数:{qcnn.nqubits}")
print(f"门数量:{len(qcnn.queue)}")
In [ ]:
Copied!
# 练习 1 的框架:多分类
class MultiClassQuantumClassifier:
"""
多类别的量子分类器
使用多个量子比特来编码多个类别
"""
def __init__(self, nqubits, nclasses=3):
self.nqubits = nqubits
self.nclasses = nclasses
# TODO: 实现多分类逻辑
def predict(self, x):
# TODO: 实现预测
# 返回类别标签 0, 1, 2, ...
pass
print("多分类量子分类器框架已定义")
print("\n实现提示:")
print("1. 使用多个测量量子比特(每个类别一个)")
print("2. 或使用 one-hot 编码")
print("3. 或使用 softmax 输出")
# 练习 1 的框架:多分类
class MultiClassQuantumClassifier:
"""
多类别的量子分类器
使用多个量子比特来编码多个类别
"""
def __init__(self, nqubits, nclasses=3):
self.nqubits = nqubits
self.nclasses = nclasses
# TODO: 实现多分类逻辑
def predict(self, x):
# TODO: 实现预测
# 返回类别标签 0, 1, 2, ...
pass
print("多分类量子分类器框架已定义")
print("\n实现提示:")
print("1. 使用多个测量量子比特(每个类别一个)")
print("2. 或使用 one-hot 编码")
print("3. 或使用 softmax 输出")
总结¶
关键要点¶
量子分类器组件:
- 数据编码:角度编码、振幅编码等
- 变分电路:RY、RZ、CZ 等门的组合
- 测量策略:期望值、概率分布等
训练过程:
- 定义损失函数(如平方损失)
- 使用经典优化器(Powell、BFGS)
- 迭代更新参数
QCNN 特点:
- 卷积层提取局部特征
- 池化层降维
- 适合空间结构数据
实际应用:
- 图像识别
- 模式分类
- 量子数据处理
下一步学习¶
- 量子优化:QAP、MVC(教程 05)
- 绝热演化:绝热量子计算(教程 06)
- 高级 QML:量子自编码器、强化学习
参考资源¶
- Qibo 示例:
examples/variational_classifier/,examples/qcnn_classifier/ - 原论文:Farhi & Neven (2018), Schuld et al. (2019)
- Qibo 文档:https://qibo.readthedocs.io/
恭喜! 你已经掌握了量子分类器的基本方法。
继续探索量子机器学习的无限可能吧!🚀