Pythonプログラミング(リカレントネットによる時系列学習)

(このページは作成中)

でんき予報

東北電力では、電力利用状況についての情報公開と、それを節電につなげるための取り組みとして でんき予報というウェブページを設けている。 ページの下段には、東北6県と新潟県の最近数年間の時間ごとの電力消費量(万KWH)の実績データがCSV形式でダウンロードできるようになっている。 例えば、2018年度のデータ()は juyo_2018_tohoku.csv 等々。 CSVの内容は、以下のように、ヘッダ部分(2行)に続いて、年月日、時刻、実績が、行ごとにコンマで区切られている。

2019/1/1 3:02 UPDATE
DATE,TIME,実績(万kW)
2018/1/1,0:00,903
2018/1/1,1:00,916
...

ここでは、これらのデータを使って過去の電力量の推移をニューラルネットに学習させ、今後の需要予想を立ててみたい。

トレーニングデータの生成

電力の使用量は、過去の履歴に加え、時間帯や曜日にも左右されるはずである。 そこで、入力データ(説明変数)として、ここでは、 [曜日, 時刻, 電力量] の3つを組にして与え、そこから、次(1時間先)の時間帯の電力量を予測することを目指す。

まず、ダウンロードしたCSVファイルを読み込んで、リストxdataにデータをセットするコードの例を示す:

import numpy as np
import codecs
import csv
import datetime

xdata=[]

with codecs.open('juyo_2018_tohoku.csv','r','Shift-JIS', 'ignore') as csvfile:
    reader = csv.reader(csvfile, delimiter = ',')
    cnt=0
    for row in reader:
        if cnt>1:
            ymd=row[0].split('/')            
            wd=datetime.datetime(int(ymd[0]),int(ymd[1]),int(ymd[2])).weekday()
            h=int( row[1].split(':')[0] )
            p=float(row[2].strip())/1000.0
            xdata.append([wd,h,p])
        cnt=cnt+1

ファイル中に日本語文字が含まれている場合にも対応できるよう、codecsモジュールを用いて文字コードの処理をしながら、csvモジュール でCSVファイルを読み込む。

最初の2行を飛ばして、それ以後の行について、

という処理を繰り返している。

続いて、xdataを切り出しながら、説明変数用と目的変数用のトレーニングデータ(それぞれ、x_trainy_trainを生成する:

timestep=24

x_train = [ ]
y_train = [ ]

for i in range(len(xdata) - timestep ):
    x = xdata[i: i+timestep]
    y = xdata[i+timestep][2]
    x_train.append(x)
    y_train.append(y)
    
x_train = np.array(x_train, dtype=np.float32)
y_train = np.array(y_train, dtype=np.float32)

GRUを用いたモデルの作成

以下は、内部状態を128変数、入力がtimestep $\times 3$のGRUに、 32素子と1素子から成るフィードフォワードネットを繋いだモデルを生成するコードである。

from keras.models import Sequential
from keras.layers import Dense,GRU

model = Sequential()
model.add(GRU(128,input_shape=(timestep,3), use_bias=True))
model.add(Dense(32, use_bias=True,activation='relu'))
model.add(Dense(1, use_bias=True, activation='linear'))
model.compile(loss='mean_squared_error', optimizer='Adam')
model.summary()

学習とデータの保存

トレーニングデータセットを用いてネットワークを学習し、モデルと荷重をファイルに保存するコードの例が以下である。

epochs=1000
batch_size=32

model.fit(x_train, y_train,
          epochs=epochs, 
          batch_size=batch_size)

scores = model.evaluate(x_train, y_train, verbose=0)
print(scores)

json_string=model.to_json()
with open("train.json","w") as f:
    f.write(json_string)

model.save_weights("train.hdf5")

上記のステップを全てまとめたコード例を以下に示す:

# coding: utf-8
from keras.models import Sequential
from keras.layers import Dense,GRU
import numpy as np
import matplotlib.pyplot as plt
import codecs
import csv
import datetime

# データの読み込み
xdata=[]

with codecs.open('juyo_2018_tohoku.csv','r','Shift-JIS', 'ignore') as csvfile:
    reader = csv.reader(csvfile, delimiter = ',')
    cnt=0
    for row in reader:
        if cnt>1:
            ymd=row[0].split('/')            
            wd=datetime.datetime(int(ymd[0]),int(ymd[1]),int(ymd[2])).weekday()
            h=int( row[1].split(':')[0] )
            p=float(row[2].strip())/1000.0
            xdata.append([wd,h,p])
        cnt=cnt+1

# トレーニングデータの生成
timestep=24

x_train = [ ]
y_train = [ ]

for i in range(len(xdata) - timestep ):
    x = xdata[i: i+timestep]
    y = xdata[i+timestep][2]
    x_train.append(x)
    y_train.append(y)

x_train = np.array(x_train, dtype=np.float32)
y_train = np.array(y_train, dtype=np.float32)

# モデルの生成
model = Sequential()
model.add(GRU(128,input_shape=(timestep,3), use_bias=True))
model.add(Dense(32, use_bias=True,activation='relu'))
model.add(Dense(1, use_bias=True, activation='linear'))
model.compile(loss='mean_squared_error', optimizer='Adam')
model.summary()

# 学習
epochs=1000
batch_size=32

model.fit(x_train, y_train,
          epochs=epochs, 
          batch_size=batch_size)

scores = model.evaluate(x_train, y_train, verbose=0)
print(scores)

# 結果の保存
json_string=model.to_json()
with open("train.json","w") as f:
    f.write(json_string)

model.save_weights("train.hdf5")

icon-pc 練習:ネットワークのトレーニング

上記のコードを実行し、モデルのデータ(train.js)、および、荷重データ(train.hdf5)を作成しなさい。

一般に、リカレントネットワークの学習においてはGPUによる高速化の恩恵が薄いため、環境によっては時間がかかるかもしれない。 GPU(CUDA)が使える環境の場合は、GRUレイヤーの代わりにCuDNNGRUレイヤーを用いることで高速化が期待できる。