#変更履歴
2016/8/31 AUC計算が「晴」だけしか見ていなかったので、修正
#概要
DeepLearningでCNN(畳み込みニューラルネットワーク)といえば、画像処理がメインになるのに、画像処理に関する分析を全くやっていなかったので、今回は 気象画像から天気予報ができるか を検証してみたいと思います。
#準備
気象画像の入手
気象画像は高知大学のサイトからぽちぽちダウンロードしました。2015年1月から2016年7月のデータを入手します。使ったのはこのような画像です。
なお、1時間ごとにデータがあるので、17時のデータを入手しました。
出典: 高知大学・東京大学・気象庁提供
過去の天気の入手
過去の天気は気象庁のページから入手します。こちらも2015年1月から2016年7月までの日ごとの天気データです。場所は東京で、日中の天気を使用しました。
#問題設定
問題としては「前日の17時の日本付近の気象画像から、次の日の晴・雨を予測する」です。
なお、気象庁の天気には「晴後雨」とか「曇」とかありますが、雨が含まれれば「雨」、それ以外は「晴」として扱い、二値分類問題としました。
#前処理
明日の天気には、東京付近の雲の動きだけではなく偏西風等の影響もあるので、もっと広い範囲の気象画像が必要ですが、日本から遠く離れた場所の天気は不要でしょう。
なので、画像をトリミングして日本付近のデータにしてあげます。
import numpy as np
from PIL import Image
import datetime as dt
w = 640
h = 480
"""日本付近だけを切り取る設定"""
sw = 320
sh = 65
ew = 540
eh = 320
"""イメージ圧縮"""
is_comp = False
def get_mat(dates=[]):
"""
:param dates:
:return:
"""
l = len(dates)
if not is_comp:
wr = ew - sw
hr = eh - sh
else:
wr = 50
hr = 50
mat = np.zeros((l,3,wr,hr),dtype=np.float32)
file_base = base_file_dir + "fe.%s" + base_hour + ".jpg"
j = 0
err_dates = []
for ddd in dates:
dd = dt.datetime.strptime(ddd,"%Y/%m/%d")
dd_str = dd.strftime("%y%m%d")
try:
im = Image.open(file_base % (dd_str))
im = im.crop((sw,sh,ew,eh))
im = im.resize((wr, hr))
mat0 = np.array(im)
for i in range(0,3):
mat[j,i,:,:] = mat0[:,:,i].T
j += 1
except:
err_dates.append(ddd)
print dd_str + " --> Error!!"
return mat[0:j],err_dates
日付のリストを受け取って、画像をnumpyの行列にして返し、ついでにエラーが出た日付も返してあげます。
イメージオブジェクトimには画像が入りますが、numpyで行列に直した場合、(幅、高、チャネル)の順になるので、転置している点に注意が必要です。
ここでは、画像(480x640)から日本列島が入る範囲でトリミングを行っています。
以下のような感じ。
行列にしたのちのデータは各セルに0-255までのデータが入るので、255で割って0から1のデータに変換します。
その後のCNNの学習時間の関係で、画像を圧縮することも考えましたが、今回はやめました。
#CNNモデル
畳み込みニューラルネットワークのモデルは従前使用していたものを使用します。
このへんとかこのへんとかこのへんを参照ください。
パラメータ設定としては、以下のようにしています。
params = {"clm_dim":clm_dim,"in_channels":3,"out_channels":3,"row_dim":row_dim,"filt_clm":3,"filt_row":3,"pool_clm":3,"pool_row":3,"batchsize":200,"hidden_dim":500,"n_classes":2}
clm_dimとrow_dimは各画像の幅と高さに対応します。また、チャネル数はRGBなので3としています。また、max poolingを使用します。
なお、フィルタサイズとかプーリングサイズを大きくすると計算時間がかかるようになります。(はまった)
この設定でも手元のmacbook proでは非常に時間がかかります。なので、今回はepoch=50としました。
#学習データとテストデータ
非常に計算時間がかかるので、学習データを2015/1/1から2015/12/31の1年間のデータ、テストデータを2016/1/1から2016/7/31までとしています。
これでも時間かかるけど。画像処理恐ろしい・・・
#モデルの学習とテスト精度
学習の進み方とテスト精度は以下のような形になりました。
また学習精度としては伸びそうだけど、テスト精度が追いついていないなぁ。
#テスト結果
AUCで 0.78 0.70 で各種指標が以下。
Precision | Recall | F-Score | |
---|---|---|---|
雨 | 0.54 | 0.67 | 0.6 |
晴 | 0.83 | 0.74 | 0.78 |
平均 | 0.74 | 0.72 | 0.72 |
まぁざくっとやった割には結構いい感じではないでしょうか。
ただ、雨と予測したうち、実際に雨だったのは54%と低めです。
雨確率で降順に並べて、実績の雨の比率と晴の比率をプロットしてみましょう。
- 雨累積 = (確率高い順での雨日数)/(合計雨日数)
- 晴累積 = (確率低い順での晴日数)/(合計晴日数)
ちゃんとランダムではなく予測しているっぽい。
テストデータ中の実際の雨の比率は30%、晴の比率は60%なので、そうでしょう。
#曇の扱い
精度が上がらない要因の一つに「曇」の扱いがあると思われます。
「晴れのち曇」の場合とか「曇一時雨」とかがあり、実際データ中の曇の比率は70%を超えます。(曇すぎ)
今回前者を晴、後者を雨として扱っています。そのため、微妙な状況というのはどちらかわからないのだと思われます。このへんは課題です。
ただ、今回の結果では、明らかな雨については結構な精度で当たっているようです。
三値分類にすると曇が支配的になってしまうので、難しい問題になります。
気象予報士さんはすごいですね。
#今後
アルゴリズム的にはこれでいこうかなぁとは思っていますが、データについては、例えば前日の画像との差分を取るとか、ベースになる地図のピクセルを抜くとか考えられます。
ちょぼちょぼとやっていこうかなぁと思います。