Nuförtiden uppskattar meteorologer att 90 % av väderförutsägelserna är korrekta på 5 dagar. De förutsägelser som görs baseras vanligtvis på två separata metoder:
-
Fysikbaserade tillvägagångssätt: Dessa tillvägagångssätt använder modeller som integrerar mätbara storheter som tryck, molnrörelser, himmelsförhållanden... Sådana modeller är bra på att förutsäga vädret för de kommande dagarna eller veckorna.
-
Fysikfria (databaserade) tillvägagångssätt: Dessa tillvägagångssätt använder historiska data för att skapa modeller som kan göra förutsägelser. Sådana modeller visar goda resultat när det gäller att förutsäga vädret i upp till 6 timmar eller vad som kallas vädersändning.
I den här artikeln kommer vi att diskutera den andra kategorin av tillvägagångssätt. Vi kommer att diskutera de olika formaten av väderdata, hur maskininlärning kan utnyttjas för att göra vädersändningar och hur de utvecklade arkitekturerna kan vara fördelaktiga för att lösa liknande problem.
Data för klimatförutsägelser
Eftersom de fysikfria tillvägagångssätten använder historiska data, låt oss börja med att titta på tillgängliga data.
Vi kommer att använda två huvudsakliga datakällor:
- Bilddata: Dessa data tar formen av radar- eller satellitbilder av ett specificerat geografiskt område. Det används för att förutsäga nederbörd, vindrörelser eller luftfuktighet.
- Tabelldata: Dessa data tar formen av registreringar av mätbara storheter såsom temperatur, luftfuktighet eller vindhastighet.
Även om båda datakällorna är viktiga för att bygga kraftfulla modeller, kommer vi att fokusera på de förstnämnda (bilddata som samlats in från radar eller satelliter) av enkelhetsskäl. De mest använda modellerna med bilddata är Convolutional Neural Networks (CNNs ).
Efter detta arbete kommer vi att använda en U-Net-arkitektur för att bygga vår egen nowcasting-modell.
Arkitektur
Att utgå från en befintlig arkitektur är användbart av många anledningar, bland annat:
Arkitekturer fungerar som riktlinjer för att skapa nya modeller. Människor som skapar nya arkitekturer använder sig av ett försök och misstag för att komma till sina slutliga resultat. Genom att återanvända deras slutresultat kan vi spara mycket tid.
Förtränade modeller är vanligtvis tillgängliga för omedelbar användning. När forskare publicerar sina nya arkitekturer publicerar de vanligtvis också de tränade parametrarna, så att användarna inte behöver gå igenom besväret med att träna/optimera från grunden. Detta är särskilt användbart för mycket stora, resurstörstande modeller.
Exempel på kända visionsarkitekturer inkluderar:
- LeNet (60k parametrar)
- AlexNet (60m parametrar)
- VGG-16 (138m parametrar)
U-Net
U-Net är en arkitektur baserad på ett helt konvolutionerande nätverk, vilket innebär att det inte har några helt anslutna lager. Det introducerades först för en medicinsk bildsegmenteringsuppgift. Dessa resultat inspirerade forskare att utvidga det till andra uppgifter inom datorseende.
Under 2019 använde Google en U-Net-baserad arkitektur för att skapa en modell för nederbördsprognos.
Namnet "U-Net" kommer från "U"-formen på dess arkitektur.
Vi identifierar tre huvudkomponenter:
-
Sammandragning/kodare: Succession av faltnings-/poollager som komprimerar ingångsbilden till en representation med mindre storlek.
-
Brygga / flaskhals: Den nedre delen av "U" ansluter kodaren till dekodern. Den bildas av en serie faltningsoperationer.
-
Avkontraktering / Avkodare: Succession av upconvolutions och faltningslager, som "dekomprimerar" utdata från flaskhalsen.
Arkitekturen för ett U-Net ser ut som en automatisk kodare än så länge. Skillnaden ligger emellertid i informationen som passerar mellan kodaren och avkodaren. Denna information vidarebefordras genom sammanlänkning av resultaten av faltningar från kodaren med resultaten av avkodarens uppkonvolut. Denna modifiering förbättrar upplösningen och gör det möjligt för modellen att mata ut en mer rumsligt exakt utdata (platsen för pixlarna i utdatan kommer att vara mer exakt, vilket löser ett problem som uppstod i modeller som inte inkluderade sammanlänkning). Sammankopplingen görs symmetriskt.
Bygga en U-Net-modell för nederbördssändning
I det här avsnittet kommer vi att bygga en U-Net-modell för att förutsäga vädret från satellitbilder. Vi kommer att använda en förtränad modell som heter Rain-Net.
Koden nedan är tillgänglig i denna colab.
Vi installerar först wradlib, ett bibliotek med öppen källkod för databearbetning av väderradar
!pip install wradlib
import wradlib as wrl
Vi skriver sedan två verktygsfunktioner för att ladda ner satellitdata från DWD:s öppna 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
Dessa verktyg låter oss ladda ner de senaste 4 satellitbilderna, vilket är antalet satellitbilder som vi behöver för att göra förutsägelser med vår förtränade modell.
Vi kan sedan använda de skapade funktionerna för att få de senaste 4 bilderna
RY_latest, RY_latest_timestep = download_data()
Efter att ha hämtat bilderna använder vi wradlibs vis.plot_ppi metod för att plotta data
for i in range(RY_latest.shape[0]):
wrl.vis.plot_ppi(RY_latest[i])
Vi har nu laddat in vår data. Låt oss ladda modellen härnäst.
Vi börjar med att importera de relevanta klasserna. Vi kommer att använda TensorFlow i den här artikeln.
från tensorflow.keras.layers importera Input, Conv2D, Activation, Concatenate, Conv2DTranspose, MaxPool2D
från tensorflow.keras.models import Modell
Låt oss konstruera 3 primitiva byggstenar. Dessa "byggstenar" kommer att användas för att skapa hela arkitekturen, enligt denna implementering.
Det första blocket motsvarar följden av faltningslager, vi kallar det "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
Det andra blocket används för att bygga från kodardelen (faltningsblock + max pooling). Vi kallar det ett "encoder_block"
def encoder_block(input, num_filters):
x = conv_block(input, num_filters)
p = MaxPool2D((2,2))(x)
return x,p
Det tredje och sista blocket är ett "decoder_block" (uppkonvolution + sammanfogning + konvolution).
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
Vi kombinerar dessa byggstenar för att konstruera U-Net-modellen
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
Lek gärna med implementeringen, förbättra den eller anpassa den efter dina behov om du vill använda den till något annat.
Att träna denna modell kan ta mycket tid. Som tur är finns det en modell som heter Rain-Net, som har skapats baserat på en U-Net-arkitektur, och som är specialiserad på nederbörds-nowcasting.
Låt oss klona dess GitHub-förråd
! git clone https://github.com/hydrogo/rainnet.git
Vi laddar sedan ner de förtränade vikterna för denna modell
!wget -O /content/rainnet/rainnet_weights.h5 https://zenodo.org/record/3630429/files/rainnet_weights.h5
Nästa steg är att skapa en modell baserad på arkitekturen som finns på förvaret och sedan ladda ner vikterna som laddats ner till denna modell
import sys
from rainnet import rainnet
model = rainnet.rainnet()
model.load_weights('/content/rainnet/rainnet_weights.h5')
model.summary()
Bilderna vi laddade ner har en storlek på 900*900 pixlar. Vi kommer att omforma dessa bilder för att matcha den förväntade ingången från 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
Vi skapar sedan en funktion som gör förutsägelserna.
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
Vi anropar sedan denna funktion på den data vi laddat ner tidigare
Y_pred = prediction(model, RY_latest)
Vi kan plotta förutsägelserna och spara dem för att använda de sparade resultaten för att skapa en gif-bild som låter oss visualisera förutsägelserna
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')
Grattis för att du har kommit så långt! Du kan nu använda ett regnnät för att göra förutsägelser och visualisera dem.
Slutsats
I den här artikeln har vi använt en maskininlärningsmodell (Rain-Net) för att göra nederbördssändning. Vi använde en U-Net-arkitektur, som vi byggde med TensorFlow. Vi laddade en förtränad modell för att förutsäga satellitbilder.
Denna implementering kan förbättras på många sätt. Till exempel:
-
Finjustera modellen på din datauppsättning
-
Använd en uppmärksamhetsbaserad modul, som CBAM (Convolutional Block Attention Module) i arkitekturen.
Referenser
Kom till en av våra kostnadsfria workshops!
Börja din karriär som datavetare med våra gratis workshops, som är baserade på en anpassningsbar läroplan och vägleds av branschexperter.