一般社団法人日本量子コンピューティング協会様が量子エンジニア(ゲート式)アドバンスコースの第3回の教材を上げていただいているので、勝手ながら解説してみます。第3回は量子畳み込みニューラルネットワークがテーマです。残念ながら今回、Jupyter notebookは間に合っていません。ごめんなさい。なお、いつもの教科書でも量子機械学習を取り上げているのですが、形態が異なるので別途取り上げたいと思っています。
教材でも量子回路は描かれているのですが、断片的であるため、ネタ元と思われるこちらから掘り下げていきたいと思います。そもそも、この量子回路で何をしようとしているのか、ですが、下のような$4\times2$のパターンを読み取って、黄色いパネルが、横に並んでいるのか縦に並んでいるのかを判定する、というものです。
回路の全体像としてはこんな感じです。
最後に$q_7$の量子ビットで縦か横かを出力します。
Convolution(畳み込み)とPoolingは(古典)畳み込みニューラルネットワークにも出てきます(というか、量子では「ニューラルネットワーク」は使っていないのだが)。「畳み込み」は馴染みのない言葉かもしれませんが、デジタル信号処理でフィルターを掛けることを指します。なので、「フィルター処理」と思ってくれればいいです。古典畳み込みニューラルネットワークでは$3\times3$や$5\times5$といったフィルターパターン(「カーネル」ともいわれる)が(複数枚)使われて、(フィルタサイズや枚数は設計者が決めるのに対し)このパターンは学習で獲得します。Poolingは畳み込みで処理された$3\times3$あるいは$5\times5$のイメージの平均値あるいは最大値を取って$1\times1$にデータ量を縮小します(「次元削減」ともいわれる)。古典畳み込みニューラルネットワークでは、平均値とするか最大値とするかといった判断は設計者が行いますが、量子畳み込みニューラルネットワークでは学習で獲得します。
一方、古典畳み込みニューラルネットワークでは出てこないZFeatureMapについて、この説明の前に、数値をどのように量子ビットの状態に落とし込むのか、エンコーディングの説明をしたいと思います。
まず考えられる方法は、古典コンピュータと同じように1つの数値を複数の量子ビットで表すというものです(図左側)。
次に考えられる方法は、数値をブロッホ球面上の1点として表わすものです(図中央)。単純に|0>と|1>の比率で表すことも考えられますが、ブロッホ球面上全体を使う方法も考えられます。ZFeatureMappingは後者の方式です。
最後に、複数の数値を複数の量子ビットで表すものです(図右側)。$n$個の量子ビットで$2^n$個の数値を表すことができます。教科書では、こちらの方式を使った量子機械学習が取り上げられていました。
で、ZfeatureMapですがこんな感じにQiskitで作れます。
>>> prep = ZFeatureMap(3, reps=3, insert_barriers=True)
>>> print(prep.decompose())
┌───┐ ░ ┌─────────────┐ ░ ┌───┐ ░ ┌─────────────┐ ░ ┌───┐ ░ ┌─────────────┐
q_0: ┤ H ├─░─┤ P(2.0*x[0]) ├─░─┤ H ├─░─┤ P(2.0*x[0]) ├─░─┤ H ├─░─┤ P(2.0*x[0]) ├
├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤
q_1: ┤ H ├─░─┤ P(2.0*x[1]) ├─░─┤ H ├─░─┤ P(2.0*x[1]) ├─░─┤ H ├─░─┤ P(2.0*x[1]) ├
├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤
q_2: ┤ H ├─░─┤ P(2.0*x[2]) ├─░─┤ H ├─░─┤ P(2.0*x[2]) ├─░─┤ H ├─░─┤ P(2.0*x[2]) ├
└───┘ ░ └─────────────┘ ░ └───┘ ░ └─────────────┘ ░ └───┘ ░ └─────────────┘
HゲートとPゲートを繰り返すことで、ブロッホ球面上に数値を拡散しようとしています。
さて、この量子畳み込みニューラルネットワークはどのように(パラメータを)”学習”するのか、というところですが、
classifier = NeuralNetworkClassifier(
qnn,
optimizer=COBYLA(maxiter=200), # Set max iterations here
callback=callback_graph,
initial_point=initial_point,
)
classifier.fit(x, y) #<==これ
でした(Qiskit賢い!!!)。