<jupyter_start><jupyter_text>Quickstart guideIn this notebook we will through all the steps from downloading the data and training a model to evaluating the results. Check out the `environment.yml` file for the required Python packages.<jupyter_code>import xarray as xr
import matplotlib.pyplot as plt<jupyter_output><empty_output><jupyter_text>Downloading the dataThe data is hosted here. For this guide we will simply download the 500 hPa geopotential data (Z500).<jupyter_code># This might take a few minutes
!wget "https://dataserv.ub.tum.de/s/m1524895/download?path=%2F5.625deg%2Fgeopotential_500&files=geopotential_500_5.625deg.zip" -O geopotential_500_5.625deg.zip
!mkdir -p geopotential_500
!unzip -d geopotential_500/ geopotential_500_5.625deg.zip<jupyter_output>Archive:  geopotential_500_5.625deg.zip
  inflating: geopotential_500/geopotential_500hPa_1979_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1980_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1981_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1982_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1983_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1984_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1985_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1986_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1987_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1988_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1989_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1990_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1991_5.625deg.nc  
  inflating: geopotential_500/geopotential_500hPa_1992_5.625deg[...]<jupyter_text>Open the data<jupyter_code>z500 = xr.open_mfdataset('geopotential_500/*.nc', combine='by_coords')
z500
# Plot an example
z500.z.isel(time=0).plot();<jupyter_output><empty_output><jupyter_text>Create a simple climatological forecastRemember that we are using the years 2017 and 2018 for testing/evaluation, so we are not allowed to use these years to train any data-driven model.For more information on the climatology and persistence forecasts used in the paper check out `notebooks/1-climatology-persistence.ipynb`.<jupyter_code># To speed things up we will just take the mean for 2016
climatology = z500.sel(time=slice('2016', '2016')).mean('time').load()
climatology.z.plot()<jupyter_output><empty_output><jupyter_text>Evaluate the climatologyPlease check the paper for details on the evaluation metric. Here we will use the functions from `src/score.py`. To make sure we are always using the same targets for testing, we also implemented a function to load the test data.<jupyter_code>from src.score import *
z500_test = load_test_data('geopotential_500/', 'z')[::12]  # Take data only every 12 hours to spped up computation on Binder
rmse_climatology = compute_weighted_rmse(climatology.z, z500_test).load()
rmse_climatology<jupyter_output><empty_output><jupyter_text>So we get a climatological RMSE of 1080 m^2/s^2 which is very similar to the RMSE we get for the climatology for all training years.  Train a neural networkNow let's train a simple convolutional neural network. We are using several functions defined in `src/train_nn.py`. You can use and modify these or write your own function for data loading etc. For more information on the the networks check out `notebooks/3-cnn-example.ipynb`.<jupyter_code>from src.train_nn import *
# This limits TF memory usage on the GPU
# limit_mem()<jupyter_output><empty_output><jupyter_text>First, we need to create the data generators for training, validation and testing. The main reason why we are using data generators instead of just loading the data as Numpy arrays is that this would require loading the same data twice since the features and targets are the same fields, just offset in time.<jupyter_code>bs = 32
lead_time = 5*24
var_dict = {'z': None}
# Use 2015 for training and 2016 for validation
dg_train = DataGenerator(
    z500.sel(time=slice('2015', '2015')), var_dict, lead_time, batch_size=bs, load=True)
dg_valid = DataGenerator(
    z500.sel(time=slice('2016', '2016')), var_dict, lead_time, batch_size=bs, mean=dg_train.mean, std=dg_train.std, shuffle=False)
# Now also a generator for testing. Impartant: Shuffle must be False!
dg_test = DataGenerator(z500.sel(time=slice('2017', '2018')).isel(time=slice(0, None, 12)), # Limiting the data for Binder
                        var_dict, lead_time, batch_size=bs, mean=dg_train.mean, std=dg_train.std, shuffle=False)
X, y = dg_train[0]
# Batches have dimensions [batch_size, lat, lon, channels]
X.shape, y.shape<jupyter_output><empty_output><jupyter_text>Now let's build a simple fully convolutional network. We are using periodic convolutions in the longitude direction. These are defined in `train_nn.py`.<jupyter_code>cnn = keras.models.Sequential([
    PeriodicConv2D(filters=32, kernel_size=5, activation='relu', input_shape=(32, 64, 1,)),
    PeriodicConv2D(filters=1, kernel_size=5)
])
cnn.summary()
cnn.compile(keras.optimizers.Adam(1e-4), 'mse')
# Train a little bit ;)
cnn.fit_generator(dg_train, epochs=1, validation_data=dg_valid)<jupyter_output>270/270 [==============================] - 6s 21ms/step - loss: 1.7766 - val_loss: 1.0282<jupyter_text>Create a prediction and compute scoreNow that we have a model (albeit a crappy one) we can create a prediction. For this we need to create a forecast for each forecast initialization time in the testing range (2017-2018) and unnormalize it. We then convert the forecasts to a Xarray dataset which allows us to easily compute the RMSE. All of this is taken care of in the `create_predictions()` function.<jupyter_code>preds = create_predictions(cnn, dg_test)
preds
compute_weighted_rmse(preds.z, z500_test).load()
time = '2017-03-02T00'
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15,5))
z500_test.sel(time=time).plot(ax=ax1)
preds.sel(time=time).z.plot(ax=ax2);<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09326083374526281, 'fraction_numerical': 0.07019278299555116, 'mean_word_length': 6.099415204678363, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '82246', 'license': 'MIT', 'n_tokens_mistral': 2384, 'n_tokens_neox': 2020, 'n_words': 567, 'path': 'quickstart.ipynb', 'repo_name': 'illorens/WeatherBench', 'size': '6069'}