Nykyään meteorologit arvioivat, että 90 % sääennusteista pitää paikkansa viiden päivän ajanjaksolla. Tehdyt ennusteet perustuvat yleensä kahteen erilliseen menetelmään:
-
Fysiikkaan perustuvat lähestymistavat: Nämä lähestymistavat käyttävät malleja, jotka yhdistävät mitattavissa olevia suureita, kuten paineita, pilvien liikettä, taivaan olosuhteet… Tällaiset mallit ovat hyviä ennustamaan säätä tuleville päiville tai viikkoille.
-
Fysiikkaa sisältämättömät (tietopohjaiset) lähestymistavat: Nämä lähestymistavat käyttävät historiallisia tietoja mallien luomiseen, jotka voivat tehdä ennusteita. Tällaiset mallit osoittavat hyviä tuloksia sään ennustamisessa jopa 6 tunnin ajaksi tai ns. sään nytcastingiksi.
Tässä artikkelissa käsittelemme toista lähestymistapaa. Keskustelemme säätietojen eri muodoista, siitä, kuinka koneoppimista voidaan hyödyntää säänäyttöön ja kuinka kehitetyistä arkkitehtuureista voi olla hyötyä vastaavien ongelmien ratkaisemisessa.
Tietoa ilmaston ennustamiseen
Koska fysiikkavapaat lähestymistavat käyttävät historiallisia tietoja, aloitetaan tarkastelemalla saatavilla olevia tietoja.
Käytämme kahta päätietolähdettä:
- Kuvatiedot: Nämä tiedot ovat tietyn maantieteellisen alueen tutka- tai satelliittikuvia. Sitä käytetään ennustamaan sademäärää, tuulen liikettä tai kosteutta.
- Taulukkotiedot: Nämä tiedot ovat mitattavissa olevia suureita, kuten lämpötilaa, kosteutta tai tuulen nopeutta.
Vaikka molemmat tietolähteet ovat tärkeitä tehokkaiden mallien rakentamisessa, keskitymme ensimmäiseen (tutkista tai satelliiteista kerättyihin kuvatietoihin) yksinkertaisuuden vuoksi. Yleisimmin käytetyt mallit kuvadatalla ovat Convolutional Neural Networks (CNN:t ).
Tämän työn jälkeen aiomme rakentaa oman nowcasting-mallimme U-Net-arkkitehtuurilla.
Arkkitehtuuri
Olemassa olevasta arkkitehtuurista aloittaminen on hyödyllistä monista syistä, kuten:
Arkkitehtuurit toimivat ohjenuorana uusien mallien luomisessa. Ihmiset, jotka luovat uusia arkkitehtuureja, ottavat käyttöön yrityksen ja erehdyksen lähestymistavan saavuttaakseen lopulliset tulokset. Käyttämällä uudelleen niiden lopullisia tuloksia voimme säästää paljon aikaa.
Esikoulutetut mallit ovat yleensä saatavilla välittömästi käyttöön. Kun tutkijat julkaisevat uusia arkkitehtuuriaan, he yleensä julkaisevat myös koulutetut parametrit, jotta käyttäjien ei tarvitse käydä läpi koulutusta/optimointia tyhjästä. Tämä on erityisen hyödyllistä erittäin suurille, resursseja kaipaaville malleille.
Esimerkkejä kuuluisista visioarkkitehtuureista ovat:
- LeNet (60 000 parametria)
- AlexNet (60 metrin parametrit)
- VGG-16 (138m parametrit)
U-Net
U-Net on täysin konvoluutioverkkoon perustuva arkkitehtuuri, mikä tarkoittaa, että siinä ei ole täysin yhdistettyjä kerroksia. Se otettiin ensimmäisen kerran käyttöön lääketieteellisen kuvan segmentointitehtävää varten. Nämä tulokset inspiroivat tutkijoita laajentamaan sitä muihin tietokonenäön tehtäviin.
Vuonna 2019 Google käytti U-Net-pohjaista arkkitehtuuria sateenennustemallin luomiseen.
Nimi "U-Net" tulee sen arkkitehtuurin "U"-muodosta.
Tunnistamme kolme pääkomponenttia:
-
Contracting / Encoder: Convolution/pooling-kerrosten peräkkäisyys, jotka pakkaavat syöttökuvan pienempään esitykseen.
-
Silta / pullonkaula: "U":n alaosa yhdistää kooderin dekooderiin. Se muodostuu sarjasta konvoluutiooperaatioita.
-
Decontracting / Dekooderi: peräkkäiset ylöskonvoluutio- ja konvoluutiokerrokset, jotka "purkaavat" pullonkaulan tulosteen.
U-Netin arkkitehtuuri näyttää toistaiseksi automaattiselta enkooderilta. Ero on kuitenkin kooderin ja dekooderin välillä kulkevassa informaatiossa. Tämä informaatio välitetään ketjuttamalla kooderin konvoluutioiden tulokset dekooderin ylöskonvoluutioten kanssa. Tämä muutos parantaa resoluutiota ja antaa mallille mahdollisuuden tuottaa spatiaalisesti tarkemman tulosteen (pikseleiden sijainti tulosteessa on tarkempi, mikä ratkaisee ongelman, joka ilmeni malleissa, joissa ei ollut ketjutusta). Yhdistäminen tapahtuu symmetrisesti.
U-Net-mallin rakentaminen sadetta varten
Tässä osiossa rakennamme U-Net-mallin ennustamaan säätä satelliittikuvien perusteella. Käytämme esikoulutettua mallia nimeltä Rain-Net.
Alla oleva koodi on saatavilla tässä colabissa.
Asennamme ensin wradlib, avoimen lähdekoodin kirjaston säätutkatietojen käsittelyä varten
!pip install wradlib
import wradlib as wrl
Tämän jälkeen kirjoitamme kaksi aputoimintoa satelliittitietojen lataamiseksi DWD:n avoimelta datapalvelimelta
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
Näiden apuohjelmien avulla voimme ladata viimeisimmät 4 satelliittikuvaa, mikä on niiden satelliittikuvien määrä, jotka tarvitsemme ennusteiden tekemiseen esiopetetulla mallillamme.
Voimme sitten käyttää luotuja toimintoja saadaksemme 4 viimeisintä kuvaa
RY_latest, RY_latest_timestep = download_data()
Kun kuvat on saatu, käytämme wradlibin vis.plot_ppi -menetelmää tietojen kuvaamiseen
for i in range(RY_latest.shape[0]):
wrl.vis.plot_ppi(RY_latest[i])
Olemme nyt ladaneet tietomme. Ladataan malli seuraavaksi.
Aloitamme tuomalla asiaankuuluvat luokat. Käytämme TensorFlow'ta tässä artikkelissa.
osoitteesta tensorflow.keras.layers tuontisyöttö, Conv2D, aktivointi, ketjuttaminen, Conv2DTranspose, MaxPool2D
osoitteesta tensorflow.keras.models tuonti Malli
Rakennetaan 3 primitiivistä rakennuspalikka. Näitä "rakennuspalikoita" käytetään koko arkkitehtuurin luomiseen tämän [toteutuksen] mukaisesti (https://github.com/hydrogo/rainnet).
Ensimmäinen lohko vastaa konvoluutiokerrosten peräkkäisyyttä, kutsumme sitä "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
Toista lohkoa käytetään enkooderin muodostamiseen (konvoluutiolohko + max pooling). Kutsumme sitä "encoder_blockiksi"
def encoder_block(input, num_filters):
x = conv_block(input, num_filters)
p = MaxPool2D((2,2))(x)
return x,p
Kolmas ja viimeinen lohko on "decoder_block" (upconvolution + concatenation + 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
Yhdistämme nämä rakennuspalikat U-Net-mallin rakentamiseksi
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
Voit vapaasti leikkiä toteutuksen kanssa, parantaa sitä tai mukauttaa sitä tarpeisiisi, jos haluat käyttää sitä johonkin muuhun.
Tämän mallin kouluttaminen voi viedä paljon aikaa. Onneksi on olemassa malli nimeltä Rain-Net, joka on luotu U-Net-arkkitehtuuriin perustuen ja on erikoistunut sateen nytvalamiseen.
Kloonataan sen GitHub-arkisto
! git clone https://github.com/hydrogo/rainnet.git
Lataamme sitten esikoulutetut painot tälle mallille
!wget -O /content/rainnet/rainnet_weights.h5 https://zenodo.org/record/3630429/files/rainnet_weights.h5
Seuraava askel on luoda malli arkistosta löytyneen arkkitehtuurin perusteella ja ladata sitten tähän malliin ladatut painot
import sys
from rainnet import rainnet
model = rainnet.rainnet()
model.load_weights('/content/rainnet/rainnet_weights.h5')
model.summary()
Lataamiemme kuvien koko on 900*900 pikseliä. Muotoilemme nämä kuvat uudelleen vastaamaan Rain-Netin odotettua syöttöä
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
Luomme sitten funktion, joka tekee ennusteet.
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
Kutsumme sitten tätä toimintoa aiemmin lataamiemme tietojen perusteella
Y_pred = prediction(model, RY_latest)
Voimme piirtää ennusteet ja tallentaa ne käyttääksemme tallennettuja tuloksia gif-kuvan luomiseen, jonka avulla voimme visualisoida ennusteet
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')
Onnittelut, että olet päässyt näin pitkälle! Nyt voit käyttää sadeverkkoa ennustamaan ja visualisoimaan niitä.
Johtopäätös
Tässä artikkelissa olemme käyttäneet koneoppimismallia (Rain-Net) sademäärän laskemiseen. Käytimme U-Net-arkkitehtuuria, jonka rakensimme TensorFlow'lla. Latasimme esikoulutetun mallin ennustamaan satelliittikuvia.
Tätä toteutusta voidaan parantaa monella tapaa. Esimerkiksi:
-
Hienosäädä mallia tietojoukossasi
-
Käytä arkkitehtuurissa huomiopohjaista moduulia, kuten CBAM:ia (Convolutional Block Attention Module).
Viitteet
Tule johonkin ilmaisista työpajoistamme!
Aloita urasi datatieteilijänä ilmaisilla työpajoillamme, jotka perustuvat mukautuvaan opetussuunnitelmaan ja joita ohjaavat alan asiantuntijat.