1130 lines
61 KiB
Plaintext
1130 lines
61 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b6131d61",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Constants"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "6144a350",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import os\n",
|
|
"\n",
|
|
"os.environ['TF_FORCE_GPU_ALLOW_GROWTH'] = 'true' # this is required\n",
|
|
"os.environ['CUDA_VISIBLE_DEVICES'] = '2' # set to '0' for GPU0, '1' for GPU1 or '2' for GPU2. Check \"gpustat\" in a terminal."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "7aa3948f",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"glob_path = '/opt/iui-datarelease3-sose2021/*.csv'\n",
|
|
"\n",
|
|
"pickle_file = '../data.pickle'"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "89eb31ab",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Config"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "e2be13e5",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Possibilities: 'SYY', 'SYN', 'SNY', 'SNN', \n",
|
|
"# 'JYY', 'JYN', 'JNY', 'JNN'\n",
|
|
"cenario = 'SYN' \n",
|
|
"\n",
|
|
"win_sz = 10\n",
|
|
"stride_sz = 5\n",
|
|
"\n",
|
|
"# divisor for neuron count step downs (hard to describe), e.g. dense_step = 3: layer1=900, layer2 = 300, layer3 = 100, layer4 = 33...\n",
|
|
"dense_steps = 3\n",
|
|
"# amount of dense/dropout layers\n",
|
|
"layer_count = 3\n",
|
|
"# how much to drop\n",
|
|
"drop_count = 0.1"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "0eca097f",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Helper Functions"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "82014801",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from matplotlib import pyplot as plt\n",
|
|
"\n",
|
|
"def pplot(dd):\n",
|
|
" x = dd.shape[0]\n",
|
|
" fix = int(x/3)+1\n",
|
|
" fiy = 3\n",
|
|
" fig, axs = plt.subplots(fix, fiy, figsize=(3*fiy, 9*fix))\n",
|
|
" \n",
|
|
" for i in range(x):\n",
|
|
" axs[int(i/3)][i%3].plot(dd[i])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e8d9944b",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Loading Data"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "0ae277a0",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from glob import glob\n",
|
|
"import pandas as pd\n",
|
|
"from tqdm import tqdm\n",
|
|
"\n",
|
|
"def dl_from_blob(filename, user_filter=None):\n",
|
|
" \n",
|
|
" dic_data = []\n",
|
|
" \n",
|
|
" for p in tqdm(glob(glob_path)):\n",
|
|
" path = p\n",
|
|
" filename = path.split('/')[-1].split('.')[0]\n",
|
|
" splitname = filename.split('_')\n",
|
|
" user = int(splitname[0][1:])\n",
|
|
" if (user_filter):\n",
|
|
" if (user != user_filter):\n",
|
|
" continue\n",
|
|
" scenario = splitname[1][len('Scenario'):]\n",
|
|
" heightnorm = splitname[2][len('HeightNormalization'):] == 'True'\n",
|
|
" armnorm = splitname[3][len('ArmNormalization'):] == 'True'\n",
|
|
" rep = int(splitname[4][len('Repetition'):])\n",
|
|
" session = int(splitname[5][len('Session'):])\n",
|
|
" data = pd.read_csv(path)\n",
|
|
" dic_data.append(\n",
|
|
" {\n",
|
|
" 'filename': path,\n",
|
|
" 'user': user,\n",
|
|
" 'scenario': scenario,\n",
|
|
" 'heightnorm': heightnorm,\n",
|
|
" 'armnorm': armnorm,\n",
|
|
" 'rep': rep,\n",
|
|
" 'session': session,\n",
|
|
" 'data': data \n",
|
|
" }\n",
|
|
" )\n",
|
|
" return dic_data"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "a7b4f994",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import pickle\n",
|
|
"\n",
|
|
"def save_pickle(f, structure):\n",
|
|
" _p = open(f, 'wb')\n",
|
|
" pickle.dump(structure, _p)\n",
|
|
" _p.close()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "b6b6fa69",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def load_pickles(f) -> list:\n",
|
|
" _p = open(pickle_file, 'rb')\n",
|
|
" _d = pickle.load(_p)\n",
|
|
" _p.close()\n",
|
|
" \n",
|
|
" return _d"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "38d131f0",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Loading data...\n",
|
|
"../data.pickle found...\n",
|
|
"768\n",
|
|
"CPU times: user 596 ms, sys: 2.15 s, total: 2.75 s\n",
|
|
"Wall time: 2.75 s\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%%time\n",
|
|
"\n",
|
|
"def load_data() -> list:\n",
|
|
" if os.path.isfile(pickle_file):\n",
|
|
" print(f'{pickle_file} found...')\n",
|
|
" return load_pickles(pickle_file)\n",
|
|
" print(f'Didn\\'t find {pickle_file}...')\n",
|
|
" all_data = dl_from_blob(glob_path)\n",
|
|
" print(f'Creating {pickle_file}...')\n",
|
|
" save_pickle(pickle_file, all_data)\n",
|
|
" return all_data\n",
|
|
"\n",
|
|
"print(\"Loading data...\")\n",
|
|
"dic_data = load_data()\n",
|
|
"print(len(dic_data))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "967f81ef",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"CPU times: user 398 µs, sys: 0 ns, total: 398 µs\n",
|
|
"Wall time: 402 µs\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%%time\n",
|
|
"\n",
|
|
"# Categorized Data\n",
|
|
"cdata = dict() \n",
|
|
"# Sorting, HeightNorm, ArmNorm\n",
|
|
"cdata['SYY'] = list() \n",
|
|
"cdata['SYN'] = list() \n",
|
|
"cdata['SNY'] = list() \n",
|
|
"cdata['SNN'] = list() \n",
|
|
"\n",
|
|
"# Jenga, HeightNorm, ArmNorm\n",
|
|
"cdata['JYY'] = list() \n",
|
|
"cdata['JYN'] = list() \n",
|
|
"cdata['JNY'] = list() \n",
|
|
"cdata['JNN'] = list() \n",
|
|
"for d in dic_data:\n",
|
|
" if d['scenario'] == 'Sorting':\n",
|
|
" if d['heightnorm']:\n",
|
|
" if d['armnorm']:\n",
|
|
" cdata['SYY'].append(d)\n",
|
|
" else:\n",
|
|
" cdata['SYN'].append(d)\n",
|
|
" else:\n",
|
|
" if d['armnorm']:\n",
|
|
" cdata['SNY'].append(d)\n",
|
|
" else:\n",
|
|
" cdata['SNN'].append(d)\n",
|
|
" elif d['scenario'] == 'Jenga':\n",
|
|
" if d['heightnorm']:\n",
|
|
" if d['armnorm']:\n",
|
|
" cdata['JYY'].append(d)\n",
|
|
" else:\n",
|
|
" cdata['JYN'].append(d)\n",
|
|
" else:\n",
|
|
" if d['armnorm']:\n",
|
|
" cdata['JNY'].append(d)\n",
|
|
" else:\n",
|
|
" cdata['JNN'].append(d)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "588af385",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Preprocessing"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"id": "375fee1d",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def drop(entry) -> pd.DataFrame:\n",
|
|
" droptable = ['participantID', 'FrameID', 'Scenario', 'HeightNormalization', 'ArmNormalization', 'Repetition', 'Session', 'Unnamed: 0']\n",
|
|
" centry = pickle.loads(pickle.dumps(entry))\n",
|
|
" return centry['data'].drop(droptable, axis=1)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"id": "e2b0b2fc",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def floatize(entry) -> pd.DataFrame:\n",
|
|
" centry = pickle.loads(pickle.dumps(entry))\n",
|
|
" centry['data']['LeftHandTrackingAccuracy'] = (entry['data']['LeftHandTrackingAccuracy'] == 'High') * 1.0\n",
|
|
" centry['data']['RightHandTrackingAccuracy'] = (entry['data']['RightHandTrackingAccuracy'] == 'High') * 1.0\n",
|
|
" return centry['data']"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"id": "9785e9f0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import numpy as np\n",
|
|
"right_Hand_ident='right_Hand'\n",
|
|
"left_Hand_ident='left_hand'\n",
|
|
"\n",
|
|
"def rem_low_acc(entry) -> pd.DataFrame:\n",
|
|
" centry = pickle.loads(pickle.dumps(entry))\n",
|
|
" right_Hand_cols = [c for c in centry['data'] if right_Hand_ident in c]\n",
|
|
" left_Hand_cols = [c for c in centry['data'] if left_Hand_ident in c]\n",
|
|
" \n",
|
|
" centry['data'].loc[centry['data']['RightHandTrackingAccuracy'] == 0.0, right_Hand_cols] = np.nan\n",
|
|
" centry['data'].loc[centry['data']['LeftHandTrackingAccuracy'] == 0.0, left_Hand_cols] = np.nan\n",
|
|
" return centry['data']"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"id": "3ec4cc1d",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from tensorflow.keras.preprocessing.sequence import pad_sequences\n",
|
|
"\n",
|
|
"stride = 150\n",
|
|
"def pad(entry) -> pd.DataFrame:\n",
|
|
" centry = pickle.loads(pickle.dumps(entry))\n",
|
|
" cols = centry['data'].columns\n",
|
|
" pentry = pad_sequences(centry['data'].T.to_numpy(),\n",
|
|
" maxlen=(int(centry['data'].shape[0]/stride)+1)*stride,\n",
|
|
" dtype='float64',\n",
|
|
" padding='pre', \n",
|
|
" truncating='post',\n",
|
|
" value=np.nan\n",
|
|
" ) \n",
|
|
" pdentry = pd.DataFrame(pentry.T, columns=cols)\n",
|
|
" pdentry.loc[0] = [0 for _ in cols]\n",
|
|
" return pdentry"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"id": "0361a89c",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def interpol(entry) -> pd.DataFrame:\n",
|
|
" centry = pickle.loads(pickle.dumps(entry))\n",
|
|
" return centry['data'].interpolate(method='linear', axis=0)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 15,
|
|
"id": "52b62534",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from tensorflow.keras.preprocessing import timeseries_dataset_from_array\n",
|
|
"\n",
|
|
"def slicing(entry):\n",
|
|
" centry = pickle.loads(pickle.dumps(entry))\n",
|
|
" return timeseries_dataset_from_array(\n",
|
|
" data=centry['data'], \n",
|
|
" targets=[centry['user'] for _ in range(centry['data'].shape[0])], \n",
|
|
" sequence_length=win_sz,\n",
|
|
" sequence_stride=stride_sz, \n",
|
|
" batch_size=8, \n",
|
|
" seed=177013\n",
|
|
" )"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"id": "383a8b9f",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from sklearn.preprocessing import (StandardScaler, \n",
|
|
" MinMaxScaler, \n",
|
|
" MaxAbsScaler,\n",
|
|
" PowerTransformer,\n",
|
|
" Binarizer)\n",
|
|
"def scaling(entry,scale):\n",
|
|
" \n",
|
|
" standard = StandardScaler()\n",
|
|
" max_Abs = MaxAbsScaler()\n",
|
|
" binarizer = Binarizer()\n",
|
|
" entry = entry.to_numpy(dtype=np.float64)\n",
|
|
" \n",
|
|
" if (scale == 0 ):\n",
|
|
" entry = min_Max.fit_transform(entry)\n",
|
|
" \n",
|
|
" if (scale == 1 ):\n",
|
|
" for i in entry:\n",
|
|
" entry = standard.fit_transform(entry)\n",
|
|
" \n",
|
|
" if (scale == 2 ):\n",
|
|
" for i in entry:\n",
|
|
" entry = max_Abs.fit_transform(entry)\n",
|
|
" \n",
|
|
" if (scale == 3 ):\n",
|
|
" for i in entry:\n",
|
|
" entry = binarizer.fit_transform(entry)\n",
|
|
" return pd.DataFrame(entry)\n",
|
|
"\n",
|
|
"\n",
|
|
"def minScale(entry):\n",
|
|
" entry = entry.to_numpy(dtype=np.float64)\n",
|
|
" min_Max = MinMaxScaler()\n",
|
|
" entry = min_Max.fit_transform(entry)\n",
|
|
" return pd.DataFrame(entry)\n",
|
|
" \n",
|
|
"\n",
|
|
"def stanScale(entry):\n",
|
|
" entry = entry.to_numpy(dtype=np.float64)\n",
|
|
" standard = StandardScaler()\n",
|
|
" entry = standard.fit_transform(entry)\n",
|
|
" return pd.DataFrame(entry)\n",
|
|
"\n",
|
|
"\n",
|
|
" \n",
|
|
"def maxScale(entry):\n",
|
|
" entry = entry.to_numpy(dtype=np.float64)\n",
|
|
" binarizer = Binarizer()\n",
|
|
" entry = binarizer.fit_transform(entry)\n",
|
|
" return pd.DataFrame(entry)\n",
|
|
" \n",
|
|
" \n",
|
|
"\n",
|
|
"def binScale(entry):\n",
|
|
" entry = entry.to_numpy(dtype=np.float64)\n",
|
|
" min_Max = MinMaxScaler()\n",
|
|
" entry = min_Max.fit_transform(entry)\n",
|
|
" return pd.DataFrame(entry)\n",
|
|
" "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 17,
|
|
"id": "29134efc",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"100%|██████████| 96/96 [00:16<00:00, 5.95it/s]\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"from sklearn.preprocessing import (StandardScaler, \n",
|
|
" MinMaxScaler, \n",
|
|
" MaxAbsScaler,\n",
|
|
" PowerTransformer,\n",
|
|
" Binarizer)\n",
|
|
"\n",
|
|
"#%%time\n",
|
|
"\n",
|
|
"classes = 16 # dynamic\n",
|
|
"\n",
|
|
"def preproc(data):\n",
|
|
" res_list = list()\n",
|
|
" temp_list= list()\n",
|
|
" for e in tqdm(data):\n",
|
|
" res_list.append(preproc_entry(e))\n",
|
|
"# for a in tqdm(temp_list):\n",
|
|
"# res_list.append(preproc_entry(a))\n",
|
|
"# \n",
|
|
" return res_list\n",
|
|
" \n",
|
|
"def preproc_entry(entry):\n",
|
|
" entry2 = pickle.loads(pickle.dumps(entry))\n",
|
|
" entry2['data'] = drop(entry2)\n",
|
|
" \n",
|
|
" entry3 = pickle.loads(pickle.dumps(entry2))\n",
|
|
" entry3['data'] = floatize(entry3)\n",
|
|
" \n",
|
|
" entry4 = pickle.loads(pickle.dumps(entry3))\n",
|
|
" entry4['data'] = rem_low_acc(entry4)\n",
|
|
" \n",
|
|
" \n",
|
|
" \n",
|
|
" entry5 = pickle.loads(pickle.dumps(entry4))\n",
|
|
" entry5['data'] = pad(entry5)\n",
|
|
" \n",
|
|
" entry6 = pickle.loads(pickle.dumps(entry5))\n",
|
|
" entry6['data'] = interpol(entry6)\n",
|
|
" \n",
|
|
" entry8 = pickle.loads(pickle.dumps(entry6))\n",
|
|
" entry8['data'] = minScale(entry8['data']) # 0 = minmax, 1 = standard, 2 = maxabs, 3 = binarizer\n",
|
|
" \n",
|
|
" entry7 = pickle.loads(pickle.dumps(entry8))\n",
|
|
" entry7['data'] = slicing(entry7)\n",
|
|
" \n",
|
|
" \n",
|
|
" \n",
|
|
" \n",
|
|
" return entry7\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"pdata = preproc(cdata[cenario])\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "f8157b26",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Building Model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 18,
|
|
"id": "2eb9c242",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import tensorflow as tf\n",
|
|
"from tensorflow.keras.models import Sequential\n",
|
|
"from tensorflow.keras.layers import Dense, Flatten, BatchNormalization, Dropout, LSTM\n",
|
|
"import tensorflow.keras as keras\n",
|
|
"\n",
|
|
"def build_model(shape, classes):\n",
|
|
" \n",
|
|
" model = Sequential()\n",
|
|
" ncount = shape[0]*shape[1]\n",
|
|
" \n",
|
|
" model.add(Flatten(input_shape=shape))\n",
|
|
" \n",
|
|
" model.add(Dropout(drop_count))\n",
|
|
" model.add(BatchNormalization())\n",
|
|
" \n",
|
|
" for i in range(1,layer_count):\n",
|
|
" neurons = int(ncount/pow(dense_steps,i))\n",
|
|
" if neurons <= classes*dense_steps:\n",
|
|
" break\n",
|
|
" model.add(Dropout(drop_count*i))\n",
|
|
" model.add(Dense(neurons, activation='relu'))\n",
|
|
" \n",
|
|
" model.add(Dense(classes, activation='softmax'))\n",
|
|
"\n",
|
|
" model.compile(\n",
|
|
" optimizer=tf.keras.optimizers.Adam(0.001),\n",
|
|
" loss=\"categorical_crossentropy\", \n",
|
|
" metrics=[\"acc\"],\n",
|
|
" )\n",
|
|
"\n",
|
|
" return model\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 19,
|
|
"id": "eb3212ae",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"checkpoint_file = './goat.weights'\n",
|
|
"\n",
|
|
"def train_model(X_train, y_train, X_test, y_test):\n",
|
|
" model = build_model(X_train[0].shape, 16)\n",
|
|
" \n",
|
|
" model.summary()\n",
|
|
"\n",
|
|
" model_checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(\n",
|
|
" filepath = checkpoint_file,\n",
|
|
" save_weights_only=True,\n",
|
|
" monitor='val_acc',\n",
|
|
" mode='max',\n",
|
|
" save_best_only=True\n",
|
|
" )\n",
|
|
" \n",
|
|
" history = model.fit(X_train, \n",
|
|
" y_train,\n",
|
|
" epochs=30,\n",
|
|
" batch_size=128,\n",
|
|
" shuffle=True,\n",
|
|
" verbose=2,\n",
|
|
" validation_data=(X_test, y_test),\n",
|
|
" callbacks=[model_checkpoint_callback]\n",
|
|
" \n",
|
|
" )\n",
|
|
" return model, history\n",
|
|
"\n",
|
|
"\n",
|
|
" "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 20,
|
|
"id": "cb296665",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"CPU times: user 375 µs, sys: 0 ns, total: 375 µs\n",
|
|
"Wall time: 396 µs\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"(48, 48)"
|
|
]
|
|
},
|
|
"execution_count": 20,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"%%time\n",
|
|
"train = np.array([x['data'] for x in pdata if x['session'] == 1])\n",
|
|
"test = np.array([x['data'] for x in pdata if x['session'] == 2])\n",
|
|
"\n",
|
|
"len(train), len(test)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 21,
|
|
"id": "bf378c00",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"CPU times: user 25.7 s, sys: 6.87 s, total: 32.6 s\n",
|
|
"Wall time: 9.2 s\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%%time\n",
|
|
"\n",
|
|
"X_train = list()\n",
|
|
"y_train = list()\n",
|
|
"\n",
|
|
"X_test = list()\n",
|
|
"y_test = list()\n",
|
|
"\n",
|
|
"train = list()\n",
|
|
"test = list()\n",
|
|
"\n",
|
|
"for x in pdata:\n",
|
|
" if x['session'] == 1:\n",
|
|
" train.append(\n",
|
|
" {\n",
|
|
" 'label': x['user'],\n",
|
|
" 'data': list()\n",
|
|
" })\n",
|
|
" for y in x['data'].unbatch().as_numpy_iterator():\n",
|
|
" X_train.append(y[0])\n",
|
|
" y_train.append(y[1])\n",
|
|
" \n",
|
|
" train[-1]['data'].append(y[0])\n",
|
|
" if x['session'] == 2:\n",
|
|
" test.append(\n",
|
|
" {\n",
|
|
" 'label': x['user'],\n",
|
|
" 'data': list()\n",
|
|
" })\n",
|
|
" for y in x['data'].unbatch().as_numpy_iterator():\n",
|
|
" X_test.append(y[0])\n",
|
|
" y_test.append(y[1])\n",
|
|
" \n",
|
|
" test[-1]['data'].append(y[0])\n",
|
|
"\n",
|
|
"X_train = np.array(X_train)\n",
|
|
"y_train = np.array(y_train)\n",
|
|
"X_test = np.array(X_test)\n",
|
|
"y_test = np.array(y_test)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 22,
|
|
"id": "fdb1b754",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"((30432, 10, 338), (30432,), (20502, 10, 338), (20502,))"
|
|
]
|
|
},
|
|
"execution_count": 22,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"X_train.shape, y_train.shape, X_test.shape, y_test.shape"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 23,
|
|
"id": "4b29f6dd",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"CPU times: user 241 ms, sys: 116 ms, total: 358 ms\n",
|
|
"Wall time: 357 ms\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%%time\n",
|
|
"\n",
|
|
"from sklearn.preprocessing import LabelBinarizer\n",
|
|
"\n",
|
|
"lb = LabelBinarizer()\n",
|
|
"yy_train = lb.fit_transform(y_train)\n",
|
|
"yy_test = lb.fit_transform(y_test)\n",
|
|
"\n",
|
|
"for e in test:\n",
|
|
" e['label'] = lb.transform([e['label']])\n",
|
|
" e['data'] = np.array(e['data'])\n",
|
|
" \n",
|
|
"for e in train:\n",
|
|
" e['label'] = lb.transform([e['label']])\n",
|
|
" e['data'] = np.array(e['data'])\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 24,
|
|
"id": "e50d9d82",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"(30432, 10, 338)\n",
|
|
"(30432, 16)\n",
|
|
"(20502, 10, 338)\n",
|
|
"(20502, 16)\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"print(X_train.shape)\n",
|
|
"print(yy_train.shape)\n",
|
|
"print(X_test.shape)\n",
|
|
"print(yy_test.shape)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 25,
|
|
"id": "29cab8e3",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Model: \"sequential\"\n",
|
|
"_________________________________________________________________\n",
|
|
"Layer (type) Output Shape Param # \n",
|
|
"=================================================================\n",
|
|
"flatten (Flatten) (None, 3380) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"dropout (Dropout) (None, 3380) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"batch_normalization (BatchNo (None, 3380) 13520 \n",
|
|
"_________________________________________________________________\n",
|
|
"dropout_1 (Dropout) (None, 3380) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"dense (Dense) (None, 1126) 3807006 \n",
|
|
"_________________________________________________________________\n",
|
|
"dropout_2 (Dropout) (None, 1126) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"dense_1 (Dense) (None, 375) 422625 \n",
|
|
"_________________________________________________________________\n",
|
|
"dense_2 (Dense) (None, 16) 6016 \n",
|
|
"=================================================================\n",
|
|
"Total params: 4,249,167\n",
|
|
"Trainable params: 4,242,407\n",
|
|
"Non-trainable params: 6,760\n",
|
|
"_________________________________________________________________\n",
|
|
"Epoch 1/30\n",
|
|
"238/238 - 2s - loss: 0.2785 - acc: 0.9139 - val_loss: 7.5618 - val_acc: 0.1295\n",
|
|
"Epoch 2/30\n",
|
|
"238/238 - 1s - loss: 0.0757 - acc: 0.9780 - val_loss: 9.8776 - val_acc: 0.1766\n",
|
|
"Epoch 3/30\n",
|
|
"238/238 - 1s - loss: 0.0565 - acc: 0.9830 - val_loss: 12.0728 - val_acc: 0.1515\n",
|
|
"Epoch 4/30\n",
|
|
"238/238 - 1s - loss: 0.0534 - acc: 0.9857 - val_loss: 14.3411 - val_acc: 0.1648\n",
|
|
"Epoch 5/30\n",
|
|
"238/238 - 1s - loss: 0.0376 - acc: 0.9897 - val_loss: 15.7724 - val_acc: 0.1598\n",
|
|
"Epoch 6/30\n",
|
|
"238/238 - 1s - loss: 0.0464 - acc: 0.9881 - val_loss: 17.0488 - val_acc: 0.1536\n",
|
|
"Epoch 7/30\n",
|
|
"238/238 - 1s - loss: 0.0417 - acc: 0.9889 - val_loss: 19.5126 - val_acc: 0.1550\n",
|
|
"Epoch 8/30\n",
|
|
"238/238 - 1s - loss: 0.0387 - acc: 0.9901 - val_loss: 19.9876 - val_acc: 0.1788\n",
|
|
"Epoch 9/30\n",
|
|
"238/238 - 1s - loss: 0.0339 - acc: 0.9908 - val_loss: 19.5807 - val_acc: 0.1572\n",
|
|
"Epoch 10/30\n",
|
|
"238/238 - 1s - loss: 0.0291 - acc: 0.9930 - val_loss: 20.1623 - val_acc: 0.1779\n",
|
|
"Epoch 11/30\n",
|
|
"238/238 - 1s - loss: 0.0433 - acc: 0.9914 - val_loss: 23.2585 - val_acc: 0.1521\n",
|
|
"Epoch 12/30\n",
|
|
"238/238 - 1s - loss: 0.0393 - acc: 0.9913 - val_loss: 25.2286 - val_acc: 0.1594\n",
|
|
"Epoch 13/30\n",
|
|
"238/238 - 1s - loss: 0.0262 - acc: 0.9946 - val_loss: 24.5537 - val_acc: 0.1794\n",
|
|
"Epoch 14/30\n",
|
|
"238/238 - 1s - loss: 0.0264 - acc: 0.9947 - val_loss: 26.0528 - val_acc: 0.1804\n",
|
|
"Epoch 15/30\n",
|
|
"238/238 - 1s - loss: 0.0484 - acc: 0.9910 - val_loss: 25.6410 - val_acc: 0.1610\n",
|
|
"Epoch 16/30\n",
|
|
"238/238 - 1s - loss: 0.0211 - acc: 0.9948 - val_loss: 28.7820 - val_acc: 0.1696\n",
|
|
"Epoch 17/30\n",
|
|
"238/238 - 1s - loss: 0.0177 - acc: 0.9957 - val_loss: 25.7378 - val_acc: 0.1955\n",
|
|
"Epoch 18/30\n",
|
|
"238/238 - 1s - loss: 0.0233 - acc: 0.9956 - val_loss: 27.1410 - val_acc: 0.1924\n",
|
|
"Epoch 19/30\n",
|
|
"238/238 - 1s - loss: 0.0380 - acc: 0.9934 - val_loss: 30.4740 - val_acc: 0.1707\n",
|
|
"Epoch 20/30\n",
|
|
"238/238 - 1s - loss: 0.0286 - acc: 0.9938 - val_loss: 27.3403 - val_acc: 0.1771\n",
|
|
"Epoch 21/30\n",
|
|
"238/238 - 1s - loss: 0.0205 - acc: 0.9954 - val_loss: 30.5033 - val_acc: 0.1706\n",
|
|
"Epoch 22/30\n",
|
|
"238/238 - 1s - loss: 0.0288 - acc: 0.9949 - val_loss: 31.7822 - val_acc: 0.1682\n",
|
|
"Epoch 23/30\n",
|
|
"238/238 - 1s - loss: 0.0309 - acc: 0.9950 - val_loss: 28.9407 - val_acc: 0.1791\n",
|
|
"Epoch 24/30\n",
|
|
"238/238 - 1s - loss: 0.0173 - acc: 0.9961 - val_loss: 32.9953 - val_acc: 0.1817\n",
|
|
"Epoch 25/30\n",
|
|
"238/238 - 1s - loss: 0.0189 - acc: 0.9965 - val_loss: 33.6316 - val_acc: 0.1817\n",
|
|
"Epoch 26/30\n",
|
|
"238/238 - 1s - loss: 0.0276 - acc: 0.9953 - val_loss: 33.3303 - val_acc: 0.1635\n",
|
|
"Epoch 27/30\n",
|
|
"238/238 - 1s - loss: 0.0243 - acc: 0.9961 - val_loss: 35.7127 - val_acc: 0.1422\n",
|
|
"Epoch 28/30\n",
|
|
"238/238 - 1s - loss: 0.0308 - acc: 0.9949 - val_loss: 33.3842 - val_acc: 0.1697\n",
|
|
"Epoch 29/30\n",
|
|
"238/238 - 1s - loss: 0.0342 - acc: 0.9952 - val_loss: 39.3381 - val_acc: 0.1698\n",
|
|
"Epoch 30/30\n",
|
|
"238/238 - 1s - loss: 0.0231 - acc: 0.9959 - val_loss: 38.9394 - val_acc: 0.1641\n",
|
|
"CPU times: user 1min 7s, sys: 26.2 s, total: 1min 33s\n",
|
|
"Wall time: 29.6 s\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%%time\n",
|
|
"\n",
|
|
"model, history = train_model(np.array(X_train), np.array(yy_train), np.array(X_test), np.array(yy_test))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "941c82f8",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Eval"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 26,
|
|
"id": "bdf45d51",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def predict(model, entry):\n",
|
|
" p_dict = dict()\n",
|
|
" predictions = np.argmax(model.predict(entry['data']), axis=-1)\n",
|
|
" for p in predictions:\n",
|
|
" if p in p_dict:\n",
|
|
" p_dict[p] += 1\n",
|
|
" else:\n",
|
|
" p_dict[p] = 1\n",
|
|
" prediction = max(p_dict, key=p_dict.get)\n",
|
|
" return prediction+1"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 27,
|
|
"id": "5dbc1e1e",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"CPU times: user 2.59 s, sys: 335 ms, total: 2.92 s\n",
|
|
"Wall time: 2.17 s\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%%time\n",
|
|
"\n",
|
|
"ltest = [lb.inverse_transform(e['label'])[0] for e in test]\n",
|
|
"ptest = [predict(model, e) for e in test]\n",
|
|
"\n",
|
|
"# for e in test:\n",
|
|
"# print(f\"Label: {lb.inverse_transform(e['label'])[0]:2d}\")\n",
|
|
"# print(f\"Prediction: {predict(model, e):2d}\\n_______________\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 28,
|
|
"id": "10056f7d",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"CPU times: user 3.2 s, sys: 264 ms, total: 3.47 s\n",
|
|
"Wall time: 2.44 s\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%%time\n",
|
|
"\n",
|
|
"ltrain = [lb.inverse_transform(e['label'])[0] for e in train]\n",
|
|
"ptrain = [predict(model, e) for e in train]\n",
|
|
"\n",
|
|
"# for e in train:\n",
|
|
"# print(f\"Label: {lb.inverse_transform(e['label'])[0]:2d}\")\n",
|
|
"# print(f\"Prediction: {predict(model, e):2d}\\n_______________\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 29,
|
|
"id": "48aad447",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "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\n",
|
|
"text/plain": [
|
|
"<Figure size 720x504 with 2 Axes>"
|
|
]
|
|
},
|
|
"metadata": {
|
|
"needs_background": "light"
|
|
},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" precision recall f1-score support\n",
|
|
"\n",
|
|
" 1 0.33 0.33 0.33 3\n",
|
|
" 2 0.00 0.00 0.00 3\n",
|
|
" 3 0.00 0.00 0.00 3\n",
|
|
" 4 0.00 0.00 0.00 3\n",
|
|
" 5 0.14 0.33 0.20 3\n",
|
|
" 6 0.00 0.00 0.00 3\n",
|
|
" 7 0.00 0.00 0.00 3\n",
|
|
" 8 0.00 0.00 0.00 3\n",
|
|
" 9 0.75 1.00 0.86 3\n",
|
|
" 10 0.00 0.00 0.00 3\n",
|
|
" 11 0.00 0.00 0.00 3\n",
|
|
" 12 0.38 1.00 0.55 3\n",
|
|
" 13 0.50 0.33 0.40 3\n",
|
|
" 14 0.00 0.00 0.00 3\n",
|
|
" 15 0.17 0.33 0.22 3\n",
|
|
" 16 0.00 0.00 0.00 3\n",
|
|
"\n",
|
|
" accuracy 0.21 48\n",
|
|
" macro avg 0.14 0.21 0.16 48\n",
|
|
"weighted avg 0.14 0.21 0.16 48\n",
|
|
"\n",
|
|
"CPU times: user 649 ms, sys: 204 ms, total: 853 ms\n",
|
|
"Wall time: 623 ms\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%%time\n",
|
|
"\n",
|
|
"from sklearn.metrics import confusion_matrix\n",
|
|
"import seaborn as sn\n",
|
|
"\n",
|
|
"from sklearn.metrics import classification_report\n",
|
|
"\n",
|
|
"set_digits = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }\n",
|
|
"\n",
|
|
"train_cm = confusion_matrix(ltrain, ptrain, normalize='true')\n",
|
|
"test_cm = confusion_matrix(ltest, ptest, normalize='true')\n",
|
|
"\n",
|
|
"df_cm = pd.DataFrame(test_cm, index=set_digits, columns=set_digits)\n",
|
|
"plt.figure(figsize = (10,7))\n",
|
|
"sn_plot = sn.heatmap(df_cm, annot=True, cmap=\"Greys\")\n",
|
|
"plt.ylabel(\"True Label\")\n",
|
|
"plt.xlabel(\"Predicted Label\")\n",
|
|
"plt.show()\n",
|
|
"\n",
|
|
"print(classification_report(ltest, ptest, zero_division=0))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 30,
|
|
"id": "9c334bde",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"cenario: SYN\n",
|
|
"win_sz: 10\n",
|
|
"stride_sz: 5\n",
|
|
"dense_steps: 3\n",
|
|
"layer_count: 3\n",
|
|
"drop_count: 0.1\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"print(f'cenario: {cenario}')\n",
|
|
"print(f'win_sz: {win_sz}')\n",
|
|
"print(f'stride_sz: {stride_sz}')\n",
|
|
"print(f'dense_steps: {dense_steps}')\n",
|
|
"print(f'layer_count: {layer_count}')\n",
|
|
"print(f'drop_count: {drop_count}')\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 31,
|
|
"id": "15fa9b96",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"exit()"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"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.8.10"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|