量子ビットをイメージでつかむ（量子畳み込みニューラルネットワーク編）

　[一般社団法人日本量子コンピューティング協会](https://www.jqca.org/)様が量子エンジニア（ゲート式）アドバンスコースの第３回の[教材](https://docs.google.com/presentation/d/1rw0B5QxWwYAYKGvUw2-tcJW9Y95T5kp5oyThY_uk6Sc/edit?usp=sharing)を上げていただいているので、勝手ながら解説してみます。第３回は量子畳み込みニューラルネットワークがテーマです。残念ながら今回、Jupyter notebookは間に合っていません。ごめんなさい。なお、いつもの[教科書](https://www.amazon.co.jp/IBM-Quantum%E3%81%A7%E5%AD%A6%E3%81%B6%E9%87%8F%E5%AD%90%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF-%E6%B9%8A%E9%9B%84%E4%B8%80%E9%83%8E/dp/4798062804/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=3FF2DREBY73NG&dib=eyJ2IjoiMSJ9.wrsK9ZUNyNK8MZsBL-TISgTccLv1cAvI4B1Cod6a_lV22-PF0N_7w5FCMsrvDT4iCn5PepoKccEV4hDfNk9PD5_a5-nDAYJGT6zF1U_Kd3RBXApKuwgG1i3Fx4YW1P4dOVZyzKADIsfm_V_mD9VbFg.hZkSyHN2vXn8hLd2yiUhLpwA921WZWzvTDwSbDmpytA&dib_tag=se&keywords=IBMQ&qid=1740563210&sprefix=ibmq%2Caps%2C173&sr=8-1)でも量子機械学習を取り上げているのですが、形態が異なるので別途取り上げたいと思っています。
 ***
 　[教材](https://docs.google.com/presentation/d/1rw0B5QxWwYAYKGvUw2-tcJW9Y95T5kp5oyThY_uk6Sc/edit?usp=sharing)でも量子回路は描かれているのですが、断片的であるため、ネタ元と思われる[こちら](https://qiskit-community.github.io/qiskit-machine-learning/locale/ja_JP/tutorials/11_quantum_convolutional_neural_networks.html)から掘り下げていきたいと思います。そもそも、この量子回路で何をしようとしているのか、ですが、下のような$4\times2$のパターンを読み取って、黄色いパネルが、横に並んでいるのか縦に並んでいるのかを判定する、というものです。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921213/b9a8f44c-bbe2-41e2-aac5-b1e232c07ee0.png)
 回路の全体像としてはこんな感じです。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921213/923665b0-062b-49d7-91e2-59978ba2f527.png)
最後に$q_7$の量子ビットで縦か横かを出力します。
***
　Convolution（畳み込み）とPoolingは（古典）畳み込みニューラルネットワークにも出てきます（というか、量子では「ニューラルネットワーク」は使っていないのだが）。「畳み込み」は馴染みのない言葉かもしれませんが、デジタル信号処理でフィルターを掛けることを指します。なので、「フィルター処理」と思ってくれればいいです。古典畳み込みニューラルネットワークでは$3\times3$や$5\times5$といったフィルターパターン（「カーネル」ともいわれる）が（複数枚）使われて、（フィルタサイズや枚数は設計者が決めるのに対し）このパターンは学習で獲得します。Poolingは畳み込みで処理された$3\times3$あるいは$5\times5$のイメージの平均値あるいは最大値を取って$1\times1$にデータ量を縮小します（「次元削減」ともいわれる）。古典畳み込みニューラルネットワークでは、平均値とするか最大値とするかといった判断は設計者が行いますが、量子畳み込みニューラルネットワークでは学習で獲得します。
　一方、古典畳み込みニューラルネットワークでは出てこないZFeatureMapについて、この説明の前に、数値をどのように量子ビットの状態に落とし込むのか、エンコーディングの説明をしたいと思います。
***
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921213/1edbff1f-24ea-49c1-b0b1-d272ce525a4c.png)
　まず考えられる方法は、古典コンピュータと同じように１つの数値を複数の量子ビットで表すというものです（図左側）。
　次に考えられる方法は、数値をブロッホ球面上の１点として表わすものです（図中央）。単純に|0>と|1>の比率で表すことも考えられますが、ブロッホ球面上全体を使う方法も考えられます。ZFeatureMappingは後者の方式です。
　最後に、複数の数値を複数の量子ビットで表すものです（図右側）。$n$個の量子ビットで$2^n$個の数値を表すことができます。[教科書](https://www.amazon.co.jp/IBM-Quantum%E3%81%A7%E5%AD%A6%E3%81%B6%E9%87%8F%E5%AD%90%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF-%E6%B9%8A%E9%9B%84%E4%B8%80%E9%83%8E/dp/4798062804/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=3FF2DREBY73NG&dib=eyJ2IjoiMSJ9.wrsK9ZUNyNK8MZsBL-TISgTccLv1cAvI4B1Cod6a_lV22-PF0N_7w5FCMsrvDT4iCn5PepoKccEV4hDfNk9PD5_a5-nDAYJGT6zF1U_Kd3RBXApKuwgG1i3Fx4YW1P4dOVZyzKADIsfm_V_mD9VbFg.hZkSyHN2vXn8hLd2yiUhLpwA921WZWzvTDwSbDmpytA&dib_tag=se&keywords=IBMQ&qid=1740563210&sprefix=ibmq%2Caps%2C173&sr=8-1)では、こちらの方式を使った量子機械学習が取り上げられていました。
 　で、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ゲートを繰り返すことで、ブロッホ球面上に数値を拡散しようとしています。
 ***
　さて、この量子畳み込みニューラルネットワークはどのように（パラメータを）”学習”するのか、というところですが、
 ```python:
 classifier = NeuralNetworkClassifier(
    qnn,
    optimizer=COBYLA(maxiter=200),  # Set max iterations here
    callback=callback_graph,
    initial_point=initial_point,
)

classifier.fit(x, y) #<==これ
 ```
でした（Qiskit賢い!!!）。