Precipitació Nowcasting amb Machine Learning

ML
DL
CNN
Predicció del temps
UNet
Precipitació Nowcasting amb Machine Learning cover image

Actualment, els meteoròlegs estimen que el 90% de les prediccions meteorològiques són correctes en un període de 5 dies. Les prediccions que es fan normalment es basen en dos mètodes diferents:

  1. Enfocaments basats en la física: aquests enfocaments utilitzen models que integren magnituds mesurables com la pressió, el moviment dels núvols, les condicions del cel... Aquests models són bons per predir el temps per als propers dies o setmanes.

  2. Enfocaments lliures de física (basats en dades): aquests enfocaments utilitzen dades històriques per crear models que poden fer prediccions. Aquests models mostren bons resultats a l'hora de predir el temps fins a 6 hores o el que es coneix com a predicció meteorològica.

En aquest article, parlarem de la segona categoria d'enfocaments. Discutirem els diferents formats de dades meteorològiques, com es pot aprofitar l'aprenentatge automàtic per fer projeccions meteorològiques i com les arquitectures desenvolupades poden ser beneficioses per resoldre problemes similars.

Dades per a la predicció del clima

Com que els enfocaments lliures de física utilitzen dades històriques, comencem per analitzar les dades disponibles.

Utilitzarem dues fonts principals de dades:

  1. Dades d'imatge: aquestes dades prenen forma d'imatges de radar o de satèl·lit d'una àrea geogràfica determinada. S'utilitza per predir la precipitació, el moviment del vent o la humitat.

Satellite Image

  1. Dades tabulars: Aquestes dades prenen forma de registres de magnituds mesurables com la temperatura, la humitat o la velocitat del vent.

Tabular Data

Tot i que ambdues fonts de dades són importants per construir models potents, ens centrarem en les primeres (dades d'imatge recollides de radars o satèl·lits) per raons de simplicitat. Els models més utilitzats amb dades d'imatge són Xarxes neuronals convolucionals (CNNs ).

Després d'aquest treball, utilitzarem una arquitectura U-Net per crear el nostre propi model de projecció immediata.

Arquitectura

Partir d'una arquitectura existent és útil per moltes raons, entre les quals:

Les arquitectures serveixen de pautes per crear nous models. Les persones que creen noves arquitectures adopten un enfocament d'assaig i error per arribar als seus resultats finals. Reutilitzant els seus resultats finals, podem estalviar molt de temps.

Els models prèviament entrenats solen estar disponibles per al seu ús immediat. Quan els investigadors publiquen les seves noves arquitectures, solen publicar també els paràmetres entrenats, de manera que els usuaris no hauran de passar per la molèstia d'entrenar/optimitzar des de zero. Això és especialment útil per a models molt grans i assedegats de recursos.

Exemples d'arquitectures de visió famoses inclouen:

  • LeNet (60k paràmetres)

LeNet

  • AlexNet (paràmetres de 60 m)

AlexNet

  • VGG-16 (138 m paràmetres)

VGG-16

U-Net

U-Net és una arquitectura basada en una xarxa totalment convolucional, és a dir, no té capes completament connectades. Es va introduir per primera vegada per a una tasca de segmentació d'imatges mèdiques. Aquests resultats van inspirar els investigadors a estendre-ho a altres tasques de visió per computador.

El 2019, Google va utilitzar una arquitectura basada en U-Net per crear un model de previsió de precipitació.

El nom "U-Net" prové de la forma "U" de la seva arquitectura.

U-net Architecture

Identifiquem tres components principals:

  1. Contractació / Codificador: Successió de capes de convolució/agrupació que comprimeixen la imatge d'entrada en una representació de mida més petita.

  2. Pont / Coll d'ampolla: La part inferior de la "U" connecta el codificador amb el descodificador. Està format per una sèrie d'operacions de convolució.

  3. Descontractació / Descodificador: Successió de convolucions ascendents i capes de convolució, que "descomprimeixen" la sortida del coll d'ampolla.

Fins ara, l'arquitectura d'una U-Net sembla un codificador automàtic. Tanmateix, la diferència resideix en la informació que passa entre el codificador i el descodificador. Aquesta informació es transmet concatenant els resultats de les circumvolucions del codificador amb el de la convolució ascendent del descodificador. Aquesta modificació millora la resolució i permet que el model emeti una sortida més precisa espacialment (la ubicació dels píxels a la sortida serà més precisa, resolent un problema que es va produir en models que no incloïen concatenació). La concatenació es fa simètricament.

Construcció d'un model U-Net per a la predicció immediata de les precipitacions

En aquesta secció, construirem un model U-Net per predir el temps a partir d'imatges de satèl·lit. Utilitzarem un model pre-entrenat anomenat Rain-Net.

El codi següent està disponible en aquest colab.

Primer instal·lem wradlib, una biblioteca de codi obert per al processament de dades del radar meteorològic

!pip install wradlib
import wradlib as wrl

A continuació, escrivim dues funcions d'utilitat per descarregar dades de satèl·lit del servidor de dades obertes 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

Aquestes utilitats ens permeten descarregar les darreres 4 imatges de satèl·lit, que és el nombre d'imatges de satèl·lit que necessitem per fer prediccions amb el nostre model preentrenat.

A continuació, podem utilitzar les funcions creades per obtenir les 4 imatges més recents


RY_latest, RY_latest_timestep = download_data()

Després d'obtenir les imatges, utilitzem el mètode vis.plot_ppi de wradlib per representar les dades.

for i in range(RY_latest.shape[0]):
   wrl.vis.plot_ppi(RY_latest[i])

VIS Radar

Ara hem carregat les nostres dades. A continuació, carreguem el model.

Comencem important les classes pertinents. Utilitzarem TensorFlow en aquest article.

des de tensorflow.keras.layers importar Entrada, Conv2D, Activació, Concatenar, Conv2DTranspose, MaxPool2D

des del model d'importació tensorflow.keras.models

Construïm 3 blocs de construcció primitius. Aquests "blocs de construcció" s'utilitzaran per crear tota l'arquitectura, segons aquesta implementació.

El primer bloc correspon a la successió de capes convolucionals, l'anomenem "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

El segon bloc s'utilitza per construir la part del codificador (bloc convolucional + agrupació màxima). L'anomenem "encoder_block"

def encoder_block(input, num_filters):
   x = conv_block(input, num_filters)
   p = MaxPool2D((2,2))(x)
   return x,p

El tercer i darrer bloc és un "decoder_block" (convolució ascendent + concatenació + convolució).

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

Combinem aquests blocs de construcció per construir el model 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

No dubteu a jugar amb la implementació, millorar-la o adaptar-la a les vostres necessitats si voleu utilitzar-la per a una altra cosa.

Entrenar aquest model pot trigar molt de temps. Afortunadament, hi ha un model anomenat Rain-Net, que s'ha creat a partir d'una arquitectura U-Net, i està especialitzat en el nowcasting de precipitació.

Clonem el seu repositori GitHub

! git clone https://github.com/hydrogo/rainnet.git

A continuació, descarreguem els pesos preentrenats per a aquest model

!wget -O /content/rainnet/rainnet_weights.h5 https://zenodo.org/record/3630429/files/rainnet_weights.h5

El següent pas és crear un model basat en l'arquitectura que es troba al dipòsit i després carregar els pesos descarregats a aquest model.

import sys
from rainnet import rainnet
model = rainnet.rainnet()
model.load_weights('/content/rainnet/rainnet_weights.h5')
model.summary()

Les imatges que hem baixat tenen una mida de 900*900 píxels. Reformarem aquestes imatges perquè coincideixin amb l'entrada esperada 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

Aleshores creem una funció que fa les prediccions.

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

Aleshores anomenem aquesta funció a les dades que hem baixat anteriorment

Y_pred = prediction(model, RY_latest)

Podem traçar les prediccions i desar-les per utilitzar els resultats desats per crear una imatge gif que ens permeti visualitzar les prediccions.

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')

Resuts

Felicitats per arribar fins aquí! Ara podeu utilitzar una xarxa de pluja per fer prediccions i visualitzar-les.

Conclusió

En aquest article, hem utilitzat un model d'aprenentatge automàtic (Rain-Net) per fer la predicció de precipitació. Hem utilitzat una arquitectura U-Net, que hem construït amb TensorFlow. Hem carregat un model preentrenat per predir imatges de satèl·lit.

Aquesta implementació es pot millorar de moltes maneres. Per exemple:

  1. Ajusteu el model al vostre conjunt de dades

  2. Utilitzeu un mòdul basat en l'atenció, com ara CBAM (Convolutional Block Attention Module) a l'arquitectura.

Referències

Vine a un dels nostres tallers gratuïts!

Comença la teva carrera com a científic de dades amb els nostres tallers gratuïts, que es basen en un currículum adaptable i estan guiats per experts del sector.


Career Services background pattern

Serveis de carrera

Contact Section background image

Seguim en contacte

Code Labs Academy © 2024 Tots els drets reservats.