Dans cet article, j'aimerais prendre des images sous forme de données de séries chronologiques et utiliser le LSTM convolutif pour prédire les images futures. Je pensais que convLSTM avait peu d'articles et d'exemples d'implémentation (peut-être parce qu'il n'est pas précis), alors j'aimerais le publier bien qu'il s'agisse d'un code rapide. Puisqu'il s'agit de l'implémentation principale, je pense que Folding Lstm est détaillé sur la structure de convLSTM.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from sklearn.model_selection import train_test_split
import glob
from PIL import Image
from tqdm import tqdm
import zipfile
import io
L'image utilisée était l'image satellite utilisée dans l'article précédent (j'ai essayé l'analyse en grappes de la carte météo). Cependant, il y avait un concours comme celui-là [SOTA] Weather Challenge: Cloud image prediction, donc je pense qu'il est pratique d'utiliser cet ensemble de données en faisant attention aux règles. .. Dans cet article, nous considérerons un modèle qui prédit l'image du lendemain à partir de 5 images toutes les 24 heures.
Ce code a été exécuté sur google colab, donc l'image est donnée sous forme de fichier zip. Par conséquent, il doit être décompressé. De plus, comme l'image d'origine est de très grande taille, la taille de l'image est réduite pour plus de simplicité.
#Taille d'image après réduction
height = 100
width = 180
#Array pour mettre l'image chargée
imgs=np.empty((0, height, width, 3))
#Lire un fichier zip dans un tableau numpy
zip_f = zipfile.ZipFile('drive/My Drive/Colab Notebooks/convLSTM/wide.zip')
for name in tqdm(zip_f.namelist()):
with zip_f.open(name) as file:
path = io.BytesIO(file.read()) #Dégivrer
img = Image.open(path)
img = img.resize((width, height))
img_np = np.array(img).reshape(1, height, width, 3)
imgs = np.append(imgs, img_np, axis=0)
Dans l'état actuel des choses, les données sont simplement alignées telles quelles, alors faites-en un formulaire qui peut être traité comme des données de séries chronologiques. La taille est x (nombre d'échantillons, longueur de la série chronologique, hauteur, largeur, nombre de canaux) et y est (nombre d'échantillons, hauteur, largeur, nombre de canaux).
#Organiser dans un format qui peut être appris dans l'ordre chronologique
n_seq = 5
n_sample = imgs.shape[0] - n_seq
x = np.zeros((n_sample, n_seq, height, width, 3))
y = np.zeros((n_sample, height, width, 3))
for i in range(n_sample):
x[i] = imgs[i:i+n_seq]
y[i] = imgs[i+n_seq]
x, y = (x-128)/128, (y-128)/128
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.1, shuffle = False)
Créez un modèle. C'est similaire à la couche de convolution, mais avec l'ajout de return_sequences
comme paramètre. Il s'agit de savoir s'il faut faire des données de série chronologique et renvoyer les données, et définir uniquement la dernière couche convLSTM sur False.
(Depuis que je m'égarais, par exemple en essayant la connexion de raccourci et la connexion de saut dans le processus d'ajustement du modèle, j'utilise l'API fonctionnelle, mais séquentielle suffit)
from keras import layers
from keras.layers.core import Activation
from tensorflow.keras.models import Model
inputs = layers.Input(shape=(5, height, width, 3))
x0 = layers.ConvLSTM2D(filters=16, kernel_size=(3,3), padding="same", return_sequences=True, data_format="channels_last")(inputs)
x0 = layers.BatchNormalization(momentum=0.6)(x0)
x0 = layers.ConvLSTM2D(filters=16, kernel_size=(3,3), padding="same", return_sequences=True, data_format="channels_last")(x0)
x0 = layers.BatchNormalization(momentum=0.8)(x0)
x0 = layers.ConvLSTM2D(filters=3, kernel_size=(3,3), padding="same", return_sequences=False, data_format="channels_last")(x0)
out = Activation('tanh')(x0)
model = Model(inputs=inputs, outputs=out)
model.summary()
Les détails du modèle sont comme ça
Model: "functional_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 5, 100, 180, 3)] 0
_________________________________________________________________
conv_lst_m2d (ConvLSTM2D) (None, 5, 100, 180, 16) 11008
_________________________________________________________________
batch_normalization (BatchNo (None, 5, 100, 180, 16) 64
_________________________________________________________________
conv_lst_m2d_1 (ConvLSTM2D) (None, 5, 100, 180, 16) 18496
_________________________________________________________________
batch_normalization_1 (Batch (None, 5, 100, 180, 16) 64
_________________________________________________________________
conv_lst_m2d_2 (ConvLSTM2D) (None, 100, 180, 3) 2064
_________________________________________________________________
activation (Activation) (None, 100, 180, 3) 0
=================================================================
Total params: 31,696
Trainable params: 31,632
Non-trainable params: 64
Apprenons. Dans le cas de colab, si la taille du lot est augmentée, l'utilisation de la mémoire sera dépassée, donc elle est réduite. (Je souhaite acheter une machine très performante et pouvoir la faire tourner localement ...)
model.compile(optimizer='rmsprop',
loss='mae', metrics=['mse'])
call_backs=[EarlyStopping(monitor="val_loss",patience=5)]
model.fit(x_train, y_train, batch_size=16, epochs=100, verbose=2, validation_split=0.2, shuffle=True, callbacks=call_backs)
La perte courante ressemble à ceci. Ça ne fait pas du bien ...
Affiche le résultat de l'exécution dans la figure.
#dessin
%matplotlib inline
i=15
fig, axes = plt.subplots(1, 2, figsize=(12,6))
axes[0].imshow((y_test[i]+1)/2)
axes[1].imshow((model.predict(x_test[[i]]).reshape(100,180,3)+1)/2)
L'image correcte et l'image prédite sont affichées côte à côte. i=0 i=20
En regardant ce résultat, il s'est avéré très vague. Cela peut être dû au fait que le flou se traduit en moyenne par des scores plus élevés que des résultats clairs. Je pense qu'il est possible que cela puisse être amélioré en changeant la fonction de perte en une autre, ou en prédisant l'image plusieurs heures plus tard, ce qui est susceptible de donner une prédiction plus précise.
Un concours pour prédire les images de nuages similaires à cet article a été organisé, et de nombreux efforts pour améliorer la précision seront utiles. Bien qu'il soit implémenté dans chainer, il y a un exemple de code dans le forum, donc je pense que ce sera utile.
Recommended Posts