Precipitación Nowcasting con Machine Learning

ML
DL
CNN
Predición do tempo
UNet
Precipitación Nowcasting con Machine Learning cover image

Hoxe en día, os meteorólogos estiman que o 90% das predicións meteorolóxicas son correctas nun período de 5 días. As predicións que se fan normalmente baséanse en dous métodos separados:

  1. Enfoques baseados na física: Estes enfoques utilizan modelos que integran cantidades medibles como a presión, o movemento das nubes, as condicións do ceo... Estes modelos son bos para predecir o tempo para os próximos días ou semanas.

  2. Enfoques sen física (baseados en datos): estes enfoques utilizan datos históricos para crear modelos que poidan facer predicións. Estes modelos amosan bos resultados na predicción do tempo durante ata 6 horas ou o que se coñece como previsión meteorolóxica.

Neste artigo, discutiremos a segunda categoría de enfoques. Discutiremos os diferentes formatos de datos meteorolóxicos, como se pode aproveitar a aprendizaxe automática para facer previsións meteorolóxicas e como as arquitecturas desenvolvidas poden ser beneficiosas para resolver problemas similares.

Datos para a predición do clima

Dado que os enfoques libres de física usan datos históricos, empecemos por analizar os datos dispoñibles.

Utilizaremos dúas fontes principais de datos:

  1. Datos de imaxe: estes datos toman a forma de imaxes de radar ou satélite dunha zona xeográfica especificada. Úsase para predicir precipitacións, movementos do vento ou humidade.

Satellite Image

  1. Datos tabulares: estes datos toman a forma de rexistros de magnitudes medibles como temperatura, humidade ou velocidade do vento.

Tabular Data

Aínda que ambas fontes de datos son importantes para construír modelos potentes, centrarémonos na primeira (datos de imaxes recollidos de radares ou satélites) por razóns de sinxeleza. Os modelos máis utilizados con datos de imaxes son Redes neuronais convolucionais (CNNs ).

Despois deste traballo, imos utilizar unha arquitectura U-Net para construír o noso propio modelo de proxección inmediata.

##Arquitectura

Partir dunha arquitectura existente é útil por moitas razóns, entre elas:

As arquitecturas serven de pautas para crear novos modelos. As persoas que crean novas arquitecturas adoptan un enfoque de proba e erro para chegar aos seus resultados finais. Ao reutilizar os seus resultados finais, podemos aforrar moito tempo.

Os modelos preadestrados adoitan estar dispoñibles para o seu uso inmediato. Cando os investigadores publican as súas novas arquitecturas, adoitan publicar tamén os parámetros adestrados, para que os usuarios non teñan que pasar pola molestia de adestrar/optimizar desde cero. Isto é especialmente útil para modelos moi grandes e sedientos de recursos.

Exemplos de arquitecturas de visión famosas inclúen:

  • LeNet (60k parámetros)

LeNet

  • AlexNet (parámetros de 60 m)

AlexNet

  • VGG-16 (parámetros de 138 m)

VGG-16

U-Net

U-Net é unha arquitectura baseada nunha rede totalmente convolucional, o que significa que non ten capas totalmente conectadas. Introduciuse por primeira vez para unha tarefa de segmentación de imaxes médicas. Estes resultados inspiraron aos investigadores a estendelo a outras tarefas en visión por ordenador.

En 2019, Google utilizou unha arquitectura basada en U-Net para crear un modelo de previsión de precipitacións.

O nome "U-Net" provén da forma "U" da súa arquitectura.

U-net Architecture

Identificamos tres compoñentes principais:

  1. Contratación / Codificador: sucesión de capas de convolución/agrupación que comprimen a imaxe de entrada nunha representación de menor tamaño.

  2. Ponte / Pescozo de botella: a parte inferior da "U" conecta o codificador co descodificador. Está formado por unha serie de operacións de convolución.

  3. Descontratación / Decodificador: Sucesión de convolucións ascendentes e capas de convolución, que "descomprimen" a saída do pescozo de botella.

A arquitectura dunha U-Net parece un codificador automático ata agora. Non obstante, a diferenza reside na información que pasa entre o codificador e o descodificador. Esta información pásase concatenando os resultados das convolucións do codificador co da convolución ascendente do decodificador. Esta modificación mellora a resolución e permite que o modelo produza unha saída máis precisa espacialmente (a localización dos píxeles na saída será máis precisa, resolvendo un problema que ocorreu en modelos que non incluían a concatenación). A concatenación realízase de forma simétrica.

Construíndo un modelo U-Net para a previsión inmediata de precipitacións

Nesta sección, imos construír un modelo U-Net para predecir o tempo a partir de imaxes de satélite. Usaremos un modelo adestrado previamente chamado Rain-Net.

O seguinte código está dispoñible neste colab.

Primeiro instalamos wradlib, unha biblioteca de código aberto para o procesamento de datos do radar meteorolóxico

!pip install wradlib
import wradlib as wrl

Despois escribimos dúas funcións de utilidade para descargar datos de satélite do servidor de datos abertos 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

Estas utilidades permítennos descargar as 4 imaxes de satélite máis recentes, que é o número de imaxes de satélite que necesitamos para facer predicións co noso modelo previamente adestrado.

Despois podemos usar as funcións creadas para obter as 4 imaxes máis recentes


RY_latest, RY_latest_timestep = download_data()

Despois de obter as imaxes, usamos o método vis.plot_ppi de wradlib para representar os datos.

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

VIS Radar

Agora cargamos os nosos datos. Carguemos o modelo a continuación.

Comezamos importando as clases relevantes. Usaremos TensorFlow neste artigo.

desde tensorflow.keras.layers importar Entrada, Conv2D, Activación, Concatenar, Conv2DTranspose, MaxPool2D

desde tensorflow.keras.models import Model

Imos construír 3 bloques de construción primitivos. Estes "bloques de construción" utilizaranse para crear toda a arquitectura, segundo esta implementación.

O primeiro bloque corresponde á sucesión de capas convolucionais, chamámoslle "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

O segundo bloque úsase para construír a parte do codificador (bloque convolucional + agrupación máxima). Chamámoslle "encoder_block"

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

O terceiro e último bloque é un "decoder_block" (convolución ascendente + concatenación + convolución).

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

Combinamos estes bloques para construír o modelo 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

Non dubides en xogar coa implementación, mellorala ou adaptala ás túas necesidades se queres usala para outra cousa.

Adestrar este modelo pode levar moito tempo. Afortunadamente, existe un modelo chamado Rain-Net, que se creou baseándose nunha arquitectura U-Net, e está especializado na previsión inmediata de precipitacións.

Imos clonar o seu repositorio de GitHub

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

Despois descargamos os pesos preadestrados para este modelo

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

O seguinte paso é crear un modelo baseado na arquitectura que se atopa no repositorio e despois cargar os pesos descargados neste modelo

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

As imaxes que descargamos teñen un tamaño de 900*900 píxeles. Imos remodelar estas imaxes para que coincidan coa 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

Despois creamos unha función que faga as predicións.

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

Despois chamamos a esta función nos datos que descargamos anteriormente

Y_pred = prediction(model, RY_latest)

Podemos trazar as predicións e gardalas para utilizar os resultados gardados para crear unha imaxe gif que nos permita visualizar as predicións

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

Parabéns por chegar ata aquí! Agora podes usar unha Rain-Net para facer predicións e visualizalas.

Conclusión

Neste artigo, usamos un modelo de aprendizaxe automática (Rain-Net) para facer a previsión de precipitación. Usamos unha arquitectura U-Net, que creamos usando TensorFlow. Cargamos un modelo preadestrado para predicir imaxes de satélite.

Esta implementación pódese mellorar de moitas maneiras. Por exemplo:

  1. Axuste o modelo no seu conxunto de datos

  2. Use un módulo baseado na atención, como CBAM (Convolutional Block Attention Module) na arquitectura.

Referencias

Ven a un dos nosos obradoiros gratuítos!

Comeza a túa carreira como científico de datos cos nosos obradoiros gratuítos, que se basean nun currículo adaptable e están guiados por expertos do sector.


Career Services background pattern

Servizos de Carreira

Contact Section background image

Mantémonos en contacto

Code Labs Academy © 2024 Todos os dereitos reservados.