量子機(jī)器學(xué)習(xí)Variational Quantum Classifier (VQC)簡(jiǎn)介
變分量子分類器(Variational Quantum Classifier,簡(jiǎn)稱VQC)是一種利用量子計(jì)算技術(shù)進(jìn)行分類任務(wù)的機(jī)器學(xué)習(xí)算法。它屬于量子機(jī)器學(xué)習(xí)算法家族,旨在利用量子計(jì)算機(jī)的計(jì)算能力,潛在地提升經(jīng)典機(jī)器學(xué)習(xí)方法的性能。
VQC的基本思想是使用一個(gè)量子電路,也稱為變分量子電路,將輸入數(shù)據(jù)編碼并映射到量子態(tài)上。然后,使用量子門和測(cè)量操作對(duì)這些量子態(tài)進(jìn)行操作,以提取與分類任務(wù)相關(guān)的特征。最后,處理測(cè)量結(jié)果,并將其用于為輸入數(shù)據(jù)分配類別標(biāo)簽。
VQC將經(jīng)典優(yōu)化技術(shù)與量子計(jì)算相結(jié)合。在訓(xùn)練過(guò)程中,將變分量子電路在量子計(jì)算機(jī)或模擬器上重復(fù)執(zhí)行,并將結(jié)果與訓(xùn)練數(shù)據(jù)的真實(shí)標(biāo)簽進(jìn)行比較。通過(guò)迭代地調(diào)整變分量子電路的參數(shù),使其在預(yù)測(cè)標(biāo)簽與真實(shí)標(biāo)簽之間的差異上最小化代價(jià)函數(shù)。這個(gè)優(yōu)化過(guò)程旨在找到最優(yōu)的量子電路配置,從而最大化分類準(zhǔn)確性。雖然看起來(lái)很簡(jiǎn)單,但這種混合計(jì)算體系結(jié)構(gòu)存在很多的挑戰(zhàn)。
特征映射是第一階段,其中數(shù)據(jù)必須編碼為量子位。有許多編碼方法,因?yàn)樘卣饔成涫菑囊粋€(gè)向量空間到另一個(gè)向量空間的數(shù)學(xué)變換。所以研究如何為每個(gè)問(wèn)題找到最佳映射,就是一個(gè)待研究的問(wèn)題
有了映射,還要設(shè)計(jì)一個(gè)量子電路作為模型,這是第二階段。在這里我們可以隨心所愿地發(fā)揮創(chuàng)意,但必須考慮到同樣的舊規(guī)則仍然很重要:對(duì)于簡(jiǎn)單的問(wèn)題,不要使用太多的參數(shù)來(lái)避免過(guò)擬合,也不能使用太少的參數(shù)來(lái)避免偏差,并且由于我們正在使用量子計(jì)算,為了從量子計(jì)算范式中獲得最佳效果,必須與疊加(superposition )和糾纏(entanglement)一起工作。
并且量子電路是線性變換,我們還需要對(duì)其輸出進(jìn)行處理。比如非線性化的激活。
數(shù)據(jù)集和特征
這里我們將基于泰坦尼克號(hào)數(shù)據(jù)集設(shè)計(jì)一個(gè)分類器,我們的數(shù)據(jù)集有以下特征:
- PassengerID
- Passenger name
- Class (First, second or third)
- Gender
- Age
- SibSP (siblings and/or spouses aboard)
- Parch (parents or children aboard)
- Ticket
- Fare
- Cabin
- Embarked
- Survived
我們要構(gòu)建一個(gè)根據(jù)乘客的特征預(yù)測(cè)乘客是否幸存的分類器。所以我們只選擇幾個(gè)變量作為示例:
- is_child (if age <12)
- is_class1 (if person is in the first class)
- is_class2
- is_female
由于只有四個(gè)變量,所以我們使用將使用Basis Embedding。我們只需將經(jīng)典位轉(zhuǎn)換為等效量子位。比如我們的四個(gè)變量是1010,這將被轉(zhuǎn)換為|1010>。
模型
我們的模型是可參數(shù)化量子電路。這個(gè)電路必須具有一定程度的疊加和糾纏,這樣才能證明使用量子組件是合理的,我們的模型如下:
這個(gè)模型可能看起來(lái)很復(fù)雜,但他的想法相當(dāng)簡(jiǎn)單。 這是一個(gè)雙層電路,因?yàn)楹诵慕Y(jié)構(gòu)重復(fù)了 2 次。 首先,我們?yōu)槊總€(gè)量子位繞 Z、Y 和 Z 軸旋轉(zhuǎn),這里的想法是分別在每個(gè)量子位上插入某種程度的疊加。 這些旋轉(zhuǎn)是參數(shù)化的,并且在算法的每次交互中,這些參數(shù)將由經(jīng)典計(jì)算機(jī)更新。 然后就是 Y 軸和 Z 軸上的旋轉(zhuǎn),因?yàn)榱孔游坏氖噶靠臻g是一個(gè)球體(布洛赫球體)。 RZ 只會(huì)改變量子比特相位,RY 會(huì)影響量子比特與 |0> 和 |1> 的接近程度。
每對(duì)量子位之間有四個(gè)受控非 (CNOT) 狀態(tài),這是一個(gè)量子門,根據(jù)另一個(gè)量子位(分別為目標(biāo)和控制)的狀態(tài)反轉(zhuǎn)一個(gè)量子位狀態(tài)。 也就是說(shuō)這個(gè)門糾纏了我們電路中的所有量子位,現(xiàn)在所有狀態(tài)都糾纏了。 在第二層中,我們應(yīng)用了一組新的旋轉(zhuǎn),這不僅僅是第一層的邏輯重復(fù),因?yàn)楝F(xiàn)在所有狀態(tài)都糾纏在一起,這意味著旋轉(zhuǎn)第一個(gè)量子比特也會(huì)影響其他量子比特! 最后我們有了一組新的 CNOT 門。
這是對(duì)我們上面模型的非常簡(jiǎn)單的解釋,下面代碼會(huì)讓這些內(nèi)容變得更清晰。
優(yōu)化器
我使用的是Adam Optimizer,但是這個(gè)優(yōu)化器是經(jīng)過(guò)特殊處理的,我們直接使用pennylane 庫(kù)。
代碼實(shí)現(xiàn)
這里我們直接使用Pennylane和sklearn實(shí)現(xiàn)代碼。
import pennylane as qml
from pennylane import numpy as np
from pennylane.optimize import AdamOptimizer
from sklearn.model_selection import train_test_split
import pandas as pd
from sklearn.metrics import accuracy_score
from sklearn.metrics import f1_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
import math
num_qubits = 4
num_layers = 2
dev = qml.device("default.qubit", wires=num_qubits)
# quantum circuit functions
def statepreparation(x):
qml.BasisEmbedding(x, wires=range(0, num_qubits))
def layer(W):
qml.Rot(W[0, 0], W[0, 1], W[0, 2], wires=0)
qml.Rot(W[1, 0], W[1, 1], W[1, 2], wires=1)
qml.Rot(W[2, 0], W[2, 1], W[2, 2], wires=2)
qml.Rot(W[3, 0], W[3, 1], W[3, 2], wires=3)
qml.CNOT(wires=[0, 1])
qml.CNOT(wires=[1, 2])
qml.CNOT(wires=[2, 3])
qml.CNOT(wires=[3, 0])
@qml.qnode(dev, interface="autograd")
def circuit(weights, x):
statepreparation(x)
for W in weights:
layer(W)
return qml.expval(qml.PauliZ(0))
def variational_classifier(weights, bias, x):
return circuit(weights, x) + bias
def square_loss(labels, predictions):
loss = 0
for l, p in zip(labels, predictions):
loss = loss + (l - p) ** 2
loss = loss / len(labels)
return loss
def accuracy(labels, predictions):
loss = 0
for l, p in zip(labels, predictions):
if abs(l - p) < 1e-5:
loss = loss + 1
loss = loss / len(labels)
return loss
def cost(weights, bias, X, Y):
predictions = [variational_classifier(weights, bias, x) for x in X]
return square_loss(Y, predictions)
# preparaing data
df_train = pd.read_csv('train.csv')
df_train['Pclass'] = df_train['Pclass'].astype(str)
df_train = pd.concat([df_train, pd.get_dummies(df_train[['Pclass', 'Sex', 'Embarked']])], axis=1)
# I will fill missings with the median
df_train['Age'] = df_train['Age'].fillna(df_train['Age'].median())
df_train['is_child'] = df_train['Age'].map(lambda x: 1 if x < 12 else 0)
cols_model = ['is_child', 'Pclass_1', 'Pclass_2', 'Sex_female']
X_train, X_test, y_train, y_test = train_test_split(df_train[cols_model], df_train['Survived'], test_size=0.10, random_state=42, stratify=df_train['Survived'])
X_train = np.array(X_train.values, requires_grad=False)
Y_train = np.array(y_train.values * 2 - np.ones(len(y_train)), requires_grad=False)
# setting init params
np.random.seed(0)
weights_init = 0.01 * np.random.randn(num_layers, num_qubits, 3, requires_grad=True)
bias_init = np.array(0.0, requires_grad=True)
opt = AdamOptimizer(0.125)
num_it = 70
batch_size = math.floor(len(X_train)/num_it)
weights = weights_init
bias = bias_init
for it in range(num_it):
# Update the weights by one optimizer step
batch_index = np.random.randint(0, len(X_train), (batch_size,))
X_batch = X_train[batch_index]
Y_batch = Y_train[batch_index]
weights, bias, _, _ = opt.step(cost, weights, bias, X_batch, Y_batch)
# Compute accuracy
predictions = [np.sign(variational_classifier(weights, bias, x)) for x in X_train]
acc = accuracy(Y_train, predictions)
print(
"Iter: {:5d} | Cost: {:0.7f} | Accuracy: {:0.7f} ".format(
it + 1, cost(weights, bias, X_train, Y_train), acc
)
)
X_test = np.array(X_test.values, requires_grad=False)
Y_test = np.array(y_test.values * 2 - np.ones(len(y_test)), requires_grad=False)
predictions = [np.sign(variational_classifier(weights, bias, x)) for x in X_test]
accuracy_score(Y_test, predictions)
precision_score(Y_test, predictions)
recall_score(Y_test, predictions)
f1_score(Y_test, predictions, average='macro')
最后得到的結(jié)果如下:
Accuracy: 78.89%
Precision: 76.67%
Recall: 65.71%
F1: 77.12%
為了比較,我們使用經(jīng)典的邏輯回歸作為對(duì)比,
Accuracy: 75.56%
Precision: 69.70%
Recall: 65.71%
F1: 74.00%
可以看到VQC比邏輯回歸模型稍微好一點(diǎn)!這并不意味著VQC一定更好,因?yàn)橹皇沁@個(gè)特定的模型和特定的優(yōu)化過(guò)程表現(xiàn)得更好。但這篇文章的主要還是是展示構(gòu)建一個(gè)量子分類器是很簡(jiǎn)單的,并且是有效的。
總結(jié)
VQC算法需要同時(shí)利用經(jīng)典資源和量子資源。經(jīng)典部分處理優(yōu)化和參數(shù)更新,而量子部分在量子態(tài)上執(zhí)行計(jì)算。VQC的性能和潛在優(yōu)勢(shì)取決于諸如分類問(wèn)題的復(fù)雜性、量子硬件的質(zhì)量以及合適的量子特征映射和量子門的可用性等因素。
最重要的是:量子機(jī)器學(xué)習(xí)領(lǐng)域仍處于早期階段,VQC的實(shí)際實(shí)現(xiàn)和有效性目前受到構(gòu)建大規(guī)模、糾錯(cuò)的量子計(jì)算機(jī)的挑戰(zhàn)所限制。但是該領(lǐng)域的研究正在不斷進(jìn)行,量子硬件和算法的進(jìn)步可能會(huì)在未來(lái)帶來(lái)更強(qiáng)大和高效的量子分類器。