From 2a57926cb8739d714b99a6726b2d05f041694252 Mon Sep 17 00:00:00 2001 From: Thassilo Helmold Date: Mon, 6 Jul 2020 22:26:34 +0200 Subject: [PATCH] Some more models --- multinet/Deepnet.ipynb | 13947 ++++++++++++++++++++++++++++++++++++ multinet/M1.html | 14321 +++++++++++++++++++++++++++++++++++++ multinet/M2-25 P1.html | 14321 +++++++++++++++++++++++++++++++++++++ multinet/M2-25 P2.html | 14319 +++++++++++++++++++++++++++++++++++++ multinet/M2-25 P3.html | 14319 +++++++++++++++++++++++++++++++++++++ multinet/M2-25 P4.html | 14319 +++++++++++++++++++++++++++++++++++++ multinet/M2-25 P5.html | 14268 +++++++++++++++++++++++++++++++++++++ multinet/M2.html | 14353 +++++++++++++++++++++++++++++++++++++ multinet/M3.html | 14356 ++++++++++++++++++++++++++++++++++++++ multinet/M3.ipynb | 14014 +++++++++++++++++++++++++++++++++++++ multinet/Multinet.ipynb | 9567 ++++++++++++------------- sepnet/S1.ipynb | 13968 +++++++++++++++++++++++++++++++++++++ sepnet/S2.ipynb | 13981 +++++++++++++++++++++++++++++++++++++ sepnet/S3.ipynb | 13896 ++++++++++++++++++++++++++++++++++++ 14 files changed, 189169 insertions(+), 4780 deletions(-) create mode 100644 multinet/Deepnet.ipynb create mode 100644 multinet/M1.html create mode 100644 multinet/M2-25 P1.html create mode 100644 multinet/M2-25 P2.html create mode 100644 multinet/M2-25 P3.html create mode 100644 multinet/M2-25 P4.html create mode 100644 multinet/M2-25 P5.html create mode 100644 multinet/M2.html create mode 100644 multinet/M3.html create mode 100644 multinet/M3.ipynb create mode 100644 sepnet/S1.ipynb create mode 100644 sepnet/S2.ipynb create mode 100644 sepnet/S3.ipynb diff --git a/multinet/Deepnet.ipynb b/multinet/Deepnet.ipynb new file mode 100644 index 0000000..3900af7 --- /dev/null +++ b/multinet/Deepnet.ipynb @@ -0,0 +1,13947 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Deepnet\n", + "A deeper variant of multinet. \n", + "Adds several more conv layers. \n", + "Doesn't perform better on test data, but takes way longer to train." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import random\n", + "import numpy as np\n", + "\n", + "from sklearn.compose import ColumnTransformer\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.metrics import accuracy_score, classification_report\n", + "\n", + "import tensorflow as tf\n", + "from tensorflow.keras.models import Sequential, Model\n", + "from tensorflow.keras.layers import Dense, Flatten, Dropout, Conv1D, MaxPooling1D, AveragePooling1D, Input, Concatenate, BatchNormalization, GaussianNoise\n", + "from tensorflow.keras.utils import to_categorical\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import plotly.graph_objects as go\n", + "import plotly.express as px" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv(\"Csv_data/all.csv\", index_col=[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
left_acc_xleft_acc_yleft_acc_zleft_gyr_xleft_gyr_yleft_gyr_zleft_quat_wleft_quat_xleft_quat_yleft_quat_z...rtls_mapped_positionrtls_statertls_x_filteredrtls_x_unfilteredrtls_y_filteredrtls_y_unfilteredrtls_z_filteredrtls_z_unfilteredlabelid
2020-05-26 08:04:14.120-0.219889-0.481445-0.724284-2.234163-1.024139-0.5431100.6697960.350221-0.5948040.273585...-1.02.03.2088453.2088451.3874821.3874822.6680982.6680980.00
2020-05-26 08:04:14.1400.157715-0.9116210.000000-1.587824-0.408662-0.0255410.6820570.343657-0.5855840.271586...-1.02.03.2088453.2088451.3874821.3874822.6680982.6680980.00
2020-05-26 08:04:14.1600.078125-0.6992190.0004880.2192300.220295-0.1106790.6851260.340926-0.5826340.273695...-1.02.03.2088453.2088451.3874821.3874822.6680982.6680980.00
2020-05-26 08:04:14.1800.116211-0.741211-0.2586260.7846890.472871-0.2220680.6789020.349042-0.5861430.271380...-1.02.03.2088453.2088451.3874821.3874822.6680982.6680980.00
2020-05-26 08:04:14.200-0.110840-1.037109-0.5678712.0656611.073803-0.1287710.6639650.362933-0.5957420.269003...-1.02.03.2088453.2088451.3874821.3874822.6680982.6680980.00
..................................................................
2020-05-26 18:07:01.200-0.580078-0.984538-0.3439130.482094-4.256191-1.7449750.342945-0.490375-0.273338-0.752820...-1.01.03.0575093.0640151.3844431.3627242.3260052.5197450.029
2020-05-26 18:07:01.220-0.625000-0.854980-0.353027-0.045762-4.401635-1.4845940.298254-0.504422-0.239510-0.774104...-1.01.03.0575093.0640151.3844431.3627232.3260052.5197450.029
2020-05-26 18:07:01.240-0.705078-0.825195-0.5024410.068110-4.489966-1.4931080.280677-0.509885-0.226557-0.780615...-1.01.03.0575093.0640151.3844431.3627232.3260052.5197450.029
2020-05-26 18:07:01.260-2.4832361.871094-4.2496745.843660-0.360063-2.7371870.248654-0.555116-0.236941-0.756464...-1.01.03.0575093.0640151.3844431.3627242.3260052.5197450.029
2020-05-26 18:07:01.2801.491699-3.767578-0.85351612.3439482.719095-5.2955850.210788-0.613207-0.315319-0.692907...-1.01.03.0575093.0640151.3844431.3627232.3260052.5197450.029
\n", + "

351868 rows × 42 columns

\n", + "
" + ], + "text/plain": [ + " left_acc_x left_acc_y left_acc_z left_gyr_x \\\n", + "2020-05-26 08:04:14.120 -0.219889 -0.481445 -0.724284 -2.234163 \n", + "2020-05-26 08:04:14.140 0.157715 -0.911621 0.000000 -1.587824 \n", + "2020-05-26 08:04:14.160 0.078125 -0.699219 0.000488 0.219230 \n", + "2020-05-26 08:04:14.180 0.116211 -0.741211 -0.258626 0.784689 \n", + "2020-05-26 08:04:14.200 -0.110840 -1.037109 -0.567871 2.065661 \n", + "... ... ... ... ... \n", + "2020-05-26 18:07:01.200 -0.580078 -0.984538 -0.343913 0.482094 \n", + "2020-05-26 18:07:01.220 -0.625000 -0.854980 -0.353027 -0.045762 \n", + "2020-05-26 18:07:01.240 -0.705078 -0.825195 -0.502441 0.068110 \n", + "2020-05-26 18:07:01.260 -2.483236 1.871094 -4.249674 5.843660 \n", + "2020-05-26 18:07:01.280 1.491699 -3.767578 -0.853516 12.343948 \n", + "\n", + " left_gyr_y left_gyr_z left_quat_w left_quat_x \\\n", + "2020-05-26 08:04:14.120 -1.024139 -0.543110 0.669796 0.350221 \n", + "2020-05-26 08:04:14.140 -0.408662 -0.025541 0.682057 0.343657 \n", + "2020-05-26 08:04:14.160 0.220295 -0.110679 0.685126 0.340926 \n", + "2020-05-26 08:04:14.180 0.472871 -0.222068 0.678902 0.349042 \n", + "2020-05-26 08:04:14.200 1.073803 -0.128771 0.663965 0.362933 \n", + "... ... ... ... ... \n", + "2020-05-26 18:07:01.200 -4.256191 -1.744975 0.342945 -0.490375 \n", + "2020-05-26 18:07:01.220 -4.401635 -1.484594 0.298254 -0.504422 \n", + "2020-05-26 18:07:01.240 -4.489966 -1.493108 0.280677 -0.509885 \n", + "2020-05-26 18:07:01.260 -0.360063 -2.737187 0.248654 -0.555116 \n", + "2020-05-26 18:07:01.280 2.719095 -5.295585 0.210788 -0.613207 \n", + "\n", + " left_quat_y left_quat_z ... rtls_mapped_position \\\n", + "2020-05-26 08:04:14.120 -0.594804 0.273585 ... -1.0 \n", + "2020-05-26 08:04:14.140 -0.585584 0.271586 ... -1.0 \n", + "2020-05-26 08:04:14.160 -0.582634 0.273695 ... -1.0 \n", + "2020-05-26 08:04:14.180 -0.586143 0.271380 ... -1.0 \n", + "2020-05-26 08:04:14.200 -0.595742 0.269003 ... -1.0 \n", + "... ... ... ... ... \n", + "2020-05-26 18:07:01.200 -0.273338 -0.752820 ... -1.0 \n", + "2020-05-26 18:07:01.220 -0.239510 -0.774104 ... -1.0 \n", + "2020-05-26 18:07:01.240 -0.226557 -0.780615 ... -1.0 \n", + "2020-05-26 18:07:01.260 -0.236941 -0.756464 ... -1.0 \n", + "2020-05-26 18:07:01.280 -0.315319 -0.692907 ... -1.0 \n", + "\n", + " rtls_state rtls_x_filtered rtls_x_unfiltered \\\n", + "2020-05-26 08:04:14.120 2.0 3.208845 3.208845 \n", + "2020-05-26 08:04:14.140 2.0 3.208845 3.208845 \n", + "2020-05-26 08:04:14.160 2.0 3.208845 3.208845 \n", + "2020-05-26 08:04:14.180 2.0 3.208845 3.208845 \n", + "2020-05-26 08:04:14.200 2.0 3.208845 3.208845 \n", + "... ... ... ... \n", + "2020-05-26 18:07:01.200 1.0 3.057509 3.064015 \n", + "2020-05-26 18:07:01.220 1.0 3.057509 3.064015 \n", + "2020-05-26 18:07:01.240 1.0 3.057509 3.064015 \n", + "2020-05-26 18:07:01.260 1.0 3.057509 3.064015 \n", + "2020-05-26 18:07:01.280 1.0 3.057509 3.064015 \n", + "\n", + " rtls_y_filtered rtls_y_unfiltered rtls_z_filtered \\\n", + "2020-05-26 08:04:14.120 1.387482 1.387482 2.668098 \n", + "2020-05-26 08:04:14.140 1.387482 1.387482 2.668098 \n", + "2020-05-26 08:04:14.160 1.387482 1.387482 2.668098 \n", + "2020-05-26 08:04:14.180 1.387482 1.387482 2.668098 \n", + "2020-05-26 08:04:14.200 1.387482 1.387482 2.668098 \n", + "... ... ... ... \n", + "2020-05-26 18:07:01.200 1.384443 1.362724 2.326005 \n", + "2020-05-26 18:07:01.220 1.384443 1.362723 2.326005 \n", + "2020-05-26 18:07:01.240 1.384443 1.362723 2.326005 \n", + "2020-05-26 18:07:01.260 1.384443 1.362724 2.326005 \n", + "2020-05-26 18:07:01.280 1.384443 1.362723 2.326005 \n", + "\n", + " rtls_z_unfiltered label id \n", + "2020-05-26 08:04:14.120 2.668098 0.0 0 \n", + "2020-05-26 08:04:14.140 2.668098 0.0 0 \n", + "2020-05-26 08:04:14.160 2.668098 0.0 0 \n", + "2020-05-26 08:04:14.180 2.668098 0.0 0 \n", + "2020-05-26 08:04:14.200 2.668098 0.0 0 \n", + "... ... ... .. \n", + "2020-05-26 18:07:01.200 2.519745 0.0 29 \n", + "2020-05-26 18:07:01.220 2.519745 0.0 29 \n", + "2020-05-26 18:07:01.240 2.519745 0.0 29 \n", + "2020-05-26 18:07:01.260 2.519745 0.0 29 \n", + "2020-05-26 18:07:01.280 2.519745 0.0 29 \n", + "\n", + "[351868 rows x 42 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['left_acc_x', 'left_acc_y', 'left_acc_z', 'left_gyr_x', 'left_gyr_y',\n", + " 'left_gyr_z', 'left_quat_w', 'left_quat_x', 'left_quat_y',\n", + " 'left_quat_z', 'hip_acc_x', 'hip_acc_y', 'hip_acc_z', 'hip_gyr_x',\n", + " 'hip_gyr_y', 'hip_gyr_z', 'hip_quat_w', 'hip_quat_x', 'hip_quat_y',\n", + " 'hip_quat_z', 'right_acc_x', 'right_acc_y', 'right_acc_z',\n", + " 'right_gyr_x', 'right_gyr_y', 'right_gyr_z', 'right_quat_w',\n", + " 'right_quat_x', 'right_quat_y', 'right_quat_z', 'rtls_accuracy',\n", + " 'rtls_accuracy_radius', 'rtls_mapped_position', 'rtls_state',\n", + " 'rtls_x_filtered', 'rtls_x_unfiltered', 'rtls_y_filtered',\n", + " 'rtls_y_unfiltered', 'rtls_z_filtered', 'rtls_z_unfiltered', 'label',\n", + " 'id'],\n", + " dtype='object')" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Preprocessing " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def split_test_proband(df, proband=5, nrec=6):\n", + " ''' Separate data from one proband as test dataset '''\n", + " train = df[np.floor(df[\"id\"]/nrec) != proband-1]\n", + " test = df[np.floor(df[\"id\"]/nrec) == proband-1]\n", + " return train, test\n", + "\n", + "train_df, test_df = split_test_proband(df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Feature selection and scaling" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "cols_body = ['left_acc_x', 'left_acc_y', 'left_acc_z', 'left_gyr_x', 'left_gyr_y',\n", + " 'left_gyr_z', 'left_quat_w', 'left_quat_x', 'left_quat_y',\n", + " 'left_quat_z', 'hip_acc_x', 'hip_acc_y', 'hip_acc_z', 'hip_gyr_x',\n", + " 'hip_gyr_y', 'hip_gyr_z', 'hip_quat_w', 'hip_quat_x', 'hip_quat_y',\n", + " 'hip_quat_z', 'right_acc_x', 'right_acc_y', 'right_acc_z',\n", + " 'right_gyr_x', 'right_gyr_y', 'right_gyr_z', 'right_quat_w',\n", + " 'right_quat_x', 'right_quat_y', 'right_quat_z']\n", + "cols_rtls = ['rtls_state',\n", + " 'rtls_x_filtered', 'rtls_x_unfiltered', 'rtls_y_filtered',\n", + " 'rtls_y_unfiltered', 'rtls_z_filtered', 'rtls_z_unfiltered']\n", + "# Dropped: ['rtls_accuracy', 'rtls_accuracy_radius', 'rtls_mapped_position'] \n", + "# These don't carry any information (See RTLS Exploration)\n", + "\n", + "column_trans = ColumnTransformer(\n", + " [('scale_sensors', StandardScaler(), cols_body),\n", + " ('rtls', 'passthrough', cols_rtls),\n", + " ('target', 'passthrough', ['label']),\n", + " ('id', 'passthrough', ['id'])],\n", + " remainder='drop')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "half_window = 50" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "train = column_trans.fit_transform(train_df)\n", + "test = column_trans.transform(test_df)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "def split_recs(data):\n", + " return {int(ID): data[data[:, -1]==ID, :-1] for ID in set(data[:,-1])}\n", + "train_recs = split_recs(train)\n", + "test_recs = split_recs(test)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "def make_window_dataset(ds, window_size, shift=1, stride=1):\n", + " windows = ds.window(window_size, shift=shift, stride=stride)\n", + "\n", + " def sub_to_batch(sub):\n", + " return sub.batch(window_size, drop_remainder=True)\n", + "\n", + " windows = windows.flat_map(sub_to_batch)\n", + " return windows" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "def make_dataset(recordings, half_window):\n", + " fulldata = None\n", + " targets = []\n", + " for rec in recordings.values():\n", + " rec_targets = rec[half_window:-half_window+1,-1].tolist()\n", + " rec_data = tf.data.Dataset.from_tensor_slices(rec[:,:-1])\n", + " windowed_data = make_window_dataset(rec_data, window_size=2*half_window)\n", + " if fulldata is None:\n", + " fulldata = windowed_data\n", + " else:\n", + " fulldata = fulldata.concatenate(windowed_data)\n", + " targets += rec_targets\n", + " return fulldata, targets" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "train_data, train_targets = make_dataset(train_recs, half_window)\n", + "test_data, test_targets = make_dataset(test_recs, half_window)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "# Interleave all recordings\n", + "\n", + "def make_interleaved_dataset(recordings, half_window, nrec=6):\n", + " datasets = []\n", + " for rec in recordings.values():\n", + " rec_targets = rec[half_window:-half_window+1,-1].tolist()\n", + " rec_data = tf.data.Dataset.from_tensor_slices(rec[:,:-1])\n", + " windowed_data = make_window_dataset(rec_data, window_size=2*half_window)\n", + " \n", + " encoded = tf.keras.utils.to_categorical(rec_targets)\n", + " weights = np.ones(len(rec_targets))\n", + " weights[np.array(rec_targets) == 1] = 2.5\n", + " weights[np.array(rec_targets) == 2] = 10\n", + " ds = tf.data.Dataset.zip((windowed_data, tf.data.Dataset.from_tensor_slices(encoded), tf.data.Dataset.from_tensor_slices(weights)))\n", + " datasets.append(ds)\n", + "\n", + " choice_dataset = tf.data.Dataset.range(len(datasets)).repeat()\n", + " return tf.data.experimental.choose_from_datasets(datasets, choice_dataset)\n", + "\n", + "traindataset = make_interleaved_dataset(train_recs, half_window)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Model training" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "feature_number = train.shape[1]-2\n", + "n_outputs = 3" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"model\"\n", + "__________________________________________________________________________________________________\n", + "Layer (type) Output Shape Param # Connected to \n", + "==================================================================================================\n", + "input_1 (InputLayer) [(None, 100, 37)] 0 \n", + "__________________________________________________________________________________________________\n", + "lambda (Lambda) (None, 100, 30) 0 input_1[0][0] \n", + "__________________________________________________________________________________________________\n", + "conv1d_2 (Conv1D) (None, 98, 64) 5824 lambda[0][0] \n", + "__________________________________________________________________________________________________\n", + "max_pooling1d_1 (MaxPooling1D) (None, 49, 64) 0 conv1d_2[0][0] \n", + "__________________________________________________________________________________________________\n", + "conv1d_3 (Conv1D) (None, 47, 96) 18528 max_pooling1d_1[0][0] \n", + "__________________________________________________________________________________________________\n", + "max_pooling1d_2 (MaxPooling1D) (None, 23, 96) 0 conv1d_3[0][0] \n", + "__________________________________________________________________________________________________\n", + "lambda_1 (Lambda) (None, 100, 7) 0 input_1[0][0] \n", + "__________________________________________________________________________________________________\n", + "dropout_1 (Dropout) (None, 23, 96) 0 max_pooling1d_2[0][0] \n", + "__________________________________________________________________________________________________\n", + "max_pooling1d_4 (MaxPooling1D) (None, 50, 7) 0 lambda_1[0][0] \n", + "__________________________________________________________________________________________________\n", + "conv1d_4 (Conv1D) (None, 21, 128) 36992 dropout_1[0][0] \n", + "__________________________________________________________________________________________________\n", + "conv1d_5 (Conv1D) (None, 48, 32) 704 max_pooling1d_4[0][0] \n", + "__________________________________________________________________________________________________\n", + "max_pooling1d_3 (MaxPooling1D) (None, 10, 128) 0 conv1d_4[0][0] \n", + "__________________________________________________________________________________________________\n", + "max_pooling1d_5 (MaxPooling1D) (None, 24, 32) 0 conv1d_5[0][0] \n", + "__________________________________________________________________________________________________\n", + "dropout_2 (Dropout) (None, 10, 128) 0 max_pooling1d_3[0][0] \n", + "__________________________________________________________________________________________________\n", + "dropout_3 (Dropout) (None, 24, 32) 0 max_pooling1d_5[0][0] \n", + "__________________________________________________________________________________________________\n", + "flatten_1 (Flatten) (None, 1280) 0 dropout_2[0][0] \n", + "__________________________________________________________________________________________________\n", + "flatten_2 (Flatten) (None, 768) 0 dropout_3[0][0] \n", + "__________________________________________________________________________________________________\n", + "concatenate (Concatenate) (None, 2048) 0 flatten_1[0][0] \n", + " flatten_2[0][0] \n", + "__________________________________________________________________________________________________\n", + "dense_2 (Dense) (None, 100) 204900 concatenate[0][0] \n", + "__________________________________________________________________________________________________\n", + "dense_3 (Dense) (None, 3) 303 dense_2[0][0] \n", + "==================================================================================================\n", + "Total params: 267,251\n", + "Trainable params: 267,251\n", + "Non-trainable params: 0\n", + "__________________________________________________________________________________________________\n" + ] + } + ], + "source": [ + "m_input = Input(shape=[half_window*2, feature_number])\n", + "m_input_body = tf.keras.layers.Lambda(lambda x: x[:,:,:len(cols_body)])(m_input)\n", + "m_input_rtls = tf.keras.layers.Lambda(lambda x: x[:,:,len(cols_body):])(m_input)\n", + "\n", + "m_x = Conv1D(filters=64, kernel_size=3, activation='relu')(m_input_body)\n", + "m_x = MaxPooling1D(pool_size=2)(m_x)\n", + "m_x = Conv1D(filters=96, kernel_size=3, activation='relu')(m_x)\n", + "m_x = MaxPooling1D(pool_size=2)(m_x)\n", + "m_x = Dropout(0.3)(m_x)\n", + "m_x = Conv1D(filters=128, kernel_size=3, activation='relu')(m_x)\n", + "m_x = MaxPooling1D(pool_size=2)(m_x)\n", + "m_x = Dropout(0.3)(m_x)\n", + "m_x = Flatten()(m_x)\n", + "\n", + "m_x2 = MaxPooling1D(pool_size=2)(m_input_rtls)\n", + "m_x2 = Conv1D(filters=32, kernel_size=3, activation='relu')(m_x2)\n", + "m_x2 = MaxPooling1D(pool_size=2)(m_x2)\n", + "m_x2 = Dropout(0.5)(m_x2)\n", + "m_x2 = Flatten()(m_x2)\n", + "\n", + "m_x = Concatenate()([m_x, m_x2])\n", + "m_x = Dense(100, activation='relu')(m_x)\n", + "m_output = Dense(n_outputs, activation='softmax')(m_x)\n", + "\n", + "model = Model(inputs=m_input, outputs=m_output)\n", + "\n", + "model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy', tf.keras.metrics.Precision(), tf.keras.metrics.Recall()])\n", + "model.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n", + "2075/2075 [==============================] - 145s 70ms/step - loss: 0.6909 - accuracy: 0.8024 - precision_1: 0.8055 - recall_1: 0.7978 - val_loss: 0.7040 - val_accuracy: 0.7521 - val_precision_1: 0.7523 - val_recall_1: 0.75000.\n", + "Epoch 2/10\n", + "2075/2075 [==============================] - 142s 68ms/step - loss: 0.5957 - accuracy: 0.8241 - precision_1: 0.8252 - recall_1: 0.8223 - val_loss: 0.7532 - val_accuracy: 0.7526 - val_precision_1: 0.7539 - val_recall_1: 0.7516\n", + "Epoch 3/10\n", + "2075/2075 [==============================] - 141s 68ms/step - loss: 0.5339 - accuracy: 0.8435 - precision_1: 0.8450 - recall_1: 0.8417 - val_loss: 0.5345 - val_accuracy: 0.7912 - val_precision_1: 0.7931 - val_recall_1: 0.7895\n", + "Epoch 4/10\n", + "2075/2075 [==============================] - 155s 75ms/step - loss: 0.4997 - accuracy: 0.8554 - precision_1: 0.8565 - recall_1: 0.8539 - val_loss: 0.6566 - val_accuracy: 0.7621 - val_precision_1: 0.7644 - val_recall_1: 0.7597\n", + "Epoch 5/10\n", + "2075/2075 [==============================] - 147s 71ms/step - loss: 0.4536 - accuracy: 0.8704 - precision_1: 0.8711 - recall_1: 0.8693 - val_loss: 0.7534 - val_accuracy: 0.7414 - val_precision_1: 0.7426 - val_recall_1: 0.7393\n", + "Epoch 6/10\n", + "2075/2075 [==============================] - 152s 73ms/step - loss: 0.4199 - accuracy: 0.8802 - precision_1: 0.8809 - recall_1: 0.8793 - val_loss: 0.7596 - val_accuracy: 0.7379 - val_precision_1: 0.7387 - val_recall_1: 0.7359\n", + "Epoch 7/10\n", + "2075/2075 [==============================] - 146s 70ms/step - loss: 0.3890 - accuracy: 0.8885 - precision_1: 0.8894 - recall_1: 0.8876 - val_loss: 0.7397 - val_accuracy: 0.7064 - val_precision_1: 0.7081 - val_recall_1: 0.7022\n", + "Epoch 8/10\n", + "2075/2075 [==============================] - 154s 74ms/step - loss: 0.3553 - accuracy: 0.8997 - precision_1: 0.9005 - recall_1: 0.8989 - val_loss: 0.6751 - val_accuracy: 0.7457 - val_precision_1: 0.7464 - val_recall_1: 0.7442\n", + "Epoch 9/10\n", + "2075/2075 [==============================] - 146s 70ms/step - loss: 0.3391 - accuracy: 0.9044 - precision_1: 0.9051 - recall_1: 0.9035 - val_loss: 0.7801 - val_accuracy: 0.7302 - val_precision_1: 0.7315 - val_recall_1: 0.7286\n", + "Epoch 10/10\n", + "2075/2075 [==============================] - 139s 67ms/step - loss: 0.3093 - accuracy: 0.9131 - precision_1: 0.9137 - recall_1: 0.9126 - val_loss: 0.7648 - val_accuracy: 0.7395 - val_precision_1: 0.7408 - val_recall_1: 0.7376\n" + ] + } + ], + "source": [ + "encoded = tf.keras.utils.to_categorical(test_targets)\n", + "testdataset = tf.data.Dataset.zip((test_data, tf.data.Dataset.from_tensor_slices(encoded)))\n", + "\n", + "EPOCHS = 10\n", + "history = model.fit(traindataset.shuffle(1000).batch(128),\n", + " validation_data=testdataset.batch(128),\n", + " epochs=EPOCHS)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEWCAYAAAB8LwAVAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3deXhU5fn/8fedhYSQsGQhLAESdkSRJWyiLC4gAm6tKIq7RavW2lZrqbW19dfWbxdrWxfqvrBpUdSKCqIsKmsQZN8MhAQChAQICVkn9++PM0AIAQbI5CQz9+u6uDIzZ7tngPnkPM95niOqijHGGFNViNsFGGOMqZssIIwxxlTLAsIYY0y1LCCMMcZUywLCGGNMtSwgjDHGVMsCwhhARN4Qkf/n47rbReRyf9dkjNssIIwxxlTLAsKYACIiYW7XYAKHBYSpN7xNO4+KyGoRKRSRV0UkUUQ+FZFDIjJXRJpVWv9qEVknIgdEZL6IdKu0rJeIfOvd7h0gssqxRovIKu+2i0Skh481jhKRlSKSLyKZIvJkleUXe/d3wLv8Du/rDUXk7yKSISIHReRr72tDRSSrms/hcu/jJ0VkhohMFpF84A4R6Scii73HyBaR50SkQaXtu4vI5yKSJyJ7ROTXItJCRA6LSFyl9fqISI6IhPvy3k3gsYAw9c0PgCuAzsAY4FPg10A8zr/nhwBEpDMwDXgYSAA+Af4nIg28X5YfAG8DscB/vfvFu21v4DXgXiAO+A/wkYhE+FBfIXAb0BQYBfxYRK717rett95/e2vqCazybvc3oA9wkbemXwIVPn4m1wAzvMecAniAn3k/k4HAZcD93hpigLnAZ0AroCPwharuBuYDYyvtdzwwXVXLfKzDBBgLCFPf/FtV96jqTuArYKmqrlTVEmAm0Mu73o3ALFX93PsF9zegIc4X8AAgHHhWVctUdQawvNIxfgT8R1WXqqpHVd8ESrzbnZKqzlfVNapaoaqrcUJqiHfxLcBcVZ3mPW6uqq4SkRDgLuCnqrrTe8xF3vfki8Wq+oH3mEWqukJVl6hquapuxwm4IzWMBnar6t9VtVhVD6nqUu+yN3FCAREJBcbhhKgJUhYQpr7ZU+lxUTXPo72PWwEZRxaoagWQCbT2Ltupx89UmVHpcTvgF94mmgMicgBo493ulESkv4jM8zbNHATuw/lNHu8+vq9ms3icJq7qlvkis0oNnUXkYxHZ7W12+pMPNQB8CJwnIu1xztIOquqys6zJBAALCBOoduF80QMgIoLz5bgTyAZae187om2lx5nAH1W1aaU/Uao6zYfjTgU+AtqoahNgEnDkOJlAh2q22QcUn2RZIRBV6X2E4jRPVVZ1SuYXgY1AJ1VtjNMEd7oaUNVi4F2cM51bsbOHoGcBYQLVu8AoEbnM28n6C5xmokXAYqAceEhEwkTkeqBfpW1fBu7zng2IiDTydj7H+HDcGCBPVYtFpB9wc6VlU4DLRWSs97hxItLTe3bzGvCMiLQSkVARGejt89gMRHqPHw78BjhdX0gMkA8UiEhX4MeVln0MtBCRh0UkQkRiRKR/peVvAXcAVwOTfXi/JoBZQJiApKqbcNrT/43zG/oYYIyqlqpqKXA9zhfhfpz+ivcrbZuG0w/xnHf5Vu+6vrgf+IOIHAJ+ixNUR/a7A7gKJ6zycDqoL/QufgRYg9MXkgf8HxCiqge9+3wF5+ynEDjuqqZqPIITTIdwwu6dSjUcwmk+GgPsBrYAwyot/wanc/xbb/+FCWJiNwwyxlQmIl8CU1X1FbdrMe6ygDDGHCUifYHPcfpQDrldj3GXNTEZYwAQkTdxxkg8bOFgwM4gjDHGnISdQRhjjKlWQE3sFR8fr8nJyW6XYYwx9caKFSv2qWrVsTVAgAVEcnIyaWlpbpdhjDH1hohknGyZNTEZY4yplgWEMcaYallAGGOMqVZA9UFUp6ysjKysLIqLi90uxa8iIyNJSkoiPNzu7WKMqRkBHxBZWVnExMSQnJzM8ZN3Bg5VJTc3l6ysLFJSUtwuxxgTIAK+iam4uJi4uLiADQcAESEuLi7gz5KMMbUr4AMCCOhwOCIY3qMxpnYFfBOTMcYEqqz9h1mansfeQyX8eGi194E6JxYQfnbgwAGmTp3K/ffff0bbXXXVVUydOpWmTZv6qTJjTH2TmXeYJem5LEnPY+m2XLL2FwHQonEkEwa3JzSkZlsSLCD87MCBA7zwwgsnBITH4yE0NPSk233yySf+Ls0YU4epKpl5RU4gbMtlaXoeOw84gRDbqAH9U2K55+IUBnSIo3PzGEJqOBzAAsLvfvWrX/H999/Ts2dPwsPDiY6OpmXLlqxatYr169dz7bXXkpmZSXFxMT/96U+ZMGECcGzakIKCAkaOHMnFF1/MokWLaN26NR9++CENGzZ0+Z0ZY2qSqpKR65whLN2Wx5L0XLIPOheexDVqQP/2sdw7pD0D2sfRMSHaL4FQVVAFxO//t471u/JrdJ/ntWrM78Z0P+nyp59+mrVr17Jq1Srmz5/PqFGjWLt27dHLUV977TViY2MpKiqib9++/OAHPyAuLu64fWzZsoVp06bx8ssvM3bsWN577z3Gjx9fo+/DGFO7VJVt+wqPNhctSc9lT34JAPHREfRvH8uA9nEMSImlY/NoVy5ECaqAqAv69et33FiFf/3rX8ycOROAzMxMtmzZckJApKSk0LNnTwD69OnD9u3ba61eY0zNUFW+zyn0hkEeS9Nz2XvICYSEmAgGtI+jf4oTCh0SGtWJKxODKiBO9Zt+bWnUqNHRx/Pnz2fu3LksXryYqKgohg4dWu1YhoiIiKOPQ0NDKSoqqpVajTFnzwmEAhanO81FS9Pz2FfgBEJi4wgGdoijf0ocA9rHkhJfNwKhqqAKCDfExMRw6FD1d288ePAgzZo1Iyoqio0bN7JkyZJars4YU1NUlS17C46GwdJtuewrKAWcq4wu7hjnNBm1j6NdXFSdDISqLCD8LC4ujkGDBnH++efTsGFDEhMTjy678sormTRpEj169KBLly4MGDDAxUqNMWeitLyC9H0FLD1yhrAtj7xCJxBaNYlkcKcEp9mofSxtY+tHIFQVUPekTk1N1ao3DNqwYQPdunVzqaLaFUzv1Rh/U1X2Hy5jR95hduQdJjPvMDtyDx99nn2wiArv12frpg2PhsHA9nEkNWtYbwJBRFaoamp1y+wMwhgTtErKPezcX3QsAI7+KSIz7zAFJeXHrZ8QE0Hb2Cj6pcTSJjaKlPgoUts5jwORXwNCRK4E/gmEAq+o6tNVljcDXgM6AMXAXaq61pdtjTHmdFSVvMLS488C8g6Tkes8zs4vpnIjSkRYCG1io2gbG0V/bwi09f5pE9uQqAbB9Tu1396tiIQCzwNXAFnAchH5SFXXV1rt18AqVb1ORLp617/Mx22NMYbiMg87DxRV2wyUmXeYwlLPces3954FDGgfdywA4pyfCdERtTIArb7wZxz2A7aqajqAiEwHrgEqf8mfB/wZQFU3ikiyiCQC7X3Y1hgTZApKypm/aS9fbd7HttxCMvMOs7vKWUBkeMjR3/oHdog7+rhtbBRJzaJo2ODkU9yY4/kzIFoDmZWeZwH9q6zzHXA98LWI9APaAUk+bguAiEwAJgC0bdu2Rgo3xtQd+wpKmLt+D7PX7eabrbmUeipo0jCczonRJwRA29goEmIi6k0HcV3nz4Co7m+o6iVTTwP/FJFVwBpgJVDu47bOi6ovAS+BcxXTWVdrjKkzMvMOM3vdbuas20NaRh4V6lwpNH5AO0Z0T6RPu2aEhQbF7Wxc5c+AyALaVHqeBOyqvIKq5gN3AogT+du8f6JOt219cbbTfQM8++yzTJgwgaiowLxCwpgjVJUN2YeYvW43s9ftZuNuZ3Bp1xYxPHhpJ0Z0T+S8lo3tzKCW+TMglgOdRCQF2AncBNxceQURaQocVtVS4B5goarmi8hpt60vTjbdty+effZZxo8fbwFhApKnQlmRsd85U1i/m8y8IkQgtV0zHr+qG8O7J9IurtHpd2T8xm8BoarlIvIgMBvnUtXXVHWdiNznXT4J6Aa8JSIenA7ou0+1rb9q9afK031fccUVNG/enHfffZeSkhKuu+46fv/731NYWMjYsWPJysrC4/HwxBNPsGfPHnbt2sWwYcOIj49n3rx5br8VY85ZcZmHRd/vY/baPczdsIfcwlIahIYwqGMc9w/tyOXdEkmIiTj9jkyt8OtFvar6CfBJldcmVXq8GOjk67bn7NNfwe41NbpLWlwAI08+RKPydN9z5sxhxowZLFu2DFXl6quvZuHCheTk5NCqVStmzZoFOHM0NWnShGeeeYZ58+YRHx9fszUbU4vyi8uYt3Evc9btYf6mvRSWeoiOCGNY1+aM6J7IkM4JxESGu12mqUZwjfpw2Zw5c5gzZw69evUCoKCggC1btnDJJZfwyCOP8NhjjzF69GguueQSlys15tzszS9mzvo9zFm/h8Xf76PMo8RHR3B1z9aM6J7IwA5xRITZ5aZ1XXAFxCl+068NqsrEiRO59957T1i2YsUKPvnkEyZOnMjw4cP57W9/60KFxpy9bfsKj3Yyr9xxAIB2cVHcOSiFEd0T6dWmmQ1Cq2eCKyBcUHm67xEjRvDEE09wyy23EB0dzc6dOwkPD6e8vJzY2FjGjx9PdHQ0b7zxxnHbWhOTqYtUlbU78492Mm/eUwDA+a0b8/MrOjOiews6J7pzJzRTMywg/KzydN8jR47k5ptvZuDAgQBER0czefJktm7dyqOPPkpISAjh4eG8+OKLAEyYMIGRI0fSsmVL66Q2dUK5p4Jl2/OYs24Pc9btZtfBYkIE+qXE8tvR5zG8eyJJzeyqu0Bh030HkGB6r6Z2FJd5WLPzIMu355G2fT9p2/PILy4nIiyESzolMKJ7Ipd1SyS2UQO3SzVnyab7Nsb45MDhUlZk7Ge5NwxWZx2k1FMBQIeERlx1QUuGdE5gSJeEoJvZNBjZ37AxQUpV2XmgiLTt+4+eIWza4/SXhYUIFyQ14Y5ByaS2a0afds2Ii7bxCcEmKAJCVQO+oyyQmgqNf3gqlE27D5GWkXf0DCH7YDEAMRFh9G7XjDEXtiQ1OZYLk5rarKcm8AMiMjKS3Nxc4uLiAjYkVJXc3FwiIyPdLsXUIcVlHr7LPEBahnOGsCJjP4eKnTukJTaOoG9yLH2TY0lNbkbXFo0JtUtQTRUBHxBJSUlkZWWRk5Pjdil+FRkZSVJSkttlGBftLywlLcM5M1i+PY81Ow9S5nHOLDsnRjPmwlb0TW5GarvYenXPZOOegA+I8PBwUlJS3C7DmBqlqmTtL2L5dqe5aPn2PLbudcYhhIcKPZKactfFKfRLjqVPu2Y0jbKrjMyZC/iAMCYQeCqUDdn5ztmB9yxhT34JADGRYaS2a8Z1vVrTNzmWHklNiAy3/gNz7iwgjKmjdh0oYuHmHBZuyeHrLfvI9/YftGoSyYD2caQmx9I3uRmdm8fYFBbGLywgjKkjiss8LNuWx4LNOSzcnMMWb5NRi8aRXHl+Cy7qEE/flFhaN23ocqUmWFhAGOMSVeX7nAIWbN7Hws05LEnPpaS8ggZhIfRPieXGvm0Y3DmBTs1tPiPjDgsIY2rRwaIyFm3dx8ItOSzcvI+dB4oAZ5Tyzf3bMrhzAgNS4mwMgqkTLCCM8aOKCmXNzoMs3JzDgs05rMw8gKdCiYkI46KOcTwwrCODO8fbBHemTrKAMKaG7T1UzEJvs9FXW3LYf7gMgB5JTfjxkA4M7pxAr7ZNCQ8NcblSY07NAsKYc1RaXkFaRh4LN+9jweYcNmTnAxAfHcGwLs0Z0iWBizvG21xGpt6xgDDmLGTkFh692mjR97kcLvUQHir0adeMX17ZhSGdE+jWorFdfmrqNQsIY3xQWFLO4u9znVDYkkNG7mEA2sZG8YPeSQzunMDADnFER9h/KRM47F+zMSdRUFLO+99m8ema3aRl5FHmUaIahDKwfRx3X5zC4E4JJMc3crtMY/zGAsKYKr7PKeDtxRnMWJFFQUk5XVvEcNfFKQzplECf5GZEhNklqCY4WEAYgzPX0byNe3lz8Xa+2rKPBqEhjO7RktsuSqZnm6Zul2eMKywgTFA7cLiUd9MyeXtJBpl5RbRoHMkjwztzU7+2xNtVRybIWUCYoLR+Vz5vLd7OB6t2UlxWQb+UWCaO7MYV5yXa+ARjvCwgTNAo81Qwe91u3lqUwbLteUSGh3Bdr9bcNjCZbi0bu12eMXWOBYQJeDmHSpi2bAdTlmawJ7+ENrENefyqboxNbUOTqHC3yzOmzrKAMAFr5Y79vLloO7PWZFPmUQZ3TuBP17VjaJfmdv9lY3xgAWECSnGZh1mrs3lr8Xa+yzpIdEQYt/Rvx60D29EhIdrt8oypVywgTEDYdaCIKUszmL4sk9zCUjo2j+apa7pzXe8kG91szFmy/zmm3lJVlqTn8dbi7cxZvwdV5bJuidxxUTIXdYizm+wYc44sIEy9c7i0nJkrd/LWogw27TlE06hw7rkkhfH929Em1u6rYExNsYAw9UZGbiFvLc7g3bRMDhWXc17LxvzlBz24umcrIsNt+gtjapoFhKnTKiqUhVtyeHPRduZvziFUhJEXtOT2ge3o066ZNSMZ40cWEKZO2l9YysyVO3l7SQbb9hWSEBPBQ5d24ub+bUlsHOl2ecYEBQsIU2ccPFzG7PW7mbU6m2+27qO8QundtikP39STkee3pEGYTYFhTG2ygDCuOlhUxufr9zBr9S6+3rqPMo/SJrYh91zSnjEXtqR7qyZul2hM0PJrQIjIlcA/gVDgFVV9usryJsBkoK23lr+p6uveZduBQ4AHKFfVVH/WampPfnEZc9fvYdbqbBZuyaHMo7Ru2pC7BqUwqkdLLmjdxPoWjKkD/BYQIhIKPA9cAWQBy0XkI1VdX2m1B4D1qjpGRBKATSIyRVVLvcuHqeo+f9Voas+h4jK+2LCXj1dns3BzDqWeClo1ieSOi5IZ1aMVFyZZKBhT1/jzDKIfsFVV0wFEZDpwDVA5IBSIEeebIRrIA8r9WJOpRQUl5XyxwTlTmL85h9LyClo0juTWge0Y1aMlPZOaEmJzIhlTZ/kzIFoDmZWeZwH9q6zzHPARsAuIAW5U1QrvMgXmiIgC/1HVl/xYq6khh0vL+XLjXmatzubLjXspKa8gsXEEt/Rvy+geLenVppmFgjH1hD8DorpvAa3yfASwCrgU6AB8LiJfqWo+MEhVd4lIc+/rG1V14QkHEZkATABo27Ztjb4B45uiUg/zNjmh8MXGPRSXVZAQE8G4fm0Z1aMlfdpaKBhTH/kzILKANpWeJ+GcKVR2J/C0qiqwVUS2AV2BZaq6C0BV94rITJwmqxMCwntm8RJAampq1QAyflJc5mH+JqdP4YsNeykq8xAf3YAb+rRhdI+WpCbH2pTaxtRz/gyI5UAnEUkBdgI3ATdXWWcHcBnwlYgkAl2AdBFpBISo6iHv4+HAH/xYq/FBcZmHBZtznDOFDXsoLPUQ16gB1/duzageLemfEmehYEwA8VtAqGq5iDwIzMa5zPU1VV0nIvd5l08CngLeEJE1OE1Sj6nqPhFpD8z0XtUSBkxV1c/8Vas5uZJyD19t3sesNdl8vn4PBSXlNIsK5+qerRndoyX9U2IJs3s4GxOQxGndCQypqamalpbmdhn1Xml5BV9vzeHj1dl8vm4Ph0rKaRoVzpXdWzCqR0sGto+zUDAmQIjIipONM7OR1Oaow6XlvLxwG69+nU5+cTlNGoYz8oIWjOrRios6xBFuoWBMULGAMJR7Kvjviiye+XwzOYdKGH5eIuP6t2VQh3ib/8iYIGYBEcRUlS827OXpzzaydW8Bfdo1Y9L4PvRp18zt0owxdYAFRJD6LvMAf/pkA0u35dE+vhGTxvdhRPdEm+7CGHOUBUSQ2ZF7mL/M3sjHq7OJj27AU9eez01921j/gjHmBBYQQWJ/YSn//nIrby/ZTlhICA9d2pEJQzoQHWH/BIwx1bNvhwBXXObh9W+288L8rRSWlDM2tQ0/u6Kz3ZXNGHNaFhABqqJCmblyJ3+fs4ldB4u5rGtzHhvZlc6JMW6XZoypJywgAtBXW3L40ycb2ZCdzwWtm/C3sRdyUYd4t8syxtQzFhABZP2ufP786Qa+2rKPpGYN+de4Xoy+oKXNpGqMOSsWEAFg14Ei/j5nM++vzKJxZDi/GdWNWwe2IyIs1O3SjDH1mAVEPZZfXMYL877n9W+2ocCES9pz/9CONIkKd7s0Y0wAsICoh0rLK5i8JIN/f7mF/YfLuL5Xa34+vDNJzaLcLs0YE0B8CggReQ94Dfi00i1BTS1TVWatyeYvn21iR95hBnWMY+LIbpzfuonbpRljApCvZxAv4tz97V8i8l/gDVXd6L+yTFVL03P506cb+S7zAF1bxPDmXf0Y3CnepsYwxviNTwGhqnOBuSLSBBiHc4/oTOBlYLKqlvmxxqC2de8hnv50E3M37KFF40j++sMeXN87ye7cZozxO5/7IEQkDhgP3AqsBKYAFwO3A0P9UVww23uomH98voV3lu8gqkEYj47owl2DUmjYwK5MMsbUDl/7IN4HugJvA2NUNdu76B0RsVu41aDCknJeWpjOy1+lU1pewW0Dk/nJpR2Ji45wuzRjTJDx9QziOVX9sroFJ7tVnTkzngpl+vId/OPzLewrKGHUBS15dEQXkuMbuV2aMSZI+RoQ3UTkW1U9ACAizYBxqvqC/0oLHquzDvD4zLWs2XmQvsnNeOm2PvRuazftMca4y9eA+JGqPn/kiaruF5EfARYQ5+BgURl/n7OJt5dkEB8dwb/G9WJMj5Z2ZZIxpk7wNSBCRERUVQFEJBRo4L+yApuq8tF3u3jq4w3kFZZw+8Bkfj68M40jbQS0Mabu8DUgZgPvisgkQIH7gM/8VlUAS88p4IkP1/LN1lx6JDXh9Tv6ckGSDXQzxtQ9vgbEY8C9wI8BAeYAr/irqEBUXObhhXlbmbQgnYjwEJ66pjs3929n4xmMMXWWrwPlKnBGU7/o33IC04LNOfz2w7Vk5B7m2p6t+PWobjSPsTu6GWPqNl/HQXQC/gycBxz9ZlPV9n6qKyDsPljMUx+vZ9aabNrHN2LKPf0Z1NFu3GOMqR98bWJ6Hfgd8A9gGM68TNY2chLlngreWpzBM59vptRTwc+v6My9Q9rb/RmMMfWKrwHRUFW/8F7JlAE8KSJf4YSGqWTljv08PnMt67PzGdI5gT9c0512cTbYzRhT//gaEMUiEgJsEZEHgZ1Ac/+VVf8cPFzGX2ZvZOqyHTSPieD5m3tz1QUtbEyDMabe8jUgHgaigIeAp3CamW73V1H1iaoyc+VO/vTJBvIKS7nzohR+dkUnYmxMgzGmnjttQHgHxY1V1UeBApz+BwNs3VvAbz5Yw5L0PHq2acobd/azm/cYYwLGaQNCVT0i0qfySOpgV1Tq4bl5W3hpYToNw0P543XnM65vW0JsTIMxJoD42sS0EvjQeze5wiMvqur7fqmqDvty4x5+++E6svYXcX2v1vx6VDfibSpuY0wA8jUgYoFc4NJKrykQNAGRfbCI33+0ns/W7aZDQiOm/WgAAzvEuV2WMcb4ja8jqYO236HcU8Ebi7bzzOeb8VQoj47owo8uaU+DsBC3SzPGGL/ydST16zhnDMdR1btqvKI6ZEVGHo/PXMvG3YcY1iWBP1xzPm1io9wuyxhjaoWvTUwfV3ocCVwH7Kr5cuqG/YWl/N9nG5m+PJOWTSKZNL43I7rbmAZjTHDxtYnpvcrPRWQaMNcvFblIVZmxIos/f7qRg0Vl/OiSFB6+vDONInzNUWOMCRxn+83XCWhbk4W4bfOeQ/xm5lqWbc+jd9um/PG6C+jWsrHbZRljjGt87YM4xPF9ELtx7hFxuu2uBP4JhAKvqOrTVZY3ASbjhE0Y8DdVfd2XbWtKcZmHZ+du4ZWv0omODOPp6y9gbGobG9NgjAl6vjYxxZzpjr0jsJ8HrgCygOUi8pGqrq+02gPAelUdIyIJwCYRmQJ4fNi2xny2Nptre7Vm4siuxNmYBmOMAXw/g7gO+FJVD3qfNwWGquoHp9isH7BVVdO920wHrgEqf8krECNO7280kAeUA/192LZGRIaH8vFDlxBt/QzGGHMcXy/m/92RcABQ1QOcfqrv1kBmpedZ3tcqew7ohnNF1Brgp9671/myLQAiMkFE0kQkLScnx5f3cgILB2OMOZGvAVHdeqf7Vq2uEb/qWIoRwCqgFdATeE5EGvu4rfOi6kuqmqqqqQkJCacpyRhjjK98DYg0EXlGRDqISHsR+Qew4jTbZAFtKj1P4sSxE3cC76tjK7AN6OrjtsYYY/zI14D4CVAKvAO8CxThdDCfynKgk4ikiEgD4Cbgoyrr7AAuAxCRRKALkO7jtsYYY/zI16uYCoFfncmOVbXce/e52TiXqr6mqutE5D7v8kk4Nx96Q0TW4DQrPaaq+wCq2/ZMjm+MMebciC+3eBCRz4EbvJ3TiEgzYLqqjvBzfWckNTVV09LS3C7DGGPqDRFZoaqp1S3ztYkp/kg4AKjqfuye1MYYE9B8DYgKETk6tYaIJHOSq4qMMcYEBl8D4nHgaxF5W0TeBhYAE/1XlnHNlrnwnyGwbaHblRhjXOZTQKjqZ0AqsAnnSqZf4FzJZAJJ5jJ4ZzzsXg1vXwfLX3G7ImOMi3wKCBG5B/gCJxh+AbwNPOm/skyt27sBptwAjVvCg2nQ4VKY9Qv4+OfgKXO7OmOMC3xtYvop0BfIUNVhQC/g7Oa1MHXP/gznjCEsEm79AOI6wLjpcNFDkPaqs+xwnttVGmNqma8BUayqxQAiEqGqG3EGtZn6riDHCYCyw3Dr+9CsnfN6SCgMfwqunQSZS+Gloc5ZhjEmaPgaEFneGVw/AD4XkQ+xqS/qv+J8mPIDyN8FN78Lid1PXKfnOLjjEygrglcuh02f1n6dxhhX+NpJfZ2qHlDVJ4EngFeBa/1ZmPGzsmKYfjPsXgtj34S2A06+bpu+MGG+0/Q0bRx8/Q/wYYClMaZ+8/UM4ihVXaCqH6lqqT8KMrWgwjKgtDsAABSOSURBVAPv3wPbv4JrX4TOPgyIb9Ia7vwMul8Hc5+E9yc4ZxXGmIBlN0IINqrw8c9gw/9gxJ/hwht937ZBFPzwNUg8D778f5C7FW6a6lz5ZIwJOGd8BmHquS+fgm/fhEt+AQPvP/PtRWDwo3DjZMjZBC8Pg52nm/ndGFMfWUAEk8UvwFd/h963w6VPnNu+uo2Bu+dASDi8fhWs/m/N1GiMqTMsIILFd+/A7InOF/vofzhnAueqxfkwYR606u30acz9PVRUnPt+jTF1ggVEMNg8Bz68H5IvgetfccY41JRG8XDbh9D7Nvj6GXjnFig5VHP7N8a4xgIi0O1YAu/e5oxxuGkqhEfW/DHCGsCYf8HIv8Dm2fDqcNi/veaPY4ypVRYQgWzPepg6Fhq3glveg8jG/juWCPS/F8a/B/k74aVhsO0r/x3PGON3FhCBan8GTL4ewqPg1pkQnVA7x+0wDH40z2l6evtaSHutdo5rjKlxFhCBqCDH+XIuK4LxleZXqi1xHeCeudB+qDPmYtYjNiOsMfWQBUSgKc53zhzys73zK53nTh2RTZzjD3wQlr/s1GQzwhpTr1hABJIj8yvtXQ9j34K2/d2tJyQURvzRmc5jxxJ4+VLYu9HdmowxPrOACBQnzK803O2Kjul5M9wxC0oLnRlhN892uyJjjA8sIAKBKnz8sDO/0pVPQ4+xbld0ojb9nEF1sSkw9Ub4+lmbEdaYOs4CIhB88Qf49i245BEY8GO3qzm5Jklw12dw3jUw93cw8z6nWcwYUydZQNR3i593RjD3uQMu/Y3b1Zxeg0Zwwxsw7HFYPR3eGAWHdrtdlTGmGhYQ9dl302H2r6Hb1TDqmZqZX6k2iMCQX8LYt50O9ZeGwc5v3a7KGFOFBUR9tXk2fHA/pAyGH9Tw/Eq15byrvTPChsLrI2HNDLcrMsZUYgFRH+1YAu/eDi0ucOZXCotwu6Kz1+ICZ+R1q17w3t3wxVM2I6wxdYQFRH2zZ50zv1KT1nDLDIiIcbuicxedALd9BL1uha/+Bu/eCiUFbldlTNCzgKhP9m+Ht12YX6k2hDWAq/8NV/4fbPrEZoQ1pg6wgKgvCvbC29dBebETDk3bul1RzROBAfc5Z0b5WfCfIbDsZfCUu12ZMUHJAqI+KD4Ik3/gXA56y3+heTe3K/Kvjpc5/RItLoBPHoH/DLapw41xgQVEXVdWDNMqza/Upp/bFdWOuA5w+/+c91ySD2+Ohv/eAQcy3a7MmKBhAVGXecqdK3syvnbmV+p0hdsV1S4RZ9T1A8tg6ETY9Ck81xcW/MWZytwY41cWEHXVkfmVNn7sdNzWxfmVakuDKBj6K3hwuTMJ4bw/wvP9nLmnbD4nY/zGAqKu+uL3sPJtGPyo03FrnI75sW85TU8NouGd8fDWNbB3g9uVGROQLCDqokXPwdf/gD53OnMWmeOlDIZ7v4KRf4XsVfDiIPj0V1B0wO3KjAkoFhB1zappMOdxp+191N/rz/xKtS00DPpPgJ+shN63wdJJ8O/esOIN594YxphzZgFRV6jCps/gwwcgZQhc/3L9nF+ptjWKgzHPwr0LIL4z/O+n8PIw2LHU7cqMqffC/LlzEbkS+CcQCryiqk9XWf4ocEulWroBCaqaJyLbgUOAByhX1VS/FTrvT84AtAoPVJRX+ul9rFWeV16unhPXP2F5eTX79hy/XL3zD7XqBTdNqd/zK7mh5YVw56ew9j2Y8wS8Nhx63AiX/x4at3S7OmPqJVE/XQUiIqHAZuAKIAtYDoxT1fUnWX8M8DNVvdT7fDuQqqr7fD1mamqqpqWlnXmxf24LnhKQUAgJc35zr+7nSZeHgYQcexwSBiFVnkvo8euHhJ643wZRznxEUbFn/h7MMSUFTh/Oon9BSDgMeRQG3G+ha0w1RGTFyX4B9+cZRD9gq6qme4uYDlwDVBsQwDhgmh/rObmJO1w5rPGTiGi47AnodQvM/g3MfdK5496VT0PnEW5XZ0y94c8+iNZA5WGvWd7XTiAiUcCVwHuVXlZgjoisEJEJJzuIiEwQkTQRScvJyamBsk3AiG0P46bC+Pecs7SpY2HyD2HfFrcrM6Ze8GdAVHf5zcnas8YA36hqXqXXBqlqb2Ak8ICIDK5uQ1V9SVVTVTU1ISGAZjc1Nafj5fDjRTD8j5C5FF4Y6PRTFOe7XZkxdZo/AyILaFPpeRKw6yTr3kSV5iVV3eX9uReYidNkZczZCWsAFz0IP1kBF97o9E88l+pcVmw3KDKmWv4MiOVAJxFJEZEGOCHwUdWVRKQJMAT4sNJrjUQk5shjYDiw1o+1mmAR3RyueR7u+RKatIEP7oNXr4CdK9yuzPjKUwbrP4LCXLcrCXh+CwhVLQceBGYDG4B3VXWdiNwnIpXnjrgOmKOqhZVeSwS+FpHvgGXALFX9zF+1miCU1Afu/hyunQQHdsDLlzpjUAr2ul2ZORVV+Ogh566D/zjPebx3o9tVBSy/XebqhrO+zNUEt+J8WPhXWPIihDd0JgbsNwFCw92uzFQ190nnEuYB90NpIax+xxnD1OFSGPCAcy8Rm33gjJzqMlcLCGOO2LcFPvsVbJ3rjMq+8mnnC8fUDUsmwWePOXOUjf6HEwSF+2DF67DsFSjYDfFdnMkte9zkjCsyp2UBYYyvVGHzbJg9EfLSocsouPhhp7+iUYIzB5SpfWvfhxl3QddRzoy+VaehKS+Fde/D4udh92po2MwJkn4/gsat3Km5nrCAMOZMlZfAkhdgwV+hzNs9JiEQFQ8xiRDdwvkZ0xKiEyGmxbHXohNt1HZN2rbQueVu6z7O/djDG558XVXIWOT83W2c5QRJ9+thwI+hde/aq7kesYAw5mwV7IXMZU7zxaE9J/4s3HtsHq3KGjarFBiVf3r/HAmVBo1q/z3VJ9mr4fWroEkS3PWp87n6Km8bLP2Pc1+V0gJoO9AJiq6jA2cizLIi2LEYDu6E3ree1S4sIIzxlwqP0w5esBsOef8U7Kn+Z0XZids3iKkmRKoJlcgmwdf5un87vDrcmafs7s+hSbUTMZxe8UFYOdmZEv7ADufGU/3vg17jnc+1PvGUw66VsG0+pC9wBn56Sp338cttZxV8FhDGuE0VivZ7A6PyWUg1oVJ2+MTtwyKd2WlH/T04rq4q3OeEw+FcuGs2NO967vus8DjNTktehB2LnHDuNd65r0hs+3Pfvz+oQs5GJwy2LYDtX0OJdwaAFhc4twZoP9Q5O4qIPqtDWEAYU1+oQsmhE88+9m6AVZOdyznHvgURMW5X6j+lhfDmGNizDm77ENoOqPlj7FrpBMXa95zg6DrKuXS23UXun6kdyHTC4EgoFOxxXm+WAu2HOKGQMhgaxdfI4SwgjAkE374F/3sYErvDLTOcJqhA4ymDaePg+y/gxsnOF7c/5WfD8pch7TXnDK9FDxj4gNOxHdbAv8c+4nCe0xF/JBTyvndeb5TgPUPwhkKzdn45vAWEMYFi8xz47+3Ob4/j34f4Tm5XVHNU4YP74bupMOaf0OeO2jt26WFn0N2SF2HfJucigr4/gtS7nLsW1vSxdiw6doaQvRpQp8kredCxUGh+Xq2czVhAGBNIdq6AKWOdq6dufgfaBMg8lkdGSQ/9NQx9zJ0aVJ2zl8UvOD/DIqHHWKf5qXm3s9unpxx2fQvp851QyFrmdCyHhEOb/sfOEFr3dqV/yQLCmECT+70zNuBQNvzwdeh6ldsVnZvqRkm7be9GWPoifDfdmc6j/TCn+anDZc4dI09G1ekzSp/v7Vj+BkoPAQItexw7Q2g7sE5c5mwBYUwgKsiBqTdA9nfO1U2pd7ld0dlZ+x7MuPvko6TdVpjrnc7jZe90Hp2dy2QvHHdsOo8DO5yzg/T5Tn9CoXfSx9gOx3cs18HbCVtAGBOoSgpgxp2wZQ4MfhSGPV43fvv2VfoCmPJDaJ0Kt75/6lHSbisvhfUfONN5ZK9yBu11uBR2fgv7tznrRCce37HctM2p91kHWEAYE8g85fDxw86I4Z63OB289WGsxLmMknaTKuxYAkued34m9T0WCgld61dAc+qAsJnHjKnvQsPg6n9D49aw4Gln3MTYt8564FSt2L/dOXOIbOLcM7y+hAM4AdBuoPMnwPnzjnLGmNoiAsMmOmcP6fPgjVF19+ZHhfvg7eudCRHHv3f2U2gYv7OAMCaQ9LkDbpoGOZvglcth31a3KzpeSQFMuQHyd8LN79bMFBrGbywgjAk0Xa6EOz52ZjB99QrIXO52RQ5PGfz3DqeD94evQ9v+bldkTsMCwphAlJTqzIAa2diZ12jTp+7Wowof/QS2fg6jn63/4zaChAWEMYEqroMTEs27wvSbIe1192qZ+yR8N825DLfP7e7VYc6IBYQxgSy6Odz+sTP69+OH4cs/Or/N16YlL8I3zzoD+QY/WrvHNufEAsKYQBcRDeOmQc/xsPAv8NGDTn9AbVj7Hnw2EbqNgav+Vu/GCAQ7GwdhTDAIDYdrnoPGrZyQOLQHbnjDv2Ml0hfA+/c6cw5d/0rdm0LDnJadQRgTLETg0sedTuLvv4A3RzvzOflD9ncw/RZnOvJx0yA80j/HMX5lAWFMsEm9E26c4sxW+uoVzsywNWn/dpjsHSV9ywxo2LRm929qjQWEMcGo61Vw+/+g+KATElkrama/R0ZJe0qdyfdslHS9ZgFhTLBq09e5DLZBtNPctHn2ue3v6CjpXc4o6YQuNVOncY0FhDHBLL4j3DPX6SuYNg5WvHl2+/GUwbu3OaOkb7BR0oHCAsKYYBfdHO6YBe2Hwv8egnl/PrOxEqrw4YNOx/foZ6HLSH9VamqZBYQxBiJinPtbX3izM2X4Rz9x7jPhi7m/g9XTYdhvbJR0gLFxEMYYR2g4XPuC07G88K/OdOE3vH7q+yYvfgG++Sf0vQcGP1J7tZpaYWcQxphjRODS38CoZ5yJ9d44xViJNTNgtneU9Mi/2CjpAGQBYYw5Ud+74cbJsHd99WMl0ufDzPug3SAbJR3ALCCMMdXrOqrSWInhsNM7ViL7O5g+3rny6aapNko6gFlAGGNOrk0/uHsONIhympvSXndGSTds6r2XtI2SDmQWEMaYU4vvBHfPhbiOzpThFWVOODRu5XZlxs/sKiZjzOnFJMKdn8CC/4Pu19so6SBhAWGM8U1EDAz/f25XYWqRNTEZY4ypll8DQkSuFJFNIrJVRH5VzfJHRWSV989aEfGISKwv2xpjjPEvvwWEiIQCzwMjgfOAcSJyXuV1VPWvqtpTVXsCE4EFqprny7bGGGP8y59nEP2AraqarqqlwHTgmlOsPw6YdpbbGmOMqWH+DIjWQGal51ne104gIlHAlcB7Z7HtBBFJE5G0nBw/3T7RGGOCkD8DorqJWU42h/AY4BtVzTvTbVX1JVVNVdXUhISEsyjTGGNMdfwZEFlAm0rPk4BdJ1n3Jo41L53ptsYYY/zAnwGxHOgkIiki0gAnBD6qupKINAGGAB+e6bbGGGP8x28D5VS1XEQeBGYDocBrqrpORO7zLp/kXfU6YI6qFp5u29Mdc8WKFftEJOMsS44H9p3ltoHGPovj2edxPPs8jgmEz6LdyRaInsmtBQOYiKSpaqrbddQF9lkczz6P49nncUygfxY2ktoYY0y1LCCMMcZUywLimJfcLqAOsc/iePZ5HM8+j2MC+rOwPghjjDHVsjMIY4wx1bKAMMYYU62gDwibVvwYEWkjIvNEZIOIrBORn7pdk9tEJFREVorIx27X4jYRaSoiM0Rko/ffyEC3a3KTiPzM+/9krYhME5FIt2uqaUEdEDat+AnKgV+oajdgAPBAkH8eAD8FNrhdRB3xT+AzVe0KXEgQfy4i0hp4CEhV1fNxBvTe5G5VNS+oAwKbVvw4qpqtqt96Hx/C+QKodhbdYCAiScAo4BW3a3GbiDQGBgOvAqhqqaoecLcq14UBDUUkDIgiAOeLC/aA8Hla8WAjIslAL2Cpu5W46lngl0CF24XUAe2BHOB1b5PbKyLSyO2i3KKqO4G/ATuAbOCgqs5xt6qaF+wBcSZTkgcNEYnGuTfHw6qa73Y9bhCR0cBeVV3hdi11RBjQG3hRVXsBhUDQ9tmJSDOc1oYUoBXQSETGu1tVzQv2gLBpxasQkXCccJiiqu+7XY+LBgFXi8h2nKbHS0VksrsluSoLyFLVI2eUM3ACI1hdDmxT1RxVLQPeBy5yuaYaF+wBYdOKVyIigtPGvEFVn3G7Hjep6kRVTVLVZJx/F1+qasD9hugrVd0NZIpIF+9LlwHrXSzJbTuAASIS5f1/cxkB2Gnvt+m+64OznVY8gA0CbgXWiMgq72u/VtVPXKzJ1B0/AaZ4f5lKB+50uR7XqOpSEZkBfItz9d9KAnDaDZtqwxhjTLWCvYnJGGPMSVhAGGOMqZYFhDHGmGpZQBhjjKmWBYQxxphqWUAYUweIyFCbMdbUNRYQxhhjqmUBYcwZEJHxIrJMRFaJyH+894soEJG/i8i3IvKFiCR41+0pIktEZLWIzPTO34OIdBSRuSLynXebDt7dR1e638IU7whdY1xjAWGMj0SkG3AjMEhVewIe4BagEfCtqvYGFgC/827yFvCYqvYA1lR6fQrwvKpeiDN/T7b39V7Awzj3JmmPM7LdGNcE9VQbxpyhy4A+wHLvL/cNgb0404G/411nMvC+iDQBmqrqAu/rbwL/FZEYoLWqzgRQ1WIA7/6WqWqW9/kqIBn42v9vy5jqWUAY4zsB3lTVice9KPJElfVONX/NqZqNSio99mD/P43LrInJGN99AfxQRJoDiEisiLTD+X/0Q+86NwNfq+pBYL+IXOJ9/VZggff+Glkicq13HxEiElWr78IYH9lvKMb4SFXXi8hvgDkiEgKUAQ/g3Dynu4isAA7i9FMA3A5M8gZA5dlPbwX+IyJ/8O7jhlp8G8b4zGZzNeYciUiBqka7XYcxNc2amIwxxlTLziCMMcZUy84gjDHGVMsCwhhjTLUsIIwxxlTLAsIYY0y1LCCMMcZU6/8DockkMfjY+A8AAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Plot training statistics\n", + "\n", + "# Accuracy\n", + "plt.plot(history.history['accuracy'])\n", + "plt.plot(history.history['val_accuracy'])\n", + "plt.title('model accuracy')\n", + "\n", + "plt.xlabel('epoch')\n", + "plt.ylabel('accuracy')\n", + "\n", + "plt.legend(['train', 'test'], loc='upper left')\n", + "plt.show()\n", + "\n", + "# Loss\n", + "plt.plot(history.history['loss'])\n", + "plt.plot(history.history['val_loss'])\n", + "plt.title('model loss')\n", + "\n", + "plt.xlabel('epoch')\n", + "plt.ylabel('loss')\n", + "\n", + "plt.legend(['train', 'test'], loc='upper left')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "pred_proba = model.predict(train_data.batch(128))\n", + "pred = np.argmax(pred_proba, axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " precision recall f1-score support\n", + "\n", + " 0.0 0.92 0.85 0.89 181307\n", + " 1.0 0.75 0.85 0.80 68169\n", + " 2.0 0.65 0.84 0.73 16023\n", + "\n", + " accuracy 0.85 265499\n", + " macro avg 0.77 0.85 0.80 265499\n", + "weighted avg 0.86 0.85 0.85 265499\n", + "\n" + ] + } + ], + "source": [ + "from sklearn.metrics import accuracy_score\n", + "print(classification_report(train_targets, pred))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Post processing" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "pred_proba = model.predict(test_data.batch(128))\n", + "pred = np.argmax(pred_proba, axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " precision recall f1-score support\n", + "\n", + " 0.0 0.90 0.74 0.82 64014\n", + " 1.0 0.51 0.69 0.58 15557\n", + " 2.0 0.34 0.85 0.49 3828\n", + "\n", + " accuracy 0.74 83399\n", + " macro avg 0.58 0.76 0.63 83399\n", + "weighted avg 0.80 0.74 0.76 83399\n", + "\n" + ] + } + ], + "source": [ + "print(classification_report(test_targets, pred))" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "