Günümüzde meteorologlar 5 günlük zaman diliminde yapılan hava tahminlerinin %90'ının doğru olduğunu tahmin ediyor. Yapılan tahminler genellikle iki ayrı yönteme dayanmaktadır:
-
Fiziğe dayalı yaklaşımlar: Bu yaklaşımlar, basınç, bulutların hareketi, gökyüzü koşulları gibi ölçülebilir büyüklükleri bütünleştiren modelleri kullanır… Bu tür modeller, önümüzdeki günlerin veya haftaların hava durumunu tahmin etmede iyidir.
-
Fizikten bağımsız (veriye dayalı) yaklaşımlar: Bu yaklaşımlar, tahmin yapabilen modeller oluşturmak için geçmiş verileri kullanır. Bu tür modeller, 6 saate kadar hava durumunu tahmin etmede veya hava durumu tahmini olarak bilinen yöntemle iyi sonuçlar verir.
Bu yazıda ikinci kategorideki yaklaşımları tartışacağız. Hava durumu verilerinin farklı formatlarını, hava durumu tahmini yapmak için makine öğreniminden nasıl yararlanılabileceğini ve geliştirilen mimarilerin benzer sorunların çözümünde nasıl faydalı olabileceğini tartışacağız.
İklim Tahmini Verileri
Fizikten bağımsız yaklaşımlar geçmiş verileri kullandığından, mevcut verilere bakarak başlayalım.
İki ana veri kaynağı kullanacağız:
- Görüntü verileri: Bu veriler, belirli bir coğrafi bölgenin radar veya uydu görüntüleri şeklini alır. Yağış, rüzgar hareketi veya nemi tahmin etmek için kullanılır.
- Tablo verileri : Bu veriler sıcaklık, nem veya rüzgar hızı gibi ölçülebilir büyüklüklerin kayıtları biçiminde olur.
Her iki veri kaynağı da güçlü modeller oluşturmak için önemli olsa da, basitlik nedeniyle ilkine (radarlardan veya uydulardan toplanan görüntü verileri) odaklanacağız. Görüntü verileriyle en sık kullanılan modeller Evrişimli Sinir Ağları (CNN'ler'dir. ).
Bu çalışmayı takiben, kendi şimdi tahmin modelimizi oluşturmak için bir U-Net mimarisi kullanacağız.
Mimarlık
Mevcut bir mimariden başlamak birçok nedenden dolayı faydalıdır:
Mimariler yeni modeller oluşturmak için kılavuz görevi görür. Yeni mimariler yaratan insanlar nihai sonuçlara ulaşmak için deneme yanılma yaklaşımını benimserler. Nihai sonuçlarını yeniden kullanarak çok fazla zaman kazanabiliriz.
Önceden eğitilmiş modeller genellikle anında kullanım için mevcuttur. Araştırmacılar yeni mimarilerini yayınladıklarında genellikle eğitilmiş parametreleri de yayınlarlar, böylece kullanıcılar sıfırdan eğitim/optimizasyon zahmetine girmek zorunda kalmazlar. Bu özellikle çok büyük, kaynağa susamış modeller için kullanışlıdır.
Örnek ünlü görüş mimarileri şunları içerir:
- LeNet (60k parametre)
- AlexNet (60m parametreler)
- VGG-16 (138m parametreler)
U-Net
U-Net tamamen evrişimli bir ağa dayalı bir mimaridir, yani tam bağlantılı katmanlara sahip değildir. İlk olarak tıbbi görüntü segmentasyon görevi için tanıtıldı. Bu sonuçlar araştırmacılara bunu bilgisayarlı görmedeki diğer görevlere genişletme konusunda ilham verdi.
Google, 2019'da yağış tahmin modeli oluşturmak için U-Net tabanlı mimarisini kullandı.
“U-Net” ismi mimarisinin “U” şeklinde olmasından gelmektedir.
Üç ana bileşeni tanımlıyoruz:
-
Sözleşme / Kodlayıcı: Giriş görüntüsünü daha küçük boyutlu bir gösterime sıkıştıran evrişim/havuzlama katmanlarının ardışıklığı.
-
Köprü / Darboğaz: “U”nun alt kısmı kodlayıcıyı kod çözücüye bağlar. Bir dizi evrişim işleminden oluşur.
-
Dekontraksiyon / Kod Çözücü : Darboğazın çıktısını "sıkıştıran" yukarı evrişim ve evrişim katmanlarının ardışıklığı.
U-Net'in mimarisi şu ana kadar bir otomatik kodlayıcıya benziyor. Ancak fark, kodlayıcı ile kod çözücü arasında geçen bilgide yatmaktadır. Bu bilgi, kodlayıcıdan gelen evrişimlerin sonuçlarının kod çözücünün yukarı evrişim sonuçlarıyla birleştirilmesiyle aktarılır. Bu değişiklik çözünürlüğü artırır ve modelin uzaysal olarak daha hassas bir çıktı vermesine olanak tanır (çıktıdaki piksellerin konumu daha kesin olacak ve birleştirme içermeyen modellerde meydana gelen bir sorun çözülecektir). Birleştirme simetrik olarak yapılır.
Yağış Anlık Tahmini için U-Net Modeli Oluşturma
Bu bölümde uydu görüntülerinden hava durumunu tahmin etmek için bir U-Net modeli oluşturacağız. Rain-Net adlı önceden eğitilmiş bir model kullanacağız.
Aşağıdaki kod bu colab'de mevcuttur.
İlk olarak Hava Durumu Radarı Veri İşleme için Açık Kaynak Kitaplığı olan wradlib kurulumunu gerçekleştiriyoruz.
!pip install wradlib
import wradlib as wrl
Daha sonra DWD'nin açık veri sunucusundan uydu verilerini indirmek için iki yardımcı fonksiyon yazıyoruz.
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
Bu yardımcı programlar, önceden eğitilmiş modelimizle tahmin yapmamız gereken uydu görüntüsü sayısı olan en son 4 uydu görüntüsünü indirmemize olanak tanır.
Daha sonra en son 4 görüntüyü elde etmek için oluşturulan işlevleri kullanabiliriz.
RY_latest, RY_latest_timestep = download_data()
Görüntüleri aldıktan sonra verileri çizmek için wradlib'in vis.plot_ppi yöntemini kullanıyoruz.
for i in range(RY_latest.shape[0]):
wrl.vis.plot_ppi(RY_latest[i])
Artık verilerimizi yükledik. Şimdi modeli yükleyelim.
İlgili sınıfları içe aktararak başlıyoruz. Bu yazıda TensorFlow'u kullanacağız.
tensorflow.keras.layers'dan içe aktarma Giriş, Conv2D, Etkinleştirme, Birleştirme, Conv2DTranspose, MaxPool2D
tensorflow.keras.models'den içe aktarma Modeli
3 ilkel yapı taşı oluşturalım. Bu "yapı taşları", bu uygulama uyarınca tüm mimariyi oluşturmak için kullanılacaktır.
İlk blok evrişimli katmanların ardışıklığına karşılık gelir, biz buna "conv_block" diyoruz
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
İkinci blok, kodlayıcı kısmından (evrişimli blok + maksimum havuzlama) oluşturmak için kullanılır. Biz buna “encoder_block” diyoruz
def encoder_block(input, num_filters):
x = conv_block(input, num_filters)
p = MaxPool2D((2,2))(x)
return x,p
Üçüncü ve son blok bir “decoder_block”tur (yukarı evrişim + birleştirme + evrişim).
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
U-Net modelini oluşturmak için bu yapı taşlarını birleştiriyoruz
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
Başka bir şey için kullanmak istiyorsanız uygulamayla oynamaktan, geliştirmekten veya ihtiyaçlarınıza göre uyarlamaktan çekinmeyin.
Bu modeli eğitmek çok zaman alabilir. Şans eseri, Rain-Net adında, U-Net mimarisine dayalı olarak oluşturulmuş ve yağışların anlık tahmini konusunda uzmanlaşmış bir model var.
GitHub deposunu klonlayalım
! git clone https://github.com/hydrogo/rainnet.git
Daha sonra bu model için önceden eğitilmiş ağırlıkları indiriyoruz
!wget -O /content/rainnet/rainnet_weights.h5 https://zenodo.org/record/3630429/files/rainnet_weights.h5
Bir sonraki adım, depoda bulunan mimariye dayalı bir model oluşturmak ve ardından indirilen ağırlıkları bu modele yüklemektir.
import sys
from rainnet import rainnet
model = rainnet.rainnet()
model.load_weights('/content/rainnet/rainnet_weights.h5')
model.summary()
İndirdiğimiz görsellerin boyutu 900*900 pikseldir. Bu görüntüleri Rain-Net'in beklenen girdisine uyacak şekilde yeniden şekillendireceğiz
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
Daha sonra tahminleri yapan bir fonksiyon yaratıyoruz.
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
Daha sonra bu fonksiyonu daha önce indirdiğimiz veriler üzerinde çağırıyoruz.
Y_pred = prediction(model, RY_latest)
Tahminleri çizebilir ve kaydedilen sonuçları kullanarak tahminleri görselleştirmemize olanak tanıyan bir gif görüntüsü oluşturabiliriz.
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')
Bu noktaya kadar geldiğiniz için tebrikler! Artık tahminlerde bulunmak ve bunları görselleştirmek için Rain-Net'i kullanabilirsiniz.
Çözüm
Bu yazıda, yağışın şimdi tahminini yapmak için bir makine öğrenme modeli (Rain-Net) kullandık. TensorFlow kullanarak oluşturduğumuz bir U-Net mimarisini kullandık. Uydu görüntülerini tahmin etmek için önceden eğitilmiş bir model yükledik.
Bu uygulama birçok yönden geliştirilebilir. Örneğin:
-
Veri kümenizdeki modele ince ayar yapın
-
Mimaride CBAM (Evrişimli Blok Dikkat Modülü) gibi dikkat tabanlı bir modül kullanın.
Referanslar
Ücretsiz Atölyelerimizden Birine Gelin!
Uyarlanabilir bir müfredatı temel alan ve sektör uzmanlarının rehberliğinde olan ücretsiz atölyelerimizle veri bilimci olarak kariyerinize başlayın.