{ "cells": [ { "cell_type": "code", "execution_count": 31, "id": "e7e09770", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import xarray as xr\n", "from sklearn.model_selection import train_test_split\n", "import matplotlib.pyplot as plt\n", "from tensorflow.keras import layers\n", "from tensorflow import keras\n", "import keras_tuner as kt" ] }, { "cell_type": "markdown", "id": "acfd64fc", "metadata": {}, "source": [ "# Making input for temp" ] }, { "cell_type": "code", "execution_count": 88, "id": "59cfc06d", "metadata": {}, "outputs": [], "source": [ "data = xr.open_dataset('conv_temp_4326.nc')" ] }, { "cell_type": "code", "execution_count": 89, "id": "a9923e31", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/44/y59xjnbx6fqfgz896mcmxfw80000gn/T/ipykernel_99782/2935343825.py:5: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.\n", " dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n" ] } ], "source": [ "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n", "feats = np.array([data[feat].values for feat in scalar_feats]).T\n", "\n", "# 1. Find correct dimension name (e.g., 'obs')\n", "dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n", "\n", "# 2. Find odd (odd) indices using xarray logic\n", "grid_ids = data[\"gridCellId\"].values.astype(int)\n", "odd_mask = grid_ids % 2 == 1\n", "odd_idx = np.where(odd_mask)[0]\n", "test_idx = np.where(~odd_mask)[0]\n", "\n", "# 3. Extract scalar features as a stacked array (samples x features)\n", "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n", "feats = np.stack([data[feat].values for feat in scalar_feats], axis=-1)\n", "\n", "# 4. Create train/test splits using .isel and values\n", "train_images = data[\"images\"].isel({dim_name: odd_idx}).values\n", "test_images = data[\"images\"].isel({dim_name: test_idx}).values\n", "\n", "train_feats = feats[odd_idx]\n", "test_feats = feats[test_idx]\n", "\n", "ytrain = data[\"THICK\"].isel({dim_name: odd_idx}).values\n", "ytest = data[\"THICK\"].isel({dim_name: test_idx}).values\n", "\n", "ytrain = data.THICK.values[odd_idx]\n", "ytest = data.THICK.values[test_idx]\n" ] }, { "cell_type": "code", "execution_count": 90, "id": "af470a6f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(104834, 27, 27)\n", "False\n", "0\n", "76454604\n" ] } ], "source": [ "train_images = data[\"images\"].isel({dim_name: odd_idx}).load().values\n", "test_images = data[\"images\"].isel({dim_name: test_idx}).load().values\n", "\n", "train_images = np.nan_to_num(train_images, nan=0.0)\n", "test_images = np.nan_to_num(test_images, nan=0.0)\n", "\n", "print(train_images.shape) # should be (N, 27, 27)\n", "print(np.isnan(train_images).all()) # should be False\n", "print(np.isnan(train_images).sum()) # total NaNs\n", "print(104876 * 27 *27)\n" ] }, { "cell_type": "code", "execution_count": 91, "id": "2ed5f281", "metadata": {}, "outputs": [], "source": [ "#---------standardize labels-------------------\n", "# Compute mean and std from training labels\n", "y_mean = ytrain.mean()\n", "y_std = ytrain.std()\n", "\n", "# Standardize ytrain and ytest using training statistics\n", "ytrain_std = (ytrain - y_mean) / y_std\n", "ytest_std = (ytest - y_mean) / y_std\n", "#to convert back to original scale, use:\n", "# ypreds_orig = ypreds * y_std + y_mean\n", "#----------------------------------------------\n", "\n", "# ytrain = ytrain.values\n", "# ytest = ytest.values\n", "\n", "# explicitly illustrating standardization\n", "def standardizeimg(img, mu, sigma):\n", " return (img-mu)/(sigma).astype(np.float32)\n", "\n", "# save for scaling test dataA\n", "mu_train = np.mean(train_images)\n", "sigma_train = np.std(train_images)\n", "\n", "# Standardize pixel distribution to have zero mean and unit variance\n", "train_images = standardizeimg(img=train_images, mu=mu_train, sigma=sigma_train)\n", "test_images = standardizeimg(img=test_images, mu=np.mean(test_images), sigma=np.std(test_images))\n", "\n", "# adapt to format required by tensorflow; Using channels_last --> (n_samples, img_rows, img_cols, n_channels)\n", "img_rows, img_cols = 27, 27 # input image dimensions\n", "train_images = train_images.reshape(train_images.shape[0], img_rows, img_cols, 1)\n", "test_images = test_images.reshape(test_images.shape[0], img_rows, img_cols, 1)" ] }, { "cell_type": "code", "execution_count": 92, "id": "571614d0", "metadata": {}, "outputs": [], "source": [ "temp_images = train_images\n", "temp_train_images = train_images\n", "temp_test_feats = test_feats\n", "temp_train_feats = train_feats\n", "temp_test_images = test_images" ] }, { "cell_type": "markdown", "id": "6233f2d7", "metadata": {}, "source": [ "# Training model for temp" ] }, { "cell_type": "code", "execution_count": 37, "id": "eb05afe1", "metadata": {}, "outputs": [], "source": [ "def build_model(hp):\n", " IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS = 27, 27, 1\n", " NUM_SCALAR_FEATURES = 7\n", "\n", " image_input = layers.Input(shape=(IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS), name='image_input')\n", " x = image_input\n", "\n", " # Tune number of conv layers: 1 to 3\n", " for i in range(hp.Int('num_conv_layers', 1, 3)):\n", " filters = hp.Int(f'filters_{i}', 32, 128, step=32)\n", " x = layers.Conv2D(filters, (3, 3), activation='relu', padding='same')(x)\n", " x = layers.MaxPooling2D((2, 2))(x)\n", "\n", " x = layers.Flatten()(x)\n", "\n", " # Scalar branch\n", " scalar_input = layers.Input(shape=(NUM_SCALAR_FEATURES,), name='scalar_input')\n", " y = scalar_input # you could also add dense layers here\n", "\n", " # Merge\n", " z = layers.concatenate([x, y])\n", "\n", " # Tune number of dense layers: 1 to 3\n", " for i in range(hp.Int('num_dense_layers', 1, 3)):\n", " units = hp.Int(f'dense_units_{i}', 64, 256, step=64)\n", " z = layers.Dense(units, activation='relu')(z)\n", " z = layers.Dropout(hp.Float(f'dropout_{i}', 0.3, 0.7, step=0.1))(z)\n", "\n", " output = layers.Dense(1, name='output')(z)\n", "\n", " model = keras.Model(inputs=[image_input, scalar_input], outputs=output)\n", "\n", " model.compile(\n", " optimizer='adam',\n", " loss='mse',\n", " metrics=['mape']\n", " )\n", "\n", " return model" ] }, { "cell_type": "code", "execution_count": 38, "id": "85802ff8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Reloading Tuner from Code/ice_thickness_cnn_temp/tuner0.json\n" ] } ], "source": [ "tuner = kt.RandomSearch(\n", " build_model,\n", " objective='val_mape',\n", " max_trials=1,\n", " executions_per_trial=1,\n", " directory='Code', #skift directory\n", " project_name='ice_thickness_cnn_temp'\n", ")\n" ] }, { "cell_type": "code", "execution_count": 39, "id": "fa473e8c", "metadata": {}, "outputs": [], "source": [ "tuner.search(\n", " {'image_input': train_images, 'scalar_input': train_feats},\n", " ytrain_std,\n", " validation_data=({'image_input': test_images, 'scalar_input': test_feats}, ytest_std),\n", " epochs=30,\n", " batch_size=320\n", ")\n" ] }, { "cell_type": "code", "execution_count": 40, "id": "9837d503", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/30\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/opt/miniconda3/envs/appml/lib/python3.12/site-packages/keras/src/saving/saving_lib.py:757: UserWarning: Skipping variable loading for optimizer 'adam', because it has 2 variables whereas the saved optimizer has 30 variables. \n", " saveable.load_own_variables(weights_store.get(inner_path))\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 47ms/step - loss: 1623841.5000 - mape: 103.7883 - val_loss: 1350029.2500 - val_mape: 65.4703\n", "Epoch 2/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 45ms/step - loss: 414066.6875 - mape: 66.1151 - val_loss: 1640908.7500 - val_mape: 68.9165\n", "Epoch 3/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 43ms/step - loss: 366676.5000 - mape: 63.9325 - val_loss: 1502926.0000 - val_mape: 65.5676\n", "Epoch 4/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 43ms/step - loss: 352633.1562 - mape: 49.7823 - val_loss: 1548254.6250 - val_mape: 66.2862\n", "Epoch 5/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 43ms/step - loss: 330374.2188 - mape: 51.2994 - val_loss: 1652841.0000 - val_mape: 66.8227\n", "Epoch 6/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 43ms/step - loss: 315108.4688 - mape: 52.3326 - val_loss: 1516739.7500 - val_mape: 65.1036\n", "Epoch 7/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 42ms/step - loss: 310951.7188 - mape: 51.1550 - val_loss: 1505773.8750 - val_mape: 65.3550\n", "Epoch 8/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 42ms/step - loss: 300632.6562 - mape: 48.4373 - val_loss: 1434880.3750 - val_mape: 63.3948\n", "Epoch 9/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 43ms/step - loss: 288077.6562 - mape: 46.9832 - val_loss: 1518280.6250 - val_mape: 64.7503\n", "Epoch 10/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 44ms/step - loss: 275742.0312 - mape: 45.3837 - val_loss: 1521084.0000 - val_mape: 64.2962\n", "Epoch 11/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 42ms/step - loss: 266654.5625 - mape: 43.6019 - val_loss: 1460578.2500 - val_mape: 64.6119\n", "Epoch 12/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 43ms/step - loss: 259868.5938 - mape: 46.8487 - val_loss: 1388735.0000 - val_mape: 62.5166\n", "Epoch 13/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 43ms/step - loss: 257574.3750 - mape: 43.2215 - val_loss: 1620815.2500 - val_mape: 65.1581\n", "Epoch 14/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m19s\u001b[0m 45ms/step - loss: 245698.5938 - mape: 43.1863 - val_loss: 1593470.3750 - val_mape: 64.7511\n", "Epoch 15/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 43ms/step - loss: 243752.4062 - mape: 47.5935 - val_loss: 1567125.0000 - val_mape: 65.5080\n", "Epoch 16/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 44ms/step - loss: 240592.4531 - mape: 48.1535 - val_loss: 1611000.5000 - val_mape: 65.6449\n", "Epoch 17/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 44ms/step - loss: 238049.5312 - mape: 44.8858 - val_loss: 1531273.7500 - val_mape: 63.8730\n", "Epoch 18/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 44ms/step - loss: 232608.1406 - mape: 44.6122 - val_loss: 1660268.1250 - val_mape: 65.5394\n", "Epoch 19/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 44ms/step - loss: 231991.0781 - mape: 45.7806 - val_loss: 1550361.5000 - val_mape: 63.9024\n", "Epoch 20/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 42ms/step - loss: 225928.7812 - mape: 41.9161 - val_loss: 1600106.6250 - val_mape: 64.0991\n", "Epoch 21/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 42ms/step - loss: 222877.0781 - mape: 40.5920 - val_loss: 1489548.6250 - val_mape: 63.3521\n", "Epoch 22/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 43ms/step - loss: 219066.1250 - mape: 43.0462 - val_loss: 1682864.0000 - val_mape: 66.9739\n", "Epoch 23/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 44ms/step - loss: 218053.4531 - mape: 42.8029 - val_loss: 1631763.2500 - val_mape: 64.7390\n", "Epoch 24/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 43ms/step - loss: 213761.1094 - mape: 46.2372 - val_loss: 1443448.2500 - val_mape: 62.3867\n", "Epoch 25/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 44ms/step - loss: 210890.1562 - mape: 39.8299 - val_loss: 1656974.6250 - val_mape: 65.4794\n", "Epoch 26/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 44ms/step - loss: 210550.2031 - mape: 45.5542 - val_loss: 1552693.3750 - val_mape: 63.8037\n", "Epoch 27/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 42ms/step - loss: 207589.0000 - mape: 41.8776 - val_loss: 1619232.2500 - val_mape: 65.8852\n", "Epoch 28/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 44ms/step - loss: 205814.3594 - mape: 36.7697 - val_loss: 1683814.7500 - val_mape: 66.1623\n", "Epoch 29/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 45ms/step - loss: 202753.2344 - mape: 44.4446 - val_loss: 1527505.2500 - val_mape: 62.4843\n", "Epoch 30/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 42ms/step - loss: 199356.7812 - mape: 41.2339 - val_loss: 1449552.6250 - val_mape: 62.4894\n", "{'num_conv_layers': 3, 'filters_0': 64, 'num_dense_layers': 3, 'dense_units_0': 256, 'dropout_0': 0.5, 'filters_1': 32, 'filters_2': 32, 'dense_units_1': 64, 'dropout_1': 0.3, 'dense_units_2': 64, 'dropout_2': 0.3}\n" ] } ], "source": [ "best_model = tuner.get_best_models(num_models=1)[0]\n", "best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]\n", "\n", "# the history object will contain a record of loss and metric values during training\n", "history = best_model.fit({'image_input': train_images, 'scalar_input': train_feats}, ytrain,\n", " batch_size=256,\n", " epochs=30,\n", " validation_data=(\n", " {'image_input': test_images, 'scalar_input': test_feats},\n", " ytest\n", " )\n", " )\n", "\n", "print(best_hps.values)\n" ] }, { "cell_type": "code", "execution_count": 41, "id": "b1ac814f", "metadata": {}, "outputs": [], "source": [ "temp_model = best_model" ] }, { "cell_type": "code", "execution_count": 42, "id": "9c6ce54d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 image_input \n", "1 conv2d \n", "2 max_pooling2d \n", "3 conv2d_1 \n", "4 max_pooling2d_1 \n", "5 conv2d_2 \n", "6 max_pooling2d_2 \n", "7 flatten \n", "8 scalar_input \n", "9 concatenate \n", "10 dense \n", "11 dropout \n", "12 dense_1 \n", "13 dropout_1 \n", "14 dense_2 \n", "15 dropout_2 \n", "16 output \n" ] } ], "source": [ "#print layer index to input in the layer views. (conv2d)\n", "for i, layer in enumerate(temp_model.layers):\n", " print(i, layer.name, type(layer))\n" ] }, { "cell_type": "markdown", "id": "9d461d50", "metadata": {}, "source": [ "# Making input for velocity x" ] }, { "cell_type": "code", "execution_count": 93, "id": "3fdbe35b", "metadata": {}, "outputs": [], "source": [ "data = xr.open_dataset('conv_velocity_x_3031.nc')\n", "#data = xr.open_dataset(r'C:\\Users\\marku\\Desktop\\4år\\AML\\Final_project_huggingface\\finalprojectdata\\conv_train_1.nc')" ] }, { "cell_type": "code", "execution_count": 94, "id": "4b553b6a", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/44/y59xjnbx6fqfgz896mcmxfw80000gn/T/ipykernel_99782/2935343825.py:5: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.\n", " dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n" ] } ], "source": [ "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n", "feats = np.array([data[feat].values for feat in scalar_feats]).T\n", "\n", "# 1. Find correct dimension name (e.g., 'obs')\n", "dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n", "\n", "# 2. Find odd (odd) indices using xarray logic\n", "grid_ids = data[\"gridCellId\"].values.astype(int)\n", "odd_mask = grid_ids % 2 == 1\n", "odd_idx = np.where(odd_mask)[0]\n", "test_idx = np.where(~odd_mask)[0]\n", "\n", "# 3. Extract scalar features as a stacked array (samples x features)\n", "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n", "feats = np.stack([data[feat].values for feat in scalar_feats], axis=-1)\n", "\n", "# 4. Create train/test splits using .isel and values\n", "train_images = data[\"images\"].isel({dim_name: odd_idx}).values\n", "test_images = data[\"images\"].isel({dim_name: test_idx}).values\n", "\n", "train_feats = feats[odd_idx]\n", "test_feats = feats[test_idx]\n", "\n", "ytrain = data[\"THICK\"].isel({dim_name: odd_idx}).values\n", "ytest = data[\"THICK\"].isel({dim_name: test_idx}).values\n", "\n", "ytrain = data.THICK.values[odd_idx]\n", "ytest = data.THICK.values[test_idx]\n" ] }, { "cell_type": "code", "execution_count": 95, "id": "787706eb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(104876, 27, 27)\n", "False\n", "0\n", "76454604\n" ] } ], "source": [ "train_images = data[\"images\"].isel({dim_name: odd_idx}).load().values\n", "test_images = data[\"images\"].isel({dim_name: test_idx}).load().values\n", "\n", "train_images = np.nan_to_num(train_images, nan=0.0)\n", "test_images = np.nan_to_num(test_images, nan=0.0)\n", "\n", "print(train_images.shape) # should be (N, 27, 27)\n", "print(np.isnan(train_images).all()) # should be False\n", "print(np.isnan(train_images).sum()) # total NaNs\n", "print(104876 * 27 *27)\n" ] }, { "cell_type": "code", "execution_count": 96, "id": "479d911e", "metadata": {}, "outputs": [], "source": [ "#---------standardize labels-------------------\n", "# Compute mean and std from training labels\n", "y_mean = ytrain.mean()\n", "y_std = ytrain.std()\n", "\n", "# Standardize ytrain and ytest using training statistics\n", "ytrain_std = (ytrain - y_mean) / y_std\n", "ytest_std = (ytest - y_mean) / y_std\n", "#to convert back to original scale, use:\n", "# ypreds_orig = ypreds * y_std + y_mean\n", "#----------------------------------------------\n", "\n", "# ytrain = ytrain.values\n", "# ytest = ytest.values\n", "\n", "# explicitly illustrating standardization\n", "def standardizeimg(img, mu, sigma):\n", " return (img-mu)/(sigma).astype(np.float32)\n", "\n", "# save for scaling test dataA\n", "mu_train = np.mean(train_images)\n", "sigma_train = np.std(train_images)\n", "\n", "# Standardize pixel distribution to have zero mean and unit variance\n", "train_images = standardizeimg(img=train_images, mu=mu_train, sigma=sigma_train)\n", "test_images = standardizeimg(img=test_images, mu=np.mean(test_images), sigma=np.std(test_images))\n", "\n", "# adapt to format required by tensorflow; Using channels_last --> (n_samples, img_rows, img_cols, n_channels)\n", "img_rows, img_cols = 27, 27 # input image dimensions\n", "train_images = train_images.reshape(train_images.shape[0], img_rows, img_cols, 1)\n", "test_images = test_images.reshape(test_images.shape[0], img_rows, img_cols, 1)" ] }, { "cell_type": "code", "execution_count": 97, "id": "97402506", "metadata": {}, "outputs": [], "source": [ "velocity_x_train_images = train_images\n", "velocity_x_test_feats = test_feats\n", "velocity_x_train_feats = train_feats\n", "velocity_x_test_images = test_images" ] }, { "cell_type": "markdown", "id": "f08a93af", "metadata": {}, "source": [ "# Making model for velocity x" ] }, { "cell_type": "code", "execution_count": 48, "id": "fa7cb71a", "metadata": {}, "outputs": [], "source": [ "def build_model(hp):\n", " IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS = 27, 27, 1\n", " NUM_SCALAR_FEATURES = 7\n", "\n", " image_input = layers.Input(shape=(IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS), name='image_input')\n", " x = image_input\n", "\n", " # Tune number of conv layers: 1 to 3\n", " for i in range(hp.Int('num_conv_layers', 1, 3)):\n", " filters = hp.Int(f'filters_{i}', 32, 128, step=32)\n", " x = layers.Conv2D(filters, (3, 3), activation='relu', padding='same')(x)\n", " x = layers.MaxPooling2D((2, 2))(x)\n", "\n", " x = layers.Flatten()(x)\n", "\n", " # Scalar branch\n", " scalar_input = layers.Input(shape=(NUM_SCALAR_FEATURES,), name='scalar_input')\n", " y = scalar_input # you could also add dense layers here\n", "\n", " # Merge\n", " z = layers.concatenate([x, y])\n", "\n", " # Tune number of dense layers: 1 to 3\n", " for i in range(hp.Int('num_dense_layers', 1, 3)):\n", " units = hp.Int(f'dense_units_{i}', 64, 256, step=64)\n", " z = layers.Dense(units, activation='relu')(z)\n", " z = layers.Dropout(hp.Float(f'dropout_{i}', 0.3, 0.7, step=0.1))(z)\n", "\n", " output = layers.Dense(1, name='output')(z)\n", "\n", " model = keras.Model(inputs=[image_input, scalar_input], outputs=output)\n", "\n", " model.compile(\n", " optimizer='adam',\n", " loss='mse',\n", " metrics=['mape']\n", " )\n", "\n", " return model\n" ] }, { "cell_type": "code", "execution_count": 49, "id": "45dad959", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Reloading Tuner from Code/ice_thickness_cnn_velocity_x/tuner0.json\n" ] } ], "source": [ "tuner = kt.RandomSearch(\n", " build_model,\n", " objective='val_mape',\n", " max_trials=1,\n", " executions_per_trial=1,\n", " directory='Code', #skift directory\n", " project_name='ice_thickness_cnn_velocity_x'\n", ")\n" ] }, { "cell_type": "code", "execution_count": 50, "id": "e81e32f3", "metadata": {}, "outputs": [], "source": [ "tuner.search(\n", " {'image_input': train_images, 'scalar_input': train_feats},\n", " ytrain_std,\n", " validation_data=({'image_input': test_images, 'scalar_input': test_feats}, ytest_std),\n", " epochs=30,\n", " batch_size=320\n", ")\n" ] }, { "cell_type": "code", "execution_count": 51, "id": "f0317f53", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/30\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/opt/miniconda3/envs/appml/lib/python3.12/site-packages/keras/src/saving/saving_lib.py:757: UserWarning: Skipping variable loading for optimizer 'adam', because it has 2 variables whereas the saved optimizer has 14 variables. \n", " saveable.load_own_variables(weights_store.get(inner_path))\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m26s\u001b[0m 62ms/step - loss: 1336781.1250 - mape: 94.4451 - val_loss: 402673.8125 - val_mape: 83.2502\n", "Epoch 2/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 62ms/step - loss: 376983.5938 - mape: 81.8606 - val_loss: 397838.0312 - val_mape: 81.0186\n", "Epoch 3/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 60ms/step - loss: 355808.5312 - mape: 75.7192 - val_loss: 425336.6250 - val_mape: 86.4529\n", "Epoch 4/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 60ms/step - loss: 349947.9688 - mape: 74.3684 - val_loss: 412210.1875 - val_mape: 80.8694\n", "Epoch 5/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 60ms/step - loss: 347800.2500 - mape: 70.8257 - val_loss: 410407.2188 - val_mape: 81.3800\n", "Epoch 6/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m24s\u001b[0m 59ms/step - loss: 343076.8750 - mape: 66.2485 - val_loss: 413585.8438 - val_mape: 80.6193\n", "Epoch 7/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 338296.5625 - mape: 61.7042 - val_loss: 440204.6562 - val_mape: 83.4736\n", "Epoch 8/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 60ms/step - loss: 338269.9688 - mape: 78.8218 - val_loss: 439547.8125 - val_mape: 83.8019\n", "Epoch 9/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 60ms/step - loss: 337441.4375 - mape: 68.3473 - val_loss: 421031.0938 - val_mape: 79.7825\n", "Epoch 10/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m24s\u001b[0m 60ms/step - loss: 334431.6875 - mape: 62.2757 - val_loss: 434559.5000 - val_mape: 81.9299\n", "Epoch 11/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m24s\u001b[0m 60ms/step - loss: 330628.7188 - mape: 67.0346 - val_loss: 426703.2188 - val_mape: 80.5096\n", "Epoch 12/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 60ms/step - loss: 329001.2188 - mape: 60.4632 - val_loss: 495423.5625 - val_mape: 90.1190\n", "Epoch 13/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 60ms/step - loss: 328941.9375 - mape: 65.3010 - val_loss: 467750.2812 - val_mape: 83.2061\n", "Epoch 14/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 331812.5625 - mape: 63.4937 - val_loss: 477939.2188 - val_mape: 84.8599\n", "Epoch 15/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 62ms/step - loss: 329210.5000 - mape: 75.2823 - val_loss: 456409.5938 - val_mape: 80.1059\n", "Epoch 16/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 328857.8125 - mape: 65.3842 - val_loss: 452057.6250 - val_mape: 80.7951\n", "Epoch 17/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m27s\u001b[0m 67ms/step - loss: 325523.3125 - mape: 62.9261 - val_loss: 491969.1562 - val_mape: 85.2202\n", "Epoch 18/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 62ms/step - loss: 324142.6562 - mape: 62.9701 - val_loss: 502907.9375 - val_mape: 84.6040\n", "Epoch 19/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 319110.1250 - mape: 67.9875 - val_loss: 502296.0000 - val_mape: 85.2477\n", "Epoch 20/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 321136.6562 - mape: 57.8185 - val_loss: 488749.4375 - val_mape: 82.2132\n", "Epoch 21/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 322892.1875 - mape: 64.9246 - val_loss: 484901.4375 - val_mape: 80.4933\n", "Epoch 22/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 62ms/step - loss: 320698.3125 - mape: 56.5604 - val_loss: 537694.0000 - val_mape: 86.5828\n", "Epoch 23/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m24s\u001b[0m 60ms/step - loss: 318536.7812 - mape: 61.6400 - val_loss: 576138.1875 - val_mape: 88.1680\n", "Epoch 24/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 312640.9062 - mape: 60.6539 - val_loss: 554938.8750 - val_mape: 85.1195\n", "Epoch 25/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 313884.0938 - mape: 64.3577 - val_loss: 559988.4375 - val_mape: 83.6795\n", "Epoch 26/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 60ms/step - loss: 310639.0625 - mape: 56.2810 - val_loss: 626199.4375 - val_mape: 90.2817\n", "Epoch 27/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 308615.3438 - mape: 64.2963 - val_loss: 636396.3125 - val_mape: 86.8326\n", "Epoch 28/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 62ms/step - loss: 312875.8438 - mape: 62.2947 - val_loss: 724409.8750 - val_mape: 94.1799\n", "Epoch 29/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 306166.5000 - mape: 71.2832 - val_loss: 620627.0625 - val_mape: 84.5451\n", "Epoch 30/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m25s\u001b[0m 61ms/step - loss: 307904.2812 - mape: 55.6592 - val_loss: 785187.5625 - val_mape: 95.3243\n", "{'num_conv_layers': 1, 'filters_0': 128, 'num_dense_layers': 1, 'dense_units_0': 192, 'dropout_0': 0.3}\n" ] } ], "source": [ "best_model = tuner.get_best_models(num_models=1)[0]\n", "best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]\n", "\n", "# the history object will contain a record of loss and metric values during training\n", "history = best_model.fit({'image_input': train_images, 'scalar_input': train_feats}, ytrain,\n", " batch_size=256,\n", " epochs=30,\n", " validation_data=(\n", " {'image_input': test_images, 'scalar_input': test_feats},\n", " ytest\n", " )\n", " )\n", "\n", "print(best_hps.values)\n" ] }, { "cell_type": "markdown", "id": "441cfd20", "metadata": {}, "source": [ "Tunable model end." ] }, { "cell_type": "code", "execution_count": 52, "id": "74958028", "metadata": {}, "outputs": [], "source": [ "velocity_x_model = best_model" ] }, { "cell_type": "code", "execution_count": 53, "id": "758ca058", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(None, 27, 27, 1), (None, 7)]\n" ] } ], "source": [ "print(velocity_x_model.input_shape)" ] }, { "cell_type": "code", "execution_count": 54, "id": "5a37e40b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 image_input \n", "1 conv2d \n", "2 max_pooling2d \n", "3 flatten \n", "4 scalar_input \n", "5 concatenate \n", "6 dense \n", "7 dropout \n", "8 output \n" ] } ], "source": [ "#print layer index to input in the layer views. (conv2d)\n", "for i, layer in enumerate(velocity_x_model.layers):\n", " print(i, layer.name, type(layer))\n" ] }, { "cell_type": "markdown", "id": "1d5ef788", "metadata": {}, "source": [ "# Making input for velocity y" ] }, { "cell_type": "code", "execution_count": 98, "id": "627307d2", "metadata": {}, "outputs": [], "source": [ "data = xr.open_dataset('conv_velocity_y_3031.nc')\n", "#data = xr.open_dataset(r'C:\\Users\\marku\\Desktop\\4år\\AML\\Final_project_huggingface\\finalprojectdata\\conv_train_1.nc')" ] }, { "cell_type": "code", "execution_count": 99, "id": "82f1d503", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/44/y59xjnbx6fqfgz896mcmxfw80000gn/T/ipykernel_99782/2935343825.py:5: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.\n", " dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n" ] } ], "source": [ "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n", "feats = np.array([data[feat].values for feat in scalar_feats]).T\n", "\n", "# 1. Find correct dimension name (e.g., 'obs')\n", "dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n", "\n", "# 2. Find odd (odd) indices using xarray logic\n", "grid_ids = data[\"gridCellId\"].values.astype(int)\n", "odd_mask = grid_ids % 2 == 1\n", "odd_idx = np.where(odd_mask)[0]\n", "test_idx = np.where(~odd_mask)[0]\n", "\n", "# 3. Extract scalar features as a stacked array (samples x features)\n", "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n", "feats = np.stack([data[feat].values for feat in scalar_feats], axis=-1)\n", "\n", "# 4. Create train/test splits using .isel and values\n", "train_images = data[\"images\"].isel({dim_name: odd_idx}).values\n", "test_images = data[\"images\"].isel({dim_name: test_idx}).values\n", "\n", "train_feats = feats[odd_idx]\n", "test_feats = feats[test_idx]\n", "\n", "ytrain = data[\"THICK\"].isel({dim_name: odd_idx}).values\n", "ytest = data[\"THICK\"].isel({dim_name: test_idx}).values\n", "\n", "ytrain = data.THICK.values[odd_idx]\n", "ytest = data.THICK.values[test_idx]\n" ] }, { "cell_type": "code", "execution_count": 100, "id": "bcd71661", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(104876, 27, 27)\n", "False\n", "0\n", "76454604\n" ] } ], "source": [ "train_images = data[\"images\"].isel({dim_name: odd_idx}).load().values\n", "test_images = data[\"images\"].isel({dim_name: test_idx}).load().values\n", "\n", "train_images = np.nan_to_num(train_images, nan=0.0)\n", "test_images = np.nan_to_num(test_images, nan=0.0)\n", "\n", "print(train_images.shape) # should be (N, 27, 27)\n", "print(np.isnan(train_images).all()) # should be False\n", "print(np.isnan(train_images).sum()) # total NaNs\n", "print(104876 * 27 *27)\n" ] }, { "cell_type": "code", "execution_count": 101, "id": "6280c3d5", "metadata": {}, "outputs": [], "source": [ "#---------standardize labels-------------------\n", "# Compute mean and std from training labels\n", "y_mean = ytrain.mean()\n", "y_std = ytrain.std()\n", "\n", "# Standardize ytrain and ytest using training statistics\n", "ytrain_std = (ytrain - y_mean) / y_std\n", "ytest_std = (ytest - y_mean) / y_std\n", "#to convert back to original scale, use:\n", "# ypreds_orig = ypreds * y_std + y_mean\n", "#----------------------------------------------\n", "\n", "# ytrain = ytrain.values\n", "# ytest = ytest.values\n", "\n", "# explicitly illustrating standardization\n", "def standardizeimg(img, mu, sigma):\n", " return (img-mu)/(sigma).astype(np.float32)\n", "\n", "# save for scaling test dataA\n", "mu_train = np.mean(train_images)\n", "sigma_train = np.std(train_images)\n", "\n", "# Standardize pixel distribution to have zero mean and unit variance\n", "train_images = standardizeimg(img=train_images, mu=mu_train, sigma=sigma_train)\n", "test_images = standardizeimg(img=test_images, mu=np.mean(test_images), sigma=np.std(test_images))\n", "\n", "# adapt to format required by tensorflow; Using channels_last --> (n_samples, img_rows, img_cols, n_channels)\n", "img_rows, img_cols = 27, 27 # input image dimensions\n", "train_images = train_images.reshape(train_images.shape[0], img_rows, img_cols, 1)\n", "test_images = test_images.reshape(test_images.shape[0], img_rows, img_cols, 1)" ] }, { "cell_type": "code", "execution_count": 102, "id": "9fd94726", "metadata": {}, "outputs": [], "source": [ "velocity_y_train_images = train_images\n", "velocity_y_test_feats = test_feats\n", "velocity_y_train_feats = train_feats\n", "velocity_y_test_images = test_images" ] }, { "cell_type": "markdown", "id": "d5c11082", "metadata": {}, "source": [ "# Making model for velocity y" ] }, { "cell_type": "code", "execution_count": 60, "id": "6a608f80", "metadata": {}, "outputs": [], "source": [ "def build_model(hp):\n", " IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS = 27, 27, 1\n", " NUM_SCALAR_FEATURES = 7\n", "\n", " image_input = layers.Input(shape=(IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS), name='image_input')\n", " x = image_input\n", "\n", " # Tune number of conv layers: 1 to 3\n", " for i in range(hp.Int('num_conv_layers', 1, 3)):\n", " filters = hp.Int(f'filters_{i}', 32, 128, step=32)\n", " x = layers.Conv2D(filters, (3, 3), activation='relu', padding='same')(x)\n", " x = layers.MaxPooling2D((2, 2))(x)\n", "\n", " x = layers.Flatten()(x)\n", "\n", " # Scalar branch\n", " scalar_input = layers.Input(shape=(NUM_SCALAR_FEATURES,), name='scalar_input')\n", " y = scalar_input # you could also add dense layers here\n", "\n", " # Merge\n", " z = layers.concatenate([x, y])\n", "\n", " # Tune number of dense layers: 1 to 3\n", " for i in range(hp.Int('num_dense_layers', 1, 3)):\n", " units = hp.Int(f'dense_units_{i}', 64, 256, step=64)\n", " z = layers.Dense(units, activation='relu')(z)\n", " z = layers.Dropout(hp.Float(f'dropout_{i}', 0.3, 0.7, step=0.1))(z)\n", "\n", " output = layers.Dense(1, name='output')(z)\n", "\n", " model = keras.Model(inputs=[image_input, scalar_input], outputs=output)\n", "\n", " model.compile(\n", " optimizer='adam',\n", " loss='mse',\n", " metrics=['mape']\n", " )\n", "\n", " return model\n" ] }, { "cell_type": "code", "execution_count": 61, "id": "3522b27b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Reloading Tuner from Code/ice_thickness_cnn_velocity_y/tuner0.json\n" ] } ], "source": [ "tuner = kt.RandomSearch(\n", " build_model,\n", " objective='val_mape',\n", " max_trials=1,\n", " executions_per_trial=1,\n", " directory='Code', #skift directory\n", " project_name='ice_thickness_cnn_velocity_y'\n", ")\n" ] }, { "cell_type": "code", "execution_count": 62, "id": "e92ba9a3", "metadata": {}, "outputs": [], "source": [ "tuner.search(\n", " {'image_input': train_images, 'scalar_input': train_feats},\n", " ytrain_std,\n", " validation_data=({'image_input': test_images, 'scalar_input': test_feats}, ytest_std),\n", " epochs=30,\n", " batch_size=320\n", ")\n" ] }, { "cell_type": "code", "execution_count": 63, "id": "49e60ba0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/30\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/opt/miniconda3/envs/appml/lib/python3.12/site-packages/keras/src/saving/saving_lib.py:757: UserWarning: Skipping variable loading for optimizer 'adam', because it has 2 variables whereas the saved optimizer has 22 variables. \n", " saveable.load_own_variables(weights_store.get(inner_path))\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m9s\u001b[0m 22ms/step - loss: 1529231.3750 - mape: 80.2615 - val_loss: 346213.4375 - val_mape: 59.4315\n", "Epoch 2/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m10s\u001b[0m 24ms/step - loss: 409711.1250 - mape: 65.2273 - val_loss: 327204.7500 - val_mape: 54.8219\n", "Epoch 3/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m9s\u001b[0m 23ms/step - loss: 389924.4375 - mape: 59.2036 - val_loss: 324795.1562 - val_mape: 53.2256\n", "Epoch 4/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 376415.0625 - mape: 61.4746 - val_loss: 376634.3438 - val_mape: 49.7954\n", "Epoch 5/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 362309.7812 - mape: 60.8802 - val_loss: 306044.6562 - val_mape: 51.8332\n", "Epoch 6/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 347181.0000 - mape: 52.1235 - val_loss: 391396.9375 - val_mape: 49.0921\n", "Epoch 7/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 347959.7812 - mape: 56.6309 - val_loss: 345264.6875 - val_mape: 49.9262\n", "Epoch 8/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 337799.5938 - mape: 57.1972 - val_loss: 339674.9062 - val_mape: 49.1977\n", "Epoch 9/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 328872.3438 - mape: 50.4590 - val_loss: 402473.8438 - val_mape: 49.1949\n", "Epoch 10/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 324722.1875 - mape: 57.0522 - val_loss: 441182.3438 - val_mape: 48.8687\n", "Epoch 11/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 20ms/step - loss: 318556.5625 - mape: 61.8797 - val_loss: 401058.9688 - val_mape: 49.6954\n", "Epoch 12/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 317519.5000 - mape: 49.2848 - val_loss: 470227.5938 - val_mape: 50.3036\n", "Epoch 13/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 310703.6250 - mape: 54.2541 - val_loss: 495772.0000 - val_mape: 49.1467\n", "Epoch 14/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 304060.4375 - mape: 47.6753 - val_loss: 429612.5312 - val_mape: 48.7872\n", "Epoch 15/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 299288.2812 - mape: 54.7837 - val_loss: 544513.1875 - val_mape: 48.7465\n", "Epoch 16/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 294479.3125 - mape: 50.6538 - val_loss: 566505.1875 - val_mape: 49.8416\n", "Epoch 17/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 292478.0312 - mape: 45.1613 - val_loss: 509046.8750 - val_mape: 48.8166\n", "Epoch 18/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 289298.4062 - mape: 52.3078 - val_loss: 534722.9375 - val_mape: 49.0063\n", "Epoch 19/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 287811.8125 - mape: 49.5821 - val_loss: 546590.0625 - val_mape: 48.8045\n", "Epoch 20/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 284118.2188 - mape: 52.2100 - val_loss: 601730.3750 - val_mape: 49.0408\n", "Epoch 21/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 20ms/step - loss: 284798.7812 - mape: 47.2230 - val_loss: 535830.1250 - val_mape: 48.4669\n", "Epoch 22/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 20ms/step - loss: 282001.2500 - mape: 58.4509 - val_loss: 668632.1875 - val_mape: 49.7857\n", "Epoch 23/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 279132.3438 - mape: 53.5629 - val_loss: 575056.6250 - val_mape: 48.7271\n", "Epoch 24/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 276172.8125 - mape: 52.9894 - val_loss: 505340.2812 - val_mape: 48.5599\n", "Epoch 25/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 273416.3750 - mape: 46.4951 - val_loss: 539189.4375 - val_mape: 47.7299\n", "Epoch 26/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 272958.5312 - mape: 53.1291 - val_loss: 498400.0625 - val_mape: 47.4175\n", "Epoch 27/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 271236.3438 - mape: 47.8248 - val_loss: 520940.8438 - val_mape: 47.1233\n", "Epoch 28/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 271854.7188 - mape: 50.6873 - val_loss: 517070.0000 - val_mape: 48.0661\n", "Epoch 29/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 268482.5000 - mape: 48.7084 - val_loss: 592744.6875 - val_mape: 48.4801\n", "Epoch 30/30\n", "\u001b[1m410/410\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 19ms/step - loss: 267370.4375 - mape: 46.2331 - val_loss: 424568.1562 - val_mape: 46.7016\n", "{'num_conv_layers': 1, 'filters_0': 32, 'num_dense_layers': 3, 'dense_units_0': 192, 'dropout_0': 0.3, 'dense_units_1': 64, 'dropout_1': 0.3, 'dense_units_2': 64, 'dropout_2': 0.3}\n" ] } ], "source": [ "best_model = tuner.get_best_models(num_models=1)[0]\n", "best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]\n", "\n", "# the history object will contain a record of loss and metric values during training\n", "history = best_model.fit({'image_input': train_images, 'scalar_input': train_feats}, ytrain,\n", " batch_size=256,\n", " epochs=30,\n", " validation_data=(\n", " {'image_input': test_images, 'scalar_input': test_feats},\n", " ytest\n", " )\n", " )\n", "\n", "print(best_hps.values)\n" ] }, { "cell_type": "markdown", "id": "c8822c05", "metadata": {}, "source": [ "Tunable model end." ] }, { "cell_type": "code", "execution_count": 64, "id": "d021de05", "metadata": {}, "outputs": [], "source": [ "velocity_y_model = best_model" ] }, { "cell_type": "code", "execution_count": 65, "id": "9d10475a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(None, 27, 27, 1), (None, 7)]\n" ] } ], "source": [ "print(velocity_y_model.input_shape)" ] }, { "cell_type": "code", "execution_count": 66, "id": "9c99bfb8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 image_input \n", "1 conv2d \n", "2 max_pooling2d \n", "3 flatten \n", "4 scalar_input \n", "5 concatenate \n", "6 dense \n", "7 dropout \n", "8 dense_1 \n", "9 dropout_1 \n", "10 dense_2 \n", "11 dropout_2 \n", "12 output \n" ] } ], "source": [ "#print layer index to input in the layer views. (conv2d)\n", "for i, layer in enumerate(velocity_y_model.layers):\n", " print(i, layer.name, type(layer))\n" ] }, { "cell_type": "markdown", "id": "52a18924", "metadata": {}, "source": [ "# Making final model" ] }, { "cell_type": "code", "execution_count": null, "id": "2557ee4c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m3277/3277\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m5s\u001b[0m 2ms/step\n", "\u001b[1m3278/3278\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m7s\u001b[0m 2ms/step\n", "\u001b[1m3278/3278\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 918us/step\n", "\u001b[1m2925/2925\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m5s\u001b[0m 2ms/step\n", "\u001b[1m2965/2965\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m6s\u001b[0m 2ms/step\n", "\u001b[1m2965/2965\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 985us/step\n" ] }, { "ename": "ValueError", "evalue": "all input arrays must have the same shape", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mValueError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[103]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 9\u001b[39m preds_velocity_y_test = velocity_y_model.predict([velocity_y_test_images, velocity_y_test_feats])\n\u001b[32m 11\u001b[39m \u001b[38;5;66;03m# 3. Stack input for ensemble\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m X_stack_train = \u001b[43mnp\u001b[49m\u001b[43m.\u001b[49m\u001b[43mstack\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mpreds_temp_train\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreds_velocity_x_train\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreds_velocity_y_train\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43maxis\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 13\u001b[39m X_stack_test = np.stack([preds_temp_test, preds_velocity_x_test, preds_velocity_y_test], axis=\u001b[32m1\u001b[39m)\n\u001b[32m 15\u001b[39m \u001b[38;5;66;03m# 4. Træn ensemble-model\u001b[39;00m\n", "\u001b[36mFile \u001b[39m\u001b[32m/opt/miniconda3/envs/appml/lib/python3.12/site-packages/numpy/_core/shape_base.py:448\u001b[39m, in \u001b[36mstack\u001b[39m\u001b[34m(arrays, axis, out, dtype, casting)\u001b[39m\n\u001b[32m 446\u001b[39m shapes = {arr.shape \u001b[38;5;28;01mfor\u001b[39;00m arr \u001b[38;5;129;01min\u001b[39;00m arrays}\n\u001b[32m 447\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(shapes) != \u001b[32m1\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m448\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33m'\u001b[39m\u001b[33mall input arrays must have the same shape\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m 450\u001b[39m result_ndim = arrays[\u001b[32m0\u001b[39m].ndim + \u001b[32m1\u001b[39m\n\u001b[32m 451\u001b[39m axis = normalize_axis_index(axis, result_ndim)\n", "\u001b[31mValueError\u001b[39m: all input arrays must have the same shape" ] } ], "source": [ "# 1. Prædiktioner på træningsdata\n", "preds_temp_train = temp_model.predict([temp_train_images, temp_train_feats])\n", "preds_velocity_x_train = velocity_x_model.predict([velocity_x_train_images, velocity_x_train_feats])\n", "preds_velocity_y_train = velocity_y_model.predict([velocity_y_train_images, velocity_y_train_feats])\n", "\n", "# 2. Prædiktioner på testdata \n", "preds_temp_test = temp_model.predict([temp_test_images, temp_test_feats])\n", "preds_velocity_x_test = velocity_x_model.predict([velocity_x_test_images, velocity_x_test_feats])\n", "preds_velocity_y_test = velocity_y_model.predict([velocity_y_test_images, velocity_y_test_feats])\n", "\n", "# 3. Stack input for ensemble\n", "X_stack_train = np.stack([preds_temp_train, preds_velocity_x_train, preds_velocity_y_train], axis=1)\n", "X_stack_test = np.stack([preds_temp_test, preds_velocity_x_test, preds_velocity_y_test], axis=1)\n", "\n", "# 4. Træn ensemble-model\n", "from sklearn.linear_model import LinearRegression\n", "\n", "stack_model = LinearRegression()\n", "stack_model.fit(X_stack_train, ytrain) # Brug den korrekte målvariabel\n", "final_preds = stack_model.predict(X_stack_test)" ] } ], "metadata": { "kernelspec": { "display_name": "appml", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.9" } }, "nbformat": 4, "nbformat_minor": 5 }