【QNN】量子機械学習で気象予測

適応領域の設定

気象予測を量子機械学習をつかって解きます。
具体的には、大阪市の天気予測をします。

データの入手・確認

気象庁から大阪市の直近一ヶ月分のCSVデータをダウンロードします。(2022/9/27日時点)

https://www.data.jma.go.jp/gmd/risk/obsdl/index.php

ダウンロードしたCSVは以下です。(2022年8月30日 ~ 2022年9月30日)
天気に関係のある項目を抽出しました。

ダウンロードした時刻:2022/10/01 14:38:59

,大阪,大阪,大阪,大阪,大阪
,平均現地気圧(hPa),合計全天日射量(MJ/㎡),平均雲量(10分比),降水量の合計(mm),天気概況(昼:06時~18時)
2022年8月30日,1002.8,13.01,10.0,6.5,曇一時雨
2022年8月31日,998.8,23.13,6.3,0.0,晴時々薄曇
2022年9月1日,1001.1,8.88,10.0,20.5,曇時々雨
2022年9月2日,1004.8,20.43,8.5,21.5,晴時々曇一時雨、雷を伴う
2022年9月3日,1005.0,15.35,9.3,17.5,晴後曇一時雨
2022年9月4日,1004.6,19.90,3.5,0.0,晴後一時曇
2022年9月5日,1002.9,19.27,3.3,0.0,晴一時曇
2022年9月6日,998.4,14.47,9.5,1.0,晴後曇一時雨
2022年9月7日,1003.6,17.47,9.8,2.5,曇一時晴
2022年9月8日,1004.8,7.79,10.0,39.0,曇後一時雨
2022年9月9日,1004.6,9.35,10.0,5.0,曇時々雨
2022年9月10日,1005.1,19.87,7.5,0.5,晴時々曇
2022年9月11日,1004.2,22.28,2.8,--,晴
2022年9月12日,1003.4,21.10,5.0,--,晴一時薄曇
2022年9月13日,1004.3,21.74,6.8,--,薄曇後晴
2022年9月14日,1004.5,19.19,7.0,--,薄曇時々晴
2022年9月15日,1003.0,19.31,7.0,--,薄曇後晴
2022年9月16日,1002.1,22.04,7.3,--,晴後薄曇
2022年9月17日,1000.4,8.23,10.0,3.5,曇
2022年9月18日,994.8,11.89,10.0,--,曇
2022年9月19日,984.1,7.09,9.8,16.0,曇一時雨
2022年9月20日,995.8,12.89,9.8,16.0,曇
2022年9月21日,1004.9,13.43,9.3,0.0,曇時々晴
2022年9月22日,1005.5,15.15,10.0,2.0,曇一時雨
2022年9月23日,1000.9,2.62,9.8,17.0,雨後曇
2022年9月24日,1002.8,19.63,5.3,--,晴
2022年9月25日,1005.6,21.19,2.3,--,晴
2022年9月26日,1005.8,20.74,1.0,--,晴
2022年9月27日,1003.7,10.36,9.5,18.5,曇後雨
2022年9月28日,1001.3,12.33,10.0,0.0,曇
2022年9月29日,1003.4,11.88,9.5,0.0,曇一時晴後一時雨
2022年9月30日,1005.4,19.61,0.5,--,晴

※APIで取得するなら

気象データの入手は
Intertrustから
Pythonのライブラリrequestsを使ってもできるみたいです。

Intertrustは世界各地の気象データが集積されています。
APIも提供されています。

14日無料トライアルの期間ではデータの取得が可能です。

https://www.intertrust.com/

実装

インポート

from blueqat import Circuit
from blueqat.pauli import Z
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

データ加工

# 気象データ(2022年08月26日 ~ 2022年09月26日)
data = np.array(
    [
        [1002.8,13.01,10.0,6.5],
        [998.8,23.13,6.3,0.0],
        [1001.1,8.88,10.0,20.5],
        [1004.8,20.43,8.5,21.5],
        [1005.0,15.35,9.3,17.5],
        [1004.6,19.90,3.5,0.0],
        [1002.9,19.27,3.3,0.0],
        [998.4,14.47,9.5,1.0],
        [1003.6,17.47,9.8,2.5],
        [1004.8,7.79,10.0,39.0],
        [1004.6,9.35,10.0,5.0],
        [1005.1,19.87,7.5,0.5],
        [1004.2,22.28,2.8,0.0],
        [1003.4,21.10,5.0,0.0],
        [1004.3,21.74,6.8,0.0],
        [1004.5,19.19,7.0,0.0],
        [1003.0,19.31,7.0,0.0],
        [1002.1,22.04,7.3,0.0],
        [1000.4,8.23,10.0,3.5],
        [994.8,11.89,10.0,0.0],
        [984.1,7.09,9.8,16.0],
        [995.8,12.89,9.8,16.0],
        [1004.9,13.43,9.3,0.0],
        [1005.5,15.15,10.0,2.0],
        [1000.9,2.62,9.8,17.0],
        [1002.8,19.63,5.3,0.0],
        [1005.6,21.19,2.3,0.0],
        [1005.8,20.74,1.0,0.0],
        [1003.7,10.36,9.5,18.5],
        [1001.3,12.33,10.0,0.0],
        [1003.4,11.88,9.5,0.0],
        [1005.4,19.61,0.5,0.0],
    ]
)

df = pd.DataFrame(data, columns=['hPa','MJ','cloud','precipitation']) # 平均現地気圧(hPa),合計全天日射量(MJ/㎡),平均雲量(10分比),降水量の合計(mm)

# 雲量で天気を判断
y = df["cloud"]
X = df.drop(columns=["cloud"], axis=1)

X_train, X_val, y_train, y_val = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=1
)

モデル開発

3量子ビットでやります。

N = 3

シードを1に、パラメーターは18個用意します。

np.random.seed = 1
params = [np.random.rand() for _ in range(N*6)] # param*18

ハミルトニアン

hamiltonian = 1*Z[0]*Z[1]*Z[2]

微分用の誤差と学習率。

h = 1e-6
e = 0.1
arr_loss = []

for k in range(100):

    for item, answer in zip(X_train.values, y_train.values):
        circuit = Circuit()
        print(item)
        for i in range(N):
            circuit.rx(params[i*3+0])[i].ry(params[i*3+1])[i].rz(params[i*3+2])[i]

        circuit.cz[0,1].cz[1,2].cz[2,3].cz[3,0]

        for i in range(N):
            circuit.rx(np.pi*2*item[i]/100)[i]

        for i in range(N):
            circuit.rx(params[i*3+N*3])[i].ry(params[i*3+N*3+1])[i].rz(params[i*3+N*3+2])[i]

        expt = circuit.run(hamiltonian = hamiltonian)
        loss = (expt - answer/100)**2

        grad_temp = np.zeros(N*6)

        for j in range(N*6):
            params_temp = params[:]
            angle_temp = params_temp[j]
            params_temp[j] += h

            circuit = Circuit()

            for i in range(N):
                circuit.rx(params_temp[i*3+0])[i].ry(params_temp[i*3+1])[i].rz(params_temp[i*3+2])[i]

            circuit.cz[0,1].cz[1,2].cz[2,3].cz[3,0]

            for i in range(N):
                circuit.rx(np.pi*2*item[i]/100)[i]

            for i in range(N):
                circuit.rx(params_temp[i*3+N*3])[i].ry(params_temp[i*3+N*3+1])[i].rz(params_temp[i*3+N*3+2])[i]

            expt_temp = circuit.run(hamiltonian = hamiltonian)
            loss_temp = (expt_temp - answer/100)**2

            grad_temp[j] = (loss_temp - loss)/h

        params -= grad_temp*e

    arr_loss.append(loss)
    print(loss)

評価/予測

plt.plot(arr_loss)
plt.show()

適当な日の天気を予測してみます。

# 2003年8月18日のデータ。雲量は8.8で一応晴れ。
X_test = [1004.8,18.6,0.5] 

circuit = Circuit()

for i in range(N):
    circuit.rx(params[i*3+0])[i].ry(params[i*3+1])[i].rz(params[i*3+2])[i]

circuit.cz[0,1].cz[1,2].cz[2,3].cz[3,0]

for i in range(N):
    circuit.rx(np.pi*2*X_test[i]/100)[i]

for i in range(N):
    circuit.rx(params[i*3+N*3])[i].ry(params[i*3+N*3+1])[i].rz(params[i*3+N*3+2])[i]

expt = circuit.run(hamiltonian = hamiltonian)
print(expt*100)

6.25270091561785とでました。

雲の量が1割以下(0~1割)の状態を「快晴」、
2割から8割の状態を「晴れ」、
9割以上の状態を「曇り」といいます。

一応、2003年8月18日は晴れ、予測結果も晴れということで良いのではないでしょうか。

結論

入力値が安牌すぎて使いものにならない。
画像(QCNN)か、GSWRシステムとQMLのハイブリッドか(よくわかってない)を調べないといけない。