model-training/POET_Training.ipynb
2025-01-15 11:55:24 +01:00

620 lines
52 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## General Information"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook is used to train a simple neural network model to predict the chemistry in the barite benchmark (50x50 grid). The training data is stored in the repository using **git large file storage** and can be downloaded after the installation of git lfs using the `git lfs pull` command.\n",
"\n",
"It is then recommended to create a Python environment using miniconda. The necessary dependencies are contained in `environment.yml` and can be installed using `conda env create -f environment.yml`.\n",
"\n",
"The data set is divided into a design and result part and consists of the iterations of a reference simulation. The design part of the data set contains the chemical concentrations at time $t$ and the result part at time $t+1$, which are to be learned by the model."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup Libraries"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Running Keras in version 3.8.0\n"
]
}
],
"source": [
"import keras\n",
"print(\"Running Keras in version {}\".format(keras.__version__))\n",
"\n",
"import h5py\n",
"import numpy as np\n",
"import pandas as pd\n",
"import time\n",
"import sklearn.model_selection as sk\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Define parameters"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"dtype = \"float32\"\n",
"activation = \"relu\"\n",
"\n",
"lr = 0.001\n",
"batch_size = 512\n",
"epochs = 50 # default 400 epochs\n",
"\n",
"lr_schedule = keras.optimizers.schedules.ExponentialDecay(\n",
" initial_learning_rate=lr,\n",
" decay_steps=2000,\n",
" decay_rate=0.9,\n",
" staircase=True\n",
")\n",
"\n",
"optimizer = keras.optimizers.Adam(learning_rate=lr_schedule)\n",
"loss = keras.losses.Huber()\n",
"\n",
"sample_fraction = 0.8"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup the model"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Model: \"sequential\"</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[1mModel: \"sequential\"\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
"┃<span style=\"font-weight: bold\"> Layer (type) </span>┃<span style=\"font-weight: bold\"> Output Shape </span>┃<span style=\"font-weight: bold\"> Param # </span>┃\n",
"┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
"│ dense (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">1,664</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">16,512</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">12</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">1,548</span> │\n",
"└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
"</pre>\n"
],
"text/plain": [
"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
"┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n",
"┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
"│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m1,664\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_1 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m16,512\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_2 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m12\u001b[0m) │ \u001b[38;5;34m1,548\u001b[0m │\n",
"└─────────────────────────────────┴────────────────────────┴───────────────┘\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Total params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">19,724</span> (77.05 KB)\n",
"</pre>\n"
],
"text/plain": [
"\u001b[1m Total params: \u001b[0m\u001b[38;5;34m19,724\u001b[0m (77.05 KB)\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">19,724</span> (77.05 KB)\n",
"</pre>\n"
],
"text/plain": [
"\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m19,724\u001b[0m (77.05 KB)\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Non-trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (0.00 B)\n",
"</pre>\n"
],
"text/plain": [
"\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"model = keras.Sequential(\n",
" [\n",
" keras.Input(shape = (12,), dtype = \"float32\"),\n",
" keras.layers.Dense(units = 128, activation = \"relu\", dtype = \"float32\"),\n",
" keras.layers.Dense(units = 128, activation = \"relu\", dtype = \"float32\"),\n",
" keras.layers.Dense(units = 12, dtype = \"float32\")\n",
" ]\n",
")\n",
"\n",
"model.compile(optimizer=optimizer, loss = loss)\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Define some functions and helper classes"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def Safelog(val):\n",
" # get range of vector\n",
" if val > 0:\n",
" return np.log10(val)\n",
" elif val < 0:\n",
" return -np.log10(-val)\n",
" else:\n",
" return 0\n",
"\n",
"def Safeexp(val):\n",
" if val > 0:\n",
" return -10 ** -val\n",
" elif val < 0:\n",
" return 10 ** val\n",
" else:\n",
" return 0\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# ? Why does the charge is using another logarithm than the other species\n",
"\n",
"func_dict_in = {\n",
" \"H\" : np.log1p,\n",
" \"O\" : np.log1p,\n",
" \"Charge\" : Safelog,\n",
" \"H_0_\" : np.log1p,\n",
" \"O_0_\" : np.log1p,\n",
" \"Ba\" : np.log1p,\n",
" \"Cl\" : np.log1p,\n",
" \"S_2_\" : np.log1p,\n",
" \"S_6_\" : np.log1p,\n",
" \"Sr\" : np.log1p,\n",
" \"Barite\" : np.log1p,\n",
" \"Celestite\" : np.log1p\n",
"}\n",
"\n",
"func_dict_out = {\n",
" \"H\" : np.expm1,\n",
" \"O\" : np.expm1,\n",
" \"Charge\" : Safeexp,\n",
" \"H_0_\" : np.expm1,\n",
" \"O_0_\" : np.expm1,\n",
" \"Ba\" : np.expm1,\n",
" \"Cl\" : np.expm1,\n",
" \"S_2_\" : np.expm1,\n",
" \"S_6_\" : np.expm1,\n",
" \"Sr\" : np.expm1,\n",
" \"Barite\" : np.expm1,\n",
" \"Celestite\" : np.expm1\n",
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Read data from `.h5` file and convert it to a `pandas.DataFrame`"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"data_file = h5py.File(\"Barite_50_Data_training.h5\")\n",
"\n",
"design = data_file[\"design\"]\n",
"results = data_file[\"result\"]\n",
"\n",
"df_design = pd.DataFrame(np.array(design[\"data\"]).transpose(), columns = design[\"names\"].asstr())\n",
"df_results = pd.DataFrame(np.array(results[\"data\"]).transpose(), columns = results[\"names\"].asstr())\n",
"\n",
"data_file.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Define Scaling and Normalization Functions"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"def log_scale(df_design, df_result, func_dict):\n",
" \n",
" df_design = df_design.copy()\n",
" df_result = df_result.copy()\n",
" \n",
" for key in df_design.keys():\n",
" df_design[key] = np.vectorize(func_dict[key])(df_design[key])\n",
" df_result[key] = np.vectorize(func_dict[key])(df_result[key])\n",
" \n",
" return df_design, df_result\n",
"\n",
"# Get minimum and maximum values for each column\n",
"def get_min_max(df_design, df_result):\n",
" \n",
" min_vals_des = df_design.min()\n",
" max_vals_des = df_design.max()\n",
" \n",
" min_vals_res = df_result.min()\n",
" max_vals_res = df_result.max()\n",
"\n",
" # minimum of input and output data to get global minimum/maximum\n",
" data_min = np.minimum(min_vals_des, min_vals_res).to_dict()\n",
" data_max = np.maximum(max_vals_des, max_vals_res).to_dict()\n",
"\n",
" return data_min, data_max\n",
"\n",
"\n",
"df_design_log, df_results_log = log_scale(df_design, df_results, func_dict_in)\n",
"data_min_log, data_max_log = get_min_max(df_design_log, df_results_log)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"def preprocess(data, func_dict, data_min, data_max):\n",
" data = data.copy()\n",
" for key in data.keys():\n",
" data[key] = (data[key] - data_min[key]) / (data_max[key] - data_min[key])\n",
"\n",
" return data\n",
"\n",
"def postprocess(data, func_dict, data_min, data_max):\n",
" data = data.copy()\n",
" for key in data.keys():\n",
" data[key] = data[key] * (data_max[key] - data_min[key]) + data_min[key]\n",
" data[key] = np.vectorize(func_dict[key])(data[key])\n",
" return data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Preprocess the data"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"pp_design = preprocess(df_design_log, func_dict_in, data_min_log, data_max_log)\n",
"pp_results = preprocess(df_results_log, func_dict_in, data_min_log, data_max_log)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sample the data"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"X_train, X_test, y_train, y_test = sk.train_test_split(pp_design, pp_results, test_size = 0.2)\n",
"X_train, X_val, y_train, y_val = sk.train_test_split(X_train, y_train, test_size = 0.1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Train the model"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 831us/step - loss: 0.0016 - val_loss: 8.9642e-07\n",
"Epoch 2/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 777us/step - loss: 1.2063e-06 - val_loss: 9.3257e-07\n",
"Epoch 3/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 808us/step - loss: 1.3414e-06 - val_loss: 7.4446e-07\n",
"Epoch 4/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m4s\u001b[0m 994us/step - loss: 9.5866e-07 - val_loss: 6.6027e-07\n",
"Epoch 5/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 957us/step - loss: 1.0071e-06 - val_loss: 6.1673e-07\n",
"Epoch 6/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 938us/step - loss: 8.1617e-07 - val_loss: 6.3258e-07\n",
"Epoch 7/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 945us/step - loss: 7.0918e-07 - val_loss: 6.3168e-07\n",
"Epoch 8/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 817us/step - loss: 7.2066e-07 - val_loss: 5.9542e-07\n",
"Epoch 9/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 830us/step - loss: 5.9725e-07 - val_loss: 5.8001e-07\n",
"Epoch 10/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 920us/step - loss: 7.0796e-07 - val_loss: 6.1479e-07\n",
"Epoch 11/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m4s\u001b[0m 1ms/step - loss: 6.1275e-07 - val_loss: 5.6376e-07\n",
"Epoch 12/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 869us/step - loss: 5.5536e-07 - val_loss: 5.7461e-07\n",
"Epoch 13/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 809us/step - loss: 6.4857e-07 - val_loss: 5.9354e-07\n",
"Epoch 14/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 819us/step - loss: 6.9492e-07 - val_loss: 6.1578e-07\n",
"Epoch 15/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 847us/step - loss: 6.0041e-07 - val_loss: 6.6684e-07\n",
"Epoch 16/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 908us/step - loss: 6.9271e-07 - val_loss: 5.5564e-07\n",
"Epoch 17/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 854us/step - loss: 7.0737e-07 - val_loss: 5.6945e-07\n",
"Epoch 18/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 835us/step - loss: 7.5155e-07 - val_loss: 5.5309e-07\n",
"Epoch 19/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 852us/step - loss: 7.4322e-07 - val_loss: 5.5036e-07\n",
"Epoch 20/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 834us/step - loss: 5.8944e-07 - val_loss: 5.6052e-07\n",
"Epoch 21/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 814us/step - loss: 6.7448e-07 - val_loss: 5.4524e-07\n",
"Epoch 22/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 811us/step - loss: 5.7292e-07 - val_loss: 5.9770e-07\n",
"Epoch 23/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 834us/step - loss: 5.7507e-07 - val_loss: 5.4916e-07\n",
"Epoch 24/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 799us/step - loss: 6.3452e-07 - val_loss: 5.4885e-07\n",
"Epoch 25/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 808us/step - loss: 5.9518e-07 - val_loss: 5.4678e-07\n",
"Epoch 26/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 822us/step - loss: 6.6424e-07 - val_loss: 5.4674e-07\n",
"Epoch 27/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 830us/step - loss: 5.9008e-07 - val_loss: 5.4434e-07\n",
"Epoch 28/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 801us/step - loss: 5.4859e-07 - val_loss: 5.4596e-07\n",
"Epoch 29/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 805us/step - loss: 4.9844e-07 - val_loss: 5.4456e-07\n",
"Epoch 30/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 815us/step - loss: 6.4763e-07 - val_loss: 5.4440e-07\n",
"Epoch 31/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 838us/step - loss: 7.3888e-07 - val_loss: 5.4584e-07\n",
"Epoch 32/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 862us/step - loss: 5.2331e-07 - val_loss: 5.4407e-07\n",
"Epoch 33/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 856us/step - loss: 6.9340e-07 - val_loss: 5.4382e-07\n",
"Epoch 34/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 857us/step - loss: 5.5593e-07 - val_loss: 5.4424e-07\n",
"Epoch 35/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 900us/step - loss: 6.2465e-07 - val_loss: 5.4352e-07\n",
"Epoch 36/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 866us/step - loss: 6.0392e-07 - val_loss: 5.4369e-07\n",
"Epoch 37/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 834us/step - loss: 6.3388e-07 - val_loss: 5.4619e-07\n",
"Epoch 38/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 813us/step - loss: 5.6506e-07 - val_loss: 5.4372e-07\n",
"Epoch 39/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 813us/step - loss: 6.9649e-07 - val_loss: 5.4339e-07\n",
"Epoch 40/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 812us/step - loss: 5.0897e-07 - val_loss: 5.4338e-07\n",
"Epoch 41/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 804us/step - loss: 6.1986e-07 - val_loss: 5.4396e-07\n",
"Epoch 42/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 825us/step - loss: 5.5556e-07 - val_loss: 5.4339e-07\n",
"Epoch 43/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 817us/step - loss: 5.9327e-07 - val_loss: 5.4372e-07\n",
"Epoch 44/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 821us/step - loss: 6.8013e-07 - val_loss: 5.4331e-07\n",
"Epoch 45/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 810us/step - loss: 5.3385e-07 - val_loss: 5.4331e-07\n",
"Epoch 46/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 817us/step - loss: 5.8341e-07 - val_loss: 5.4332e-07\n",
"Epoch 47/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 815us/step - loss: 5.8649e-07 - val_loss: 5.4331e-07\n",
"Epoch 48/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 805us/step - loss: 5.4243e-07 - val_loss: 5.4334e-07\n",
"Epoch 49/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 814us/step - loss: 6.0889e-07 - val_loss: 5.4330e-07\n",
"Epoch 50/50\n",
"\u001b[1m3520/3520\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 804us/step - loss: 5.9065e-07 - val_loss: 5.4327e-07\n",
"Training took 150.442538022995 seconds\n"
]
}
],
"source": [
"# measure time\n",
"start = time.time()\n",
"\n",
"history = model.fit(X_train, \n",
" y_train, \n",
" batch_size = batch_size, \n",
" epochs = epochs, \n",
" validation_data = (X_val, y_val)\n",
")\n",
"\n",
"end = time.time()\n",
"\n",
"print(\"Training took {} seconds\".format(end - start))"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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1rp16/weezweVVRU6IUXXtDs2bNDNjCElm9Gy0PQAgDAKkEHrZEjRza7Nnr0aF122WVas2aN7rzzzpAMDKHFh0oDAGC9kO3R6tu3rzZu3Biq7hBibjbDAwBguZAErePHj+tXv/qVunXrForuYAJXdLQkghYAAFYKeumwc+fOfpvhDcPQ4cOH1aFDB7344oshHRxCh6VDAACsF3TQeuqpp/yCVlRUlC644AL17duXzzpsx7xBq7HJUGOToeio1t85CgAAQiPooHXHHXeYMAyYzRu0pFPLh+e5om0cDQAAkSHgoPX+++8H1O6KK65o82BgHu85WhJBCwAAqwQctL797W/L4XDIMAxJ8i0feh97r3FgafvkjP5iqbC+sVGS077BAAAQIQIOWpWVlb4/G4ahjIwMFRUVqXv37qYMDKHlcDjkiolSw8km3nkIAIBFAg5apwcqh8Ohbt26EbTOIe5oghYAAFbiQ6UjCEc8AABgLYJWBHFxOjwAAJb6SkHry+dpof3jY3gAALBWwHu0evfu7Resjh8/rhtvvFEul8uvXXl5eehGh5BiRgsAAGsFHLRuvvlmv8cjR44M9VhgMm/QqmePFgAAlgg4aBUWFpo5DljAe2gpM1oAAFiDzfARhKVDAACsFVDQGjZsmDZv3nzWdocPH9a8efO0cOHCrzwwhJ4r5tTH7hC0AACwRkBLh//93/+tMWPGKC4uTjfddJOysrKUkpKi2NhYff755/rwww+1adMmFRUV6YYbbtDPf/5zs8eNNvAtHbJHCwAASwQUtO68807l5ubqD3/4g9asWaPnnntOhw4dknTqiIf09HQNHTpUW7du1aWXXmrmePEVcLwDAADWCngzvMvl0vjx4zV+/HhJUm1trY4fP66uXbvK6eQDis8F7NECAMBaAQet08XHxys+Pj6UY4HJWDoEAMBavOswgvjO0WJGCwAASxC0IghLhwAAWIugFUEIWgAAWIugFUG+2KPVaPNIAACIDEEHrU8++USffvqp7/GWLVs0efJkLV26NKQDQ+gxowUAgLWCDlrjx4/Xm2++KUmqrq7WkCFDtGXLFj3yyCOaM2dOyAeI0OEcLQAArBV00Prggw901VVXSZL+93//VxkZGdq8ebN+97vfafny5aEeH0LIN6PF8Q4AAFgi6KDl8XjkdrslSRs3btRNN90kSerVq5eqqqpCOzqElG+PFjNaAABYIuigddlll2nJkiV66623VFJSomHDhkmS9u/fr65du4Z8gAgdztECAMBaQQetefPm6dlnn9XgwYP1ve99T1deeaUkacOGDb4lRbRPBC0AAKwV9EfwDB48WDU1Naqrq1Pnzp1913/0ox+pQ4cOIR0cQoulQwAArBX0jNbx48dVX1/vC1l79uzR/PnztWvXLl144YUhHyBCh+MdAACwVtBBa+TIkVqxYoUk6dChQ+rbt69++ctf6uabb9bixYtDPkCEDu86BADAWkEHrfLycg0YMECS9Ic//EGJiYnas2ePVqxYoWeeeSbkA0TocI4WAADWCjpoHTt2THFxcZKk4uJi3XrrrYqKitLVV1+tPXv2BD2ARYsWKS0tTbGxscrMzNRbb711xvalpaXKzMxUbGysLrnkEi1ZsqRZm7Vr1yo9PV1ut1vp6elat25d0Pd96aWXNHToUCUkJMjhcGjbtm3N+qivr9f999+vhIQEdezYUTfddJPfqfntjSs6WhJBCwAAqwQdtL7xjW9o/fr1+uSTT/T6668rJydHknTgwAF16tQpqL7WrFmjyZMna8aMGaqoqNCAAQM0fPhw7d27t8X2lZWVGjFihAYMGKCKigo98sgjeuCBB7R27Vpfm7KyMo0dO1a5ubnavn27cnNzNWbMGL3zzjtB3ffo0aPq37+/nnjiiVbHP3nyZK1bt06rV6/Wpk2bdOTIEd1www1qbKefJcjSIQAA1gr6XYc/+clPNH78eE2ZMkXXXnutsrOzJZ2a3erdu3dQfT355JO68847ddddd0mS5s+fr9dff12LFy/W3Llzm7VfsmSJLrroIs2fP1+S9K1vfUvvvfeefvGLX2jUqFG+PoYMGaLp06dLkqZPn67S0lLNnz9fq1atCvi+ubm5kqR//vOfLY69trZWy5Yt029/+1t997vflSS9+OKLSk1N1caNGzV06NAWX1dfX6/6+nrf47q6OkmnDoL1eDyBFS4A3r6+3GeUTgXA+pONIb0XWq43zEO9rUfNrUW9rdWWegfaNuigNXr0aF1zzTWqqqrynaElSdddd51uueWWgPtpaGjQ1q1bNW3aNL/rOTk52rx5c4uvKSsr882geQ0dOlTLli2Tx+OR0+lUWVmZpkyZ0qyNN5y15b4t2bp1qzwej994UlJSfB9J1FrQmjt3rmbPnt3senFxsSnHY5SUlPj+fLBekmJ0ouGkioqKQn4v+Ncb5qPe1qPm1qLe1gqm3seOHQuoXdBBS5KSkpKUlJSkTz/9VA6HQ1//+teDPqy0pqZGjY2NSkxM9LuemJio6urqFl9TXV3dYvuTJ0+qpqZGycnJrbbx9tmW+7Y2FpfL5XeWWCD9TJ8+XQUFBb7HdXV1Sk1NVU5OTtBLr2fi8XhUUlKiIUOGyOl0SpJqjtRrdnmpGg2Hhg8fLofDEbL7RbqW6g3zUG/rUXNrUW9rtaXe3hWpswk6aDU1NemnP/2pfvnLX+rIkSOSpLi4OE2dOlUzZsxQVFRw275O/2VvGMYZA0BL7U+/Hkifwd43UGfrx+12+z4r8sucTqcp/5i+3G+H2C+NMyparpjokN8v0pn1c0TLqLf1qLm1qLe1gql3oO2CDlozZszQsmXL9MQTT6h///4yDEN/+9vfNGvWLJ04cUKPPfZYQP0kJCQoOjq62ezPgQMHms02eSUlJbXYPiYmxvc5i6218fbZlvu2NpaGhgZ9/vnnfrNaBw4cUL9+/QLux0re4x2kU+88dBO0AAAwVdDvOnzhhRf061//Wvfcc4+uuOIKXXnllZo4caKee+45LV++POB+XC6XMjMzm62HlpSUtBpUsrOzm7UvLi5WVlaWL1m21sbbZ1vu25LMzEw5nU6/fqqqqvTBBx+026Dl/QgeiSMeAACwQtAzWgcPHlSvXr2aXe/Vq5cOHjwYVF8FBQXKzc1VVlaWsrOztXTpUu3du1f5+fmSTu1n2rdvn+8k+vz8fC1YsEAFBQXKy8tTWVmZli1b5ns3oSRNmjRJAwcO1Lx58zRy5Ei9/PLL2rhxozZt2hTwfb3f5969e7V//35J0q5duyR9sT8tPj5ed955p6ZOnaquXbuqS5cuevDBB3X55Zf73oXY3kRFOeSMdsjTaHDEAwAAFgg6aF155ZVasGBBs1PgFyxY4PcuxECMHTtWn332mebMmaOqqiplZGSoqKhI3bt3l3RqhujLZ1ulpaWpqKhIU6ZM0cKFC5WSkqJnnnnGd7SDJPXr10+rV6/Wo48+qpkzZ6pHjx5as2aN+vbtG/B9JWnDhg36wQ9+4Hs8btw4SVJhYaFmzZolSXrqqacUExOjMWPG6Pjx47ruuuu0fPlyRUe33yU5V3SUPI2NzGgBAGABh+HdTR6g0tJSXX/99brooouUnZ0th8OhzZs365NPPlFRUZHv43kQmLq6OsXHx6u2tjbk7zosKirSiBEj/Dbs9Z5TrM+PeVQyZaB6JsaF7H6RrrV6wxzU23rU3FrU21ptqXegv7+D3qM1aNAg/f3vf9ctt9yiQ4cO6eDBg7r11lu1a9cuQtY5wHs6fD0zWgAAmK5N52ilpKQ0e3fhJ598oh/+8If6zW9+E5KBwRx8DA8AANYJekarNQcPHtQLL7wQqu5gEu87D9mjBQCA+UIWtHBu8B5SStACAMB8BK0I41s6JGgBAGA6glaEcUezRwsAAKsEvBn+1ltvPePzhw4d+qpjgQWY0QIAwDoBB634+PizPv/973//Kw8I5iJoAQBgnYCD1vPPP2/mOGAR77sO61k6BADAdOzRijDMaAEAYB2CVoQhaAEAYB2CVoQhaAEAYB2CVoTxnQzf2GjzSAAACH8ErQjjZkYLAADLELQiDEuHAABYh6AVYVycDA8AgGUIWhHGO6NV7yFoAQBgNoJWhPEFLWa0AAAwHUErwrBHCwAA6xC0IoxvjxZBCwAA0xG0IgwzWgAAWIegFWF852ixRwsAANMRtCIMM1oAAFiHoBVhXNHRkghaAABYgaAVYVwsHQIAYBmCVoRh6RAAAOsQtCKM93iHeoIWAACmI2hFmC9mtBptHgkAAOGPoBVhON4BAADrELQijJs9WgAAWIagFWG8S4dNhnSSWS0AAExF0Iow3qAlsXwIAIDZCFoRxvuuQ4nlQwAAzEbQijAx0VGKcpz6M0ELAABzEbQikHf5kLO0AAAwF0ErAnmXD9mjBQCAuQhaEcgVwwdLAwBgBYJWBOIsLQAArEHQikAuTocHAMASBK0I5NujxYwWAACmImhFIBdLhwAAWIKgFYE43gEAAGsQtCIQxzsAAGANglYEYukQAABrELQiEEELAABrELQi0BdBq9HmkQAAEN4IWhHIzR4tAAAsQdCKQCwdAgBgDYJWBOJ4BwAArEHQikCcDA8AgDUIWhGIGS0AAKxB0IpAfKg0AADWIGhFIDbDAwBgDYJWBGKPFgAA1iBoRSA3M1oAAFiCoBWB2KMFAIA1CFoRiD1aAABYw/agtWjRIqWlpSk2NlaZmZl66623zti+tLRUmZmZio2N1SWXXKIlS5Y0a7N27Vqlp6fL7XYrPT1d69atC/q+hmFo1qxZSklJ0XnnnafBgwdr586dfm0GDx4sh8Ph9zVu3Lg2VMFaruhoSQQtAADMZmvQWrNmjSZPnqwZM2aooqJCAwYM0PDhw7V3794W21dWVmrEiBEaMGCAKioq9Mgjj+iBBx7Q2rVrfW3Kyso0duxY5ebmavv27crNzdWYMWP0zjvvBHXfn/3sZ3ryySe1YMECvfvuu0pKStKQIUN0+PBhvzHl5eWpqqrK9/Xss8+GuEqh5ztHi6VDAABMZWvQevLJJ3XnnXfqrrvu0re+9S3Nnz9fqampWrx4cYvtlyxZoosuukjz58/Xt771Ld1111364Q9/qF/84he+NvPnz9eQIUM0ffp09erVS9OnT9d1112n+fPnB3xfwzA0f/58zZgxQ7feeqsyMjL0wgsv6NixY/rd737nN6YOHTooKSnJ9xUfHx/6QoUYS4cAAFgjxq4bNzQ0aOvWrZo2bZrf9ZycHG3evLnF15SVlSknJ8fv2tChQ7Vs2TJ5PB45nU6VlZVpypQpzdp4g1Yg962srFR1dbXfvdxutwYNGqTNmzfr7rvv9l1fuXKlXnzxRSUmJmr48OEqLCxUXFxcq993fX296uvrfY/r6uokSR6PRx6Pp9XXBcvbV0t9RutUwKr3NIb0npHsTPVG6FFv61Fza1Fva7Wl3oG2tS1o1dTUqLGxUYmJiX7XExMTVV1d3eJrqqurW2x/8uRJ1dTUKDk5udU23j4Dua/3v1tqs2fPHt/j2267TWlpaUpKStIHH3yg6dOna/v27SopKWn1+547d65mz57d7HpxcbE6dOjQ6uvaqqWx/POwJMWo9vARFRUVhfyekexMP3uEHvW2HjW3FvW2VjD1PnbsWEDtbAtaXg6Hw++xYRjNrp2t/enXA+kzFG3y8vJ8f87IyFDPnj2VlZWl8vJy9enTp8XxT58+XQUFBb7HdXV1Sk1NVU5Ojjp16tTia9rC4/GopKREQ4YMkdPp9Htu5/46PfXB24pxxWrEiEEhu2ckO1O9EXrU23rU3FrU21ptqbd3RepsbAtaCQkJio6ObjZ7deDAgWYzSV5JSUktto+JiVHXrl3P2MbbZyD3TUpKknRqZis5OTmgsUlSnz595HQ6tXv37laDltvtltvtbnbd6XSa8o+ppX47xroknTpHi3/AoWXWzxEto97Wo+bWot7WCqbegbazbTO8y+VSZmZms2m6kpIS9evXr8XXZGdnN2tfXFysrKws3zfcWhtvn4Hc17sc+OU2DQ0NKi0tbXVskrRz5055PB6/cNYesRkeAABr2Lp0WFBQoNzcXGVlZSk7O1tLly7V3r17lZ+fL+nUMtu+ffu0YsUKSVJ+fr4WLFiggoIC5eXlqaysTMuWLdOqVat8fU6aNEkDBw7UvHnzNHLkSL388svauHGjNm3aFPB9HQ6HJk+erMcff1w9e/ZUz5499fjjj6tDhw4aP368JOnjjz/WypUrNWLECCUkJOjDDz/U1KlT1bt3b/Xv39+qErYJJ8MDAGANW4PW2LFj9dlnn2nOnDmqqqpSRkaGioqK1L17d0lSVVWV39lWaWlpKioq0pQpU7Rw4UKlpKTomWee0ahRo3xt+vXrp9WrV+vRRx/VzJkz1aNHD61Zs0Z9+/YN+L6S9NBDD+n48eOaOHGiPv/8c/Xt21fFxcW+dxS6XC698cYbevrpp3XkyBGlpqbq+uuvV2FhoaL/cyBoe+X9UGlPo6GmJkNRUa3viQMAAG1n+2b4iRMnauLEiS0+t3z58mbXBg0apPLy8jP2OXr0aI0ePbrN95VOzWrNmjVLs2bNavH51NRUlZaWnvEe7ZV3Rks6NasVG9W+gyEAAOcq2z+CB9Y7PWgBAABzELQikHfpUGJDPAAAZiJoRSCHw+ELWwQtAADMQ9CKUBzxAACA+QhaEYojHgAAMB9BK0KxdAgAgPkIWhHKO6NVT9ACAMA0BK0IxR4tAADMR9CKUL6lQ/ZoAQBgGoJWhGJGCwAA8xG0IhRBCwAA8xG0IpTbd7xDo80jAQAgfBG0IpR3j1a9hxktAADMQtCKUBxYCgCA+QhaEYo9WgAAmI+gFaF8S4cELQAATEPQilDMaAEAYD6CVoRijxYAAOYjaEUoZrQAADAfQStCuaMJWgAAmI2gFaGY0QIAwHwErQjFHi0AAMxH0IpQLpYOAQAwHUErQrlioiVxjhYAAGYiaEUolg4BADAfQStCuX2b4RttHgkAAOGLoBWheNchAADmI2hFKJYOAQAwH0ErQnFgKQAA5iNoRSiWDgEAMB9BK0IRtAAAMB9BK0KxRwsAAPMRtCKU92R4DiwFAMA8BK0IxdIhAADmI2hFqC8vHRqGYfNoAAAITwStCOWOPvVZh4YhnWwiaAEAYAaCVoTyzmhJLB8CAGAWglaEImgBAGA+glaEio5yKDrKIYkjHgAAMAtBK4K5+BgeAABMRdCKYN7lQ87SAgDAHAStCMZZWgAAmIugFcF8S4fs0QIAwBQErQjmZkYLAABTEbQi2Bd7tBptHgkAAOGJoBXB2KMFAIC5CFoRjOMdAAAwF0Ergn35g6UBAEDoEbQiGOdoAQBgLoJWBGPpEAAAcxG0Ihib4QEAMBdBK4KxRwsAAHMRtCIYB5YCAGAuglYEY48WAADmImhFMJYOAQAwV4zdA4B9YqIdkqT/q6pT2cef6aq0LoqOcvi1aWwytKXyoA4cPqEL42JNbQMAQLghaEWo1z6o0m/L9kqS/rq7Rn/dXaPk+FgV3piuYRnJvjaz//ihqmpP+F5nVhsp8DBmZfgLtM07lQe1tcahrpUHlf2NC8+ZcVNvahnouM9W8/Y67vY0Jurd/tpYwWEYhmH5XeFTV1en+Ph41dbWqlOnTiHr1+PxqKioSCNGjJDT6fR77rUPqnTPi+U6/Qfv/eu3+PY+kmRZm2EZyQGHMSvDXyhDZHsbE+NmTIy7/bVpj2MK93F7nel3ZmsC/f1te9BatGiRfv7zn6uqqkqXXXaZ5s+frwEDBrTavrS0VAUFBdq5c6dSUlL00EMPKT8/36/N2rVrNXPmTH388cfq0aOHHnvsMd1yyy1B3dcwDM2ePVtLly7V559/rr59+2rhwoW67LLLfG3q6+v14IMPatWqVTp+/Liuu+46LVq0SN26dQv4+7c6aDU2Gbpm3p/9/vJ9mUNSYie3JIeq68xvkxQfq5nXp+ve3wUWxtpTQAykDeNm3O1xTIybcTNu/7AVtkFrzZo1ys3N1aJFi9S/f389++yz+vWvf60PP/xQF110UbP2lZWVysjIUF5enu6++2797W9/08SJE7Vq1SqNGjVKklRWVqYBAwbof/7nf3TLLbdo3bp1+slPfqJNmzapb9++Ad933rx5euyxx7R8+XJ985vf1E9/+lP99a9/1a5duxQXFydJuueee/THP/5Ry5cvV9euXTV16lQdPHhQW7duVXR0dEA1sDpolX38mb733Nshu08onOeM0nFP6xvyO8XGaPKQnppfslt1J0622i4+NkZyOFR73NNqm/PPi5HD4dDnx1pv07nDqXqdqU2XDk7J4dDBow2ttun6NZcWfq+P7v1duT47U7uOTkmOs7dxOPTZkdbbJHR0SQ6p5iu2ueBrbi3/wXc04fktZ+7ray5JZ7lfiNpc8J82/z5Dmwvj3Fp5V1+Nf+4d/ftI/Vfq61QbRwD9nLnNhXFurcq7WuOee1v/PvzV+rKyzbk87tU/ulpjlzJuxt1yG+//wd/08LV+y4hhG7T69u2rPn36aPHixb5r3/rWt3TzzTdr7ty5zdo//PDD2rBhgz766CPftfz8fG3fvl1lZWWSpLFjx6qurk6vvvqqr82wYcPUuXNnrVq1KqD7GoahlJQUTZ48WQ8//LCkU7NXiYmJmjdvnu6++27V1tbqggsu0G9/+1uNHTtWkrR//36lpqaqqKhIQ4cODagGVgetl7ft06TV20J2HwAAzjWr8q5Wdo+uvsdmBi3bjndoaGjQ1q1blZOT43c9JydHmzdvbvE1ZWVlzdoPHTpU7733njwezxnbePsM5L6VlZWqrq72a+N2uzVo0CBfm61bt8rj8fi1SUlJUUZGRqvjl04Ftrq6Or8v6dQPOdRfLfXbtcO5+f6Hi7qcZ/cQ2qSjO7CZzfbGHX1uviM0ph0eWHOOlpJxW+xcfRP2uTruqkNHA/qdGcjv2bOx7bduTU2NGhsblZiY6Hc9MTFR1dXVLb6murq6xfYnT55UTU2NkpOTW23j7TOQ+3r/u6U2e/bs8bVxuVzq3LlzwOOXpLlz52r27NnNrhcXF6tDhw6tvq6tSkpK/B43GdL5rmgdapC+WLH+MkPxp1ayVGtBm44x0tGTZ/+X2ifuiPYePPdCy5CkBq3fc+6Ne3i3k+fkuG9IbWx3477xovY3pkAwbmvdxLgt9Y+d21T0aUWz66f/zjyTY8eOBdTO9ukNh8P/l6xhGM2una396dcD6TNUbU53tjbTp09XQUGB73FdXZ1SU1OVk5MT8qXDkpISDRkypNk0qPPif+n+1dtPjfdL1x3/+c/HRl0pSZa0mXvrFXr8tV36V119s42L3nZJ8W49dscAvf3UW2dsl9jp1Np8e2nDuBl3exwT42bcjNut+8YObLZHq7Xfma3xrkidjW0T7QkJCYqOjm42+3PgwIFmM0leSUlJLbaPiYlR165dz9jG22cg901KSpKks7ZpaGjQ559/HvD4pVNLkJ06dfL7kiSn0xnyr9b6veHb3bT49j5Kio/1r298rBbf3kc3fLubZW1u6pOqWTedeifn6fHU+7jwxsvU8Tz3WdvNuimjXbVh3Iy7PY6JcTNuxn2ZYt2ugH9nnu337NnYvhk+MzNTixYt8l1LT0/XyJEjW90M/8c//lEffvih79o999yjbdu2+W2GP3z4sIqKinxthg8frvPPP99vM/yZ7uvdDD9lyhQ99NBDkk7t7brwwgubbYZ/8cUXNWbMGElSVVWVunXr1q43w39Zezo4LtzPamlvY2LcjIlxt7827XFM4T5ur7B916H3mIUlS5YoOztbS5cu1XPPPaedO3eqe/fumj59uvbt26cVK1ZI+uJ4h7vvvlt5eXkqKytTfn6+3/EOmzdv1sCBA/XYY49p5MiRevnll/Xoo4+2eLxDa/eVTh3vMHfuXD3//PPq2bOnHn/8cf3lL39pdrzDK6+8ouXLl6tLly568MEH9dlnn7Xr4x3as3P59OGy/3dAxW+9o5wBfc+Zk8qpN7UMZtxnq3l7HXd7GhP1bn9tvMwMWjJstnDhQqN79+6Gy+Uy+vTpY5SWlvqemzBhgjFo0CC/9n/5y1+M3r17Gy6Xy7j44ouNxYsXN+vz97//vXHppZcaTqfT6NWrl7F27dqg7msYhtHU1GQUFhYaSUlJhtvtNgYOHGjs2LHDr83x48eN++67z+jSpYtx3nnnGTfccIOxd+/eoL7/2tpaQ5JRW1sb1OvOpqGhwVi/fr3R0NAQ0n7RMuptLeptPWpuLeptrbbUO9Df37afDB/pmNEKD9TbWtTbetTcWtTbWmF5jhYAAEC4I2gBAACYhKAFAABgEoIWAACASQhaAAAAJiFoAQAAmISgBQAAYBKCFgAAgEli7B5ApPOeFxvop4AHyuPx6NixY6qrq+OwOwtQb2tRb+tRc2tRb2u1pd7e39tnO/edoGWzw4cPS5JSU1NtHgkAAAjW4cOHFR8f3+rzfASPzZqamrR//37FxcXJ4Wj5wy7boq6uTqmpqfrkk09C+tE+aBn1thb1th41txb1tlZb6m0Yhg4fPqyUlBRFRbW+E4sZLZtFRUWpW7dupvXfqVMn/pFaiHpbi3pbj5pbi3pbK9h6n2kmy4vN8AAAACYhaAEAAJiEoBWm3G63CgsL5Xa77R5KRKDe1qLe1qPm1qLe1jKz3myGBwAAMAkzWgAAACYhaAEAAJiEoAUAAGASghYAAIBJCFphatGiRUpLS1NsbKwyMzP11ltv2T2ksPDXv/5VN954o1JSUuRwOLR+/Xq/5w3D0KxZs5SSkqLzzjtPgwcP1s6dO+0ZbBiYO3euvvOd7yguLk4XXnihbr75Zu3atcuvDTUPncWLF+uKK67wHdqYnZ2tV1991fc8tTbP3Llz5XA4NHnyZN816h1as2bNksPh8PtKSkryPW9WvQlaYWjNmjWaPHmyZsyYoYqKCg0YMEDDhw/X3r177R7aOe/o0aO68sortWDBghaf/9nPfqYnn3xSCxYs0LvvvqukpCQNGTLE95mWCE5paanuvfdevf322yopKdHJkyeVk5Ojo0eP+tpQ89Dp1q2bnnjiCb333nt67733dO2112rkyJG+XzbU2hzvvvuuli5dqiuuuMLvOvUOvcsuu0xVVVW+rx07dvieM63eBsLOVVddZeTn5/td69WrlzFt2jSbRhSeJBnr1q3zPW5qajKSkpKMJ554wnftxIkTRnx8vLFkyRIbRhh+Dhw4YEgySktLDcOg5lbo3Lmz8etf/5pam+Tw4cNGz549jZKSEmPQoEHGpEmTDMPg77YZCgsLjSuvvLLF58ysNzNaYaahoUFbt25VTk6O3/WcnBxt3rzZplFFhsrKSlVXV/vV3u12a9CgQdQ+RGprayVJXbp0kUTNzdTY2KjVq1fr6NGjys7OptYmuffee3X99dfru9/9rt916m2O3bt3KyUlRWlpaRo3bpz+8Y9/SDK33nyodJipqalRY2OjEhMT/a4nJiaqurraplFFBm99W6r9nj177BhSWDEMQwUFBbrmmmuUkZEhiZqbYceOHcrOztaJEyf0ta99TevWrVN6errvlw21Dp3Vq1ervLxc7777brPn+Lsden379tWKFSv0zW9+U//617/005/+VP369dPOnTtNrTdBK0w5HA6/x4ZhNLsGc1B7c9x33316//33tWnTpmbPUfPQufTSS7Vt2zYdOnRIa9eu1YQJE1RaWup7nlqHxieffKJJkyapuLhYsbGxrbaj3qEzfPhw358vv/xyZWdnq0ePHnrhhRd09dVXSzKn3iwdhpmEhARFR0c3m706cOBAs6SO0PK+e4Xah97999+vDRs26M0331S3bt1816l56LlcLn3jG99QVlaW5s6dqyuvvFJPP/00tQ6xrVu36sCBA8rMzFRMTIxiYmJUWlqqZ555RjExMb6aUm/zdOzYUZdffrl2795t6t9vglaYcblcyszMVElJid/1kpIS9evXz6ZRRYa0tDQlJSX51b6hoUGlpaXUvo0Mw9B9992nl156SX/+85+Vlpbm9zw1N59hGKqvr6fWIXbddddpx44d2rZtm+8rKytLt912m7Zt26ZLLrmEepusvr5eH330kZKTk839+/2VttKjXVq9erXhdDqNZcuWGR9++KExefJko2PHjsY///lPu4d2zjt8+LBRUVFhVFRUGJKMJ5980qioqDD27NljGIZhPPHEE0Z8fLzx0ksvGTt27DC+973vGcnJyUZdXZ3NIz833XPPPUZ8fLzxl7/8xaiqqvJ9HTt2zNeGmofO9OnTjb/+9a9GZWWl8f777xuPPPKIERUVZRQXFxuGQa3N9uV3HRoG9Q61qVOnGn/5y1+Mf/zjH8bbb79t3HDDDUZcXJzvd6NZ9SZohamFCxca3bt3N1wul9GnTx/f2+Hx1bz55puGpGZfEyZMMAzj1FuECwsLjaSkJMPtdhsDBw40duzYYe+gz2Et1VqS8fzzz/vaUPPQ+eEPf+j7340LLrjAuO6663whyzCotdlOD1rUO7TGjh1rJCcnG06n00hJSTFuvfVWY+fOnb7nzaq3wzAM46vNiQEAAKAl7NECAAAwCUELAADAJAQtAAAAkxC0AAAATELQAgAAMAlBCwAAwCQELQAAAJMQtAAAAExC0AKAdsbhcGj9+vV2DwNACBC0AOBL7rjjDjkcjmZfw4YNs3toAM5BMXYPAADam2HDhun555/3u+Z2u20aDYBzGTNaAHAat9utpKQkv6/OnTtLOrWst3jxYg0fPlznnXee0tLS9Pvf/97v9Tt27NC1116r8847T127dtWPfvQjHTlyxK/Nb37zG1122WVyu91KTk7Wfffd5/d8TU2NbrnlFnXo0EE9e/bUhg0bzP2mAZiCoAUAQZo5c6ZGjRql7du36/bbb9f3vvc9ffTRR5KkY8eOadiwYercubPeffdd/f73v9fGjRv9gtTixYt177336kc/+pF27NihDRs26Bvf+IbfPWbPnq0xY8bo/fff14gRI3Tbbbfp4MGDln6fAELAAAD4TJgwwYiOjjY6duzo9zVnzhzDMAxDkpGfn+/3mr59+xr33HOPYRiGsXTpUqNz587GkSNHfM//6U9/MqKioozq6mrDMAwjJSXFmDFjRqtjkGQ8+uijvsdHjhwxHA6H8eqrr4bs+wRgDfZoAcBp/uu//kuLFy/2u9alSxffn7Ozs/2ey87O1rZt2yRJH330ka688kp17NjR93z//v3V1NSkXbt2yeFwaP/+/bruuuvOOIYrrrjC9+eOHTsqLi5OBw4caOu3BMAmBC0AOE3Hjh2bLeWdjcPhkCQZhuH7c0ttzjvvvID6czqdzV7b1NQU1JgA2I89WgAQpLfffrvZ4169ekmS0tPTtW3bNh09etT3/N/+9jdFRUXpm9/8puLi4nTxxRfrjTfesHTMAOzBjBYAnKa+vl7V1dV+12JiYpSQkCBJ+v3vf6+srCxdc801WrlypbZs2aJly5ZJkm677TYVFhZqwoQJmjVrlv7973/r/vvvV25urhITEyVJs2bNUn5+vi688EINHz5chw8f1t/+9jfdf//91n6jAExH0AKA07z22mtKTk72u3bppZfq//7v/ySdekfg6tWrNXHiRCUlJWnlypVKT0+XJHXo0EGvv/66Jk2apO985zvq0KGDRo0apSeffNLX14QJE3TixAk99dRTevDBB5WQkKDRo0db9w0CsIzDMAzD7kEAwLnC4XBo3bp1uvnmm+0eCoBzAHu0AAAATELQAgAAMAl7tAAgCOy2ABAMZrQAAABMQtACAAAwCUELAADAJAQtAAAAkxC0AAAATELQAgAAMAlBCwAAwCQELQAAAJP8f5x4ryrrUJxEAAAAAElFTkSuQmCC",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.plot(history.history[\"loss\"], \"o-\", label = \"Training Loss\")\n",
"plt.xlabel(\"Epoch\")\n",
"plt.ylabel(\"Loss (Hubert)\")\n",
"plt.grid('on')\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Test the model"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m15641/15641\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m4s\u001b[0m 232us/step - loss: 1.0855e-06\n"
]
},
{
"data": {
"text/plain": [
"1.0228196742900764e-06"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.evaluate(X_test, y_test)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Save the model"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [],
"source": [
"# Save the model\n",
"model.save(\"Barite_50_Model_additional_species.keras\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "ai",
"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.11.11"
}
},
"nbformat": 4,
"nbformat_minor": 2
}