├── .gitignore ├── LICENSE ├── README.md ├── keystroke dynamics authentication.ipynb ├── model.h5 └── model.png /.gitignore: -------------------------------------------------------------------------------- 1 | datasets 2 | .ipynb_checkpoints -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Piyush Malhotra 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Keystroke Dynamics Using LSTMs 2 | This repository is a demo for using a LSTM based model to predict whether the person trying to login is authentic or not using keystroke dynamics. 3 | 4 | ## Dependencies 5 | 1. Keras 6 | 2. TensorFlow 7 | 3. Numpy 8 | 4. Pandas 9 | 5. Jupyter 10 | 11 | ## Usage 12 | Run ```jupyter notebook keystroke dynamics authentication.ipynb``` to run the notebook 13 | 14 | ## Dataset 15 | ```Cs.cmu.edu. (2018). Keystroke Dynamics - Benchmark Data Set. [online] Available at: https://www.cs.cmu.edu/~keystroke/``` -------------------------------------------------------------------------------- /keystroke dynamics authentication.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Keystroke Dynamics Using RNNs\n", 8 | "This notebook goes from the process of cleaning and preparing data to train and test a RNN for the job of Keystroke Dynamics. The Authentication Procedure comprises of using the timing of key strike, key hold, key change and so on to reach a conclusion whether the subject under observation is authentic or not." 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## Data Preparation & Cleaning" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 1, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "import pandas as pd\n", 25 | "import numpy as np\n", 26 | "import matplotlib.pyplot as plt\n", 27 | "\n", 28 | "%matplotlib inline" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 2, 34 | "metadata": {}, 35 | "outputs": [ 36 | { 37 | "data": { 38 | "text/html": [ 39 | "
\n", 40 | "\n", 41 | " \n", 42 | " \n", 43 | " \n", 44 | " \n", 45 | " \n", 46 | " \n", 47 | " \n", 48 | " \n", 49 | " \n", 50 | " \n", 51 | " \n", 52 | " \n", 53 | " \n", 54 | " \n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | "
subjectsessionIndexrepH.periodDD.period.tUD.period.tH.tDD.t.iUD.t.iH.i...H.aDD.a.nUD.a.nH.nDD.n.lUD.n.lH.lDD.l.ReturnUD.l.ReturnH.Return
0s002110.14910.39790.24880.10690.16740.06050.1169...0.13490.14840.01350.09320.35150.25830.13380.35090.21710.0742
1s002120.11110.34510.23400.06940.12830.05890.0908...0.14120.25580.11460.11460.26420.14960.08390.27560.19170.0747
2s002130.13280.20720.07440.07310.12910.05600.0821...0.16210.23320.07110.11720.27050.15330.10850.28470.17620.0945
3s002140.12910.25150.12240.10590.24950.14360.1040...0.14570.16290.01720.08660.23410.14750.08450.32320.23870.0813
4s002150.12490.23170.10680.08950.16760.07810.0903...0.13120.15820.02700.08840.25170.16330.09030.25170.16140.0818
\n", 190 | "

5 rows × 34 columns

\n", 191 | "
" 192 | ], 193 | "text/plain": [ 194 | " subject sessionIndex rep H.period DD.period.t UD.period.t H.t \\\n", 195 | "0 s002 1 1 0.1491 0.3979 0.2488 0.1069 \n", 196 | "1 s002 1 2 0.1111 0.3451 0.2340 0.0694 \n", 197 | "2 s002 1 3 0.1328 0.2072 0.0744 0.0731 \n", 198 | "3 s002 1 4 0.1291 0.2515 0.1224 0.1059 \n", 199 | "4 s002 1 5 0.1249 0.2317 0.1068 0.0895 \n", 200 | "\n", 201 | " DD.t.i UD.t.i H.i ... H.a DD.a.n UD.a.n H.n DD.n.l \\\n", 202 | "0 0.1674 0.0605 0.1169 ... 0.1349 0.1484 0.0135 0.0932 0.3515 \n", 203 | "1 0.1283 0.0589 0.0908 ... 0.1412 0.2558 0.1146 0.1146 0.2642 \n", 204 | "2 0.1291 0.0560 0.0821 ... 0.1621 0.2332 0.0711 0.1172 0.2705 \n", 205 | "3 0.2495 0.1436 0.1040 ... 0.1457 0.1629 0.0172 0.0866 0.2341 \n", 206 | "4 0.1676 0.0781 0.0903 ... 0.1312 0.1582 0.0270 0.0884 0.2517 \n", 207 | "\n", 208 | " UD.n.l H.l DD.l.Return UD.l.Return H.Return \n", 209 | "0 0.2583 0.1338 0.3509 0.2171 0.0742 \n", 210 | "1 0.1496 0.0839 0.2756 0.1917 0.0747 \n", 211 | "2 0.1533 0.1085 0.2847 0.1762 0.0945 \n", 212 | "3 0.1475 0.0845 0.3232 0.2387 0.0813 \n", 213 | "4 0.1633 0.0903 0.2517 0.1614 0.0818 \n", 214 | "\n", 215 | "[5 rows x 34 columns]" 216 | ] 217 | }, 218 | "execution_count": 2, 219 | "metadata": {}, 220 | "output_type": "execute_result" 221 | } 222 | ], 223 | "source": [ 224 | "df = pd.read_csv('./datasets/data.csv')\n", 225 | "\n", 226 | "df.head()" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 3, 232 | "metadata": {}, 233 | "outputs": [], 234 | "source": [ 235 | "subjects = df['subject'].unique()" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": 4, 241 | "metadata": {}, 242 | "outputs": [], 243 | "source": [ 244 | "subjects_to_int = {subject: i for i, subject in enumerate(subjects)}\n", 245 | "int_to_subjects = {i: subject for i, subject in enumerate(subjects)}" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": 5, 251 | "metadata": {}, 252 | "outputs": [], 253 | "source": [ 254 | "df = df.replace(subjects_to_int)" 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "execution_count": 6, 260 | "metadata": {}, 261 | "outputs": [ 262 | { 263 | "data": { 264 | "text/html": [ 265 | "
\n", 266 | "\n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | "
subjectsessionIndexrepH.periodDD.period.tUD.period.tH.tDD.t.iUD.t.iH.i...H.aDD.a.nUD.a.nH.nDD.n.lUD.n.lH.lDD.l.ReturnUD.l.ReturnH.Return
00110.14910.39790.24880.10690.16740.06050.1169...0.13490.14840.01350.09320.35150.25830.13380.35090.21710.0742
10120.11110.34510.23400.06940.12830.05890.0908...0.14120.25580.11460.11460.26420.14960.08390.27560.19170.0747
20130.13280.20720.07440.07310.12910.05600.0821...0.16210.23320.07110.11720.27050.15330.10850.28470.17620.0945
30140.12910.25150.12240.10590.24950.14360.1040...0.14570.16290.01720.08660.23410.14750.08450.32320.23870.0813
40150.12490.23170.10680.08950.16760.07810.0903...0.13120.15820.02700.08840.25170.16330.09030.25170.16140.0818
\n", 416 | "

5 rows × 34 columns

\n", 417 | "
" 418 | ], 419 | "text/plain": [ 420 | " subject sessionIndex rep H.period DD.period.t UD.period.t H.t \\\n", 421 | "0 0 1 1 0.1491 0.3979 0.2488 0.1069 \n", 422 | "1 0 1 2 0.1111 0.3451 0.2340 0.0694 \n", 423 | "2 0 1 3 0.1328 0.2072 0.0744 0.0731 \n", 424 | "3 0 1 4 0.1291 0.2515 0.1224 0.1059 \n", 425 | "4 0 1 5 0.1249 0.2317 0.1068 0.0895 \n", 426 | "\n", 427 | " DD.t.i UD.t.i H.i ... H.a DD.a.n UD.a.n H.n DD.n.l \\\n", 428 | "0 0.1674 0.0605 0.1169 ... 0.1349 0.1484 0.0135 0.0932 0.3515 \n", 429 | "1 0.1283 0.0589 0.0908 ... 0.1412 0.2558 0.1146 0.1146 0.2642 \n", 430 | "2 0.1291 0.0560 0.0821 ... 0.1621 0.2332 0.0711 0.1172 0.2705 \n", 431 | "3 0.2495 0.1436 0.1040 ... 0.1457 0.1629 0.0172 0.0866 0.2341 \n", 432 | "4 0.1676 0.0781 0.0903 ... 0.1312 0.1582 0.0270 0.0884 0.2517 \n", 433 | "\n", 434 | " UD.n.l H.l DD.l.Return UD.l.Return H.Return \n", 435 | "0 0.2583 0.1338 0.3509 0.2171 0.0742 \n", 436 | "1 0.1496 0.0839 0.2756 0.1917 0.0747 \n", 437 | "2 0.1533 0.1085 0.2847 0.1762 0.0945 \n", 438 | "3 0.1475 0.0845 0.3232 0.2387 0.0813 \n", 439 | "4 0.1633 0.0903 0.2517 0.1614 0.0818 \n", 440 | "\n", 441 | "[5 rows x 34 columns]" 442 | ] 443 | }, 444 | "execution_count": 6, 445 | "metadata": {}, 446 | "output_type": "execute_result" 447 | } 448 | ], 449 | "source": [ 450 | "df.head()" 451 | ] 452 | }, 453 | { 454 | "cell_type": "code", 455 | "execution_count": 7, 456 | "metadata": {}, 457 | "outputs": [], 458 | "source": [ 459 | "data = df.as_matrix()" 460 | ] 461 | }, 462 | { 463 | "cell_type": "code", 464 | "execution_count": 8, 465 | "metadata": {}, 466 | "outputs": [], 467 | "source": [ 468 | "def generate_positives(data, n_pos_per_subject=150):\n", 469 | " n_subjects = np.unique(data[:, 0]).shape[0]\n", 470 | " poss = []\n", 471 | " for i in range(n_subjects):\n", 472 | " temp_d = data[data[:, 0] == i]\n", 473 | " first_half = temp_d[np.random.choice(400, n_pos_per_subject), 3:-1]\n", 474 | " second_half = temp_d[np.random.choice(400, n_pos_per_subject), 3:-1]\n", 475 | " poss.append(np.hstack([first_half, second_half]))\n", 476 | " return np.vstack(poss)" 477 | ] 478 | }, 479 | { 480 | "cell_type": "code", 481 | "execution_count": 9, 482 | "metadata": {}, 483 | "outputs": [ 484 | { 485 | "data": { 486 | "text/plain": [ 487 | "(7650, 60)" 488 | ] 489 | }, 490 | "execution_count": 9, 491 | "metadata": {}, 492 | "output_type": "execute_result" 493 | } 494 | ], 495 | "source": [ 496 | "poss = generate_positives(data)\n", 497 | "poss.shape" 498 | ] 499 | }, 500 | { 501 | "cell_type": "code", 502 | "execution_count": 10, 503 | "metadata": {}, 504 | "outputs": [], 505 | "source": [ 506 | "def generate_negatives(data, n_neg_per_subject=150):\n", 507 | " n_subjects = np.unique(data[:, 0]).shape[0]\n", 508 | " negs = []\n", 509 | " for i in range(n_subjects):\n", 510 | " temp_d = data[data[:, 0] == i]\n", 511 | " temp_not_d = data[data[:, 0] != i]\n", 512 | " first_half = temp_d[np.random.choice(400, n_neg_per_subject), 3:-1]\n", 513 | " second_half = temp_not_d[np.random.choice(400, n_neg_per_subject), 3:-1]\n", 514 | " negs.append(np.hstack([first_half, second_half]))\n", 515 | " return np.vstack(negs)" 516 | ] 517 | }, 518 | { 519 | "cell_type": "code", 520 | "execution_count": 11, 521 | "metadata": {}, 522 | "outputs": [ 523 | { 524 | "data": { 525 | "text/plain": [ 526 | "(7650, 60)" 527 | ] 528 | }, 529 | "execution_count": 11, 530 | "metadata": {}, 531 | "output_type": "execute_result" 532 | } 533 | ], 534 | "source": [ 535 | "negs = generate_negatives(data)\n", 536 | "negs.shape" 537 | ] 538 | }, 539 | { 540 | "cell_type": "code", 541 | "execution_count": 12, 542 | "metadata": {}, 543 | "outputs": [ 544 | { 545 | "data": { 546 | "text/plain": [ 547 | "(15300, 1)" 548 | ] 549 | }, 550 | "execution_count": 12, 551 | "metadata": {}, 552 | "output_type": "execute_result" 553 | } 554 | ], 555 | "source": [ 556 | "labels = np.zeros(poss.shape[0] + negs.shape[0])\n", 557 | "labels[:poss.shape[0]] = 1\n", 558 | "labels = np.expand_dims(labels, axis=1)\n", 559 | "labels.shape" 560 | ] 561 | }, 562 | { 563 | "cell_type": "code", 564 | "execution_count": 13, 565 | "metadata": {}, 566 | "outputs": [ 567 | { 568 | "data": { 569 | "text/plain": [ 570 | "array([[ 0.1024, 0.1622, 0.0598, ..., 0.3598, 0.2524, 1. ],\n", 571 | " [ 0.1074, 0.1525, 0.0451, ..., 0.2532, 0.1466, 1. ],\n", 572 | " [ 0.0953, 0.1032, 0.0079, ..., 0.2263, 0.1413, 1. ],\n", 573 | " ..., \n", 574 | " [ 0.0765, 0.1231, 0.0466, ..., 0.192 , 0.1073, 0. ],\n", 575 | " [ 0.1031, 0.1049, 0.0018, ..., 0.2313, 0.1252, 0. ],\n", 576 | " [ 0.1055, 0.1089, 0.0034, ..., 0.2089, 0.1279, 0. ]])" 577 | ] 578 | }, 579 | "execution_count": 13, 580 | "metadata": {}, 581 | "output_type": "execute_result" 582 | } 583 | ], 584 | "source": [ 585 | "all_data = np.hstack([np.vstack([poss, negs]), labels])\n", 586 | "all_data" 587 | ] 588 | }, 589 | { 590 | "cell_type": "code", 591 | "execution_count": 14, 592 | "metadata": {}, 593 | "outputs": [], 594 | "source": [ 595 | "np.random.shuffle(all_data)" 596 | ] 597 | }, 598 | { 599 | "cell_type": "code", 600 | "execution_count": 15, 601 | "metadata": {}, 602 | "outputs": [], 603 | "source": [ 604 | "all_data_t = np.zeros((all_data.shape[0], 15, 4))\n", 605 | "\n", 606 | "ctr = 0\n", 607 | "for i, j in zip(range(0, 30, 2), range(30, 60, 2)):\n", 608 | " all_data_t[:, ctr, :] = np.hstack([all_data[:, i:i+2], all_data[:, j:j+2]])\n", 609 | " ctr += 1" 610 | ] 611 | }, 612 | { 613 | "cell_type": "code", 614 | "execution_count": 16, 615 | "metadata": {}, 616 | "outputs": [], 617 | "source": [ 618 | "X, y = all_data_t, all_data[:, -1]" 619 | ] 620 | }, 621 | { 622 | "cell_type": "markdown", 623 | "metadata": {}, 624 | "source": [ 625 | "## Training Phase\n", 626 | "This Phase defines parameters of the model, the model itself along with its training to produce a simple RNN that can predict whether a person is the genuine holder of account or not." 627 | ] 628 | }, 629 | { 630 | "cell_type": "markdown", 631 | "metadata": {}, 632 | "source": [ 633 | "### Some Params and HyperParams" 634 | ] 635 | }, 636 | { 637 | "cell_type": "code", 638 | "execution_count": 17, 639 | "metadata": {}, 640 | "outputs": [ 641 | { 642 | "name": "stderr", 643 | "output_type": "stream", 644 | "text": [ 645 | "Using TensorFlow backend.\n" 646 | ] 647 | } 648 | ], 649 | "source": [ 650 | "from keras.layers import Dense, Activation, Dropout, Input, LSTM, Reshape, Lambda, RepeatVector, Concatenate\n", 651 | "from keras.initializers import glorot_uniform\n", 652 | "from keras.utils import to_categorical\n", 653 | "from keras.models import Model\n", 654 | "from keras.optimizers import Adam" 655 | ] 656 | }, 657 | { 658 | "cell_type": "code", 659 | "execution_count": 18, 660 | "metadata": {}, 661 | "outputs": [], 662 | "source": [ 663 | "VALIDATION_SPLIT = 0.1\n", 664 | "\n", 665 | "INPUT_SHAPE = [None, 2]\n", 666 | "\n", 667 | "BATCH_SIZE = 32\n", 668 | "\n", 669 | "EPOCHS = 20" 670 | ] 671 | }, 672 | { 673 | "cell_type": "code", 674 | "execution_count": 19, 675 | "metadata": {}, 676 | "outputs": [], 677 | "source": [ 678 | "def train_dev_split(x, y, val_split=0.1):\n", 679 | " m = x.shape[0]\n", 680 | " val_size = int(0.1 * m)\n", 681 | " return x[:-val_size], y[:, :-val_size, :], x[-val_size:], y[:, -val_size:, :]" 682 | ] 683 | }, 684 | { 685 | "cell_type": "code", 686 | "execution_count": 20, 687 | "metadata": {}, 688 | "outputs": [], 689 | "source": [ 690 | "y = to_categorical(y)\n", 691 | "\n", 692 | "y_ = np.zeros((15, y.shape[0], y.shape[1]))\n", 693 | "\n", 694 | "for i in range(15):\n", 695 | " y_[i, :, :] = y" 696 | ] 697 | }, 698 | { 699 | "cell_type": "code", 700 | "execution_count": 21, 701 | "metadata": {}, 702 | "outputs": [ 703 | { 704 | "data": { 705 | "text/plain": [ 706 | "(array([ 0., 1.]), array([ 0., 1.]))" 707 | ] 708 | }, 709 | "execution_count": 21, 710 | "metadata": {}, 711 | "output_type": "execute_result" 712 | } 713 | ], 714 | "source": [ 715 | "y_[0, 0, :], y[0]" 716 | ] 717 | }, 718 | { 719 | "cell_type": "code", 720 | "execution_count": 22, 721 | "metadata": {}, 722 | "outputs": [ 723 | { 724 | "data": { 725 | "text/plain": [ 726 | "((13770, 15, 4), (15, 13770, 2), (1530, 15, 4), (15, 1530, 2))" 727 | ] 728 | }, 729 | "execution_count": 22, 730 | "metadata": {}, 731 | "output_type": "execute_result" 732 | } 733 | ], 734 | "source": [ 735 | "x_train, y_train, x_test, y_test = train_dev_split(X, y_)\n", 736 | "\n", 737 | "x_train.shape, y_train.shape, x_test.shape, y_test.shape" 738 | ] 739 | }, 740 | { 741 | "cell_type": "code", 742 | "execution_count": 23, 743 | "metadata": {}, 744 | "outputs": [], 745 | "source": [ 746 | "n_a = 10\n", 747 | "n_out = 2" 748 | ] 749 | }, 750 | { 751 | "cell_type": "code", 752 | "execution_count": 24, 753 | "metadata": {}, 754 | "outputs": [], 755 | "source": [ 756 | "reshapor = Reshape((1, 4))\n", 757 | "LSTM_cell = LSTM(n_a, return_state = True)\n", 758 | "densor = Dense(n_out, activation='softmax')" 759 | ] 760 | }, 761 | { 762 | "cell_type": "code", 763 | "execution_count": 25, 764 | "metadata": {}, 765 | "outputs": [], 766 | "source": [ 767 | "def keystroke_model(Tx, n_in, n_a, n_out):\n", 768 | " X = Input(shape=(Tx, n_in))\n", 769 | " \n", 770 | " a0 = Input(shape=(n_a,), name='a0')\n", 771 | " c0 = Input(shape=(n_a,), name='c0')\n", 772 | " a = a0\n", 773 | " c = c0\n", 774 | " \n", 775 | " outputs = []\n", 776 | "\n", 777 | " for t in range(Tx):\n", 778 | " \n", 779 | " x = Lambda(lambda x: X[:, t, :])(X)\n", 780 | " x = reshapor(x)\n", 781 | "\n", 782 | " a, _, c = LSTM_cell(x, initial_state=[a, c])\n", 783 | "\n", 784 | " out = densor(a)\n", 785 | "\n", 786 | " outputs.append(out)\n", 787 | "\n", 788 | " model = Model(inputs=[X, a0, c0], outputs=outputs)\n", 789 | " \n", 790 | " return model" 791 | ] 792 | }, 793 | { 794 | "cell_type": "code", 795 | "execution_count": 26, 796 | "metadata": {}, 797 | "outputs": [], 798 | "source": [ 799 | "model = keystroke_model(15, 4, n_a, n_out)" 800 | ] 801 | }, 802 | { 803 | "cell_type": "code", 804 | "execution_count": 27, 805 | "metadata": {}, 806 | "outputs": [], 807 | "source": [ 808 | "opt = Adam(lr=0.01, beta_1=0.9, beta_2=0.999, decay=0.01)\n", 809 | "\n", 810 | "model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])" 811 | ] 812 | }, 813 | { 814 | "cell_type": "code", 815 | "execution_count": 28, 816 | "metadata": {}, 817 | "outputs": [ 818 | { 819 | "name": "stdout", 820 | "output_type": "stream", 821 | "text": [ 822 | "__________________________________________________________________________________________________\n", 823 | "Layer (type) Output Shape Param # Connected to \n", 824 | "==================================================================================================\n", 825 | "input_1 (InputLayer) (None, 15, 4) 0 \n", 826 | "__________________________________________________________________________________________________\n", 827 | "lambda_1 (Lambda) (None, 4) 0 input_1[0][0] \n", 828 | "__________________________________________________________________________________________________\n", 829 | "reshape_1 (Reshape) (None, 1, 4) 0 lambda_1[0][0] \n", 830 | " lambda_2[0][0] \n", 831 | " lambda_3[0][0] \n", 832 | " lambda_4[0][0] \n", 833 | " lambda_5[0][0] \n", 834 | " lambda_6[0][0] \n", 835 | " lambda_7[0][0] \n", 836 | " lambda_8[0][0] \n", 837 | " lambda_9[0][0] \n", 838 | " lambda_10[0][0] \n", 839 | " lambda_11[0][0] \n", 840 | " lambda_12[0][0] \n", 841 | " lambda_13[0][0] \n", 842 | " lambda_14[0][0] \n", 843 | " lambda_15[0][0] \n", 844 | "__________________________________________________________________________________________________\n", 845 | "a0 (InputLayer) (None, 10) 0 \n", 846 | "__________________________________________________________________________________________________\n", 847 | "c0 (InputLayer) (None, 10) 0 \n", 848 | "__________________________________________________________________________________________________\n", 849 | "lambda_2 (Lambda) (None, 4) 0 input_1[0][0] \n", 850 | "__________________________________________________________________________________________________\n", 851 | "lstm_1 (LSTM) [(None, 10), (None, 600 reshape_1[0][0] \n", 852 | " a0[0][0] \n", 853 | " c0[0][0] \n", 854 | " reshape_1[1][0] \n", 855 | " lstm_1[0][0] \n", 856 | " lstm_1[0][2] \n", 857 | " reshape_1[2][0] \n", 858 | " lstm_1[1][0] \n", 859 | " lstm_1[1][2] \n", 860 | " reshape_1[3][0] \n", 861 | " lstm_1[2][0] \n", 862 | " lstm_1[2][2] \n", 863 | " reshape_1[4][0] \n", 864 | " lstm_1[3][0] \n", 865 | " lstm_1[3][2] \n", 866 | " reshape_1[5][0] \n", 867 | " lstm_1[4][0] \n", 868 | " lstm_1[4][2] \n", 869 | " reshape_1[6][0] \n", 870 | " lstm_1[5][0] \n", 871 | " lstm_1[5][2] \n", 872 | " reshape_1[7][0] \n", 873 | " lstm_1[6][0] \n", 874 | " lstm_1[6][2] \n", 875 | " reshape_1[8][0] \n", 876 | " lstm_1[7][0] \n", 877 | " lstm_1[7][2] \n", 878 | " reshape_1[9][0] \n", 879 | " lstm_1[8][0] \n", 880 | " lstm_1[8][2] \n", 881 | " reshape_1[10][0] \n", 882 | " lstm_1[9][0] \n", 883 | " lstm_1[9][2] \n", 884 | " reshape_1[11][0] \n", 885 | " lstm_1[10][0] \n", 886 | " lstm_1[10][2] \n", 887 | " reshape_1[12][0] \n", 888 | " lstm_1[11][0] \n", 889 | " lstm_1[11][2] \n", 890 | " reshape_1[13][0] \n", 891 | " lstm_1[12][0] \n", 892 | " lstm_1[12][2] \n", 893 | " reshape_1[14][0] \n", 894 | " lstm_1[13][0] \n", 895 | " lstm_1[13][2] \n", 896 | "__________________________________________________________________________________________________\n", 897 | "lambda_3 (Lambda) (None, 4) 0 input_1[0][0] \n", 898 | "__________________________________________________________________________________________________\n", 899 | "lambda_4 (Lambda) (None, 4) 0 input_1[0][0] \n", 900 | "__________________________________________________________________________________________________\n", 901 | "lambda_5 (Lambda) (None, 4) 0 input_1[0][0] \n", 902 | "__________________________________________________________________________________________________\n", 903 | "lambda_6 (Lambda) (None, 4) 0 input_1[0][0] \n", 904 | "__________________________________________________________________________________________________\n", 905 | "lambda_7 (Lambda) (None, 4) 0 input_1[0][0] \n", 906 | "__________________________________________________________________________________________________\n", 907 | "lambda_8 (Lambda) (None, 4) 0 input_1[0][0] \n", 908 | "__________________________________________________________________________________________________\n", 909 | "lambda_9 (Lambda) (None, 4) 0 input_1[0][0] \n", 910 | "__________________________________________________________________________________________________\n", 911 | "lambda_10 (Lambda) (None, 4) 0 input_1[0][0] \n", 912 | "__________________________________________________________________________________________________\n", 913 | "lambda_11 (Lambda) (None, 4) 0 input_1[0][0] \n", 914 | "__________________________________________________________________________________________________\n", 915 | "lambda_12 (Lambda) (None, 4) 0 input_1[0][0] \n", 916 | "__________________________________________________________________________________________________\n", 917 | "lambda_13 (Lambda) (None, 4) 0 input_1[0][0] \n", 918 | "__________________________________________________________________________________________________\n", 919 | "lambda_14 (Lambda) (None, 4) 0 input_1[0][0] \n", 920 | "__________________________________________________________________________________________________\n", 921 | "lambda_15 (Lambda) (None, 4) 0 input_1[0][0] \n", 922 | "__________________________________________________________________________________________________\n", 923 | "dense_1 (Dense) (None, 2) 22 lstm_1[0][0] \n", 924 | " lstm_1[1][0] \n", 925 | " lstm_1[2][0] \n", 926 | " lstm_1[3][0] \n", 927 | " lstm_1[4][0] \n", 928 | " lstm_1[5][0] \n", 929 | " lstm_1[6][0] \n", 930 | " lstm_1[7][0] \n", 931 | " lstm_1[8][0] \n", 932 | " lstm_1[9][0] \n", 933 | " lstm_1[10][0] \n", 934 | " lstm_1[11][0] \n", 935 | " lstm_1[12][0] \n", 936 | " lstm_1[13][0] \n", 937 | " lstm_1[14][0] \n", 938 | "==================================================================================================\n", 939 | "Total params: 622\n", 940 | "Trainable params: 622\n", 941 | "Non-trainable params: 0\n", 942 | "__________________________________________________________________________________________________\n" 943 | ] 944 | } 945 | ], 946 | "source": [ 947 | "model.summary()" 948 | ] 949 | }, 950 | { 951 | "cell_type": "code", 952 | "execution_count": 29, 953 | "metadata": {}, 954 | "outputs": [], 955 | "source": [ 956 | "m = x_train.shape[0]\n", 957 | "a0 = np.zeros((m, n_a))\n", 958 | "c0 = np.zeros((m, n_a))" 959 | ] 960 | }, 961 | { 962 | "cell_type": "code", 963 | "execution_count": 31, 964 | "metadata": {}, 965 | "outputs": [ 966 | { 967 | "name": "stdout", 968 | "output_type": "stream", 969 | "text": [ 970 | "Epoch 1/10\n", 971 | "13770/13770 [==============================] - 56s 4ms/step - loss: 10.3848 - dense_1_loss_1: 0.6944 - dense_1_loss_2: 0.6916 - dense_1_loss_3: 0.6912 - dense_1_loss_4: 0.6914 - dense_1_loss_5: 0.6906 - dense_1_loss_6: 0.6920 - dense_1_loss_7: 0.6923 - dense_1_loss_8: 0.6927 - dense_1_loss_9: 0.6925 - dense_1_loss_10: 0.6931 - dense_1_loss_11: 0.6929 - dense_1_loss_12: 0.6928 - dense_1_loss_13: 0.6927 - dense_1_loss_14: 0.6927 - dense_1_loss_15: 0.6918 - dense_1_acc_1: 0.4810 - dense_1_acc_2: 0.5246 - dense_1_acc_3: 0.5251 - dense_1_acc_4: 0.5248 - dense_1_acc_5: 0.5301 - dense_1_acc_6: 0.5130 - dense_1_acc_7: 0.5113 - dense_1_acc_8: 0.5106 - dense_1_acc_9: 0.5076 - dense_1_acc_10: 0.5081 - dense_1_acc_11: 0.5081 - dense_1_acc_12: 0.5078 - dense_1_acc_13: 0.5093 - dense_1_acc_14: 0.5089 - dense_1_acc_15: 0.5086: 11s - loss: 10.3932 - dense_1_loss_1: 0.6946 - dense_1_loss_2: 0.6922 - dense_1_loss_3: 0.6920 - dense_1_loss_4: 0.6922 - dense_1_loss_5: 0.6916 - dense_1_loss_6: 0.6925 - dense_1_loss_7: 0.6928 - dense_1_loss_8: 0.6930 - dense_1_loss_9: 0.6932 - dense_1_loss_10: 0.6935 - dense_1_loss_11: 0.6933 - dense_1_loss_12: 0.6933 - dense_1_loss_13: 0.6932 - dense_1_loss_14: 0.6932 - dense_1_loss_15: 0.6927 - dense_1_acc_1: 0.4784 - dense_1_acc_2: 0.5163 - dense_1_acc_3: 0.5151 - dense_1_acc_4: 0.5158 - dense_1_acc_5: 0.5212 - dense_1_acc_6: 0.5150 - dense_1_acc_7: 0.5135 - dense_1_acc_8: 0.5130 - dense_1_acc_9: 0.5055 - dense_1_acc_10: 0.5064 - dense_1_acc_11: 0.50\n", 972 | "Epoch 2/10\n", 973 | "13770/13770 [==============================] - 49s 4ms/step - loss: 9.6077 - dense_1_loss_1: 0.6934 - dense_1_loss_2: 0.6853 - dense_1_loss_3: 0.6792 - dense_1_loss_4: 0.6721 - dense_1_loss_5: 0.6626 - dense_1_loss_6: 0.6462 - dense_1_loss_7: 0.6392 - dense_1_loss_8: 0.6265 - dense_1_loss_9: 0.6190 - dense_1_loss_10: 0.6149 - dense_1_loss_11: 0.6108 - dense_1_loss_12: 0.6105 - dense_1_loss_13: 0.6103 - dense_1_loss_14: 0.6139 - dense_1_loss_15: 0.6240 - dense_1_acc_1: 0.4833 - dense_1_acc_2: 0.5985 - dense_1_acc_3: 0.6121 - dense_1_acc_4: 0.6129 - dense_1_acc_5: 0.6158 - dense_1_acc_6: 0.6251 - dense_1_acc_7: 0.6381 - dense_1_acc_8: 0.6356 - dense_1_acc_9: 0.6411 - dense_1_acc_10: 0.6469 - dense_1_acc_11: 0.6493 - dense_1_acc_12: 0.6477 - dense_1_acc_13: 0.6486 - dense_1_acc_14: 0.6434 - dense_1_acc_15: 0.6433\n", 974 | "Epoch 3/10\n", 975 | "13770/13770 [==============================] - 49s 4ms/step - loss: 9.0376 - dense_1_loss_1: 0.6912 - dense_1_loss_2: 0.6796 - dense_1_loss_3: 0.6677 - dense_1_loss_4: 0.6541 - dense_1_loss_5: 0.6386 - dense_1_loss_6: 0.6075 - dense_1_loss_7: 0.5959 - dense_1_loss_8: 0.5776 - dense_1_loss_9: 0.5702 - dense_1_loss_10: 0.5629 - dense_1_loss_11: 0.5564 - dense_1_loss_12: 0.5562 - dense_1_loss_13: 0.5541 - dense_1_loss_14: 0.5566 - dense_1_loss_15: 0.5688 - dense_1_acc_1: 0.5065 - dense_1_acc_2: 0.6169 - dense_1_acc_3: 0.6268 - dense_1_acc_4: 0.6336 - dense_1_acc_5: 0.6393 - dense_1_acc_6: 0.6777 - dense_1_acc_7: 0.7076 - dense_1_acc_8: 0.7195 - dense_1_acc_9: 0.7211 - dense_1_acc_10: 0.7277 - dense_1_acc_11: 0.7283 - dense_1_acc_12: 0.7275 - dense_1_acc_13: 0.7284 - dense_1_acc_14: 0.7253 - dense_1_acc_15: 0.7248\n", 976 | "Epoch 4/10\n", 977 | "13770/13770 [==============================] - 53s 4ms/step - loss: 8.7896 - dense_1_loss_1: 0.6898 - dense_1_loss_2: 0.6765 - dense_1_loss_3: 0.6621 - dense_1_loss_4: 0.6466 - dense_1_loss_5: 0.6297 - dense_1_loss_6: 0.5935 - dense_1_loss_7: 0.5781 - dense_1_loss_8: 0.5577 - dense_1_loss_9: 0.5499 - dense_1_loss_10: 0.5406 - dense_1_loss_11: 0.5328 - dense_1_loss_12: 0.5324 - dense_1_loss_13: 0.5293 - dense_1_loss_14: 0.5303 - dense_1_loss_15: 0.5402 - dense_1_acc_1: 0.5075 - dense_1_acc_2: 0.6200 - dense_1_acc_3: 0.6325 - dense_1_acc_4: 0.6382 - dense_1_acc_5: 0.6402 - dense_1_acc_6: 0.6963 - dense_1_acc_7: 0.7275 - dense_1_acc_8: 0.7453 - dense_1_acc_9: 0.7449 - dense_1_acc_10: 0.7474 - dense_1_acc_11: 0.7522 - dense_1_acc_12: 0.7502 - dense_1_acc_13: 0.7530 - dense_1_acc_14: 0.7525 - dense_1_acc_15: 0.7527\n", 978 | "Epoch 5/10\n", 979 | "13770/13770 [==============================] - 50s 4ms/step - loss: 8.6522 - dense_1_loss_1: 0.6887 - dense_1_loss_2: 0.6739 - dense_1_loss_3: 0.6579 - dense_1_loss_4: 0.6412 - dense_1_loss_5: 0.6236 - dense_1_loss_6: 0.5845 - dense_1_loss_7: 0.5674 - dense_1_loss_8: 0.5466 - dense_1_loss_9: 0.5389 - dense_1_loss_10: 0.5292 - dense_1_loss_11: 0.5208 - dense_1_loss_12: 0.5201 - dense_1_loss_13: 0.5168 - dense_1_loss_14: 0.5172 - dense_1_loss_15: 0.5254 - dense_1_acc_1: 0.5094 - dense_1_acc_2: 0.6211 - dense_1_acc_3: 0.6336 - dense_1_acc_4: 0.6452 - dense_1_acc_5: 0.6438 - dense_1_acc_6: 0.7056 - dense_1_acc_7: 0.7328 - dense_1_acc_8: 0.7508 - dense_1_acc_9: 0.7524 - dense_1_acc_10: 0.7554 - dense_1_acc_11: 0.7601 - dense_1_acc_12: 0.7588 - dense_1_acc_13: 0.7614 - dense_1_acc_14: 0.7630 - dense_1_acc_15: 0.7628\n", 980 | "Epoch 6/10\n", 981 | "13770/13770 [==============================] - 50s 4ms/step - loss: 8.5593 - dense_1_loss_1: 0.6877 - dense_1_loss_2: 0.6717 - dense_1_loss_3: 0.6544 - dense_1_loss_4: 0.6365 - dense_1_loss_5: 0.6186 - dense_1_loss_6: 0.5780 - dense_1_loss_7: 0.5602 - dense_1_loss_8: 0.5397 - dense_1_loss_9: 0.5321 - dense_1_loss_10: 0.5218 - dense_1_loss_11: 0.5131 - dense_1_loss_12: 0.5124 - dense_1_loss_13: 0.5086 - dense_1_loss_14: 0.5085 - dense_1_loss_15: 0.5161 - dense_1_acc_1: 0.5081 - dense_1_acc_2: 0.6282 - dense_1_acc_3: 0.6383 - dense_1_acc_4: 0.6476 - dense_1_acc_5: 0.6470 - dense_1_acc_6: 0.7078 - dense_1_acc_7: 0.7378 - dense_1_acc_8: 0.7574 - dense_1_acc_9: 0.7574 - dense_1_acc_10: 0.7619 - dense_1_acc_11: 0.7644 - dense_1_acc_12: 0.7639 - dense_1_acc_13: 0.7658 - dense_1_acc_14: 0.7679 - dense_1_acc_15: 0.7676\n", 982 | "Epoch 7/10\n", 983 | "13770/13770 [==============================] - 51s 4ms/step - loss: 8.5034 - dense_1_loss_1: 0.6868 - dense_1_loss_2: 0.6698 - dense_1_loss_3: 0.6514 - dense_1_loss_4: 0.6328 - dense_1_loss_5: 0.6147 - dense_1_loss_6: 0.5735 - dense_1_loss_7: 0.5555 - dense_1_loss_8: 0.5358 - dense_1_loss_9: 0.5283 - dense_1_loss_10: 0.5176 - dense_1_loss_11: 0.5087 - dense_1_loss_12: 0.5081 - dense_1_loss_13: 0.5042 - dense_1_loss_14: 0.5044 - dense_1_loss_15: 0.5118 - dense_1_acc_1: 0.5094 - dense_1_acc_2: 0.6304 - dense_1_acc_3: 0.6410 - dense_1_acc_4: 0.6476 - dense_1_acc_5: 0.6470 - dense_1_acc_6: 0.7105 - dense_1_acc_7: 0.7394 - dense_1_acc_8: 0.7588 - dense_1_acc_9: 0.7577 - dense_1_acc_10: 0.7635 - dense_1_acc_11: 0.7676 - dense_1_acc_12: 0.7670 - dense_1_acc_13: 0.7698 - dense_1_acc_14: 0.7710 - dense_1_acc_15: 0.7702\n", 984 | "Epoch 8/10\n", 985 | "13770/13770 [==============================] - 51s 4ms/step - loss: 8.4593 - dense_1_loss_1: 0.6861 - dense_1_loss_2: 0.6684 - dense_1_loss_3: 0.6493 - dense_1_loss_4: 0.6298 - dense_1_loss_5: 0.6115 - dense_1_loss_6: 0.5701 - dense_1_loss_7: 0.5525 - dense_1_loss_8: 0.5334 - dense_1_loss_9: 0.5259 - dense_1_loss_10: 0.5143 - dense_1_loss_11: 0.5050 - dense_1_loss_12: 0.5044 - dense_1_loss_13: 0.5003 - dense_1_loss_14: 0.5003 - dense_1_loss_15: 0.5079 - dense_1_acc_1: 0.5147 - dense_1_acc_2: 0.6299 - dense_1_acc_3: 0.6415 - dense_1_acc_4: 0.6495 - dense_1_acc_5: 0.6468 - dense_1_acc_6: 0.7113 - dense_1_acc_7: 0.7410 - dense_1_acc_8: 0.7611 - dense_1_acc_9: 0.7605 - dense_1_acc_10: 0.7646 - dense_1_acc_11: 0.7709 - dense_1_acc_12: 0.7683 - dense_1_acc_13: 0.7714 - dense_1_acc_14: 0.7745 - dense_1_acc_15: 0.7747\n", 986 | "Epoch 9/10\n", 987 | "13770/13770 [==============================] - 51s 4ms/step - loss: 8.4227 - dense_1_loss_1: 0.6855 - dense_1_loss_2: 0.6675 - dense_1_loss_3: 0.6478 - dense_1_loss_4: 0.6282 - dense_1_loss_5: 0.6105 - dense_1_loss_6: 0.5681 - dense_1_loss_7: 0.5491 - dense_1_loss_8: 0.5302 - dense_1_loss_9: 0.5228 - dense_1_loss_10: 0.5106 - dense_1_loss_11: 0.5012 - dense_1_loss_12: 0.5010 - dense_1_loss_13: 0.4971 - dense_1_loss_14: 0.4975 - dense_1_loss_15: 0.5058 - dense_1_acc_1: 0.5182 - dense_1_acc_2: 0.6318 - dense_1_acc_3: 0.6430 - dense_1_acc_4: 0.6506 - dense_1_acc_5: 0.6499 - dense_1_acc_6: 0.7138 - dense_1_acc_7: 0.7463 - dense_1_acc_8: 0.7618 - dense_1_acc_9: 0.7622 - dense_1_acc_10: 0.7650 - dense_1_acc_11: 0.7714 - dense_1_acc_12: 0.7697 - dense_1_acc_13: 0.7744 - dense_1_acc_14: 0.7765 - dense_1_acc_15: 0.7749\n", 988 | "Epoch 10/10\n" 989 | ] 990 | }, 991 | { 992 | "name": "stdout", 993 | "output_type": "stream", 994 | "text": [ 995 | "13770/13770 [==============================] - 50s 4ms/step - loss: 8.3825 - dense_1_loss_1: 0.6850 - dense_1_loss_2: 0.6665 - dense_1_loss_3: 0.6463 - dense_1_loss_4: 0.6262 - dense_1_loss_5: 0.6081 - dense_1_loss_6: 0.5651 - dense_1_loss_7: 0.5465 - dense_1_loss_8: 0.5276 - dense_1_loss_9: 0.5200 - dense_1_loss_10: 0.5072 - dense_1_loss_11: 0.4977 - dense_1_loss_12: 0.4974 - dense_1_loss_13: 0.4934 - dense_1_loss_14: 0.4936 - dense_1_loss_15: 0.5019 - dense_1_acc_1: 0.5252 - dense_1_acc_2: 0.6338 - dense_1_acc_3: 0.6433 - dense_1_acc_4: 0.6529 - dense_1_acc_5: 0.6486 - dense_1_acc_6: 0.7179 - dense_1_acc_7: 0.7445 - dense_1_acc_8: 0.7640 - dense_1_acc_9: 0.7635 - dense_1_acc_10: 0.7683 - dense_1_acc_11: 0.7759 - dense_1_acc_12: 0.7744 - dense_1_acc_13: 0.7805 - dense_1_acc_14: 0.7815 - dense_1_acc_15: 0.7796\n" 996 | ] 997 | }, 998 | { 999 | "data": { 1000 | "text/plain": [ 1001 | "" 1002 | ] 1003 | }, 1004 | "execution_count": 31, 1005 | "metadata": {}, 1006 | "output_type": "execute_result" 1007 | } 1008 | ], 1009 | "source": [ 1010 | "model.fit([x_train, a0, c0], list(y_train), epochs=10)" 1011 | ] 1012 | }, 1013 | { 1014 | "cell_type": "code", 1015 | "execution_count": 32, 1016 | "metadata": {}, 1017 | "outputs": [], 1018 | "source": [ 1019 | "m_t = x_test.shape[0]\n", 1020 | "a0_t = np.zeros((m_t, n_a))\n", 1021 | "c0_t = np.zeros((m_t, n_a))" 1022 | ] 1023 | }, 1024 | { 1025 | "cell_type": "code", 1026 | "execution_count": 34, 1027 | "metadata": {}, 1028 | "outputs": [ 1029 | { 1030 | "name": "stdout", 1031 | "output_type": "stream", 1032 | "text": [ 1033 | "1530/1530 [==============================] - 3s 2ms/step\n" 1034 | ] 1035 | }, 1036 | { 1037 | "data": { 1038 | "text/plain": [ 1039 | "[8.1394441193225333,\n", 1040 | " 0.68649219843297227,\n", 1041 | " 0.66842293131585218,\n", 1042 | " 0.6474493969499675,\n", 1043 | " 0.62604353209726171,\n", 1044 | " 0.60595984139473613,\n", 1045 | " 0.55427271182241,\n", 1046 | " 0.53408347352657448,\n", 1047 | " 0.51291458419725011,\n", 1048 | " 0.50179924154593269,\n", 1049 | " 0.48426854883144105,\n", 1050 | " 0.47200996883554397,\n", 1051 | " 0.467594226980521,\n", 1052 | " 0.45899881054373348,\n", 1053 | " 0.45738684663585588,\n", 1054 | " 0.46174781665303349,\n", 1055 | " 0.5294117646279678,\n", 1056 | " 0.63333333372290612,\n", 1057 | " 0.65163398677227546,\n", 1058 | " 0.65947712457257934,\n", 1059 | " 0.67450980423322693,\n", 1060 | " 0.73464052264207325,\n", 1061 | " 0.76143790880839035,\n", 1062 | " 0.76928104551789023,\n", 1063 | " 0.78169934663897245,\n", 1064 | " 0.78888888912263255,\n", 1065 | " 0.79607843160629277,\n", 1066 | " 0.79411764674716523,\n", 1067 | " 0.79411764674716523,\n", 1068 | " 0.80196078400206716,\n", 1069 | " 0.80326797354455093]" 1070 | ] 1071 | }, 1072 | "execution_count": 34, 1073 | "metadata": {}, 1074 | "output_type": "execute_result" 1075 | } 1076 | ], 1077 | "source": [ 1078 | "model.evaluate([x_test, a0_t, c0_t], list(y_test))" 1079 | ] 1080 | }, 1081 | { 1082 | "cell_type": "code", 1083 | "execution_count": 36, 1084 | "metadata": {}, 1085 | "outputs": [], 1086 | "source": [ 1087 | "from keras.utils import plot_model\n", 1088 | "plot_model(model, to_file='model.png')" 1089 | ] 1090 | }, 1091 | { 1092 | "cell_type": "markdown", 1093 | "metadata": {}, 1094 | "source": [ 1095 | "![](model.png)" 1096 | ] 1097 | }, 1098 | { 1099 | "cell_type": "code", 1100 | "execution_count": 45, 1101 | "metadata": {}, 1102 | "outputs": [], 1103 | "source": [ 1104 | "model.save_weights('model.h5')" 1105 | ] 1106 | } 1107 | ], 1108 | "metadata": { 1109 | "kernelspec": { 1110 | "display_name": "Python 3", 1111 | "language": "python", 1112 | "name": "python3" 1113 | }, 1114 | "language_info": { 1115 | "codemirror_mode": { 1116 | "name": "ipython", 1117 | "version": 3 1118 | }, 1119 | "file_extension": ".py", 1120 | "mimetype": "text/x-python", 1121 | "name": "python", 1122 | "nbconvert_exporter": "python", 1123 | "pygments_lexer": "ipython3", 1124 | "version": "3.5.1" 1125 | } 1126 | }, 1127 | "nbformat": 4, 1128 | "nbformat_minor": 2 1129 | } 1130 | -------------------------------------------------------------------------------- /model.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piyush2896/Keystroke-Dynamics-Using-LSTMs/bcb1a361e8fad94ac45daa13e48b1b42c68984b2/model.h5 -------------------------------------------------------------------------------- /model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piyush2896/Keystroke-Dynamics-Using-LSTMs/bcb1a361e8fad94ac45daa13e48b1b42c68984b2/model.png --------------------------------------------------------------------------------