De nos jours, les météorologues estiment que 90 % des prévisions météorologiques sont correctes sur une période de 5 jours. Les prédictions qui sont faites reposent généralement sur deux méthodes distinctes :
-
Approches basées sur la physique : ces approches utilisent des modèles qui intègrent des quantités mesurables telles que la pression, le mouvement des nuages, les conditions du ciel… De tels modèles sont efficaces pour prédire la météo pour les jours ou les semaines à venir.
-
Approches sans physique (basées sur des données) : ces approches utilisent des données historiques pour créer des modèles capables de faire des prédictions. De tels modèles donnent de bons résultats dans la prévision du temps jusqu'à 6 heures ou ce que l'on appelle la prévision météorologique immédiate.
Dans cet article, nous aborderons la deuxième catégorie d’approches. Nous discuterons des différents formats de données météorologiques, de la manière dont l'apprentissage automatique peut être exploité pour effectuer des prévisions météorologiques immédiates et de la manière dont les architectures développées peuvent être bénéfiques pour résoudre des problèmes similaires.
Données pour la prévision climatique
Puisque les approches sans physique utilisent des données historiques, commençons par examiner les données disponibles.
Nous utiliserons deux sources principales de données :
- Données d'images : Ces données prennent la forme d'images radar ou satellite d'une zone géographique spécifiée. Il est utilisé pour prédire les précipitations, le mouvement du vent ou l’humidité.
- Données tabulaires : Ces données prennent la forme d'enregistrements de grandeurs mesurables telles que la température, l'humidité ou la vitesse du vent.
Bien que les deux sources de données soient importantes pour construire des modèles puissants, nous nous concentrerons sur la première (données d'images collectées à partir de radars ou de satellites) pour des raisons de simplicité. Les modèles les plus couramment utilisés avec des données d'image sont les Réseaux de neurones convolutifs (CNN ).
Suite à ce travail, nous allons utiliser une architecture U-Net pour créer notre propre modèle de prévision immédiate.
Architecture
Partir d’une architecture existante est utile pour de nombreuses raisons, parmi lesquelles :
Les architectures servent de lignes directrices pour créer de nouveaux modèles. Les personnes qui créent de nouvelles architectures adoptent une approche par essais et erreurs pour arriver à leurs résultats finaux. En réutilisant leurs résultats finaux, nous pouvons gagner beaucoup de temps.
Les modèles pré-entraînés sont généralement disponibles pour une utilisation immédiate. Lorsque les chercheurs publient leurs nouvelles architectures, ils publient généralement également les paramètres formés, afin que les utilisateurs n'aient pas à se soucier de la formation/de l'optimisation à partir de zéro. Ceci est particulièrement utile pour les très grands modèles assoiffés de ressources.
Des exemples d'architectures de vision célèbres incluent :
- LeNet (60k paramètres)
- AlexNet (paramètres 60m)
- VGG-16 (paramètres 138m)
U-Net
U-Net est une architecture basée sur un réseau entièrement convolutif, ce qui signifie qu'elle ne comporte aucune couche entièrement connectée. Il a été introduit pour la première fois pour une tâche de segmentation d’images médicales. Ces résultats ont incité les chercheurs à l’étendre à d’autres tâches de vision par ordinateur.
En 2019, Google a utilisé une architecture basée sur U-Net pour créer un modèle de prévision des précipitations.
Le nom « U-Net » vient de la forme en « U » de son architecture.
Nous identifions trois composantes principales :
-
Contraction / Encodeur : Succession de couches de convolution/pooling qui compressent l'image d'entrée dans une représentation de plus petite taille.
-
Pont / Goulot d'étranglement : La partie inférieure du « U » relie l'encodeur au décodeur. Il est formé par une série d’opérations de convolution.
-
Décontractant / Décodeur : Succession de upconvolutions et de couches de convolution, qui « décompressent » la sortie du goulot d'étranglement.
L'architecture d'un U-Net ressemble jusqu'à présent à un encodeur automatique. Cependant, la différence réside dans les informations qui transitent entre le codeur et le décodeur. Cette information est transmise en concaténant les résultats des convolutions du codeur avec ceux de la convolution ascendante du décodeur. Cette modification améliore la résolution et permet au modèle de produire une sortie spatialement plus précise (l'emplacement des pixels dans la sortie sera plus précis, résolvant ainsi un problème survenu dans les modèles qui n'incluaient pas de concaténation). La concaténation se fait symétriquement.
Création d'un modèle U-Net pour la prévision immédiate des précipitations
Dans cette section, nous allons construire un modèle U-Net pour prédire la météo à partir d'images satellite. Nous utiliserons un modèle pré-entraîné appelé Rain-Net.
Le code ci-dessous est disponible dans ce colab.
Nous installons d'abord wradlib, une bibliothèque Open Source pour le traitement des données des radars météorologiques
!pip install wradlib
import wradlib as wrl
Nous écrivons ensuite deux fonctions utilitaires pour télécharger des données satellite à partir du serveur de données ouvertes de DWD
import urllib.request
import io
import numpy as np
import datetime
def download_and_read_RY(RY_timestamp):
url = f"https://opendata.dwd.de/weather/radar/radolan/ry/raa01-ry_10000-{RY_timestamp}-dwd---bin"
data_binary = urllib.request.urlopen(url).read()
data, attr = wrl.io.read_radolan_composite(io.BytesIO(data_binary), missing = 0)
data = data.astype("float32")
return data,attr
def download_data():
latest_scan, latest_attr = download_and_read_RY("latest")
latest_datetime = latest_attr["datetime"]
list_for_downloading = [ts.strftime("%y%m%d%H%M") for ts in
[latest_datetime - datetime.timedelta(minutes=t) for t in [15, 10, 5]]]
previous_scans = np.array([download_and_read_RY(ts)[0] for ts in list_for_downloading])
print(list_for_downloading)
scans = np.concatenate([previous_scans, latest_scan[np.newaxis, ::, ::]], axis = 0)
return scans, latest_datetime
Ces utilitaires nous permettent de télécharger les 4 dernières images satellite, soit le nombre d'images satellite dont nous avons besoin pour faire des prédictions avec notre modèle pré-entraîné.
On peut ensuite utiliser les fonctions créées pour récupérer les 4 dernières images
RY_latest, RY_latest_timestep = download_data()
Après avoir obtenu les images, nous utilisons la méthode vis.plot_ppi de wradlib pour tracer les données
for i in range(RY_latest.shape[0]):
wrl.vis.plot_ppi(RY_latest[i])
Nous avons maintenant chargé nos données. Chargeons ensuite le modèle.
Nous commençons par importer les classes pertinentes. Nous utiliserons TensorFlow dans cet article.
à partir de tensorflow.keras.layers importer Entrée, Conv2D, Activation, Concaténer, Conv2DTranspose, MaxPool2D
à partir de tensorflow.keras.models, importer le modèle
Construisons 3 blocs de construction primitifs. Ces "blocs de construction" seront utilisés pour créer l'architecture entière, selon cette implémentation.
Le premier bloc correspond à la succession de couches convolutives, on l'appelle "conv_block"
def conv_block(input, num_filters):
x = Conv2D(num_filters, 3, padding ="same", kernel_initializer="he_normal"(input))
x = Activation("relu")(x)
x = Conv2D(num_filters, 3, padding ="same", kernel_initializer="he_normal"(x))
x = Activation("relu")(x)
return x
Le deuxième bloc est utilisé pour construire le à partir de la partie encodeur (bloc convolutif + pooling maximum). Nous l'appelons un "encoder_block"
def encoder_block(input, num_filters):
x = conv_block(input, num_filters)
p = MaxPool2D((2,2))(x)
return x,p
Le troisième et dernier bloc est un « decoder_block » (upconvolution + concaténation + convolution).
def decoder_block(input, skip_features, num_filters):
x = Conv2DTranspose(num_filters, (2,2), strides=2, padding="same", kernel_initializer="he_normal")
x = Concatenate()([x, skip_features])
x = conv_block(x, num_filters)
return x
Nous combinons ces éléments de base pour construire le modèle U-Net
def build_unet(input_shape = (928, 928, 4)):
inputs = Input(input_shape)
e1, p1 = encoder_bock(inputs, 64)
e2, p2 = encoder_bock(p1, 128)
e3, p3 = encoder_bock(p2, 256)
e4, p4 = encoder_bock(p3, 512)
b1 = conv_block(p4, 1024)
d1 = decoder_block(b1, e4, 512)
d2 = decoder_block(d1, e3, 256)
d3 = decoder_block(d2, e2, 128)
d4 = decoder_block(d3, e1, 64)
outputs = Conv2D(1, 1, padding="same", activation="linear")(d4)
unet = Model(inputs, outputs, name="U-Net")
return unet
N'hésitez pas à jouer avec l'implémentation, à l'améliorer ou à l'adapter à vos besoins si vous souhaitez l'utiliser pour autre chose.
La formation de ce modèle peut prendre beaucoup de temps. Heureusement, il existe un modèle appelé Rain-Net, créé sur la base d'une architecture U-Net et spécialisé dans la prévision immédiate des précipitations.
Clonons son dépôt GitHub
! git clone https://github.com/hydrogo/rainnet.git
Nous téléchargeons ensuite les poids pré-entraînés pour ce modèle
!wget -O /content/rainnet/rainnet_weights.h5 https://zenodo.org/record/3630429/files/rainnet_weights.h5
L'étape suivante consiste à créer un modèle basé sur l'architecture trouvée sur le référentiel puis à charger les poids téléchargés sur ce modèle
import sys
from rainnet import rainnet
model = rainnet.rainnet()
model.load_weights('/content/rainnet/rainnet_weights.h5')
model.summary()
Les images que nous avons téléchargées ont une taille de 900*900 pixels. Nous allons remodeler ces images pour qu'elles correspondent à l'entrée attendue de Rain-Net
def Scaler(array):
return np.log(array+0.01)
def invScaler(array):
return np.exp(array) - 0.01
def pad_to_shape(array, from_shape=900, to_shape=928, how="mirror"):
# calculate how much to pad in respect with native resolution
padding = int( (to_shape - from_shape) / 2)
# for input shape as (batch, W, H, channels)
if how == "zero":
array_padded = np.pad(array, ((0,0),(padding,padding),(padding,padding),(0,0)), mode="constant", constant_values=0)
elif how == "mirror":
array_padded = np.pad(array, ((0,0),(padding,padding),(padding,padding),(0,0)), mode="reflect")
return array_padded
def pred_to_rad(pred, from_shape=928, to_shape=900):
# pred shape 12,928,928
padding = int( (from_shape - to_shape) / 2)
return pred[::, padding:padding+to_shape, padding:padding+to_shape].copy()
'''
the spatial extent of input data has to be a multiple of 2n+1
where n is the number of max pooling layers
'''
def data_preprocessing(X):
# 0. Right shape for batch
X = np.moveaxis(X, 0, -1)
X = X[np.newaxis, ::, ::, ::]
# 1. To log scale
'''
We use a log scale to respond to skewness towards large values
'''
X = Scaler(X)
# 2. from 900x900 to 928x928
X = pad_to_shape(X)
return X
def data_postprocessing(nwcst):
# 0. Squeeze empty dimensions
nwcst = np.squeeze(np.array(nwcst))
# 1. Convert back to rainfall depth
nwcst = invScaler(nwcst)
# 2. Convert from 928x928 back to 900x900
nwcst = pred_to_rad(nwcst)
# 3. Return only positive values
nwcst = np.where(nwcst>0, nwcst, 0)
return nwcst
Nous créons ensuite une fonction qui fait les prédictions.
def prediction(model_instance, input_data, lead_time=24):
input_data = data_preprocessing(input_data)
nwcst = []
for _ in range(lead_time):
pred = model_instance.predict(input_data)
nwcst.append(pred)
input_data = np.concatenate([input_data[::, ::, ::, 1:], pred], axis = -1)
nwcst = data_postprocessing(nwcst)
return nwcst
Nous appelons ensuite cette fonction sur les données que nous avons téléchargées précédemment
Y_pred = prediction(model, RY_latest)
Nous pouvons tracer les prédictions et les enregistrer pour utiliser les résultats enregistrés pour créer une image GIF qui nous permet de visualiser les prédictions
import matplotlib.pyplot as plt
names = []
for i in range(0, 19):
im = wrl.vis.plot_ppi(Y_pred[i])
name = '/content/image'+str(i)+'.png'
names.append(name)
plt.savefig(name)
import imageio
from google.colab import files
imgs = []
for name in names:
imgs.append(imageio.imread(name))
imageio.mimsave('/content/pred.gif', imgs, fps=4)
files.download('/content/pred.gif')
Félicitations pour être arrivé jusqu'ici ! Vous pouvez désormais utiliser un Rain-Net pour faire des prédictions et les visualiser.
Conclusion
Dans cet article, nous avons utilisé un modèle d'apprentissage automatique (Rain-Net) pour effectuer une prévision immédiate des précipitations. Nous avons utilisé une architecture U-Net, que nous avons construite à l'aide de TensorFlow. Nous avons chargé un modèle pré-entraîné pour prédire les images satellite.
Cette mise en œuvre peut être améliorée de plusieurs manières. Par exemple:
-
Affinez le modèle sur votre ensemble de données
-
Utilisez un module basé sur l'attention, tel que CBAM (Convolutional Block Attention Module) dans l'architecture.
Les références
Venez à l'un de nos ateliers gratuits !
Commencez votre carrière en tant que data scientist avec nos ateliers gratuits, qui sont basés sur un programme adaptable et guidés par des experts du secteur.