三點二. 量子對抗生成網路 (Quantum GAN)

理論基礎

之前我們介紹了強化學習

Leo:和Leo一起學量子計算:三點一. 微分線路和強化學習?

zhuanlan.zhihu.com圖標

上面這篇博文告訴我們如何把量子線路類比為神經網路,並獲取它的導數。在可微分線路的基礎上,我們可以做一些更加酷的事情,比如量子對抗學習。

2018年,量子機器學習領域出現了幾篇奪人眼球的關於量子對抗生成學習的文章,它們分別是

  • Seth Lloyd, Christian Weedbrook
    • [1804.09139] Quantum generative adversarial learning
  • Quantum generative adversarial networks
    • [1804.08641] Quantum generative adversarial networks
  • Benedetti, M., Grant, E., Wossnig, L., & Severini, S.
    • [1806.00463] Adversarial quantum circuit learning for pure state approximation
  • Haozhen Situ, Zhimin He, Lvzhou Li, Shenggen Zheng
    • [1807.01235] Quantum generative adversarial network for generating discrete data
  • Jinfeng Zeng,Yufeng Wu,Jin-Guo Liu,Lei Wang,Jiangping Hu
    • [1808.03425] Learning and Inference on Generative Adversarial Quantum Circuits

理論基礎

下面簡單介紹下第三篇工作的基本思想,也就是今年 6 月份的這篇學習純態波函數的文章, 他是對第一篇和第二篇文章思想的傳承和簡化版本。這篇文章要解決的問題是,給定一個未知量子線路T,它可以讓波函數從 |0
angle 態演化到 |psi
angle_t 。我們希望構造一個線路G生成另外一個波函數 |psi
angle_g ,得到這個波函數的儘可能與目標線路產生的態相似, 也就是 minlimits_G||psi
angle_g- |psi
angle_t| 。那麼為什麼要學習一個量子線路產生量子力學波函數呢?一個原因是量子波函數具有不可克隆的特性,為了能夠隨時隨地復現它,一個好的想法就是把能夠產生這個波函數的隨機線路的參數,用經典浮點數把它保存在磁碟上。

圖1:量子線路對抗學習示意圖,T, G 和 D 均為量子線路,T 即 Target,是需要被學習的線路,G 即 Generator,是用來仿製 T 的量子波函數生成線路,D 即 Discriminator,它通過對輔助比特的 POVM 測量來判別 T 和 G 的量子線路。(引自arXiv: 1806.00463)

如圖1所示,QuGAN 的量子線路主體包括兩個部分,生成線路和判別線路,生成線路盡量去仿製T線路的波函數以達到以假亂真的效果,而判別器則通過一個量子線路儘可能的僅通過輔助比特的測量知道輸入的波函數是真還是假。Loss函數可以寫作

V(θ, φ) ={
m tr}left[ E_0D(φ)( |ψ_t
anglelangle ψ_t| ? |0
angle langle 0|) D(φ)^dagger 
ight] P(t) \? {
m tr}left[E_0D(φ)(G(θ)|0
anglelangle 0|G(θ)^? ? |0
anglelangle0|) D(φ)^?
ight]P(g)

其中, P(t) P(g) 分別是來自 T 和 G 的樣本的概率, E_0 則是定義在輔助比特上的POVM測量中的一個投影算符,一般可以取 E_0 = |0
anglelangle0| . 當 P(t) = P(g)= frac 1 2 , 判別器完美工作的情況下,這個Loss函數等價於 trace distance 的定義,生成器希望減少這個distance, 判別器則希望增加這個 distance 以探測區別。在對抗訓練中, 良好的判別器是訓練生成器的前提. 以下討論認為 P(t) = P(g)= frac 1 2 恆成立。

具體的線路細節以及Loss函數的描述請見arXiv: 1806.00463。


代碼實現

首先申明下,Yao最近將會發布0.3更新,會有更加豐富的API和GPU的支持。但是也面臨著API不穩定的問題,建議安裝master分支 ]add Yao#master 以及`]add QuAlgorithmZoo#master`。如果在嘗試實現Tutorial代碼的過程中遇到了問題,請以知乎評論或者issue的形式反饋。我會在發布0.3版本後系統的更新這個系列的代碼。

using LinearAlgebra

using Yao
using Yao.Blocks
using QuAlgorithmZoo: diff_circuit, pair_ring

"""
Quantum GAN.

Reference:
Benedetti, M., Grant, E., Wossnig, L., & Severini, S. (2018).
Adversarial quantum circuit learning for pure state approximation, 1–14.
"""
struct QuGAN{N}
target::DefaultRegister
generator::MatrixBlock{N}
discriminator::MatrixBlock
reg0::DefaultRegister
witness_op::MatrixBlock
circuit::AbstractBlock
gdiffs
ddiffs

function QuGAN(target::DefaultRegister, gen::MatrixBlock, dis::MatrixBlock)
N = nqubits(target)
c = sequence(gen, addbit(1), dis)
witness_op = put(N+1, (N+1)=>P0)
gdiffs = collect(gen, AbstractDiff)
ddiffs = collect(dis, AbstractDiff)
new{N}(target, gen, dis, zero_state(N), witness_op, c, gdiffs, ddiffs)
end
end

首先,申明QuGAN結構體,其中witness_op是loss中的E_0 項,這裡定義為在輔助比特 (也就是第N+1個qubit) |0
angle 態的投影的算符。gdiffsddiffs分別記錄了生成器和判別器的微分模塊,這些微分模塊可以用collect函數來自動獲取,該函數做的事情是對Block Tree做深度有限的搜索,把特定類型的gate放入sequence裡面並返回。 整個線路(變數circuit)包含生成器,增加一個qubit,判別器三部分。

"""loss function"""
loss(qcg::QuGAN) = p0t(qcg) - p0g(qcg)
"""probability to get evidense qubit 0 on generation set."""
p0g(qg::QuGAN) = expect(qg.witness_op, psi_discgen(qg)) |> real
"""probability to get evidense qubit 0 on target set."""
p0t(qg::QuGAN) = expect(qg.witness_op, psi_disctarget(qg)) |> real
"""generated wave function"""
psi(qg::QuGAN) = copy(qg.reg0) |> qg.generator
"""input |> generator |> discriminator"""
psi_discgen(qg::QuGAN) = copy(qg.reg0) |> qg.circuit
"""target |> discriminator"""
psi_disctarget(qg::QuGAN) = copy(qg.target) |> qg.circuit[2:end]
"""tracedistance between target and generated wave function"""
distance(qg::QuGAN) = tracedist(qg.target, psi(qg))[]

p0g函數計算Loss中的第二項

 {
m tr}left[E_0D(φ)(G(θ)|0
anglelangle 0|G(θ)^? ? |0
anglelangle0|) D(φ)^?
ight]

p0t則計算Loss中第一項

{
m tr}left[ E_0D(φ)( |ψ_t
anglelangle ψ_t| ? |0
angle langle 0|) D(φ)^dagger 
ight]

我們用trace distance作為衡量訓練結果的好壞的最終標準。但trace distance實驗的操作性不強,這時候可以用swap test來計算兩個態的overlap,也是不錯的選擇。

"""obtain the gradient"""
function grad(qcg::QuGAN)
ggrad_g = opdiff.(()->psi_discgen(qcg), qcg.gdiffs, Ref(qcg.witness_op))
dgrad_g = opdiff.(()->psi_discgen(qcg), qcg.ddiffs, Ref(qcg.witness_op))
dgrad_t = opdiff.(()->psi_disctarget(qcg), qcg.ddiffs, Ref(qcg.witness_op))
[-ggrad_g; dgrad_t - dgrad_g]
end

"""the training process"""
function train(qcg::QuGAN{N}, g_learning_rate::Real,
d_learning_rate::Real, niter::Int) where N
ng = length(qcg.gdiffs)
for i in 1:niter
g = grad(qcg)
dispatch!(+, qcg.generator, -g[1:ng]*g_learning_rate)
dispatch!(-, qcg.discriminator, -g[ng+1:end]*d_learning_rate)
(i*20)%niter==0 && println("Step = $i, Trance Distance = $(distance(qcg))")
end
end

量子線路對於可觀測量的微分可以見三點一章節的討論。

在訓練中,這裡簡單的給generator和discriminator定了兩個不同的learning rate,但是梯度方向是相反的。生成器會往下降 loss 的方向訓練, 而判別器則往提升 loss 的方向訓練, 判別器的 learning rate 一般要高一點才有助於收斂. 其實更加妥當的做法是, 內部加一個對discriminator的訓練的loop,保證discriminator總是收斂。

nbit = 3
target = rand_state(nbit)
gen = dispatch!(random_diff_circuit(nbit, 2,
pair_ring(nbit)), :random) |> autodiff(:QC)
discriminator = dispatch!(random_diff_circuit(nbit+1,
5, pair_ring(nbit+1)), :random) |> autodiff(:QC)
qcg = QuGAN(target, gen, discriminator)
train(qcg, 0.1, 0.2, 1000)

這裡嘗試學習一個3 qubit的量子隨機態, 生成和判別用的線路深度分別為 2 和 5, 學習速率分別是 0.1 和 0.2. 如果運行順利,將會看到如下結果

Step = 50, Trance Distance = 0.6342280675404924
Step = 100, Trance Distance = 0.2556083335074918
Step = 150, Trance Distance = 0.20588883282356
Step = 200, Trance Distance = 0.18588876599788512
Step = 250, Trance Distance = 0.14383386098057532
Step = 300, Trance Distance = 0.11122073204131669
Step = 350, Trance Distance = 0.12055174236882853
Step = 400, Trance Distance = 0.08476938309711918
Step = 450, Trance Distance = 0.055730139169513575
Step = 500, Trance Distance = 0.0658058630141474
Step = 550, Trance Distance = 0.030654404721949198
Step = 600, Trance Distance = 0.05670115284050363
Step = 650, Trance Distance = 0.026043726656018153
Step = 700, Trance Distance = 0.03717624105785262
Step = 750, Trance Distance = 0.018583002816583323
Step = 800, Trance Distance = 0.038243650242252694
Step = 850, Trance Distance = 0.02220738846752642
Step = 900, Trance Distance = 0.016162779109655048
Step = 950, Trance Distance = 0.0070184081980637705
Step = 1000, Trance Distance = 0.016831931463320904

我們發現trace distance的確可以下降,可以學到目標狀態,但是收斂的並不快。也是所有基於GAN的方法的通病吧~

這裡談一下 QuGAN 的優點和缺點, 優點是結構簡單, 形式也很酷, 有很多可以繼續玩的東西. 缺點也很明顯.

首先文章裡面用到的 loss 和經典 GAN 的 loss 其實不一樣, 這種不一樣是由於求導方案必須要求最終的輸出為可觀測量這個約束導致的. 這也是為什麼 arXiv: 1807.01235 和 arXiv: 1808.03425 會採用量子經典的對抗學習的方案.

其次, 這裡的生成型模型生成的是量子力學波函數, 一般生成型包括很多量子生成型模型的目標都是得到經典數據, 比如 arXiv: 1804.04168中提到的 Born Machine. 但是這裡連同波函數相位一起學習了, 學習難度也高了很多, 作為經典數據的生成器是做了無用功的. 但也要考慮到它的應用場景不一樣.

最後, 所有 GAN 的通病, Modal Collapse, 收斂慢, 它都有, 所有量子變分線路的通病, 比如求導複雜度高 (比如經典深度學習 BP 方案的O(N), 它是O(N^2), 其中 N 為參數個數), 它也有.

雖然有這麼多缺點, 但是毫無疑問, 它為理論學家們提供了很不錯的新玩具!


推薦閱讀:

TAG:量子物理 | 量子計算 | 機器學習 |