mewamuwa commited on
Commit
1270c59
·
verified ·
1 Parent(s): cf678ce

Kode der træner CNN-modeller og mislykket forsøger at samle dem.

Browse files

Modellerne kan ikke samles med en stacker som de er lavet nu, fordi de alle er trænet og testet på forskellig data. De er hver især trænet og testet på billederne for deres unikke variabel (velocity, temperature,...). For at kunne samle dem skal de trænes og testes på sammenligneligt data. Derfor skal der laves billeder i de samme punkter. Det ved jeg ikke om vi kan når opløsningen ikke er ens.

Files changed (1) hide show
  1. conv_antarctis_samlet_model.ipynb +1331 -0
conv_antarctis_samlet_model.ipynb ADDED
@@ -0,0 +1,1331 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 31,
6
+ "id": "e7e09770",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "import numpy as np\n",
11
+ "import xarray as xr\n",
12
+ "from sklearn.model_selection import train_test_split\n",
13
+ "import matplotlib.pyplot as plt\n",
14
+ "from tensorflow.keras import layers\n",
15
+ "from tensorflow import keras\n",
16
+ "import keras_tuner as kt"
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "markdown",
21
+ "id": "acfd64fc",
22
+ "metadata": {},
23
+ "source": [
24
+ "# Making input for temp"
25
+ ]
26
+ },
27
+ {
28
+ "cell_type": "code",
29
+ "execution_count": 88,
30
+ "id": "59cfc06d",
31
+ "metadata": {},
32
+ "outputs": [],
33
+ "source": [
34
+ "data = xr.open_dataset('conv_temp_4326.nc')"
35
+ ]
36
+ },
37
+ {
38
+ "cell_type": "code",
39
+ "execution_count": 89,
40
+ "id": "a9923e31",
41
+ "metadata": {},
42
+ "outputs": [
43
+ {
44
+ "name": "stderr",
45
+ "output_type": "stream",
46
+ "text": [
47
+ "/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",
48
+ " dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n"
49
+ ]
50
+ }
51
+ ],
52
+ "source": [
53
+ "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n",
54
+ "feats = np.array([data[feat].values for feat in scalar_feats]).T\n",
55
+ "\n",
56
+ "# 1. Find correct dimension name (e.g., 'obs')\n",
57
+ "dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n",
58
+ "\n",
59
+ "# 2. Find odd (odd) indices using xarray logic\n",
60
+ "grid_ids = data[\"gridCellId\"].values.astype(int)\n",
61
+ "odd_mask = grid_ids % 2 == 1\n",
62
+ "odd_idx = np.where(odd_mask)[0]\n",
63
+ "test_idx = np.where(~odd_mask)[0]\n",
64
+ "\n",
65
+ "# 3. Extract scalar features as a stacked array (samples x features)\n",
66
+ "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n",
67
+ "feats = np.stack([data[feat].values for feat in scalar_feats], axis=-1)\n",
68
+ "\n",
69
+ "# 4. Create train/test splits using .isel and values\n",
70
+ "train_images = data[\"images\"].isel({dim_name: odd_idx}).values\n",
71
+ "test_images = data[\"images\"].isel({dim_name: test_idx}).values\n",
72
+ "\n",
73
+ "train_feats = feats[odd_idx]\n",
74
+ "test_feats = feats[test_idx]\n",
75
+ "\n",
76
+ "ytrain = data[\"THICK\"].isel({dim_name: odd_idx}).values\n",
77
+ "ytest = data[\"THICK\"].isel({dim_name: test_idx}).values\n",
78
+ "\n",
79
+ "ytrain = data.THICK.values[odd_idx]\n",
80
+ "ytest = data.THICK.values[test_idx]\n"
81
+ ]
82
+ },
83
+ {
84
+ "cell_type": "code",
85
+ "execution_count": 90,
86
+ "id": "af470a6f",
87
+ "metadata": {},
88
+ "outputs": [
89
+ {
90
+ "name": "stdout",
91
+ "output_type": "stream",
92
+ "text": [
93
+ "(104834, 27, 27)\n",
94
+ "False\n",
95
+ "0\n",
96
+ "76454604\n"
97
+ ]
98
+ }
99
+ ],
100
+ "source": [
101
+ "train_images = data[\"images\"].isel({dim_name: odd_idx}).load().values\n",
102
+ "test_images = data[\"images\"].isel({dim_name: test_idx}).load().values\n",
103
+ "\n",
104
+ "train_images = np.nan_to_num(train_images, nan=0.0)\n",
105
+ "test_images = np.nan_to_num(test_images, nan=0.0)\n",
106
+ "\n",
107
+ "print(train_images.shape) # should be (N, 27, 27)\n",
108
+ "print(np.isnan(train_images).all()) # should be False\n",
109
+ "print(np.isnan(train_images).sum()) # total NaNs\n",
110
+ "print(104876 * 27 *27)\n"
111
+ ]
112
+ },
113
+ {
114
+ "cell_type": "code",
115
+ "execution_count": 91,
116
+ "id": "2ed5f281",
117
+ "metadata": {},
118
+ "outputs": [],
119
+ "source": [
120
+ "#---------standardize labels-------------------\n",
121
+ "# Compute mean and std from training labels\n",
122
+ "y_mean = ytrain.mean()\n",
123
+ "y_std = ytrain.std()\n",
124
+ "\n",
125
+ "# Standardize ytrain and ytest using training statistics\n",
126
+ "ytrain_std = (ytrain - y_mean) / y_std\n",
127
+ "ytest_std = (ytest - y_mean) / y_std\n",
128
+ "#to convert back to original scale, use:\n",
129
+ "# ypreds_orig = ypreds * y_std + y_mean\n",
130
+ "#----------------------------------------------\n",
131
+ "\n",
132
+ "# ytrain = ytrain.values\n",
133
+ "# ytest = ytest.values\n",
134
+ "\n",
135
+ "# explicitly illustrating standardization\n",
136
+ "def standardizeimg(img, mu, sigma):\n",
137
+ " return (img-mu)/(sigma).astype(np.float32)\n",
138
+ "\n",
139
+ "# save for scaling test dataA\n",
140
+ "mu_train = np.mean(train_images)\n",
141
+ "sigma_train = np.std(train_images)\n",
142
+ "\n",
143
+ "# Standardize pixel distribution to have zero mean and unit variance\n",
144
+ "train_images = standardizeimg(img=train_images, mu=mu_train, sigma=sigma_train)\n",
145
+ "test_images = standardizeimg(img=test_images, mu=np.mean(test_images), sigma=np.std(test_images))\n",
146
+ "\n",
147
+ "# adapt to format required by tensorflow; Using channels_last --> (n_samples, img_rows, img_cols, n_channels)\n",
148
+ "img_rows, img_cols = 27, 27 # input image dimensions\n",
149
+ "train_images = train_images.reshape(train_images.shape[0], img_rows, img_cols, 1)\n",
150
+ "test_images = test_images.reshape(test_images.shape[0], img_rows, img_cols, 1)"
151
+ ]
152
+ },
153
+ {
154
+ "cell_type": "code",
155
+ "execution_count": 92,
156
+ "id": "571614d0",
157
+ "metadata": {},
158
+ "outputs": [],
159
+ "source": [
160
+ "temp_images = train_images\n",
161
+ "temp_train_images = train_images\n",
162
+ "temp_test_feats = test_feats\n",
163
+ "temp_train_feats = train_feats\n",
164
+ "temp_test_images = test_images"
165
+ ]
166
+ },
167
+ {
168
+ "cell_type": "markdown",
169
+ "id": "6233f2d7",
170
+ "metadata": {},
171
+ "source": [
172
+ "# Training model for temp"
173
+ ]
174
+ },
175
+ {
176
+ "cell_type": "code",
177
+ "execution_count": 37,
178
+ "id": "eb05afe1",
179
+ "metadata": {},
180
+ "outputs": [],
181
+ "source": [
182
+ "def build_model(hp):\n",
183
+ " IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS = 27, 27, 1\n",
184
+ " NUM_SCALAR_FEATURES = 7\n",
185
+ "\n",
186
+ " image_input = layers.Input(shape=(IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS), name='image_input')\n",
187
+ " x = image_input\n",
188
+ "\n",
189
+ " # Tune number of conv layers: 1 to 3\n",
190
+ " for i in range(hp.Int('num_conv_layers', 1, 3)):\n",
191
+ " filters = hp.Int(f'filters_{i}', 32, 128, step=32)\n",
192
+ " x = layers.Conv2D(filters, (3, 3), activation='relu', padding='same')(x)\n",
193
+ " x = layers.MaxPooling2D((2, 2))(x)\n",
194
+ "\n",
195
+ " x = layers.Flatten()(x)\n",
196
+ "\n",
197
+ " # Scalar branch\n",
198
+ " scalar_input = layers.Input(shape=(NUM_SCALAR_FEATURES,), name='scalar_input')\n",
199
+ " y = scalar_input # you could also add dense layers here\n",
200
+ "\n",
201
+ " # Merge\n",
202
+ " z = layers.concatenate([x, y])\n",
203
+ "\n",
204
+ " # Tune number of dense layers: 1 to 3\n",
205
+ " for i in range(hp.Int('num_dense_layers', 1, 3)):\n",
206
+ " units = hp.Int(f'dense_units_{i}', 64, 256, step=64)\n",
207
+ " z = layers.Dense(units, activation='relu')(z)\n",
208
+ " z = layers.Dropout(hp.Float(f'dropout_{i}', 0.3, 0.7, step=0.1))(z)\n",
209
+ "\n",
210
+ " output = layers.Dense(1, name='output')(z)\n",
211
+ "\n",
212
+ " model = keras.Model(inputs=[image_input, scalar_input], outputs=output)\n",
213
+ "\n",
214
+ " model.compile(\n",
215
+ " optimizer='adam',\n",
216
+ " loss='mse',\n",
217
+ " metrics=['mape']\n",
218
+ " )\n",
219
+ "\n",
220
+ " return model"
221
+ ]
222
+ },
223
+ {
224
+ "cell_type": "code",
225
+ "execution_count": 38,
226
+ "id": "85802ff8",
227
+ "metadata": {},
228
+ "outputs": [
229
+ {
230
+ "name": "stdout",
231
+ "output_type": "stream",
232
+ "text": [
233
+ "Reloading Tuner from Code/ice_thickness_cnn_temp/tuner0.json\n"
234
+ ]
235
+ }
236
+ ],
237
+ "source": [
238
+ "tuner = kt.RandomSearch(\n",
239
+ " build_model,\n",
240
+ " objective='val_mape',\n",
241
+ " max_trials=1,\n",
242
+ " executions_per_trial=1,\n",
243
+ " directory='Code', #skift directory\n",
244
+ " project_name='ice_thickness_cnn_temp'\n",
245
+ ")\n"
246
+ ]
247
+ },
248
+ {
249
+ "cell_type": "code",
250
+ "execution_count": 39,
251
+ "id": "fa473e8c",
252
+ "metadata": {},
253
+ "outputs": [],
254
+ "source": [
255
+ "tuner.search(\n",
256
+ " {'image_input': train_images, 'scalar_input': train_feats},\n",
257
+ " ytrain_std,\n",
258
+ " validation_data=({'image_input': test_images, 'scalar_input': test_feats}, ytest_std),\n",
259
+ " epochs=30,\n",
260
+ " batch_size=320\n",
261
+ ")\n"
262
+ ]
263
+ },
264
+ {
265
+ "cell_type": "code",
266
+ "execution_count": 40,
267
+ "id": "9837d503",
268
+ "metadata": {},
269
+ "outputs": [
270
+ {
271
+ "name": "stdout",
272
+ "output_type": "stream",
273
+ "text": [
274
+ "Epoch 1/30\n"
275
+ ]
276
+ },
277
+ {
278
+ "name": "stderr",
279
+ "output_type": "stream",
280
+ "text": [
281
+ "/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",
282
+ " saveable.load_own_variables(weights_store.get(inner_path))\n"
283
+ ]
284
+ },
285
+ {
286
+ "name": "stdout",
287
+ "output_type": "stream",
288
+ "text": [
289
+ "\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",
290
+ "Epoch 2/30\n",
291
+ "\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",
292
+ "Epoch 3/30\n",
293
+ "\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",
294
+ "Epoch 4/30\n",
295
+ "\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",
296
+ "Epoch 5/30\n",
297
+ "\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",
298
+ "Epoch 6/30\n",
299
+ "\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",
300
+ "Epoch 7/30\n",
301
+ "\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",
302
+ "Epoch 8/30\n",
303
+ "\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",
304
+ "Epoch 9/30\n",
305
+ "\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",
306
+ "Epoch 10/30\n",
307
+ "\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",
308
+ "Epoch 11/30\n",
309
+ "\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",
310
+ "Epoch 12/30\n",
311
+ "\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",
312
+ "Epoch 13/30\n",
313
+ "\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",
314
+ "Epoch 14/30\n",
315
+ "\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",
316
+ "Epoch 15/30\n",
317
+ "\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",
318
+ "Epoch 16/30\n",
319
+ "\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",
320
+ "Epoch 17/30\n",
321
+ "\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",
322
+ "Epoch 18/30\n",
323
+ "\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",
324
+ "Epoch 19/30\n",
325
+ "\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",
326
+ "Epoch 20/30\n",
327
+ "\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",
328
+ "Epoch 21/30\n",
329
+ "\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",
330
+ "Epoch 22/30\n",
331
+ "\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",
332
+ "Epoch 23/30\n",
333
+ "\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",
334
+ "Epoch 24/30\n",
335
+ "\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",
336
+ "Epoch 25/30\n",
337
+ "\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",
338
+ "Epoch 26/30\n",
339
+ "\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",
340
+ "Epoch 27/30\n",
341
+ "\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",
342
+ "Epoch 28/30\n",
343
+ "\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",
344
+ "Epoch 29/30\n",
345
+ "\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",
346
+ "Epoch 30/30\n",
347
+ "\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",
348
+ "{'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"
349
+ ]
350
+ }
351
+ ],
352
+ "source": [
353
+ "best_model = tuner.get_best_models(num_models=1)[0]\n",
354
+ "best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]\n",
355
+ "\n",
356
+ "# the history object will contain a record of loss and metric values during training\n",
357
+ "history = best_model.fit({'image_input': train_images, 'scalar_input': train_feats}, ytrain,\n",
358
+ " batch_size=256,\n",
359
+ " epochs=30,\n",
360
+ " validation_data=(\n",
361
+ " {'image_input': test_images, 'scalar_input': test_feats},\n",
362
+ " ytest\n",
363
+ " )\n",
364
+ " )\n",
365
+ "\n",
366
+ "print(best_hps.values)\n"
367
+ ]
368
+ },
369
+ {
370
+ "cell_type": "code",
371
+ "execution_count": 41,
372
+ "id": "b1ac814f",
373
+ "metadata": {},
374
+ "outputs": [],
375
+ "source": [
376
+ "temp_model = best_model"
377
+ ]
378
+ },
379
+ {
380
+ "cell_type": "code",
381
+ "execution_count": 42,
382
+ "id": "9c6ce54d",
383
+ "metadata": {},
384
+ "outputs": [
385
+ {
386
+ "name": "stdout",
387
+ "output_type": "stream",
388
+ "text": [
389
+ "0 image_input <class 'keras.src.layers.core.input_layer.InputLayer'>\n",
390
+ "1 conv2d <class 'keras.src.layers.convolutional.conv2d.Conv2D'>\n",
391
+ "2 max_pooling2d <class 'keras.src.layers.pooling.max_pooling2d.MaxPooling2D'>\n",
392
+ "3 conv2d_1 <class 'keras.src.layers.convolutional.conv2d.Conv2D'>\n",
393
+ "4 max_pooling2d_1 <class 'keras.src.layers.pooling.max_pooling2d.MaxPooling2D'>\n",
394
+ "5 conv2d_2 <class 'keras.src.layers.convolutional.conv2d.Conv2D'>\n",
395
+ "6 max_pooling2d_2 <class 'keras.src.layers.pooling.max_pooling2d.MaxPooling2D'>\n",
396
+ "7 flatten <class 'keras.src.layers.reshaping.flatten.Flatten'>\n",
397
+ "8 scalar_input <class 'keras.src.layers.core.input_layer.InputLayer'>\n",
398
+ "9 concatenate <class 'keras.src.layers.merging.concatenate.Concatenate'>\n",
399
+ "10 dense <class 'keras.src.layers.core.dense.Dense'>\n",
400
+ "11 dropout <class 'keras.src.layers.regularization.dropout.Dropout'>\n",
401
+ "12 dense_1 <class 'keras.src.layers.core.dense.Dense'>\n",
402
+ "13 dropout_1 <class 'keras.src.layers.regularization.dropout.Dropout'>\n",
403
+ "14 dense_2 <class 'keras.src.layers.core.dense.Dense'>\n",
404
+ "15 dropout_2 <class 'keras.src.layers.regularization.dropout.Dropout'>\n",
405
+ "16 output <class 'keras.src.layers.core.dense.Dense'>\n"
406
+ ]
407
+ }
408
+ ],
409
+ "source": [
410
+ "#print layer index to input in the layer views. (conv2d)\n",
411
+ "for i, layer in enumerate(temp_model.layers):\n",
412
+ " print(i, layer.name, type(layer))\n"
413
+ ]
414
+ },
415
+ {
416
+ "cell_type": "markdown",
417
+ "id": "9d461d50",
418
+ "metadata": {},
419
+ "source": [
420
+ "# Making input for velocity x"
421
+ ]
422
+ },
423
+ {
424
+ "cell_type": "code",
425
+ "execution_count": 93,
426
+ "id": "3fdbe35b",
427
+ "metadata": {},
428
+ "outputs": [],
429
+ "source": [
430
+ "data = xr.open_dataset('conv_velocity_x_3031.nc')\n",
431
+ "#data = xr.open_dataset(r'C:\\Users\\marku\\Desktop\\4år\\AML\\Final_project_huggingface\\finalprojectdata\\conv_train_1.nc')"
432
+ ]
433
+ },
434
+ {
435
+ "cell_type": "code",
436
+ "execution_count": 94,
437
+ "id": "4b553b6a",
438
+ "metadata": {},
439
+ "outputs": [
440
+ {
441
+ "name": "stderr",
442
+ "output_type": "stream",
443
+ "text": [
444
+ "/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",
445
+ " dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n"
446
+ ]
447
+ }
448
+ ],
449
+ "source": [
450
+ "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n",
451
+ "feats = np.array([data[feat].values for feat in scalar_feats]).T\n",
452
+ "\n",
453
+ "# 1. Find correct dimension name (e.g., 'obs')\n",
454
+ "dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n",
455
+ "\n",
456
+ "# 2. Find odd (odd) indices using xarray logic\n",
457
+ "grid_ids = data[\"gridCellId\"].values.astype(int)\n",
458
+ "odd_mask = grid_ids % 2 == 1\n",
459
+ "odd_idx = np.where(odd_mask)[0]\n",
460
+ "test_idx = np.where(~odd_mask)[0]\n",
461
+ "\n",
462
+ "# 3. Extract scalar features as a stacked array (samples x features)\n",
463
+ "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n",
464
+ "feats = np.stack([data[feat].values for feat in scalar_feats], axis=-1)\n",
465
+ "\n",
466
+ "# 4. Create train/test splits using .isel and values\n",
467
+ "train_images = data[\"images\"].isel({dim_name: odd_idx}).values\n",
468
+ "test_images = data[\"images\"].isel({dim_name: test_idx}).values\n",
469
+ "\n",
470
+ "train_feats = feats[odd_idx]\n",
471
+ "test_feats = feats[test_idx]\n",
472
+ "\n",
473
+ "ytrain = data[\"THICK\"].isel({dim_name: odd_idx}).values\n",
474
+ "ytest = data[\"THICK\"].isel({dim_name: test_idx}).values\n",
475
+ "\n",
476
+ "ytrain = data.THICK.values[odd_idx]\n",
477
+ "ytest = data.THICK.values[test_idx]\n"
478
+ ]
479
+ },
480
+ {
481
+ "cell_type": "code",
482
+ "execution_count": 95,
483
+ "id": "787706eb",
484
+ "metadata": {},
485
+ "outputs": [
486
+ {
487
+ "name": "stdout",
488
+ "output_type": "stream",
489
+ "text": [
490
+ "(104876, 27, 27)\n",
491
+ "False\n",
492
+ "0\n",
493
+ "76454604\n"
494
+ ]
495
+ }
496
+ ],
497
+ "source": [
498
+ "train_images = data[\"images\"].isel({dim_name: odd_idx}).load().values\n",
499
+ "test_images = data[\"images\"].isel({dim_name: test_idx}).load().values\n",
500
+ "\n",
501
+ "train_images = np.nan_to_num(train_images, nan=0.0)\n",
502
+ "test_images = np.nan_to_num(test_images, nan=0.0)\n",
503
+ "\n",
504
+ "print(train_images.shape) # should be (N, 27, 27)\n",
505
+ "print(np.isnan(train_images).all()) # should be False\n",
506
+ "print(np.isnan(train_images).sum()) # total NaNs\n",
507
+ "print(104876 * 27 *27)\n"
508
+ ]
509
+ },
510
+ {
511
+ "cell_type": "code",
512
+ "execution_count": 96,
513
+ "id": "479d911e",
514
+ "metadata": {},
515
+ "outputs": [],
516
+ "source": [
517
+ "#---------standardize labels-------------------\n",
518
+ "# Compute mean and std from training labels\n",
519
+ "y_mean = ytrain.mean()\n",
520
+ "y_std = ytrain.std()\n",
521
+ "\n",
522
+ "# Standardize ytrain and ytest using training statistics\n",
523
+ "ytrain_std = (ytrain - y_mean) / y_std\n",
524
+ "ytest_std = (ytest - y_mean) / y_std\n",
525
+ "#to convert back to original scale, use:\n",
526
+ "# ypreds_orig = ypreds * y_std + y_mean\n",
527
+ "#----------------------------------------------\n",
528
+ "\n",
529
+ "# ytrain = ytrain.values\n",
530
+ "# ytest = ytest.values\n",
531
+ "\n",
532
+ "# explicitly illustrating standardization\n",
533
+ "def standardizeimg(img, mu, sigma):\n",
534
+ " return (img-mu)/(sigma).astype(np.float32)\n",
535
+ "\n",
536
+ "# save for scaling test dataA\n",
537
+ "mu_train = np.mean(train_images)\n",
538
+ "sigma_train = np.std(train_images)\n",
539
+ "\n",
540
+ "# Standardize pixel distribution to have zero mean and unit variance\n",
541
+ "train_images = standardizeimg(img=train_images, mu=mu_train, sigma=sigma_train)\n",
542
+ "test_images = standardizeimg(img=test_images, mu=np.mean(test_images), sigma=np.std(test_images))\n",
543
+ "\n",
544
+ "# adapt to format required by tensorflow; Using channels_last --> (n_samples, img_rows, img_cols, n_channels)\n",
545
+ "img_rows, img_cols = 27, 27 # input image dimensions\n",
546
+ "train_images = train_images.reshape(train_images.shape[0], img_rows, img_cols, 1)\n",
547
+ "test_images = test_images.reshape(test_images.shape[0], img_rows, img_cols, 1)"
548
+ ]
549
+ },
550
+ {
551
+ "cell_type": "code",
552
+ "execution_count": 97,
553
+ "id": "97402506",
554
+ "metadata": {},
555
+ "outputs": [],
556
+ "source": [
557
+ "velocity_x_train_images = train_images\n",
558
+ "velocity_x_test_feats = test_feats\n",
559
+ "velocity_x_train_feats = train_feats\n",
560
+ "velocity_x_test_images = test_images"
561
+ ]
562
+ },
563
+ {
564
+ "cell_type": "markdown",
565
+ "id": "f08a93af",
566
+ "metadata": {},
567
+ "source": [
568
+ "# Making model for velocity x"
569
+ ]
570
+ },
571
+ {
572
+ "cell_type": "code",
573
+ "execution_count": 48,
574
+ "id": "fa7cb71a",
575
+ "metadata": {},
576
+ "outputs": [],
577
+ "source": [
578
+ "def build_model(hp):\n",
579
+ " IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS = 27, 27, 1\n",
580
+ " NUM_SCALAR_FEATURES = 7\n",
581
+ "\n",
582
+ " image_input = layers.Input(shape=(IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS), name='image_input')\n",
583
+ " x = image_input\n",
584
+ "\n",
585
+ " # Tune number of conv layers: 1 to 3\n",
586
+ " for i in range(hp.Int('num_conv_layers', 1, 3)):\n",
587
+ " filters = hp.Int(f'filters_{i}', 32, 128, step=32)\n",
588
+ " x = layers.Conv2D(filters, (3, 3), activation='relu', padding='same')(x)\n",
589
+ " x = layers.MaxPooling2D((2, 2))(x)\n",
590
+ "\n",
591
+ " x = layers.Flatten()(x)\n",
592
+ "\n",
593
+ " # Scalar branch\n",
594
+ " scalar_input = layers.Input(shape=(NUM_SCALAR_FEATURES,), name='scalar_input')\n",
595
+ " y = scalar_input # you could also add dense layers here\n",
596
+ "\n",
597
+ " # Merge\n",
598
+ " z = layers.concatenate([x, y])\n",
599
+ "\n",
600
+ " # Tune number of dense layers: 1 to 3\n",
601
+ " for i in range(hp.Int('num_dense_layers', 1, 3)):\n",
602
+ " units = hp.Int(f'dense_units_{i}', 64, 256, step=64)\n",
603
+ " z = layers.Dense(units, activation='relu')(z)\n",
604
+ " z = layers.Dropout(hp.Float(f'dropout_{i}', 0.3, 0.7, step=0.1))(z)\n",
605
+ "\n",
606
+ " output = layers.Dense(1, name='output')(z)\n",
607
+ "\n",
608
+ " model = keras.Model(inputs=[image_input, scalar_input], outputs=output)\n",
609
+ "\n",
610
+ " model.compile(\n",
611
+ " optimizer='adam',\n",
612
+ " loss='mse',\n",
613
+ " metrics=['mape']\n",
614
+ " )\n",
615
+ "\n",
616
+ " return model\n"
617
+ ]
618
+ },
619
+ {
620
+ "cell_type": "code",
621
+ "execution_count": 49,
622
+ "id": "45dad959",
623
+ "metadata": {},
624
+ "outputs": [
625
+ {
626
+ "name": "stdout",
627
+ "output_type": "stream",
628
+ "text": [
629
+ "Reloading Tuner from Code/ice_thickness_cnn_velocity_x/tuner0.json\n"
630
+ ]
631
+ }
632
+ ],
633
+ "source": [
634
+ "tuner = kt.RandomSearch(\n",
635
+ " build_model,\n",
636
+ " objective='val_mape',\n",
637
+ " max_trials=1,\n",
638
+ " executions_per_trial=1,\n",
639
+ " directory='Code', #skift directory\n",
640
+ " project_name='ice_thickness_cnn_velocity_x'\n",
641
+ ")\n"
642
+ ]
643
+ },
644
+ {
645
+ "cell_type": "code",
646
+ "execution_count": 50,
647
+ "id": "e81e32f3",
648
+ "metadata": {},
649
+ "outputs": [],
650
+ "source": [
651
+ "tuner.search(\n",
652
+ " {'image_input': train_images, 'scalar_input': train_feats},\n",
653
+ " ytrain_std,\n",
654
+ " validation_data=({'image_input': test_images, 'scalar_input': test_feats}, ytest_std),\n",
655
+ " epochs=30,\n",
656
+ " batch_size=320\n",
657
+ ")\n"
658
+ ]
659
+ },
660
+ {
661
+ "cell_type": "code",
662
+ "execution_count": 51,
663
+ "id": "f0317f53",
664
+ "metadata": {},
665
+ "outputs": [
666
+ {
667
+ "name": "stdout",
668
+ "output_type": "stream",
669
+ "text": [
670
+ "Epoch 1/30\n"
671
+ ]
672
+ },
673
+ {
674
+ "name": "stderr",
675
+ "output_type": "stream",
676
+ "text": [
677
+ "/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",
678
+ " saveable.load_own_variables(weights_store.get(inner_path))\n"
679
+ ]
680
+ },
681
+ {
682
+ "name": "stdout",
683
+ "output_type": "stream",
684
+ "text": [
685
+ "\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",
686
+ "Epoch 2/30\n",
687
+ "\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",
688
+ "Epoch 3/30\n",
689
+ "\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",
690
+ "Epoch 4/30\n",
691
+ "\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",
692
+ "Epoch 5/30\n",
693
+ "\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",
694
+ "Epoch 6/30\n",
695
+ "\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",
696
+ "Epoch 7/30\n",
697
+ "\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",
698
+ "Epoch 8/30\n",
699
+ "\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",
700
+ "Epoch 9/30\n",
701
+ "\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",
702
+ "Epoch 10/30\n",
703
+ "\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",
704
+ "Epoch 11/30\n",
705
+ "\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",
706
+ "Epoch 12/30\n",
707
+ "\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",
708
+ "Epoch 13/30\n",
709
+ "\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",
710
+ "Epoch 14/30\n",
711
+ "\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",
712
+ "Epoch 15/30\n",
713
+ "\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",
714
+ "Epoch 16/30\n",
715
+ "\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",
716
+ "Epoch 17/30\n",
717
+ "\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",
718
+ "Epoch 18/30\n",
719
+ "\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",
720
+ "Epoch 19/30\n",
721
+ "\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",
722
+ "Epoch 20/30\n",
723
+ "\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",
724
+ "Epoch 21/30\n",
725
+ "\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",
726
+ "Epoch 22/30\n",
727
+ "\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",
728
+ "Epoch 23/30\n",
729
+ "\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",
730
+ "Epoch 24/30\n",
731
+ "\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",
732
+ "Epoch 25/30\n",
733
+ "\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",
734
+ "Epoch 26/30\n",
735
+ "\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",
736
+ "Epoch 27/30\n",
737
+ "\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",
738
+ "Epoch 28/30\n",
739
+ "\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",
740
+ "Epoch 29/30\n",
741
+ "\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",
742
+ "Epoch 30/30\n",
743
+ "\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",
744
+ "{'num_conv_layers': 1, 'filters_0': 128, 'num_dense_layers': 1, 'dense_units_0': 192, 'dropout_0': 0.3}\n"
745
+ ]
746
+ }
747
+ ],
748
+ "source": [
749
+ "best_model = tuner.get_best_models(num_models=1)[0]\n",
750
+ "best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]\n",
751
+ "\n",
752
+ "# the history object will contain a record of loss and metric values during training\n",
753
+ "history = best_model.fit({'image_input': train_images, 'scalar_input': train_feats}, ytrain,\n",
754
+ " batch_size=256,\n",
755
+ " epochs=30,\n",
756
+ " validation_data=(\n",
757
+ " {'image_input': test_images, 'scalar_input': test_feats},\n",
758
+ " ytest\n",
759
+ " )\n",
760
+ " )\n",
761
+ "\n",
762
+ "print(best_hps.values)\n"
763
+ ]
764
+ },
765
+ {
766
+ "cell_type": "markdown",
767
+ "id": "441cfd20",
768
+ "metadata": {},
769
+ "source": [
770
+ "Tunable model end."
771
+ ]
772
+ },
773
+ {
774
+ "cell_type": "code",
775
+ "execution_count": 52,
776
+ "id": "74958028",
777
+ "metadata": {},
778
+ "outputs": [],
779
+ "source": [
780
+ "velocity_x_model = best_model"
781
+ ]
782
+ },
783
+ {
784
+ "cell_type": "code",
785
+ "execution_count": 53,
786
+ "id": "758ca058",
787
+ "metadata": {},
788
+ "outputs": [
789
+ {
790
+ "name": "stdout",
791
+ "output_type": "stream",
792
+ "text": [
793
+ "[(None, 27, 27, 1), (None, 7)]\n"
794
+ ]
795
+ }
796
+ ],
797
+ "source": [
798
+ "print(velocity_x_model.input_shape)"
799
+ ]
800
+ },
801
+ {
802
+ "cell_type": "code",
803
+ "execution_count": 54,
804
+ "id": "5a37e40b",
805
+ "metadata": {},
806
+ "outputs": [
807
+ {
808
+ "name": "stdout",
809
+ "output_type": "stream",
810
+ "text": [
811
+ "0 image_input <class 'keras.src.layers.core.input_layer.InputLayer'>\n",
812
+ "1 conv2d <class 'keras.src.layers.convolutional.conv2d.Conv2D'>\n",
813
+ "2 max_pooling2d <class 'keras.src.layers.pooling.max_pooling2d.MaxPooling2D'>\n",
814
+ "3 flatten <class 'keras.src.layers.reshaping.flatten.Flatten'>\n",
815
+ "4 scalar_input <class 'keras.src.layers.core.input_layer.InputLayer'>\n",
816
+ "5 concatenate <class 'keras.src.layers.merging.concatenate.Concatenate'>\n",
817
+ "6 dense <class 'keras.src.layers.core.dense.Dense'>\n",
818
+ "7 dropout <class 'keras.src.layers.regularization.dropout.Dropout'>\n",
819
+ "8 output <class 'keras.src.layers.core.dense.Dense'>\n"
820
+ ]
821
+ }
822
+ ],
823
+ "source": [
824
+ "#print layer index to input in the layer views. (conv2d)\n",
825
+ "for i, layer in enumerate(velocity_x_model.layers):\n",
826
+ " print(i, layer.name, type(layer))\n"
827
+ ]
828
+ },
829
+ {
830
+ "cell_type": "markdown",
831
+ "id": "1d5ef788",
832
+ "metadata": {},
833
+ "source": [
834
+ "# Making input for velocity y"
835
+ ]
836
+ },
837
+ {
838
+ "cell_type": "code",
839
+ "execution_count": 98,
840
+ "id": "627307d2",
841
+ "metadata": {},
842
+ "outputs": [],
843
+ "source": [
844
+ "data = xr.open_dataset('conv_velocity_y_3031.nc')\n",
845
+ "#data = xr.open_dataset(r'C:\\Users\\marku\\Desktop\\4år\\AML\\Final_project_huggingface\\finalprojectdata\\conv_train_1.nc')"
846
+ ]
847
+ },
848
+ {
849
+ "cell_type": "code",
850
+ "execution_count": 99,
851
+ "id": "82f1d503",
852
+ "metadata": {},
853
+ "outputs": [
854
+ {
855
+ "name": "stderr",
856
+ "output_type": "stream",
857
+ "text": [
858
+ "/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",
859
+ " dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n"
860
+ ]
861
+ }
862
+ ],
863
+ "source": [
864
+ "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n",
865
+ "feats = np.array([data[feat].values for feat in scalar_feats]).T\n",
866
+ "\n",
867
+ "# 1. Find correct dimension name (e.g., 'obs')\n",
868
+ "dim_name = list(data.dims.keys())[0] # assumes single major dimension like 'obs'\n",
869
+ "\n",
870
+ "# 2. Find odd (odd) indices using xarray logic\n",
871
+ "grid_ids = data[\"gridCellId\"].values.astype(int)\n",
872
+ "odd_mask = grid_ids % 2 == 1\n",
873
+ "odd_idx = np.where(odd_mask)[0]\n",
874
+ "test_idx = np.where(~odd_mask)[0]\n",
875
+ "\n",
876
+ "# 3. Extract scalar features as a stacked array (samples x features)\n",
877
+ "scalar_feats = ['vx', 'vy', 'v', 'smb', 'z', 's', 'temp']\n",
878
+ "feats = np.stack([data[feat].values for feat in scalar_feats], axis=-1)\n",
879
+ "\n",
880
+ "# 4. Create train/test splits using .isel and values\n",
881
+ "train_images = data[\"images\"].isel({dim_name: odd_idx}).values\n",
882
+ "test_images = data[\"images\"].isel({dim_name: test_idx}).values\n",
883
+ "\n",
884
+ "train_feats = feats[odd_idx]\n",
885
+ "test_feats = feats[test_idx]\n",
886
+ "\n",
887
+ "ytrain = data[\"THICK\"].isel({dim_name: odd_idx}).values\n",
888
+ "ytest = data[\"THICK\"].isel({dim_name: test_idx}).values\n",
889
+ "\n",
890
+ "ytrain = data.THICK.values[odd_idx]\n",
891
+ "ytest = data.THICK.values[test_idx]\n"
892
+ ]
893
+ },
894
+ {
895
+ "cell_type": "code",
896
+ "execution_count": 100,
897
+ "id": "bcd71661",
898
+ "metadata": {},
899
+ "outputs": [
900
+ {
901
+ "name": "stdout",
902
+ "output_type": "stream",
903
+ "text": [
904
+ "(104876, 27, 27)\n",
905
+ "False\n",
906
+ "0\n",
907
+ "76454604\n"
908
+ ]
909
+ }
910
+ ],
911
+ "source": [
912
+ "train_images = data[\"images\"].isel({dim_name: odd_idx}).load().values\n",
913
+ "test_images = data[\"images\"].isel({dim_name: test_idx}).load().values\n",
914
+ "\n",
915
+ "train_images = np.nan_to_num(train_images, nan=0.0)\n",
916
+ "test_images = np.nan_to_num(test_images, nan=0.0)\n",
917
+ "\n",
918
+ "print(train_images.shape) # should be (N, 27, 27)\n",
919
+ "print(np.isnan(train_images).all()) # should be False\n",
920
+ "print(np.isnan(train_images).sum()) # total NaNs\n",
921
+ "print(104876 * 27 *27)\n"
922
+ ]
923
+ },
924
+ {
925
+ "cell_type": "code",
926
+ "execution_count": 101,
927
+ "id": "6280c3d5",
928
+ "metadata": {},
929
+ "outputs": [],
930
+ "source": [
931
+ "#---------standardize labels-------------------\n",
932
+ "# Compute mean and std from training labels\n",
933
+ "y_mean = ytrain.mean()\n",
934
+ "y_std = ytrain.std()\n",
935
+ "\n",
936
+ "# Standardize ytrain and ytest using training statistics\n",
937
+ "ytrain_std = (ytrain - y_mean) / y_std\n",
938
+ "ytest_std = (ytest - y_mean) / y_std\n",
939
+ "#to convert back to original scale, use:\n",
940
+ "# ypreds_orig = ypreds * y_std + y_mean\n",
941
+ "#----------------------------------------------\n",
942
+ "\n",
943
+ "# ytrain = ytrain.values\n",
944
+ "# ytest = ytest.values\n",
945
+ "\n",
946
+ "# explicitly illustrating standardization\n",
947
+ "def standardizeimg(img, mu, sigma):\n",
948
+ " return (img-mu)/(sigma).astype(np.float32)\n",
949
+ "\n",
950
+ "# save for scaling test dataA\n",
951
+ "mu_train = np.mean(train_images)\n",
952
+ "sigma_train = np.std(train_images)\n",
953
+ "\n",
954
+ "# Standardize pixel distribution to have zero mean and unit variance\n",
955
+ "train_images = standardizeimg(img=train_images, mu=mu_train, sigma=sigma_train)\n",
956
+ "test_images = standardizeimg(img=test_images, mu=np.mean(test_images), sigma=np.std(test_images))\n",
957
+ "\n",
958
+ "# adapt to format required by tensorflow; Using channels_last --> (n_samples, img_rows, img_cols, n_channels)\n",
959
+ "img_rows, img_cols = 27, 27 # input image dimensions\n",
960
+ "train_images = train_images.reshape(train_images.shape[0], img_rows, img_cols, 1)\n",
961
+ "test_images = test_images.reshape(test_images.shape[0], img_rows, img_cols, 1)"
962
+ ]
963
+ },
964
+ {
965
+ "cell_type": "code",
966
+ "execution_count": 102,
967
+ "id": "9fd94726",
968
+ "metadata": {},
969
+ "outputs": [],
970
+ "source": [
971
+ "velocity_y_train_images = train_images\n",
972
+ "velocity_y_test_feats = test_feats\n",
973
+ "velocity_y_train_feats = train_feats\n",
974
+ "velocity_y_test_images = test_images"
975
+ ]
976
+ },
977
+ {
978
+ "cell_type": "markdown",
979
+ "id": "d5c11082",
980
+ "metadata": {},
981
+ "source": [
982
+ "# Making model for velocity y"
983
+ ]
984
+ },
985
+ {
986
+ "cell_type": "code",
987
+ "execution_count": 60,
988
+ "id": "6a608f80",
989
+ "metadata": {},
990
+ "outputs": [],
991
+ "source": [
992
+ "def build_model(hp):\n",
993
+ " IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS = 27, 27, 1\n",
994
+ " NUM_SCALAR_FEATURES = 7\n",
995
+ "\n",
996
+ " image_input = layers.Input(shape=(IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS), name='image_input')\n",
997
+ " x = image_input\n",
998
+ "\n",
999
+ " # Tune number of conv layers: 1 to 3\n",
1000
+ " for i in range(hp.Int('num_conv_layers', 1, 3)):\n",
1001
+ " filters = hp.Int(f'filters_{i}', 32, 128, step=32)\n",
1002
+ " x = layers.Conv2D(filters, (3, 3), activation='relu', padding='same')(x)\n",
1003
+ " x = layers.MaxPooling2D((2, 2))(x)\n",
1004
+ "\n",
1005
+ " x = layers.Flatten()(x)\n",
1006
+ "\n",
1007
+ " # Scalar branch\n",
1008
+ " scalar_input = layers.Input(shape=(NUM_SCALAR_FEATURES,), name='scalar_input')\n",
1009
+ " y = scalar_input # you could also add dense layers here\n",
1010
+ "\n",
1011
+ " # Merge\n",
1012
+ " z = layers.concatenate([x, y])\n",
1013
+ "\n",
1014
+ " # Tune number of dense layers: 1 to 3\n",
1015
+ " for i in range(hp.Int('num_dense_layers', 1, 3)):\n",
1016
+ " units = hp.Int(f'dense_units_{i}', 64, 256, step=64)\n",
1017
+ " z = layers.Dense(units, activation='relu')(z)\n",
1018
+ " z = layers.Dropout(hp.Float(f'dropout_{i}', 0.3, 0.7, step=0.1))(z)\n",
1019
+ "\n",
1020
+ " output = layers.Dense(1, name='output')(z)\n",
1021
+ "\n",
1022
+ " model = keras.Model(inputs=[image_input, scalar_input], outputs=output)\n",
1023
+ "\n",
1024
+ " model.compile(\n",
1025
+ " optimizer='adam',\n",
1026
+ " loss='mse',\n",
1027
+ " metrics=['mape']\n",
1028
+ " )\n",
1029
+ "\n",
1030
+ " return model\n"
1031
+ ]
1032
+ },
1033
+ {
1034
+ "cell_type": "code",
1035
+ "execution_count": 61,
1036
+ "id": "3522b27b",
1037
+ "metadata": {},
1038
+ "outputs": [
1039
+ {
1040
+ "name": "stdout",
1041
+ "output_type": "stream",
1042
+ "text": [
1043
+ "Reloading Tuner from Code/ice_thickness_cnn_velocity_y/tuner0.json\n"
1044
+ ]
1045
+ }
1046
+ ],
1047
+ "source": [
1048
+ "tuner = kt.RandomSearch(\n",
1049
+ " build_model,\n",
1050
+ " objective='val_mape',\n",
1051
+ " max_trials=1,\n",
1052
+ " executions_per_trial=1,\n",
1053
+ " directory='Code', #skift directory\n",
1054
+ " project_name='ice_thickness_cnn_velocity_y'\n",
1055
+ ")\n"
1056
+ ]
1057
+ },
1058
+ {
1059
+ "cell_type": "code",
1060
+ "execution_count": 62,
1061
+ "id": "e92ba9a3",
1062
+ "metadata": {},
1063
+ "outputs": [],
1064
+ "source": [
1065
+ "tuner.search(\n",
1066
+ " {'image_input': train_images, 'scalar_input': train_feats},\n",
1067
+ " ytrain_std,\n",
1068
+ " validation_data=({'image_input': test_images, 'scalar_input': test_feats}, ytest_std),\n",
1069
+ " epochs=30,\n",
1070
+ " batch_size=320\n",
1071
+ ")\n"
1072
+ ]
1073
+ },
1074
+ {
1075
+ "cell_type": "code",
1076
+ "execution_count": 63,
1077
+ "id": "49e60ba0",
1078
+ "metadata": {},
1079
+ "outputs": [
1080
+ {
1081
+ "name": "stdout",
1082
+ "output_type": "stream",
1083
+ "text": [
1084
+ "Epoch 1/30\n"
1085
+ ]
1086
+ },
1087
+ {
1088
+ "name": "stderr",
1089
+ "output_type": "stream",
1090
+ "text": [
1091
+ "/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",
1092
+ " saveable.load_own_variables(weights_store.get(inner_path))\n"
1093
+ ]
1094
+ },
1095
+ {
1096
+ "name": "stdout",
1097
+ "output_type": "stream",
1098
+ "text": [
1099
+ "\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",
1100
+ "Epoch 2/30\n",
1101
+ "\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",
1102
+ "Epoch 3/30\n",
1103
+ "\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",
1104
+ "Epoch 4/30\n",
1105
+ "\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",
1106
+ "Epoch 5/30\n",
1107
+ "\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",
1108
+ "Epoch 6/30\n",
1109
+ "\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",
1110
+ "Epoch 7/30\n",
1111
+ "\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",
1112
+ "Epoch 8/30\n",
1113
+ "\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",
1114
+ "Epoch 9/30\n",
1115
+ "\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",
1116
+ "Epoch 10/30\n",
1117
+ "\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",
1118
+ "Epoch 11/30\n",
1119
+ "\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",
1120
+ "Epoch 12/30\n",
1121
+ "\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",
1122
+ "Epoch 13/30\n",
1123
+ "\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",
1124
+ "Epoch 14/30\n",
1125
+ "\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",
1126
+ "Epoch 15/30\n",
1127
+ "\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",
1128
+ "Epoch 16/30\n",
1129
+ "\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",
1130
+ "Epoch 17/30\n",
1131
+ "\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",
1132
+ "Epoch 18/30\n",
1133
+ "\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",
1134
+ "Epoch 19/30\n",
1135
+ "\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",
1136
+ "Epoch 20/30\n",
1137
+ "\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",
1138
+ "Epoch 21/30\n",
1139
+ "\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",
1140
+ "Epoch 22/30\n",
1141
+ "\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",
1142
+ "Epoch 23/30\n",
1143
+ "\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",
1144
+ "Epoch 24/30\n",
1145
+ "\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",
1146
+ "Epoch 25/30\n",
1147
+ "\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",
1148
+ "Epoch 26/30\n",
1149
+ "\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",
1150
+ "Epoch 27/30\n",
1151
+ "\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",
1152
+ "Epoch 28/30\n",
1153
+ "\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",
1154
+ "Epoch 29/30\n",
1155
+ "\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",
1156
+ "Epoch 30/30\n",
1157
+ "\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",
1158
+ "{'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"
1159
+ ]
1160
+ }
1161
+ ],
1162
+ "source": [
1163
+ "best_model = tuner.get_best_models(num_models=1)[0]\n",
1164
+ "best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]\n",
1165
+ "\n",
1166
+ "# the history object will contain a record of loss and metric values during training\n",
1167
+ "history = best_model.fit({'image_input': train_images, 'scalar_input': train_feats}, ytrain,\n",
1168
+ " batch_size=256,\n",
1169
+ " epochs=30,\n",
1170
+ " validation_data=(\n",
1171
+ " {'image_input': test_images, 'scalar_input': test_feats},\n",
1172
+ " ytest\n",
1173
+ " )\n",
1174
+ " )\n",
1175
+ "\n",
1176
+ "print(best_hps.values)\n"
1177
+ ]
1178
+ },
1179
+ {
1180
+ "cell_type": "markdown",
1181
+ "id": "c8822c05",
1182
+ "metadata": {},
1183
+ "source": [
1184
+ "Tunable model end."
1185
+ ]
1186
+ },
1187
+ {
1188
+ "cell_type": "code",
1189
+ "execution_count": 64,
1190
+ "id": "d021de05",
1191
+ "metadata": {},
1192
+ "outputs": [],
1193
+ "source": [
1194
+ "velocity_y_model = best_model"
1195
+ ]
1196
+ },
1197
+ {
1198
+ "cell_type": "code",
1199
+ "execution_count": 65,
1200
+ "id": "9d10475a",
1201
+ "metadata": {},
1202
+ "outputs": [
1203
+ {
1204
+ "name": "stdout",
1205
+ "output_type": "stream",
1206
+ "text": [
1207
+ "[(None, 27, 27, 1), (None, 7)]\n"
1208
+ ]
1209
+ }
1210
+ ],
1211
+ "source": [
1212
+ "print(velocity_y_model.input_shape)"
1213
+ ]
1214
+ },
1215
+ {
1216
+ "cell_type": "code",
1217
+ "execution_count": 66,
1218
+ "id": "9c99bfb8",
1219
+ "metadata": {},
1220
+ "outputs": [
1221
+ {
1222
+ "name": "stdout",
1223
+ "output_type": "stream",
1224
+ "text": [
1225
+ "0 image_input <class 'keras.src.layers.core.input_layer.InputLayer'>\n",
1226
+ "1 conv2d <class 'keras.src.layers.convolutional.conv2d.Conv2D'>\n",
1227
+ "2 max_pooling2d <class 'keras.src.layers.pooling.max_pooling2d.MaxPooling2D'>\n",
1228
+ "3 flatten <class 'keras.src.layers.reshaping.flatten.Flatten'>\n",
1229
+ "4 scalar_input <class 'keras.src.layers.core.input_layer.InputLayer'>\n",
1230
+ "5 concatenate <class 'keras.src.layers.merging.concatenate.Concatenate'>\n",
1231
+ "6 dense <class 'keras.src.layers.core.dense.Dense'>\n",
1232
+ "7 dropout <class 'keras.src.layers.regularization.dropout.Dropout'>\n",
1233
+ "8 dense_1 <class 'keras.src.layers.core.dense.Dense'>\n",
1234
+ "9 dropout_1 <class 'keras.src.layers.regularization.dropout.Dropout'>\n",
1235
+ "10 dense_2 <class 'keras.src.layers.core.dense.Dense'>\n",
1236
+ "11 dropout_2 <class 'keras.src.layers.regularization.dropout.Dropout'>\n",
1237
+ "12 output <class 'keras.src.layers.core.dense.Dense'>\n"
1238
+ ]
1239
+ }
1240
+ ],
1241
+ "source": [
1242
+ "#print layer index to input in the layer views. (conv2d)\n",
1243
+ "for i, layer in enumerate(velocity_y_model.layers):\n",
1244
+ " print(i, layer.name, type(layer))\n"
1245
+ ]
1246
+ },
1247
+ {
1248
+ "cell_type": "markdown",
1249
+ "id": "52a18924",
1250
+ "metadata": {},
1251
+ "source": [
1252
+ "# Making final model"
1253
+ ]
1254
+ },
1255
+ {
1256
+ "cell_type": "code",
1257
+ "execution_count": null,
1258
+ "id": "2557ee4c",
1259
+ "metadata": {},
1260
+ "outputs": [
1261
+ {
1262
+ "name": "stdout",
1263
+ "output_type": "stream",
1264
+ "text": [
1265
+ "\u001b[1m3277/3277\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m5s\u001b[0m 2ms/step\n",
1266
+ "\u001b[1m3278/3278\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m7s\u001b[0m 2ms/step\n",
1267
+ "\u001b[1m3278/3278\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 918us/step\n",
1268
+ "\u001b[1m2925/2925\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m5s\u001b[0m 2ms/step\n",
1269
+ "\u001b[1m2965/2965\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m6s\u001b[0m 2ms/step\n",
1270
+ "\u001b[1m2965/2965\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 985us/step\n"
1271
+ ]
1272
+ },
1273
+ {
1274
+ "ename": "ValueError",
1275
+ "evalue": "all input arrays must have the same shape",
1276
+ "output_type": "error",
1277
+ "traceback": [
1278
+ "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
1279
+ "\u001b[31mValueError\u001b[39m Traceback (most recent call last)",
1280
+ "\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",
1281
+ "\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",
1282
+ "\u001b[31mValueError\u001b[39m: all input arrays must have the same shape"
1283
+ ]
1284
+ }
1285
+ ],
1286
+ "source": [
1287
+ "# 1. Prædiktioner på træningsdata\n",
1288
+ "preds_temp_train = temp_model.predict([temp_train_images, temp_train_feats])\n",
1289
+ "preds_velocity_x_train = velocity_x_model.predict([velocity_x_train_images, velocity_x_train_feats])\n",
1290
+ "preds_velocity_y_train = velocity_y_model.predict([velocity_y_train_images, velocity_y_train_feats])\n",
1291
+ "\n",
1292
+ "# 2. Prædiktioner på testdata \n",
1293
+ "preds_temp_test = temp_model.predict([temp_test_images, temp_test_feats])\n",
1294
+ "preds_velocity_x_test = velocity_x_model.predict([velocity_x_test_images, velocity_x_test_feats])\n",
1295
+ "preds_velocity_y_test = velocity_y_model.predict([velocity_y_test_images, velocity_y_test_feats])\n",
1296
+ "\n",
1297
+ "# 3. Stack input for ensemble\n",
1298
+ "X_stack_train = np.stack([preds_temp_train, preds_velocity_x_train, preds_velocity_y_train], axis=1)\n",
1299
+ "X_stack_test = np.stack([preds_temp_test, preds_velocity_x_test, preds_velocity_y_test], axis=1)\n",
1300
+ "\n",
1301
+ "# 4. Træn ensemble-model\n",
1302
+ "from sklearn.linear_model import LinearRegression\n",
1303
+ "\n",
1304
+ "stack_model = LinearRegression()\n",
1305
+ "stack_model.fit(X_stack_train, ytrain) # Brug den korrekte målvariabel\n",
1306
+ "final_preds = stack_model.predict(X_stack_test)"
1307
+ ]
1308
+ }
1309
+ ],
1310
+ "metadata": {
1311
+ "kernelspec": {
1312
+ "display_name": "appml",
1313
+ "language": "python",
1314
+ "name": "python3"
1315
+ },
1316
+ "language_info": {
1317
+ "codemirror_mode": {
1318
+ "name": "ipython",
1319
+ "version": 3
1320
+ },
1321
+ "file_extension": ".py",
1322
+ "mimetype": "text/x-python",
1323
+ "name": "python",
1324
+ "nbconvert_exporter": "python",
1325
+ "pygments_lexer": "ipython3",
1326
+ "version": "3.12.9"
1327
+ }
1328
+ },
1329
+ "nbformat": 4,
1330
+ "nbformat_minor": 5
1331
+ }