#はじめに
以前、地図上にデータをプロットしたり、cifar10で分類をさせてみたりしましたが、今回はそれを組み合わせてやろうという思いつきで始めてみました。要するに、既存のデータセットではなく自作データでやってみようというわけです。
###目次
・使用したもの
・画像データの作成
・訓練データ、テストデータの作成
・識別機に放り込む
###使用したもの
import cartopy.crs as ccrs
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from PIL import Image
from tensorflow.keras.utils import to_categorical
いろいろimportしているときなんかワクワクするの私だけでしょうか。
###画像データの作成
まず、日本周辺の気温と気圧配置の図をcartopyを使って作成しました。その点は、使っているデータセットによるのでコードは割愛します。
このような画像データを3年分、365*3枚の画像を作成しました。
###訓練データ、テストデータの作成
保存したままのデータだと(4000, 4000, 4)のデータで、一度に乗せることができなかったので解像度を荒くしていきます。画像データがpic_0.pngとして保存されているとすると
from PIL import Image
img = Image.open(f'pic_0.png')
img = img.resize((300, 300))
(300, 300, 4)まで落とすことができました。これを全データで行いました。ここから、訓練データとテストデータを作っていきます。画像1年分は1月から365日分12月までです。また、冬を0、春を1、夏を2、秋を3としてラベルを振り当てます。
import numpy as np
from tensorflow.keras.utils import to_categorical
x_all = np.zeros((365*3, 300, 300, 4))
y_all = np.zeros((365*3, 1))
for y in range(3):
for i in range(365*3):
k = y * 365
img = Image.open(f'pic_{i+k}.png')
img = img.resize((300, 300))
x_all[i+k, :, :, :] = img
if i < 59+k:
y_all[k+d, :] = 0
elif 59+k <= d < 151+k:
y_all[k+d, :] = 1
elif 151+k <= d < 243+k:
y_all[k+d, :] = 2
elif 243+k <= d < 334+k:
y_all[k+d, :] = 3
else:
y_all[k+d, :] = 0
x_test = x_all[:250, :, :, :].astype('float32') / 255
x_train = x_all[250:, :, :, :].astype('float32') / 255
y_test = to_categorical(y_all[:250, :], 4)
y_train = to_categorical(y_all[250:, :], 4)
np.savez(f'season_data.npz', x_train=x_train, x_test=x_test, y_train=y_train, y_test=y_test)
訓練するたびにこれを実行するのはめんどくさいので保存。これで準備ができました。
###識別機に放り込む
識別機自体は以前作成したのでこちらから
[cifar10のkerasでの分類にチャレンジ]
https://qiita.com/white_coffee/items/bda12686ff490934caed
コード以下の通りです。
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.layers import Input, Dense, BatchNormalization, Dropout, Conv2D, LeakyReLU, Flatten
class discri():
def __init__(self, input_dim, fil, ker, stri, use_batch, use_dropout, lr):
self.input_dim = input_dim
self.fil = fil
self.ker = ker
self.stri = stri
self.name = 'discri'
self.n_layers = len(fil)
self.use_batch = use_batch
self.use_dropout = use_dropout
self.lr = lr
self.build()
def build(self):
input_layer = Input(shape=self.input_dim)
x = input_layer
for i in range(self.n_layers):
conv = Conv2D(filters=self.fil[i], kernel_size=self.ker[i], strides=self.stri[i],
padding='same', name='conv_'+str(i))
x = conv(x)
if self.use_batch:
x = BatchNormalization(momentum=self.use_batch)(x)
x = LeakyReLU()(x)
if self.use_dropout:
x = Dropout(rate=0.5)(x)
x = Flatten()(x)
x = Dense(units=4, activation='sigmoid')(x)
output_layer = x
self.model = Model(input_layer, output_layer)
def compile(self, lr):
self.model.compile(optimizer=Adam(lr=lr), loss='categorical_crossentropy', metrics=['accuracy'])
def train(self, data1, data2, batch_size, epochs):
self.model.fit(data1, data2, batch_size=batch_size, epochs=epochs, shuffle='True')
各値を以下のように設定。
indim = (300, 300, 4)
filter = [300, 600, 600, 300]
kernel = [3, 3, 3, 3]
stri = [3, 3, 3, 2]
usebatch = None
usedrop = True
Lr = 0.0005
Epochs = 10
Batchsize = 32
最初の入力の次元、フィルターの数を変更。動物の顔等と違いそこまで細かく見なくても大丈夫かなと思いストライドは3と2でやってみることに、Batchsizeは前回のまま変え忘れました。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
out = np.load(f'season_data.npz')
x_train = out['x_train']
x_test = out['x_test']
y_train = out['y_train']
y_test = out['y_test']
DISCRI = discri(input_dim=indim, fil=filter, ker=kernel, stri=stri, \
use_batch=usebatch, use_dropout=usedrop, lr=Lr)
DISCRI.model.summary()
DISCRI.compile(lr=Lr)
DISCRI.train(data1=x_train, data2=y_train, batch_size=Batchsize, epochs=Epochs)
確かめてみましょう。
y = DISCRI.model.predict(x_test)
season_list = {0:'winter', 1:'spring', 2:'summer', 3:'autumn'}
y.shape
fig = plt.figure(1, figsize=(20, 10), dpi=300, facecolor='white')
ax = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
for i in range(10):
n = 24 * i
img = x_test[n, :, :, :]
name = season_list[np.argmax(y[n, :])]
name2 = season_list[np.argmax(y_test[n, :])]
ax[i] = fig.add_subplot(2, 5, i+1)
ax[i].axis('off')
ax[i].set_title('pred={0:}, actual={1:}'.format(name, name2))
ax[i].imshow(img)
plt.show()
いい感じ予測できてる気がしますが、やはり季節の変わり目、そして秋と春の違いは難しいみたいですね。やっぱkeras 楽しい。
###参考文献
[生成Deep Learning]
・David foster 著
・松田晃一、小沼千絵 訳
・オライリージャパン
・2020年発行