[PYTHON] Prédiction d'images dans le cloud à l'aide de convLSTM

introduction

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.

Charger la bibliothèque


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

Image utilisée

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.

Chargement des images

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)

Mise en forme des données

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)

Construire un modèle

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. image.png Ç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 image.png i=20 image.png

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.

développement

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.

Références

Recommended Posts

Prédiction d'images dans le cloud à l'aide de convLSTM
Segmentation d'image à l'aide de U-net
Essayez d'utiliser l'image Docker de Jupyter
Générer une image Docker à l'aide de Fabric
Imprimez un PDF à l'aide de Google Cloud Print. (GoogleAPI)
Capture d'image de Firefox en utilisant Python
[Python] Utilisation d'OpenCV avec Python (filtrage d'image)
Jugement de l'image rétroéclairée avec OpenCV
Prédiction géolocalisée à partir d'images à l'aide de DNN
[Python] Utilisation d'OpenCV avec Python (transformation d'image)
Utiliser Cloud Storage depuis Python3 (Introduction)
Grattage écologique grâce au traitement d'image
[FSL] Mesure d'image à l'aide du ROI (VOI)
Binarisation d'images par analyse discriminante linéaire
Reconnaissance d'image des fruits avec VGG16
100 traitement du langage knock-74 (en utilisant scicit-learn): prédiction