【その4】DeepLearningを使って気象画像から天気予報をする


前回まで

前回までは以下

【その1】DeepLearningを使って気象画像から天気予報をする
【その2】DeepLearningを使って気象画像から天気予報をする
【その3】DeepLearningを使って気象画像から天気予報をする

最終的な結果だけをまとめておくと

Epochを50世代から100世代に増加させ、平均AUCで0.724で以下のような結果が現時点で最もよい結果でした。

天気 precision recall f1-score
0.53 0.77 0.63
0.86 0.68 0.76
平均 0.76 0.71 0.72

少なくとも世代が少なすぎた、というのはありました。
ただ、画像を変更したり、学習データを増やしたり、三値分類にしても結果は良くなりませんでした。

試行錯誤

いろいろと試行錯誤して、あーでもないこーでもないとやってみましたが、なかなかこのAUCを超えるものは現れず・・・

結果だけまとめておくと、

世代を1000世代とかにしてみると、逆に精度が落ちる。

これは過学習ですね。学習データでは精度で0.95とかまで行きますが、テストデータでは結果が悪くなるという。

隠れ層を増やしてみても精度は上がらず、むしろ落ちる。

今は隠れ層で500ノードとしていますが、これを1000ノードにしても精度は上がりませんでした。

晴モデル、雨モデル、曇モデルを作ってみるものの、精度は落ちる。

晴かどうか、雨かどうか、曇かどうか、の二値分類を行うモデルを3つ作ってみましたが、精度は落ちました。

畳み込み層を増やしてみるものの、これも精度は上がらず。

増やしたほうがいいって言われていましたが、これもダメ。

などなど。

行き着いた可能性

その結果、行き着いた候補が以下。

1.スケーリングの方法を変える。

これまで画像データのスケーリングは

img_mat /= 255.

という、なんとも単純なスケーリングを行っていました。
従前の機械学習でもスケーリングは大事で、適切なスケールをしてあげないと、学習がうまくできないことが多々あります。

ですので、これを以下のように学習データの各RGBチャネルごとの標準化を行うことで変更します。

for i in range(0,3):
    m = x_train_mat[:,i,:,:].mean()
    s = x_train_mat[:,i,:,:].std()
    x_train_mat[:,i,:,:] = (x_train_mat[:,i,:,:] - m)/s
    x_test_mat[:,i,:,:] = (x_test_mat[:,i,:,:] - m)/s

結果、学習の過程をみると今までと学習速度が大きく変わり、少ない世代で精度が上がるようになりました。

2.バッチ処理の追加

ものの論文によると、CNNは事前学習をしたモデルを使用すると良いそうなので、これを簡易的に導入してみます。
通常の学習では、バッチサイズというのは1Epoch内での学習データの分割を行うものですが、モデルに導入する学習データそのものを分割します。

つまり、

学習データA → モデルチューニング → 学習データB → モデルチューニング → (ry

のようにAでモデルチューニングをしたのち、そのパラメータを使ってBでモデルチューニングを行います。

考え方的には、過学習抑制とFine-Tuningを意図しています。

コードで書くと

N = len(x_train_mat)
wbatch = N/3
perm = np.random.permutation(N)
for i in six.moves.range(0, N, wbatch):
    t_x_data = x_train_mat[perm[i:i + wbatch]]
    t_y_data = y_train[perm[i:i + wbatch]]
    if len(t_y_data) > wbatch / 2:
        """学習データが少なすぎる場合は捨てる"""
        cnn.fit_test(t_x_data,t_y_data,x_test_mat,y_test)

こんな感じ。

3.教師データの加工

学習データ中の教師データには偏りがあり、雨 < 晴のような関係になっています。
そのため、晴側に過剰にフィットしてしまい、雨の精度が上がらないことが見えてきました。
なので、学習データ中の雨データをもっと増やすために以下のような処理を行いました。

  1. 2015年のデータをすべて学習データにする。
  2. 2013年と2014年の「雨」データを学習データに追加する。
  3. テストデータは変えずに2016年すべてのデータを使用する。

4.地味なモデル変更

過学習を抑制するために、CNNのmax poolingの結果にdrop outを入れました。

5.フィルターサイズとプーリングサイズの調整

今までこのあたりは調整せずに決めて3にしていましたが、これを変えてみます。

途中経過

上記までの条件のもとで、フィルターサイズとプーリングサイズを変更していきます。

フィルターサイズ3、プーリングサイズ2の場合

平均AUC : 0.711
晴AUC : 0.790

天気 precision recall f1-score
0.6 0.61 0.6
0.82 0.82 0.82
平均 0.75 0.75 0.75

フィルターサイズ3、プーリングサイズ4の場合

平均AUC : 0.719
晴AUC : 0.783

天気 precision recall f1-score
0.66 0.58 0.61
0.82 0.86 0.84
平均 0.77 0.77 0.77

フィルターサイズ3、プーリングサイズ6の場合

平均AUC : 0.735
晴AUC : 0.780

天気 precision recall f1-score
0.67 0.61 0.63
0.83 0.86 0.85
平均 0.78 0.78 0.78

フィルターサイズ3、プーリングサイズ8の場合

平均AUC : 0.688
晴AUC : 0.790

天気 precision recall f1-score
0.67 0.48 0.56
0.79 0.89 0.84
平均 0.75 0.76 0.75

フィルターサイズ5、プーリングサイズ6の場合

平均AUC : 0.741
晴AUC : 0.784

天気 precision recall f1-score
0.53 0.8 0.64
0.88 0.68 0.77
平均 0.77 0.72 0.73

フィルターサイズ1、プーリングサイズ6の場合

平均AUC : 0.750
晴AUC : 0.790

天気 precision recall f1-score
0.61 0.7 0.65
0.85 0.8 0.83
平均 0.78 0.77 0.77

どうやらフィルターサイズを0に、プーリングサイズを少し大きめにしたほうが結果が良くなるようです。プーリングサイズを大きくするということは、より特徴的な特徴を抽出するようになるので、今回はこのほうがいいのかもしれません。
フィルターサイズとプーリングサイズは問題によって良い組み合わせがあるのだと思います。

試行錯誤の結果

最終的に今回出来上がったモデルでの結果は以下のようになります。

  • フィルターサイズ : 1
  • プーリングサイズ : 6
  • 出力チャネル数 : 12

平均AUC : 0.767
晴AUC : 0.806

天気 precision recall f1-score
0.59 0.77 0.67
0.88 0.76 0.82
平均 0.79 0.76 0.77

だいぶAUCとしては上がりました。

結論

いろいろと条件を変えて試行錯誤を続けているところですが、なんかパターンみたいなものがなかなか見つからず、組み合わせをいろいろと試しています。
ただ、テストデータでの評価を行いすぎているので、逆にテストデータも学習データの一部ではないか?説が出てきているのも確かです。
最終的なモデルができた段階で、別のテストデータも使ったほうがいいかもしれませんね。