Neerslag Nowcasting met Machine Learning

ML
DL
CNN
Weervoorspelling
UNet
Neerslag Nowcasting met Machine Learning cover image

Tegenwoordig schatten meteorologen dat 90% van de weersvoorspellingen binnen vijf dagen correct zijn. De voorspellingen die worden gedaan zijn meestal gebaseerd op twee afzonderlijke methoden:

  1. Op natuurkunde gebaseerde benaderingen: deze benaderingen maken gebruik van modellen die meetbare grootheden integreren, zoals druk, wolkenbewegingen, luchtomstandigheden… Dergelijke modellen zijn goed in het voorspellen van het weer voor de komende dagen of weken.

  2. Natuurkundevrije (datagebaseerde) benaderingen: Deze benaderingen gebruiken historische gegevens om modellen te creëren die voorspellingen kunnen doen. Dergelijke modellen laten goede resultaten zien bij het voorspellen van het weer tot 6 uur of wat bekend staat als weer-nowcasting.

In dit artikel bespreken we de tweede categorie benaderingen. We zullen de verschillende formaten van weergegevens bespreken, hoe machinaal leren kan worden ingezet om weer-nowcasting uit te voeren, en hoe de ontwikkelde architecturen nuttig kunnen zijn voor het oplossen van soortgelijke problemen.

Gegevens voor klimaatvoorspelling

Omdat de natuurkundevrije benaderingen gebruik maken van historische gegevens, gaan we eerst kijken naar de beschikbare gegevens.

We zullen twee belangrijke gegevensbronnen gebruiken:

  1. Beeldgegevens: Deze gegevens nemen de vorm aan van radar- of satellietbeelden van een bepaald geografisch gebied. Het wordt gebruikt om neerslag, windbeweging of vochtigheid te voorspellen.

Satellite Image

  1. Gegevens in tabelvorm: deze gegevens nemen de vorm aan van registraties van meetbare grootheden zoals temperatuur, vochtigheid of windsnelheid.

Tabular Data

Hoewel beide gegevensbronnen belangrijk zijn om krachtige modellen te bouwen, zullen we ons om redenen van eenvoud concentreren op de eerstgenoemde (beeldgegevens verzameld door radars of satellieten). De meest gebruikte modellen met beeldgegevens zijn Convolutional Neural Networks (CNNs ).

Na dit werk gaan we een U-Net-architectuur gebruiken om ons eigen nowcasting-model te bouwen.

Architectuur

Uitgaan van een bestaande architectuur is om vele redenen nuttig, waaronder:

Architecturen dienen als leidraad voor het creëren van nieuwe modellen. Mensen die nieuwe architecturen creëren, hanteren een aanpak van vallen en opstaan ​​om tot hun uiteindelijke resultaten te komen. Door hun eindresultaten te hergebruiken, kunnen we veel tijd besparen.

Voorgetrainde modellen zijn meestal beschikbaar voor onmiddellijk gebruik. Wanneer onderzoekers hun nieuwe architecturen publiceren, publiceren ze meestal ook de getrainde parameters, zodat gebruikers niet de moeite hoeven te doen om helemaal opnieuw te trainen/optimaliseren. Dit is vooral handig voor zeer grote, hulpbronnen-dorstige modellen.

Voorbeelden van beroemde visie-architecturen zijn onder meer:

  • LeNet (60k-parameters)

LeNet

  • AlexNet (60m-parameters)

AlexNet

  • VGG-16 (138m-parameters)

VGG-16

U-Net

U-Net is een architectuur gebaseerd op een volledig convolutioneel netwerk, wat betekent dat het geen volledig verbonden lagen heeft. Het werd voor het eerst geïntroduceerd voor een taak voor het segmenteren van medische beelden. Deze resultaten inspireerden onderzoekers om het uit te breiden naar andere taken in computer vision.

In 2019 gebruikte Google een U-Net-gebaseerde architectuur om een ​​model voor neerslagvoorspelling te maken.

De naam “U-Net” komt van de “U”-vorm van de architectuur.

U-net Architecture

We identificeren drie hoofdcomponenten:

  1. Contracting / Encoder: Opeenvolging van convolutie-/poolinglagen die het invoerbeeld comprimeren tot een kleinere representatie.

  2. Brug / Knelpunt: Het onderste deel van de “U” verbindt de encoder met de decoder. Het wordt gevormd door een reeks convolutiebewerkingen.

  3. Decontracting / Decoder: Opeenvolging van opconvoluties en convolutielagen, die de output van het knelpunt "decomprimeren".

De architectuur van een U-Net lijkt tot nu toe op een automatische encoder. Het verschil zit echter in de informatie die tussen de encoder en de decoder wordt doorgegeven. Deze informatie wordt doorgegeven door de resultaten van convoluties van de encoder aan elkaar te koppelen met die van de opconvolutie van de decoder. Deze wijziging verbetert de resolutie en zorgt ervoor dat het model een ruimtelijker nauwkeurige uitvoer kan uitvoeren (de locatie van de pixels in de uitvoer zal nauwkeuriger zijn, waardoor een probleem wordt opgelost dat zich voordeed in modellen die geen aaneenschakeling bevatten). De aaneenschakeling gebeurt symmetrisch.

Bouwen aan een U-Net-model voor het nu uitzenden van neerslag

In deze sectie zullen we een U-Net-model bouwen om het weer te voorspellen op basis van satellietbeelden. We zullen een vooraf getraind model gebruiken genaamd Rain-Net.

De onderstaande code is beschikbaar in dit colab.

We installeren eerst wradlib, een open source-bibliotheek voor de verwerking van weerradargegevens

!pip install wradlib
import wradlib as wrl

Vervolgens schrijven we twee hulpprogramma's om satellietgegevens te downloaden van de DWD's open dataserver


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

Met deze hulpprogramma's kunnen we de nieuwste vier satellietbeelden downloaden, wat het aantal satellietbeelden is dat we nodig hebben om voorspellingen te doen met ons vooraf getrainde model.

We kunnen dan de gemaakte functies gebruiken om de nieuwste 4 afbeeldingen te krijgen


RY_latest, RY_latest_timestep = download_data()

Nadat we de afbeeldingen hebben opgehaald, gebruiken we de methode vis.plot_ppi van wradlib om de gegevens te plotten

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

VIS Radar

We hebben nu onze gegevens geladen. Laten we het model vervolgens laden.

We beginnen met het importeren van de relevante klassen. In dit artikel zullen we TensorFlow gebruiken.

van tensorflow.keras.layers importeer invoer, Conv2D, activering, concatenate, Conv2DTranspose, MaxPool2D

van tensorflow.keras.models importeer model

Laten we 3 primitieve bouwstenen construeren. Deze "bouwstenen" zullen worden gebruikt om de hele architectuur te creëren, volgens deze implementatie.

Het eerste blok komt overeen met de opeenvolging van convolutionele lagen, we noemen het "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

Het tweede blok wordt gebruikt om het encodergedeelte op te bouwen (convolutioneel blok + maximale pooling). We noemen het een “encoder_block”

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

Het derde en laatste blok is een “decoder_block” (opconvolutie + concatenatie + convolutie).

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

We combineren deze bouwstenen om het U-Net-model te construeren

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

Voel je vrij om met de implementatie te spelen, deze te verbeteren of aan te passen aan jouw wensen als je hem voor iets anders wilt gebruiken.

Het trainen van dit model kan veel tijd kosten. Gelukkig is er een model genaamd Rain-Net, dat is gemaakt op basis van een U-Net-architectuur en gespecialiseerd is in het nu uitzenden van neerslag.

Laten we de GitHub-repository klonen

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

Vervolgens downloaden we de voorgetrainde gewichten voor dit model

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

De volgende stap is het maken van een model op basis van de architectuur die in de repository wordt gevonden en het laden van de gewichten die naar dit model zijn gedownload

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

De afbeeldingen die we hebben gedownload hebben een grootte van 900*900 pixels. We gaan deze afbeeldingen opnieuw vormgeven zodat ze overeenkomen met de verwachte input van 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

Vervolgens maken we een functie die de voorspellingen doet.

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

Deze functie roepen we vervolgens aan op de gegevens die we eerder hebben gedownload

Y_pred = prediction(model, RY_latest)

We kunnen de voorspellingen uitzetten en opslaan om de opgeslagen resultaten te gebruiken om een ​​GIF-afbeelding te maken waarmee we de voorspellingen kunnen visualiseren

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

Gefeliciteerd dat je zo ver bent gekomen! Je kunt nu een Rain-Net gebruiken om voorspellingen te doen en deze te visualiseren.

Conclusie

In dit artikel hebben we een machine learning-model (Rain-Net) gebruikt om neerslag nowcasting uit te voeren. We gebruikten een U-Net-architectuur, die we bouwden met behulp van TensorFlow. We hebben een voorgetraind model geladen om satellietbeelden te voorspellen.

Deze implementatie kan op veel manieren worden verbeterd. Bijvoorbeeld:

  1. Verfijn het model op uw dataset

  2. Gebruik een op aandacht gebaseerde module, zoals CBAM (Convolutional Block Attention Module) in de architectuur.

Referenties

Kom naar een van onze gratis workshops!

Begin je carrière als datawetenschapper met onze gratis workshops, die zijn gebaseerd op een aanpasbaar curriculum en worden begeleid door experts uit de industrie.


Career Services background pattern

Carrièrediensten

Contact Section background image

Laten we in contact blijven

Code Labs Academy © 2024 Alle rechten voorbehouden.