├── Decision Trees and Ensemble Learning ├── bag_paste1.1.ipynb ├── bag_paste1.ipynb ├── decision_tree2.1.ipynb ├── decision_tree2.ipynb ├── decision_tree3.1.ipynb ├── decision_tree3.ipynb └── feature_selection_and_xgboost │ ├── feature_selection_16_features.ipynb │ ├── feature_selection_32_features.ipynb │ ├── reduced_featureset1_gridsearch.ipynb │ └── reduced_featureset2_gridsearch.ipynb ├── Deep Neural Networks ├── Convolutional_Neural_Networks │ ├── CNN_2conv_1dense.0.1.ipynb │ ├── CNN_2conv_1dense.0.ipynb │ ├── CNN_leakyrelu_xavier.ipynb │ ├── CNN_narrow_deep4.ipynb │ ├── CNN_narrow_deep5.ipynb │ ├── CNN_relu_he.ipynb │ ├── CNN_single_conv_dropout2.4.ipynb │ ├── CNN_single_conv_dropout2.ipynb │ └── regularized_CNN │ │ ├── CNN_regtech1.ipynb │ │ ├── CNN_regtech_l1.1.ipynb │ │ ├── CNN_regtech_l2.2.ipynb │ │ └── CNN_regtech_maxnorm.ipynb ├── DNN4layer_regtech_dropout.ipynb ├── DNN4layer_regtech_l1.ipynb ├── DNN4layer_regtech_l2.ipynb └── DNN4layer_regtech_maxnorm.ipynb ├── K Nearest Neighbors ├── KNN1_gridsearch.ipynb ├── KNN1_randsearch.ipynb ├── KNN2_gridsearch.ipynb └── KNN2_randsearch.ipynb ├── README.md ├── Support Vector Machine ├── SVM1_gridsearch.ipynb ├── SVM1_randsearch.ipynb ├── SVM2_gridsearch.ipynb └── SVM2_randsearch.ipynb └── data_feature-engineering.ipynb /Decision Trees and Ensemble Learning/feature_selection_and_xgboost/feature_selection_16_features.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Perform Feature Selection using XGB Classifier\n", 8 | "Train XGBClassifier on features set 1- samples have 16 features. Then select features with top importance scores to form a new feature set. " 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## Get the data" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 11, 21 | "metadata": {}, 22 | "outputs": [ 23 | { 24 | "name": "stdout", 25 | "output_type": "stream", 26 | "text": [ 27 | "Stored variables and their in-db values:\n", 28 | "X_16_val -> array([[ 0.10924883, 1.83030605, -0.14807631, ...\n", 29 | "X_32_val -> array([[ 0.66944195, 0.46536115, 0.79919788, ...\n", 30 | "X_32test_std -> defaultdict(, {0: array([[ 0.6694419\n", 31 | "X_32train_std -> array([[-0.74031227, 0.0126481 , -0.30967801, ...\n", 32 | "X_test -> defaultdict(, {0: array([[[ -6.40490\n", 33 | "X_test_std -> defaultdict(, {0: array([[ 0.1092488\n", 34 | "X_train -> array([[[ 0.00119031, 0.00873315, 0.00641749, ..\n", 35 | "X_train_std -> array([[-0.74031227, 0.0126481 , -0.30967801, ...\n", 36 | "snrs -> [-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, \n", 37 | "y_16_val -> array([6, 6, 5, ..., 0, 4, 1])\n", 38 | "y_32_test -> defaultdict(, {0: array([2, 2, 4, ..\n", 39 | "y_32_train -> array([0, 3, 4, ..., 0, 3, 1])\n", 40 | "y_32_val -> array([2, 2, 4, ..., 0, 7, 3])\n", 41 | "y_test -> defaultdict(, {0: array([6, 6, 5, ..\n", 42 | "y_train -> array([0, 3, 4, ..., 0, 3, 1])\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "import warnings\n", 48 | "warnings.filterwarnings('ignore')\n", 49 | "\n", 50 | "import matplotlib.pyplot as plt\n", 51 | "import numpy as np\n", 52 | "from collections import defaultdict\n", 53 | "import xgboost as xgb\n", 54 | "from xgboost.sklearn import XGBClassifier\n", 55 | "from sklearn.cross_validation import train_test_split\n", 56 | "from sklearn.datasets import dump_svmlight_file\n", 57 | "from sklearn.externals import joblib\n", 58 | "from sklearn.metrics import precision_score\n", 59 | "from sklearn import cross_validation, metrics\n", 60 | "from time import time\n", 61 | "import pandas as pd\n", 62 | "import collections\n", 63 | "from sklearn.metrics import accuracy_score\n", 64 | "from sklearn.feature_selection import SelectFromModel\n", 65 | "from numpy import sort\n", 66 | "\n", 67 | "%store -r\n", 68 | "%store" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 3, 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "name": "stdout", 78 | "output_type": "stream", 79 | "text": [ 80 | "Training data: (80000, 16) and labels: (80000,)\n", 81 | " \n", 82 | "Test data:\n", 83 | "Total 20 (4000, 16) arrays for SNR values:\n", 84 | "[-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]\n" 85 | ] 86 | } 87 | ], 88 | "source": [ 89 | "print(\"Training data: \", X_train_std.shape, \"and labels: \", y_train.shape)\n", 90 | "print(\" \")\n", 91 | "print(\"Test data:\")\n", 92 | "print(\"Total\", len(X_test_std), X_test_std[18].shape, \"arrays for SNR values:\")\n", 93 | "print(sorted(X_test_std.keys()))" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "## Train and test" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 4, 106 | "metadata": { 107 | "collapsed": true 108 | }, 109 | "outputs": [], 110 | "source": [ 111 | "def train_and_test(model, train_data=X_train_std, train_labels=y_train, test_data=X_test_std, test_labels=y_test):\n", 112 | " \n", 113 | " dtrain = xgb.DMatrix(X_train_std, label=y_train)\n", 114 | " dtest = defaultdict(list)\n", 115 | " for snr in snrs:\n", 116 | " dtest[snr] = xgb.DMatrix(X_test_std[snr], label=y_test[snr])\n", 117 | " parameters = model.get_xgb_params()\n", 118 | " \n", 119 | " eval_history = xgb.cv(parameters, dtrain, metrics = 'mlogloss', nfold = 5, early_stopping_rounds = 20,\n", 120 | " num_boost_round = model.get_params()['n_estimators'])\n", 121 | " model.set_params(n_estimators = eval_history.shape[0])\n", 122 | " \n", 123 | " eval_set = [(X_train_std, y_train), (X_test_std[10], y_test[10])]\n", 124 | " start = time()\n", 125 | " model.fit(train_data, train_labels, eval_metric = 'mlogloss', eval_set = eval_set) #fit model to data\n", 126 | " print(\"Fitting model to data took {} minutes\".format(time() - start))\n", 127 | " \n", 128 | " # Compute metric for training data\n", 129 | " train_predict = model.predict(train_data)\n", 130 | " train_predict_prob = model.predict_proba(train_data)\n", 131 | " print(\"Log loss on training set =\", metrics.log_loss(train_labels, train_predict_prob))\n", 132 | " \n", 133 | " # Compute metric for test data\n", 134 | " test_logloss = []\n", 135 | " for snr in snrs:\n", 136 | " test_predict = model.predict(test_data[snr])\n", 137 | " test_predict_prob = model.predict_proba(test_data[snr])\n", 138 | " loss = metrics.log_loss(test_labels[snr], test_predict_prob)\n", 139 | " test_logloss.append(loss)\n", 140 | " print(\"Log loss on test set =\", np.mean(test_logloss))\n", 141 | " \n", 142 | " return model" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 5, 148 | "metadata": {}, 149 | "outputs": [ 150 | { 151 | "name": "stdout", 152 | "output_type": "stream", 153 | "text": [ 154 | "[0]\tvalidation_0-mlogloss:1.95789\tvalidation_1-mlogloss:1.83349\n", 155 | "[1]\tvalidation_0-mlogloss:1.86774\tvalidation_1-mlogloss:1.65038\n", 156 | "Fitting model to data took 1.2433075904846191 minutes\n", 157 | "Log loss on training set = 1.86773986322\n", 158 | "Log loss on test set = 1.86907329542\n" 159 | ] 160 | } 161 | ], 162 | "source": [ 163 | "xgb1 = XGBClassifier(\n", 164 | " learning_rate =0.1,\n", 165 | " n_estimators=2,\n", 166 | " max_depth=5,\n", 167 | " min_child_weight=1,\n", 168 | " gamma=0,\n", 169 | " subsample=0.8,\n", 170 | " colsample_bytree=0.8,\n", 171 | " objective= 'multi:softmax',\n", 172 | " num_class = 8,\n", 173 | " nthread=4,\n", 174 | " scale_pos_weight=1,\n", 175 | " seed=27)\n", 176 | "model = train_and_test(xgb1)" 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "metadata": {}, 182 | "source": [ 183 | "## Accuracy vs. SNR on test set" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 6, 189 | "metadata": {}, 190 | "outputs": [ 191 | { 192 | "name": "stdout", 193 | "output_type": "stream", 194 | "text": [ 195 | "Test accuracy at -20 dB = 0.12425\n", 196 | "Test accuracy at -18 dB = 0.12525\n", 197 | "Test accuracy at -16 dB = 0.1235\n", 198 | "Test accuracy at -14 dB = 0.12725\n", 199 | "Test accuracy at -12 dB = 0.153\n", 200 | "Test accuracy at -10 dB = 0.1695\n", 201 | "Test accuracy at -8 dB = 0.2575\n", 202 | "Test accuracy at -6 dB = 0.334\n", 203 | "Test accuracy at -4 dB = 0.3795\n", 204 | "Test accuracy at -2 dB = 0.37775\n", 205 | "Test accuracy at 0 dB = 0.407\n", 206 | "Test accuracy at 2 dB = 0.5415\n", 207 | "Test accuracy at 4 dB = 0.73275\n", 208 | "Test accuracy at 6 dB = 0.77825\n", 209 | "Test accuracy at 8 dB = 0.79475\n", 210 | "Test accuracy at 10 dB = 0.811\n", 211 | "Test accuracy at 12 dB = 0.80825\n", 212 | "Test accuracy at 14 dB = 0.81025\n", 213 | "Test accuracy at 16 dB = 0.80325\n", 214 | "Test accuracy at 18 dB = 0.81125\n" 215 | ] 216 | } 217 | ], 218 | "source": [ 219 | "predictions = defaultdict(list)\n", 220 | "accuracy = defaultdict(list)\n", 221 | "y_pred = defaultdict(list)\n", 222 | " \n", 223 | "for snr in snrs:\n", 224 | " y_pred[snr] = model.predict(X_test_std[snr])\n", 225 | " predictions[snr] = [round(value) for value in y_pred[snr]]\n", 226 | " accuracy[snr] = accuracy_score(y_test[snr], predictions[snr])\n", 227 | " print (\"Test accuracy at \",snr,\"dB =\", accuracy[snr])" 228 | ] 229 | }, 230 | { 231 | "cell_type": "markdown", 232 | "metadata": {}, 233 | "source": [ 234 | "## Importance score" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 7, 240 | "metadata": {}, 241 | "outputs": [ 242 | { 243 | "name": "stdout", 244 | "output_type": "stream", 245 | "text": [ 246 | "Feature importance scores- highest first\n" 247 | ] 248 | }, 249 | { 250 | "data": { 251 | "text/html": [ 252 | "
\n", 253 | "\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 | "
FeaturesImportance Scores
0f140.194570
1f50.158371
2f60.115385
3f130.115385
4f100.095023
5f90.090498
6f10.065611
7f110.036199
8f150.036199
9f120.029412
10f40.020362
11f20.018100
12f30.015837
13f70.006787
14f160.002262
15f80.000000
\n", 357 | "
" 358 | ], 359 | "text/plain": [ 360 | " Features Importance Scores\n", 361 | "0 f14 0.194570\n", 362 | "1 f5 0.158371\n", 363 | "2 f6 0.115385\n", 364 | "3 f13 0.115385\n", 365 | "4 f10 0.095023\n", 366 | "5 f9 0.090498\n", 367 | "6 f1 0.065611\n", 368 | "7 f11 0.036199\n", 369 | "8 f15 0.036199\n", 370 | "9 f12 0.029412\n", 371 | "10 f4 0.020362\n", 372 | "11 f2 0.018100\n", 373 | "12 f3 0.015837\n", 374 | "13 f7 0.006787\n", 375 | "14 f16 0.002262\n", 376 | "15 f8 0.000000" 377 | ] 378 | }, 379 | "execution_count": 7, 380 | "metadata": {}, 381 | "output_type": "execute_result" 382 | } 383 | ], 384 | "source": [ 385 | "feature_names = ['f'+str(i) for i in range(1,17)]\n", 386 | "print(\"Feature importance scores- highest first\")\n", 387 | "df1 = pd.DataFrame(data = {'Features':feature_names, 'Importance Scores': model.feature_importances_})\n", 388 | "sorted_df = df1.sort_values(by = ['Importance Scores'], ascending = False)\n", 389 | "sorted_df.reset_index(inplace = True)\n", 390 | "del sorted_df['index']\n", 391 | "sorted_df" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": 8, 397 | "metadata": {}, 398 | "outputs": [ 399 | { 400 | "data": { 401 | "image/png": "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\n", 402 | "text/plain": [ 403 | "" 404 | ] 405 | }, 406 | "metadata": {}, 407 | "output_type": "display_data" 408 | }, 409 | { 410 | "name": "stdout", 411 | "output_type": "stream", 412 | "text": [ 413 | "Scores using XGBoost's function:\n" 414 | ] 415 | }, 416 | { 417 | "data": { 418 | "text/plain": [ 419 | "" 420 | ] 421 | }, 422 | "execution_count": 8, 423 | "metadata": {}, 424 | "output_type": "execute_result" 425 | }, 426 | { 427 | "data": { 428 | "image/png": "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\n9AAAAABJRU5ErkJggg==\n", 429 | "text/plain": [ 430 | "" 431 | ] 432 | }, 433 | "metadata": {}, 434 | "output_type": "display_data" 435 | } 436 | ], 437 | "source": [ 438 | "%matplotlib inline\n", 439 | "plt.bar(range(len(model.feature_importances_)), model.feature_importances_)\n", 440 | "plt.xlabel(\"Features\")\n", 441 | "plt.xticks(np.arange(X_train_std.shape[1]+1), feature_names)\n", 442 | "plt.ylabel(\"Importance score\")\n", 443 | "plt.show()\n", 444 | "print(\"Scores using XGBoost's function:\")\n", 445 | "xgb.plot_importance(model, ylabel = 'Features')" 446 | ] 447 | }, 448 | { 449 | "cell_type": "markdown", 450 | "metadata": {}, 451 | "source": [ 452 | "## Feature Selection" 453 | ] 454 | }, 455 | { 456 | "cell_type": "code", 457 | "execution_count": 9, 458 | "metadata": {}, 459 | "outputs": [ 460 | { 461 | "data": { 462 | "text/plain": [ 463 | "array([ 0. , 0.00226244, 0.00678733, 0.0158371 , 0.01809955,\n", 464 | " 0.02036199, 0.02941176, 0.0361991 , 0.0361991 , 0.06561086,\n", 465 | " 0.09049774, 0.09502263, 0.11538462, 0.11538462, 0.15837105,\n", 466 | " 0.19457014], dtype=float32)" 467 | ] 468 | }, 469 | "execution_count": 9, 470 | "metadata": {}, 471 | "output_type": "execute_result" 472 | } 473 | ], 474 | "source": [ 475 | "# Fit model using each importance as a threshold\n", 476 | "thresholds = sort(model.feature_importances_)\n", 477 | "thresholds" 478 | ] 479 | }, 480 | { 481 | "cell_type": "markdown", 482 | "metadata": {}, 483 | "source": [ 484 | "## On training set" 485 | ] 486 | }, 487 | { 488 | "cell_type": "code", 489 | "execution_count": 13, 490 | "metadata": {}, 491 | "outputs": [ 492 | { 493 | "name": "stdout", 494 | "output_type": "stream", 495 | "text": [ 496 | "Top 16 features selected\n", 497 | "Thresh=0.000, n_features=16, Accuracy: 50.07%\n", 498 | " \n", 499 | "Top 15 features selected\n", 500 | "Thresh=0.002, n_features=15, Accuracy: 50.07%\n", 501 | " \n", 502 | "Top 14 features selected\n", 503 | "Thresh=0.007, n_features=14, Accuracy: 50.07%\n", 504 | " \n", 505 | "Top 13 features selected\n", 506 | "Thresh=0.016, n_features=13, Accuracy: 50.05%\n", 507 | " \n", 508 | "Top 12 features selected\n", 509 | "Thresh=0.018, n_features=12, Accuracy: 50.10%\n", 510 | " \n", 511 | "Top 11 features selected\n", 512 | "Thresh=0.020, n_features=11, Accuracy: 50.15%\n", 513 | " \n", 514 | "Top 10 features selected\n", 515 | "Thresh=0.029, n_features=10, Accuracy: 50.08%\n", 516 | " \n", 517 | "Top 9 features selected\n", 518 | "Thresh=0.036, n_features=9, Accuracy: 50.13%\n", 519 | " \n", 520 | "Top 9 features selected\n", 521 | "Thresh=0.036, n_features=9, Accuracy: 50.13%\n", 522 | " \n", 523 | "Top 7 features selected\n", 524 | "Thresh=0.066, n_features=7, Accuracy: 49.99%\n", 525 | " \n", 526 | "Top 6 features selected\n", 527 | "Thresh=0.090, n_features=6, Accuracy: 48.70%\n", 528 | " \n", 529 | "Top 5 features selected\n", 530 | "Thresh=0.095, n_features=5, Accuracy: 48.18%\n", 531 | " \n", 532 | "Top 4 features selected\n", 533 | "Thresh=0.115, n_features=4, Accuracy: 48.16%\n", 534 | " \n", 535 | "Top 4 features selected\n", 536 | "Thresh=0.115, n_features=4, Accuracy: 48.16%\n", 537 | " \n", 538 | "Top 2 features selected\n", 539 | "Thresh=0.158, n_features=2, Accuracy: 42.41%\n", 540 | " \n", 541 | "Top 1 features selected\n", 542 | "Thresh=0.195, n_features=1, Accuracy: 31.14%\n", 543 | " \n" 544 | ] 545 | } 546 | ], 547 | "source": [ 548 | "train_accs = []\n", 549 | "num_features = []\n", 550 | "thresh_vals = []\n", 551 | "\n", 552 | "for thresh in thresholds:\n", 553 | " \n", 554 | " # select features using threshold\n", 555 | " selection = SelectFromModel(model, threshold=thresh, prefit=True)\n", 556 | " #selecting features based on importance weights\n", 557 | " #features whose importance is >= thresh are kept, and the remaining discarded\n", 558 | " \n", 559 | " select_X_train = selection.transform(X_train_std)\n", 560 | " n_features = select_X_train.shape[1]\n", 561 | " print(\"Top {} features selected\".format(n_features))\n", 562 | " selection_model = XGBClassifier()\n", 563 | " selection_model.fit(select_X_train, y_train)\n", 564 | " \n", 565 | " #Evaluate model on training set\n", 566 | " y_pred = selection_model.predict(select_X_train)\n", 567 | " predictions = [round(value) for value in y_pred]\n", 568 | " accuracy = accuracy_score(y_train, predictions)\n", 569 | " print(\"Thresh=%.3f, n_features=%d, Accuracy: %.2f%%\" % (thresh, n_features, accuracy*100.0))\n", 570 | " print(\" \")\n", 571 | " train_accs.append(accuracy)\n", 572 | " num_features.append(n_features)\n", 573 | " thresh_vals.append(thresh)" 574 | ] 575 | }, 576 | { 577 | "cell_type": "code", 578 | "execution_count": 21, 579 | "metadata": {}, 580 | "outputs": [ 581 | { 582 | "name": "stdout", 583 | "output_type": "stream", 584 | "text": [ 585 | " Threshold Training accuracy n_features\n", 586 | "5 0.020362 0.501513 11\n", 587 | "7 0.036199 0.501300 9\n", 588 | "8 0.036199 0.501300 9\n", 589 | "4 0.018100 0.501038 12\n", 590 | "6 0.029412 0.500750 10\n", 591 | "0 0.000000 0.500700 16\n", 592 | "1 0.002262 0.500700 15\n", 593 | "2 0.006787 0.500700 14\n", 594 | "3 0.015837 0.500500 13\n", 595 | "9 0.065611 0.499925 7\n", 596 | "10 0.090498 0.486988 6\n", 597 | "11 0.095023 0.481750 5\n", 598 | "12 0.115385 0.481637 4\n", 599 | "13 0.115385 0.481637 4\n", 600 | "14 0.158371 0.424088 2\n", 601 | "15 0.194570 0.311350 1\n", 602 | "Best training accuracy is obtained upon selection of top 11 features (according to importance score)\n", 603 | "The corresponding threshold value is 0.020361991599202156\n" 604 | ] 605 | } 606 | ], 607 | "source": [ 608 | "df = pd.DataFrame(data= {'Threshold':thresh_vals,'n_features':num_features, 'Training accuracy':train_accs})\n", 609 | "sorted_df = df.sort_values(by = ['Training accuracy'], ascending = False)\n", 610 | "print(sorted_df)\n", 611 | "sorted_df.reset_index(inplace = True) #reset because sorting messed up the indices\n", 612 | "idx = sorted_df['Training accuracy'].idxmax()\n", 613 | "sel_row= sorted_df.iloc[idx]\n", 614 | "best_features = int(sel_row['n_features'])\n", 615 | "best_thresh = sel_row['Threshold']\n", 616 | "print('Best training accuracy is obtained upon selection of top {} features (according to importance score)'.format(best_features))\n", 617 | "print(\"The corresponding threshold value is {}\".format(best_thresh))" 618 | ] 619 | }, 620 | { 621 | "cell_type": "markdown", 622 | "metadata": {}, 623 | "source": [ 624 | "## Modify training and test data to include only selected features" 625 | ] 626 | }, 627 | { 628 | "cell_type": "code", 629 | "execution_count": 23, 630 | "metadata": {}, 631 | "outputs": [ 632 | { 633 | "name": "stdout", 634 | "output_type": "stream", 635 | "text": [ 636 | "Top 11 features selected\n", 637 | "New training set (80000, 11) and labels (80000,)\n", 638 | "New test set (4000, 11) and labels (4000,) for each SNR value\n" 639 | ] 640 | } 641 | ], 642 | "source": [ 643 | "X_test_new = defaultdict(list)\n", 644 | "\n", 645 | "selection = SelectFromModel(model, threshold = best_thresh, prefit=True)\n", 646 | "\n", 647 | "X_train_new = selection.transform(X_train_std)\n", 648 | "n_features = select_X_train.shape[1]\n", 649 | "print(\"Top {} features selected\".format(best_features))\n", 650 | "print(\"New training set {} and labels {}\".format(X_train_new.shape, y_train.shape))\n", 651 | "\n", 652 | "for snr in snrs:\n", 653 | " X_test_new[snr] = selection.transform(X_test_std[snr])\n", 654 | "print(\"New test set {} and labels {} for each SNR value\".format(X_test_new[10].shape, y_test[10].shape))" 655 | ] 656 | }, 657 | { 658 | "cell_type": "markdown", 659 | "metadata": {}, 660 | "source": [ 661 | "## Store the new training and test sets in Jupyter's db" 662 | ] 663 | }, 664 | { 665 | "cell_type": "code", 666 | "execution_count": 25, 667 | "metadata": {}, 668 | "outputs": [ 669 | { 670 | "name": "stdout", 671 | "output_type": "stream", 672 | "text": [ 673 | "Stored 'X_train_new' (ndarray)\n", 674 | "Stored 'X_test_new' (defaultdict)\n", 675 | "Stored variables and their in-db values:\n", 676 | "X_16_val -> array([[ 0.10924883, 1.83030605, -0.14807631, ...\n", 677 | "X_32_val -> array([[ 0.66944195, 0.46536115, 0.79919788, ...\n", 678 | "X_32test_std -> defaultdict(, {0: array([[ 0.6694419\n", 679 | "X_32train_std -> array([[-0.74031227, 0.0126481 , -0.30967801, ...\n", 680 | "X_test -> defaultdict(, {0: array([[[ -6.40490\n", 681 | "X_test_new -> defaultdict(, {0: array([[ 0.1092488\n", 682 | "X_test_std -> defaultdict(, {0: array([[ 0.1092488\n", 683 | "X_train -> array([[[ 0.00119031, 0.00873315, 0.00641749, ..\n", 684 | "X_train_new -> array([[-0.74031227, 0.23616372, -0.18182195, ...\n", 685 | "X_train_std -> array([[-0.74031227, 0.0126481 , -0.30967801, ...\n", 686 | "snrs -> [-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, \n", 687 | "y_16_val -> array([6, 6, 5, ..., 0, 4, 1])\n", 688 | "y_32_test -> defaultdict(, {0: array([2, 2, 4, ..\n", 689 | "y_32_train -> array([0, 3, 4, ..., 0, 3, 1])\n", 690 | "y_32_val -> array([2, 2, 4, ..., 0, 7, 3])\n", 691 | "y_test -> defaultdict(, {0: array([6, 6, 5, ..\n", 692 | "y_train -> array([0, 3, 4, ..., 0, 3, 1])\n" 693 | ] 694 | } 695 | ], 696 | "source": [ 697 | "%store X_train_new\n", 698 | "%store X_test_new\n", 699 | "%store" 700 | ] 701 | }, 702 | { 703 | "cell_type": "code", 704 | "execution_count": null, 705 | "metadata": { 706 | "collapsed": true 707 | }, 708 | "outputs": [], 709 | "source": [] 710 | } 711 | ], 712 | "metadata": { 713 | "anaconda-cloud": {}, 714 | "kernelspec": { 715 | "display_name": "Python 3", 716 | "language": "python", 717 | "name": "python3" 718 | }, 719 | "language_info": { 720 | "codemirror_mode": { 721 | "name": "ipython", 722 | "version": 3 723 | }, 724 | "file_extension": ".py", 725 | "mimetype": "text/x-python", 726 | "name": "python", 727 | "nbconvert_exporter": "python", 728 | "pygments_lexer": "ipython3", 729 | "version": "3.6.3" 730 | } 731 | }, 732 | "nbformat": 4, 733 | "nbformat_minor": 1 734 | } 735 | -------------------------------------------------------------------------------- /Deep Neural Networks/Convolutional_Neural_Networks/CNN_2conv_1dense.0.1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Convolutional Neural Network\n", 8 | "\n", 9 | "### Convolutional Layers: [512,512] ; Dense Layers [512] \n", 10 | "\n", 11 | "CNN is trained on raw data" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "## Get the data" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 1, 24 | "metadata": {}, 25 | "outputs": [ 26 | { 27 | "name": "stdout", 28 | "output_type": "stream", 29 | "text": [ 30 | "Stored variables and their in-db values:\n", 31 | "X_test -> defaultdict(, {0: array([[[ 6.37165\n", 32 | "X_train -> array([[[-0.00462901, -0.00327594, 0.00218376, ..\n", 33 | "snrs -> [-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, \n", 34 | "y_test -> defaultdict(, {0: array([7, 1, 3, ..\n", 35 | "y_train -> array([2, 4, 7, ..., 6, 4, 5])\n" 36 | ] 37 | } 38 | ], 39 | "source": [ 40 | "import warnings\n", 41 | "warnings.filterwarnings('ignore')\n", 42 | "\n", 43 | "import matplotlib.pyplot as plt\n", 44 | "import numpy as np\n", 45 | "import tensorflow as tf\n", 46 | "from collections import defaultdict\n", 47 | "from time import time\n", 48 | "\n", 49 | "%store -r\n", 50 | "%store" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 2, 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "name": "stdout", 60 | "output_type": "stream", 61 | "text": [ 62 | "Training data: (80000, 2, 128) and labels: (80000,)\n", 63 | "\n", 64 | "Test data:\n", 65 | "Total 20 (4000, 2, 128) arrays for SNR values:\n", 66 | "[-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]\n" 67 | ] 68 | } 69 | ], 70 | "source": [ 71 | "print(\"Training data: \", X_train.shape, \"and labels: \", y_train.shape)\n", 72 | "print()\n", 73 | "print(\"Test data:\")\n", 74 | "print(\"Total\", len(X_test), X_test[18].shape, \"arrays for SNR values:\")\n", 75 | "print(sorted(X_test.keys()))" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "## Standardize the features" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 3, 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "name": "stdout", 92 | "output_type": "stream", 93 | "text": [ 94 | "Training set (80000, 2, 128)\n", 95 | "Test set corresponding to one snr value (4000, 2, 128)\n" 96 | ] 97 | } 98 | ], 99 | "source": [ 100 | "from sklearn.preprocessing import StandardScaler\n", 101 | "\n", 102 | "sc = StandardScaler()\n", 103 | "_X_train = np.reshape(X_train, [X_train.shape[0], X_train.shape[1]*X_train.shape[2]])\n", 104 | "_X_train = sc.fit_transform(_X_train)\n", 105 | "\n", 106 | "X_train = np.reshape(_X_train, X_train.shape)\n", 107 | "print(\"Training set\", X_train.shape)\n", 108 | "\n", 109 | "_X_test = defaultdict(list)\n", 110 | "for snr in snrs:\n", 111 | " _X_test[snr] = np.reshape(X_test[snr], [X_test[snr].shape[0], X_test[snr].shape[1]*X_test[snr].shape[2]])\n", 112 | " _X_test[snr] = sc.transform(_X_test[snr])\n", 113 | " X_test[snr] = np.reshape(_X_test[snr], X_test[snr].shape)\n", 114 | " \n", 115 | "print(\"Test set corresponding to one snr value\", X_test[18].shape)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "## Design and train the CNN" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 4, 128 | "metadata": {}, 129 | "outputs": [ 130 | { 131 | "name": "stdout", 132 | "output_type": "stream", 133 | "text": [ 134 | "Epoch 0 training accuracy : 0.2490234375\n", 135 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 136 | "Epoch 1 training accuracy : 0.34375\n", 137 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 138 | "Epoch 2 training accuracy : 0.3720703125\n", 139 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 140 | "Epoch 3 training accuracy : 0.4306640625\n", 141 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 142 | "Epoch 4 training accuracy : 0.4404296875\n", 143 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 144 | "Epoch 5 training accuracy : 0.4794921875\n", 145 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 146 | "Epoch 6 training accuracy : 0.45703125\n", 147 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 148 | "Epoch 7 training accuracy : 0.4716796875\n", 149 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 150 | "Epoch 8 training accuracy : 0.51171875\n", 151 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 152 | "Epoch 9 training accuracy : 0.5556640625\n", 153 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 154 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 155 | "Training took 157.154333 minutes\n" 156 | ] 157 | } 158 | ], 159 | "source": [ 160 | "height = 2\n", 161 | "width = 128\n", 162 | "channels = 1\n", 163 | "n_features = height * width\n", 164 | "\n", 165 | "feature_map1 = 512\n", 166 | "ksize_conv1 = 2\n", 167 | "stride_conv1 = 1\n", 168 | "\n", 169 | "feature_map2 = 512\n", 170 | "ksize_conv2 = ksize_conv1\n", 171 | "stride_conv2 = stride_conv1\n", 172 | "\n", 173 | "pool_layer_maps2 = feature_map2\n", 174 | "\n", 175 | "n_fully_conn1 = 512\n", 176 | "\n", 177 | "n_classes = 8\n", 178 | " \n", 179 | "X = tf.placeholder(tf.float32, shape=[None, height, width])\n", 180 | "X_reshaped = tf.reshape(X, shape=[-1, height, width, channels])\n", 181 | "labels = tf.placeholder(tf.int32, shape=[None])\n", 182 | "training_ = tf.placeholder_with_default(False, shape=[])\n", 183 | "\n", 184 | "xavier_init = tf.contrib.layers.xavier_initializer()\n", 185 | "relu_act = tf.nn.relu\n", 186 | "\n", 187 | "# ------------------ Convolutional and pooling layers ----------------------------\n", 188 | "\n", 189 | "def convolutional_layer(X, filter_, ksize, kernel_init, strides, padding):\n", 190 | " convolutional_layer = tf.layers.conv2d(X, filters = filter_, kernel_initializer = kernel_init,\n", 191 | " kernel_size = ksize, strides = strides,\n", 192 | " padding = padding, activation = relu_act)\n", 193 | " return convolutional_layer\n", 194 | "\n", 195 | "def pool_layer(convlayer, ksize, strides, padding, pool_maps):\n", 196 | " pool = tf.nn.max_pool(convlayer, ksize, strides, padding)\n", 197 | " dim1, dim2 = int(pool.get_shape()[1]), int(pool.get_shape()[2])\n", 198 | " pool_flat = tf.reshape(pool, shape = [-1, pool_maps * dim1 * dim2])\n", 199 | " return pool_flat\n", 200 | "\n", 201 | "conv_layer1 = convolutional_layer(X_reshaped, feature_map1, ksize_conv1, xavier_init, stride_conv1, padding = \"SAME\")\n", 202 | "\n", 203 | "conv_layer2 = convolutional_layer(conv_layer1, feature_map2, ksize_conv2, xavier_init, stride_conv2, padding = \"SAME\")\n", 204 | "\n", 205 | "pool_layer2_flat = pool_layer(conv_layer2, [1,2,2,1], [1,2,2,1], \"VALID\", pool_layer_maps2)\n", 206 | "\n", 207 | "# ----------------- Fully connected and dropout layers -------------------\n", 208 | "\n", 209 | "def dense_layer(input_layer, n_neurons, kernel_init, activation):\n", 210 | " fully_conn = tf.layers.dense(inputs = input_layer, units = n_neurons, activation = activation,\n", 211 | " kernel_initializer = kernel_init)\n", 212 | " return fully_conn\n", 213 | " \n", 214 | "dense_layer1 = dense_layer(pool_layer2_flat, n_fully_conn1, xavier_init, relu_act)\n", 215 | "\n", 216 | "# ----------------- Output softmax layer ---------------------------\n", 217 | "\n", 218 | "logits = tf.layers.dense(dense_layer1, n_classes)\n", 219 | "softmax_activations = tf.nn.softmax(logits)\n", 220 | "\n", 221 | "# ----------------- Specify performance measure -------------------------------\n", 222 | "\n", 223 | "cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits = logits, labels = labels)\n", 224 | "loss = tf.reduce_mean(cross_entropy)\n", 225 | "optimizer = tf.train.AdamOptimizer()\n", 226 | "train_operation = optimizer.minimize(loss)\n", 227 | "\n", 228 | "correct_predictions = tf.nn.in_top_k(logits, labels, 1)\n", 229 | "accuracy = tf.reduce_mean(tf.cast(correct_predictions, tf.float32))\n", 230 | "\n", 231 | "# ---------------- Execution phase -------------------------------------------\n", 232 | " \n", 233 | "n_epochs = 10\n", 234 | "batch_size = 1024\n", 235 | "n_train = X_train.shape[0]\n", 236 | "n_iter = n_train//batch_size\n", 237 | "\n", 238 | "acc_test = defaultdict(list)\n", 239 | "\n", 240 | "path = \"./CNN_2conv_1dense.0.1\" \n", 241 | "saver = tf.train.Saver()\n", 242 | "\n", 243 | "start = time()\n", 244 | "\n", 245 | "with tf.Session() as sess:\n", 246 | " tf.global_variables_initializer().run()\n", 247 | " for epoch in range(n_epochs):\n", 248 | " for iteration in range(n_iter):\n", 249 | " rand_indices = np.random.choice(n_train,batch_size) \n", 250 | " X_batch, y_batch = X_train[rand_indices], y_train[rand_indices]\n", 251 | " sess.run(train_operation, feed_dict={X: X_batch, labels: y_batch, training_: True})\n", 252 | " acc_train = accuracy.eval(feed_dict={X: X_batch, labels: y_batch})\n", 253 | " print(\"Epoch {} training accuracy : {}\".format(epoch, acc_train))\n", 254 | " save_path = saver.save(sess, path)\n", 255 | " saver.restore(sess, path)\n", 256 | " saver.restore(sess, path)\n", 257 | " for snr in snrs:\n", 258 | " acc_test[snr] = accuracy.eval(feed_dict={X: X_test[snr], labels: y_test[snr]})\n", 259 | "\n", 260 | "print(\"Training took %f minutes\"%(float(time() - start)/60.0))" 261 | ] 262 | }, 263 | { 264 | "cell_type": "markdown", 265 | "metadata": {}, 266 | "source": [ 267 | "## Test the classifier" 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": 5, 273 | "metadata": {}, 274 | "outputs": [ 275 | { 276 | "name": "stdout", 277 | "output_type": "stream", 278 | "text": [ 279 | "CNN's test accuracy on -20dB SNR samples = 0.13075000047683716\n", 280 | "CNN's test accuracy on -18dB SNR samples = 0.1264999955892563\n", 281 | "CNN's test accuracy on -16dB SNR samples = 0.12800000607967377\n", 282 | "CNN's test accuracy on -14dB SNR samples = 0.1392499953508377\n", 283 | "CNN's test accuracy on -12dB SNR samples = 0.15649999678134918\n", 284 | "CNN's test accuracy on -10dB SNR samples = 0.1912499964237213\n", 285 | "CNN's test accuracy on -8dB SNR samples = 0.2549999952316284\n", 286 | "CNN's test accuracy on -6dB SNR samples = 0.3687500059604645\n", 287 | "CNN's test accuracy on -4dB SNR samples = 0.49399998784065247\n", 288 | "CNN's test accuracy on -2dB SNR samples = 0.6167500019073486\n", 289 | "CNN's test accuracy on 0dB SNR samples = 0.6662499904632568\n", 290 | "CNN's test accuracy on 2dB SNR samples = 0.6915000081062317\n", 291 | "CNN's test accuracy on 4dB SNR samples = 0.7124999761581421\n", 292 | "CNN's test accuracy on 6dB SNR samples = 0.7129999995231628\n", 293 | "CNN's test accuracy on 8dB SNR samples = 0.722000002861023\n", 294 | "CNN's test accuracy on 10dB SNR samples = 0.721750020980835\n", 295 | "CNN's test accuracy on 12dB SNR samples = 0.7135000228881836\n", 296 | "CNN's test accuracy on 14dB SNR samples = 0.7145000100135803\n", 297 | "CNN's test accuracy on 16dB SNR samples = 0.715749979019165\n", 298 | "CNN's test accuracy on 18dB SNR samples = 0.7254999876022339\n" 299 | ] 300 | } 301 | ], 302 | "source": [ 303 | "for snr in snrs:\n", 304 | " print(\"CNN's test accuracy on {}dB SNR samples = {}\".format(snr,acc_test[snr])) " 305 | ] 306 | }, 307 | { 308 | "cell_type": "markdown", 309 | "metadata": {}, 310 | "source": [ 311 | "## Visualize classifier's performance on test set" 312 | ] 313 | }, 314 | { 315 | "cell_type": "code", 316 | "execution_count": 6, 317 | "metadata": {}, 318 | "outputs": [ 319 | { 320 | "data": { 321 | "image/png": "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\n", 322 | "text/plain": [ 323 | "" 324 | ] 325 | }, 326 | "metadata": {}, 327 | "output_type": "display_data" 328 | } 329 | ], 330 | "source": [ 331 | "plt.style.use('classic')\n", 332 | "%matplotlib inline\n", 333 | "\n", 334 | "acc_test = sorted(acc_test.items())\n", 335 | "new_acc = []\n", 336 | "for i in range(len(acc_test)):\n", 337 | " new_acc.append(acc_test[i][1])\n", 338 | "acc_test_values = new_acc \n", 339 | "\n", 340 | "fig1 = plt.figure(figsize=(10, 6), dpi=100)\n", 341 | "x = snrs\n", 342 | "y = list(acc_test_values)\n", 343 | "plt.plot(x, y, marker=\"o\", linewidth=2.0, linestyle='dashed', color='royalblue')\n", 344 | "plt.axis([-20, 20, 0, 1])\n", 345 | "plt.xticks(np.arange(min(x), max(x)+1, 2.0))\n", 346 | "plt.yticks(np.arange(0, 1, 0.10))\n", 347 | "\n", 348 | "ttl = plt.title('SNR vs Accuracy', fontsize=16)\n", 349 | "ttl.set_weight('bold')\n", 350 | "plt.xlabel('SNR (dB)', fontsize=14)\n", 351 | "plt.ylabel('Test accuracy', fontsize=14)\n", 352 | "plt.grid()\n", 353 | "\n", 354 | "plt.show()" 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": 7, 360 | "metadata": {}, 361 | "outputs": [ 362 | { 363 | "name": "stdout", 364 | "output_type": "stream", 365 | "text": [ 366 | "INFO:tensorflow:Restoring parameters from ./CNN_2conv_1dense.0.1\n", 367 | "Confusion Matrix\n", 368 | " 8PSK BPSK CPFSK GFSK PAM4 QAM16 QAM64 QPSK\n", 369 | "8PSK 0.55 0.01 0.03 0.00 0.00 0.03 0.03 0.34\n", 370 | "BPSK 0.00 0.97 0.00 0.00 0.02 0.00 0.00 0.01\n", 371 | "CPFSK 0.02 0.00 0.92 0.01 0.00 0.01 0.00 0.04\n", 372 | "GFSK 0.02 0.01 0.01 0.95 0.00 0.00 0.00 0.01\n", 373 | "PAM4 0.00 0.02 0.00 0.00 0.97 0.01 0.01 0.00\n", 374 | "QAM16 0.07 0.00 0.00 0.00 0.02 0.44 0.43 0.04\n", 375 | "QAM64 0.04 0.01 0.00 0.00 0.03 0.42 0.48 0.02\n", 376 | "QPSK 0.28 0.07 0.01 0.00 0.00 0.05 0.01 0.58\n" 377 | ] 378 | }, 379 | { 380 | "data": { 381 | "image/png": "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\n", 382 | "text/plain": [ 383 | "" 384 | ] 385 | }, 386 | "metadata": {}, 387 | "output_type": "display_data" 388 | } 389 | ], 390 | "source": [ 391 | "# Confusion Matrix\n", 392 | "\n", 393 | "with tf.Session() as sess:\n", 394 | " saver.restore(sess, path)\n", 395 | " Z = logits.eval(feed_dict = {X : X_test[18]})\n", 396 | " predicted_18dB = np.argmax(Z, axis = 1)\n", 397 | " \n", 398 | "from sklearn.metrics import confusion_matrix\n", 399 | "%matplotlib inline\n", 400 | "\n", 401 | "classes = ['8PSK', 'BPSK', 'CPFSK', 'GFSK', 'PAM4', 'QAM16', 'QAM64', 'QPSK']\n", 402 | "conf_matrix = confusion_matrix(predicted_18dB, y_test[18]) \n", 403 | "\n", 404 | "conf_matrix = conf_matrix.astype('float') / conf_matrix.sum(axis=1)[:, np.newaxis]\n", 405 | "conf_matrix = conf_matrix.round(decimals = 2)\n", 406 | "\n", 407 | "import pandas as pd\n", 408 | "\n", 409 | "df = pd.DataFrame(data = conf_matrix, columns = classes, index = classes) \n", 410 | "print(\"Confusion Matrix\")\n", 411 | "print(df)\n", 412 | "\n", 413 | "fig1 = plt.figure(figsize=(10, 6), dpi=100)\n", 414 | "plt.imshow(conf_matrix, interpolation = 'nearest', cmap = plt.cm.Purples)\n", 415 | "ticks = np.arange(len(classes))\n", 416 | "plt.title(\"Confusion Matrix\")\n", 417 | "plt.xticks(ticks, classes, rotation=45)\n", 418 | "plt.yticks(ticks, classes)\n", 419 | "\n", 420 | "plt.ylabel('True class')\n", 421 | "plt.xlabel('Predicted class')\n", 422 | "\n", 423 | "plt.tight_layout()\n", 424 | "plt.colorbar()\n", 425 | "plt.show()" 426 | ] 427 | }, 428 | { 429 | "cell_type": "code", 430 | "execution_count": null, 431 | "metadata": { 432 | "collapsed": true 433 | }, 434 | "outputs": [], 435 | "source": [] 436 | } 437 | ], 438 | "metadata": { 439 | "anaconda-cloud": {}, 440 | "kernelspec": { 441 | "display_name": "Python 3", 442 | "language": "python", 443 | "name": "python3" 444 | }, 445 | "language_info": { 446 | "codemirror_mode": { 447 | "name": "ipython", 448 | "version": 3 449 | }, 450 | "file_extension": ".py", 451 | "mimetype": "text/x-python", 452 | "name": "python", 453 | "nbconvert_exporter": "python", 454 | "pygments_lexer": "ipython3", 455 | "version": "3.6.3" 456 | } 457 | }, 458 | "nbformat": 4, 459 | "nbformat_minor": 1 460 | } 461 | -------------------------------------------------------------------------------- /Deep Neural Networks/Convolutional_Neural_Networks/CNN_single_conv_dropout2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "#
Convolutional Neural Network\n", 8 | "\n", 9 | "### Convolutional Layers: [512] ; Dropout layer ; Dense Layers [512]\n", 10 | "\n", 11 | "CNN is trained on raw data" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "## Get the data" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 1, 24 | "metadata": { 25 | "collapsed": false 26 | }, 27 | "outputs": [ 28 | { 29 | "name": "stdout", 30 | "output_type": "stream", 31 | "text": [ 32 | "Stored variables and their in-db values:\n", 33 | "X_16_val -> array([[-0.86867832, 0.90982973, -0.41354501, ...\n", 34 | "X_32_val -> array([[ 0.58128519, 1.18391134, 1.03769373, ...\n", 35 | "X_32test_std -> defaultdict(, {0: array([[ 0.5812851\n", 36 | "X_32train_std -> array([[-0.8119218 , 0.28416571, -0.9279788 , ...\n", 37 | "X_test -> defaultdict(, {0: array([[[ -1.08940\n", 38 | "X_test_std -> defaultdict(, {0: array([[-0.8686783\n", 39 | "X_train -> array([[[-0.00749793, 0.00696769, 0.00273202, ..\n", 40 | "X_train_std -> array([[-0.8119218 , 0.28416571, -0.9279788 , ...\n", 41 | "snrs -> [-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, \n", 42 | "y_16_val -> array([0, 2, 1, ..., 1, 4, 2])\n", 43 | "y_32_test -> defaultdict(, {0: array([0, 7, 1, ..\n", 44 | "y_32_train -> array([2, 4, 3, ..., 3, 0, 0])\n", 45 | "y_32_val -> array([0, 7, 1, ..., 1, 0, 3])\n", 46 | "y_test -> defaultdict(, {0: array([0, 2, 1, ..\n", 47 | "y_train -> array([2, 4, 3, ..., 3, 0, 0])\n" 48 | ] 49 | } 50 | ], 51 | "source": [ 52 | "import warnings\n", 53 | "warnings.filterwarnings('ignore')\n", 54 | "\n", 55 | "import matplotlib.pyplot as plt\n", 56 | "import numpy as np\n", 57 | "import tensorflow as tf\n", 58 | "from collections import defaultdict\n", 59 | "from time import time\n", 60 | "\n", 61 | "%store -r\n", 62 | "%store" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 2, 68 | "metadata": { 69 | "collapsed": false 70 | }, 71 | "outputs": [ 72 | { 73 | "name": "stdout", 74 | "output_type": "stream", 75 | "text": [ 76 | "Training data: (80000, 2, 128) and labels: (80000,)\n", 77 | "\n", 78 | "Test data:\n", 79 | "Total 20 (4000, 2, 128) arrays for SNR values:\n", 80 | "[-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]\n" 81 | ] 82 | } 83 | ], 84 | "source": [ 85 | "print(\"Training data: \", X_train.shape, \"and labels: \", y_train.shape)\n", 86 | "print()\n", 87 | "print(\"Test data:\")\n", 88 | "print(\"Total\", len(X_test), X_test[18].shape, \"arrays for SNR values:\")\n", 89 | "print(sorted(X_test.keys()))" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "## Standardize the features" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 3, 102 | "metadata": { 103 | "collapsed": false 104 | }, 105 | "outputs": [ 106 | { 107 | "name": "stdout", 108 | "output_type": "stream", 109 | "text": [ 110 | "Training set (80000, 2, 128)\n", 111 | "Test set corresponding to one snr value (4000, 2, 128)\n" 112 | ] 113 | } 114 | ], 115 | "source": [ 116 | "from sklearn.preprocessing import StandardScaler\n", 117 | "\n", 118 | "sc = StandardScaler()\n", 119 | "_X_train = np.reshape(X_train, [X_train.shape[0], X_train.shape[1]*X_train.shape[2]])\n", 120 | "_X_train = sc.fit_transform(_X_train)\n", 121 | "\n", 122 | "X_train = np.reshape(_X_train, X_train.shape)\n", 123 | "print(\"Training set\", X_train.shape)\n", 124 | "\n", 125 | "_X_test = defaultdict(list)\n", 126 | "for snr in snrs:\n", 127 | " _X_test[snr] = np.reshape(X_test[snr], [X_test[snr].shape[0], X_test[snr].shape[1]*X_test[snr].shape[2]])\n", 128 | " _X_test[snr] = sc.transform(_X_test[snr])\n", 129 | " X_test[snr] = np.reshape(_X_test[snr], X_test[snr].shape)\n", 130 | " \n", 131 | "print(\"Test set corresponding to one snr value\", X_test[18].shape)" 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "## Design and train the CNN" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 4, 144 | "metadata": { 145 | "collapsed": false 146 | }, 147 | "outputs": [ 148 | { 149 | "name": "stdout", 150 | "output_type": "stream", 151 | "text": [ 152 | "Epoch 0 training accuracy : 0.2001953125\n", 153 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 154 | "Epoch 1 training accuracy : 0.2998046875\n", 155 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 156 | "Epoch 2 training accuracy : 0.357421875\n", 157 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 158 | "Epoch 3 training accuracy : 0.4150390625\n", 159 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 160 | "Epoch 4 training accuracy : 0.4697265625\n", 161 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 162 | "Epoch 5 training accuracy : 0.5048828125\n", 163 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 164 | "Epoch 6 training accuracy : 0.4921875\n", 165 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 166 | "Epoch 7 training accuracy : 0.4765625\n", 167 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 168 | "Epoch 8 training accuracy : 0.4931640625\n", 169 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 170 | "Epoch 9 training accuracy : 0.482421875\n", 171 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 172 | "INFO:tensorflow:Restoring parameters from ./CNN_single_conv_dropout2\n", 173 | "Training took 43.068458 minutes\n" 174 | ] 175 | } 176 | ], 177 | "source": [ 178 | "height = 2\n", 179 | "width = 128\n", 180 | "channels = 1\n", 181 | "n_features = height * width\n", 182 | "\n", 183 | "feature_map1 = 512\n", 184 | "ksize_conv1 = 2\n", 185 | "stride_conv1 = 1\n", 186 | "conv1_dropout_rate = 0.3\n", 187 | "\n", 188 | "pool_layer_maps1 = 512\n", 189 | "\n", 190 | "n_fully_conn1 = 512\n", 191 | "dense1_dropout_rate = conv1_dropout_rate\n", 192 | "\n", 193 | "n_classes = 8\n", 194 | " \n", 195 | "X = tf.placeholder(tf.float32, shape=[None, height, width])\n", 196 | "X_reshaped = tf.reshape(X, shape=[-1, height, width, channels])\n", 197 | "labels = tf.placeholder(tf.int32, shape=[None])\n", 198 | "training_ = tf.placeholder_with_default(False, shape=[])\n", 199 | "\n", 200 | "xavier_init = tf.contrib.layers.xavier_initializer()\n", 201 | "relu_act = tf.nn.relu\n", 202 | "\n", 203 | "# ------------------ Convolutional and dropout layers ----------------------------\n", 204 | "\n", 205 | "def convolutional_layer(X, filter_, ksize, kernel_init, strides, padding):\n", 206 | " convolutional_layer = tf.layers.conv2d(X, filters = filter_, kernel_initializer = kernel_init,\n", 207 | " kernel_size = ksize, strides = strides,\n", 208 | " padding = padding, activation = relu_act)\n", 209 | " return convolutional_layer\n", 210 | "\n", 211 | "conv_layer1 = convolutional_layer(X_reshaped, feature_map1, ksize_conv1, xavier_init, stride_conv1, padding = \"SAME\")\n", 212 | "\n", 213 | "def drop_out(layer, rate):\n", 214 | " dropout_layer = tf.layers.dropout(layer, rate, training = training_)\n", 215 | " return dropout_layer\n", 216 | " \n", 217 | "conv1_dropout = drop_out(conv_layer1, conv1_dropout_rate)\n", 218 | "\n", 219 | "# ----------------- Pooling layers -------------------------------------\n", 220 | "\n", 221 | "def pooling_layer(convlayer, ksize, strides, padding, pool_maps):\n", 222 | " pool = tf.nn.max_pool(convlayer, ksize, strides, padding)\n", 223 | " dim1, dim2 = int(pool.get_shape()[1]), int(pool.get_shape()[2])\n", 224 | " pool_flat = tf.reshape(pool, shape = [-1, pool_maps * dim1 * dim2])\n", 225 | " return pool_flat\n", 226 | "\n", 227 | "pool_layer1_flat = pooling_layer(conv1_dropout, [1,2,2,1], [1,2,2,1], \"VALID\", pool_layer_maps1)\n", 228 | "\n", 229 | "# ----------------- Fully connected and dropout layers -------------------\n", 230 | "\n", 231 | "def dense_layer(input_layer, n_neurons, kernel_init, activation):\n", 232 | " fully_conn = tf.layers.dense(inputs = input_layer, units = n_neurons, activation = activation,\n", 233 | " kernel_initializer = kernel_init)\n", 234 | " return fully_conn\n", 235 | " \n", 236 | "dense_layer1 = dense_layer(pool_layer1_flat, n_fully_conn1, xavier_init, relu_act)\n", 237 | "\n", 238 | "dense1_dropout = drop_out(dense_layer1, dense1_dropout_rate)\n", 239 | "\n", 240 | "# ----------------- Output softmax layer ---------------------------\n", 241 | "\n", 242 | "logits = tf.layers.dense(dense1_dropout, n_classes)\n", 243 | "softmax_activations = tf.nn.softmax(logits)\n", 244 | "\n", 245 | "# ----------------- Specify performance measure -------------------------------\n", 246 | "\n", 247 | "cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits = logits, labels = labels)\n", 248 | "loss = tf.reduce_mean(cross_entropy)\n", 249 | "optimizer = tf.train.AdamOptimizer()\n", 250 | "train_operation = optimizer.minimize(loss)\n", 251 | "\n", 252 | "correct_predictions = tf.nn.in_top_k(logits, labels, 1)\n", 253 | "accuracy = tf.reduce_mean(tf.cast(correct_predictions, tf.float32))\n", 254 | "\n", 255 | "# ---------------- Execution phase -------------------------------------------\n", 256 | " \n", 257 | "n_epochs = 10\n", 258 | "batch_size = 1024\n", 259 | "n_train = X_train.shape[0]\n", 260 | "n_iter = n_train//batch_size\n", 261 | "\n", 262 | "acc_test = defaultdict(list)\n", 263 | "\n", 264 | "path = \"./CNN_single_conv_dropout2\" \n", 265 | "saver = tf.train.Saver()\n", 266 | "\n", 267 | "start = time()\n", 268 | "\n", 269 | "with tf.Session() as sess:\n", 270 | " tf.global_variables_initializer().run()\n", 271 | " for epoch in range(n_epochs):\n", 272 | " for iteration in range(n_iter):\n", 273 | " rand_indices = np.random.choice(n_train,batch_size) \n", 274 | " X_batch, y_batch = X_train[rand_indices], y_train[rand_indices]\n", 275 | " sess.run(train_operation, feed_dict={X: X_batch, labels: y_batch, training_: True})\n", 276 | " acc_train = accuracy.eval(feed_dict={X: X_batch, labels: y_batch})\n", 277 | " print(\"Epoch {} training accuracy : {}\".format(epoch, acc_train))\n", 278 | " save_path = saver.save(sess, path)\n", 279 | " saver.restore(sess, path)\n", 280 | " saver.restore(sess, path)\n", 281 | " for snr in snrs:\n", 282 | " acc_test[snr] = accuracy.eval(feed_dict={X: X_test[snr], labels: y_test[snr]})\n", 283 | "\n", 284 | "print(\"Training took %f minutes\"%(float(time() - start)/60.0))" 285 | ] 286 | }, 287 | { 288 | "cell_type": "markdown", 289 | "metadata": {}, 290 | "source": [ 291 | "## Test the classifier" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 5, 297 | "metadata": { 298 | "collapsed": false 299 | }, 300 | "outputs": [ 301 | { 302 | "name": "stdout", 303 | "output_type": "stream", 304 | "text": [ 305 | "CNN's test accuracy on -20dB SNR samples = 0.1197500005364418\n", 306 | "CNN's test accuracy on -18dB SNR samples = 0.12250000238418579\n", 307 | "CNN's test accuracy on -16dB SNR samples = 0.12600000202655792\n", 308 | "CNN's test accuracy on -14dB SNR samples = 0.13500000536441803\n", 309 | "CNN's test accuracy on -12dB SNR samples = 0.13750000298023224\n", 310 | "CNN's test accuracy on -10dB SNR samples = 0.16975000500679016\n", 311 | "CNN's test accuracy on -8dB SNR samples = 0.2565000057220459\n", 312 | "CNN's test accuracy on -6dB SNR samples = 0.40400001406669617\n", 313 | "CNN's test accuracy on -4dB SNR samples = 0.4897499978542328\n", 314 | "CNN's test accuracy on -2dB SNR samples = 0.5214999914169312\n", 315 | "CNN's test accuracy on 0dB SNR samples = 0.5702499747276306\n", 316 | "CNN's test accuracy on 2dB SNR samples = 0.6575000286102295\n", 317 | "CNN's test accuracy on 4dB SNR samples = 0.6957499980926514\n", 318 | "CNN's test accuracy on 6dB SNR samples = 0.703249990940094\n", 319 | "CNN's test accuracy on 8dB SNR samples = 0.7135000228881836\n", 320 | "CNN's test accuracy on 10dB SNR samples = 0.7242500185966492\n", 321 | "CNN's test accuracy on 12dB SNR samples = 0.7082499861717224\n", 322 | "CNN's test accuracy on 14dB SNR samples = 0.7197499871253967\n", 323 | "CNN's test accuracy on 16dB SNR samples = 0.6949999928474426\n", 324 | "CNN's test accuracy on 18dB SNR samples = 0.7222499847412109\n" 325 | ] 326 | } 327 | ], 328 | "source": [ 329 | "for snr in snrs:\n", 330 | " print(\"CNN's test accuracy on {}dB SNR samples = {}\".format(snr,acc_test[snr])) " 331 | ] 332 | }, 333 | { 334 | "cell_type": "markdown", 335 | "metadata": {}, 336 | "source": [ 337 | "## Visualize classifier's performance on test set" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": 8, 343 | "metadata": { 344 | "collapsed": false 345 | }, 346 | "outputs": [ 347 | { 348 | "data": { 349 | "image/png": "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\nAAAAAElFTkSuQmCC\n", 350 | "text/plain": [ 351 | "" 352 | ] 353 | }, 354 | "metadata": {}, 355 | "output_type": "display_data" 356 | } 357 | ], 358 | "source": [ 359 | "plt.style.use('classic')\n", 360 | "%matplotlib inline\n", 361 | "\n", 362 | "acc_test = sorted(acc_test.items())\n", 363 | "new_acc = []\n", 364 | "for i in range(len(acc_test)):\n", 365 | " new_acc.append(acc_test[i][1])\n", 366 | "acc_test_values = new_acc \n", 367 | "\n", 368 | "fig1 = plt.figure(figsize=(10, 6), dpi=100)\n", 369 | "x = snrs\n", 370 | "y = list(acc_test_values)\n", 371 | "plt.plot(x, y, marker=\"o\", linewidth=2.0, linestyle='dashed', color='royalblue')\n", 372 | "plt.axis([-20, 20, 0, 1])\n", 373 | "plt.xticks(np.arange(min(x), max(x)+1, 2.0))\n", 374 | "plt.yticks(np.arange(0, 1, 0.10))\n", 375 | "\n", 376 | "ttl = plt.title('SNR vs Accuracy', fontsize=16)\n", 377 | "ttl.set_weight('bold')\n", 378 | "plt.xlabel('SNR (dB)', fontsize=14)\n", 379 | "plt.ylabel('Test accuracy', fontsize=14)\n", 380 | "plt.grid()\n", 381 | "\n", 382 | "plt.show()" 383 | ] 384 | }, 385 | { 386 | "cell_type": "code", 387 | "execution_count": 17, 388 | "metadata": { 389 | "collapsed": false 390 | }, 391 | "outputs": [ 392 | { 393 | "name": "stdout", 394 | "output_type": "stream", 395 | "text": [ 396 | "Confusion Matrix\n", 397 | " 8PSK BPSK CPFSK GFSK PAM4 QAM16 QAM64 QPSK\n", 398 | "8PSK 0.52 0.00 0.03 0.00 0.00 0.03 0.01 0.41\n", 399 | "BPSK 0.01 0.92 0.00 0.00 0.02 0.02 0.01 0.03\n", 400 | "CPFSK 0.00 0.00 0.96 0.03 0.00 0.00 0.00 0.01\n", 401 | "GFSK 0.00 0.00 0.03 0.96 0.00 0.00 0.00 0.00\n", 402 | "PAM4 0.00 0.07 0.00 0.00 0.90 0.02 0.01 0.00\n", 403 | "QAM16 0.11 0.00 0.00 0.00 0.00 0.42 0.34 0.13\n", 404 | "QAM64 0.02 0.00 0.00 0.00 0.00 0.44 0.54 0.01\n", 405 | "QPSK 0.42 0.00 0.01 0.00 0.00 0.03 0.02 0.53\n" 406 | ] 407 | }, 408 | { 409 | "data": { 410 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAUIAAAEbCAYAAACvLI2jAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJztnXe8lNXxh5/vBSygYsHeY4lGRbFFjXJRY40FWxQ1MYkx\nscYWNfnFElvUmKZGjRp7w66xYgWsEQsKWLF3Y1cURZjfH3P28rLsvdv3Luw8fPbDvuc97znnfe/u\n7JyZOWdkZgRBELQybd09gCAIgu4mBGEQBC1PCMIgCFqeEIRBELQ8IQiDIGh5QhAGQdDyhCAMiiJp\nNkk3S/pE0lVVtLOrpDtqObbuQNJtkn7S3eMIakcIwpmIJGhGSfpc0luSbpX0gxo0vSMwPzCPme1c\naSNmdoWZbV6D8UyDpHZJUyRdm1feP5XfW2I7x0i6pFg9M9vSzC6tdLxB8xGCcCZB0iHA34ATgAWA\nJYCzgG1q0PySwAvW3NH3/wPWkzRPpmwP4PladiJJtWwvaBLMLF4z+AuYC/gc2L6LOrMA/wDeAt4E\n/g70SufagTeAQ4D3Up090rk/Al8D3wCfAT8HjgEuzbS9JDAFaEvHPwNeSvVfAoak8j2A+zPXrQc8\nCnwM/BdYN3PuPuA44IHUzh3AvJ3cW278ZwH7prK2VHYkcG+m7j+A14FPgVHA+ql8s3SfX6dn+WRm\nHCekcUwAvpPKfpHOnwVck2n/FOCu7v5MxKu8V2iEMwfrArMCN3ZR50hgbaA/sGp6f2Tm/ELAnMAi\nwC+BsyT1NbM/An8ChprZXGZ2Yaqfrx0agKTewGnAZmY2Fy7sRheoNw9wCy6Y5sMF8615Gt0QXHjO\nn+7vt13cnwGXAD9Nx5sBY4F38uo9mp7BPMAVwDWSZjGzYek+rzKzOc1sQOaa3dMzmRMXolkOBVaR\n9FNJG+A/FD8lmKEIQThzMB/wgZlN6aLOrsCxZvahmX0IHAtkDf7fAMeb2WQzux34AvhuheOZjAuH\n2czsPTN7tkCdH+HT7SvMbIqZDQWeA7bO1LnQzF4ys6+Bq4HVuurUzB4B5pG0PC6MprP3pf4+SX3+\nHRewxe7zIjN7Ll3zbV57X+GC8u+pv/3NLF/4Bk1OCMKZgw+BfpK6+nsuwrTazGuprKONPEH6JTBH\nuQMxsy+BnYF9gHeSt7mQoFkkjSHLa8CimeN3KxjPpcD+wCDghvyTkg6V9IykjyV9jJsV+hVp842u\nTprZY8DLgIBrShhj0GSEIJw5eBiYCAzuos5buC0vx5LA2xX2NwHonTleOHvSzO4ys03x6fbzwLkF\n2ngbWCqvbIk0zmq4DNgXuNXMJmZPpKnr4cCOZjaPmc2D2x9zDpDOnEFdOokk7YfbYN8Gjqhi7EE3\nEYJwJsDMPsMdGGdK2lbS7JJ6StpC0smp2lDgSEn9JPUDjsK1p0oYDQyUtLikvsDvcickLSBp62Qr\nnIRPsScXaOM2YDlJu0jqIWlnYEXg5grHBICZvQoMZFr7Z4450pg+lDSLpKNxu1+O94ClyvEMp2n4\n8cBu+HT8MEn9Kxx+0E2EIJxJSPauQ3AB8D4+Dd6XqQ6UE4DHgKeBp9L7E7tqsou+7gauSm2NYlrh\n1YY7EN4CPsCF0r4F2vgI2Ap3gHyQ/v+RmX1crP9imNlDZvZugVPDcO/zC8Ar+HQ7O+29BtcOP5T0\nWBfjyDl8euA/JieZ2VgzGw/8AbhUUq9Kxx80Hpk1c2hYEARB/QmNMAiClicEYRAELU8IwiAIWp4Q\nhEEQtDw9u3sA3YWk8BIFQYmYWc02m5hNc9vXfFpK1dfMbKla9dsVLes1lmT//Mf9ZV1z6+0X8KMt\nflFy/b33W6/cYXHsccdyzNHHlHXNt98WCtPrnONPOI6jjjy6rGt69uxRVn2o7F4a0UcjnhdAjx7l\nTbiOO+5Yji7zXm65pdDqxc4ZOvQsdtllumimLtlu+1VqKggl2SAVf57D7bia9tsVLasRBkHQjZQi\n3hqoo4UgDIKg4bT1KEESdrWFSI0JQVgGyy07oHilKmlvb697HwMH1r8PaMy9xPMqj5VXXqvufZRE\nk+1vG4KwDJZfrv6CcFD7oLr30d6gL3Yj7mVmel7tDbiXZhGETSYHQxAGQdB41NZckjAEYRAEDafZ\nBGFTBVRLOljSWElPS7pc0qyShkt6TtJoSfdLWi7V3UrSE6l8rKS9UvkxKZFRLg3lnZKO6s77CoJg\nWiQVfXVx7eZJJrwgabr9HyUtIeluSU9JulfSIoXaydI0gjAN9gBgdTPrj2uru+C+oyFmthq+Ffqp\nknoC5+DbNq0GDACG57XXC7gWGGVmxzfsRoIgKI5KeBW6zHdh/yeek2YlYIikFfKq/QVPr7AqngDs\nZIrQNIIw0QPokwRdb3xPu+xjGQksi2+m2QPPfoaZTTKzFzPt9MI3In3BzP7QoLEHQVAialPRVyes\nDbxoZq+Z2ST8e75tXp3vAfcCmNnwAueno2kEoZm9DfwV31D0LeCTtAFolm2AMWnzzpuB1yRdkRKb\nZ5/c4cAkMzukEWMPgqA8qhCEizLtZrpvMm2eG/Ad1HcAkLQ9MEdedsTpaBpniaS5ccm9JJ5z9hpJ\nu6XTl0v6CngVnz5jZntJ+gfwQ3xH5B8CufVv9wPrSlouT1Ochltvv6Dj/XLLDmhIeEwQNDtjx45i\n7NhRde2jkAnww0kv89GkV4peWqAsfw3KYcA/Jf0Mn0W+BXybf1GWphGEuCB7OW3hjqQb8Jy4Buxm\nZk/kX2Bm44Bxki7Ds4jlBOFI4GLgdknrd7Jte1nrhoOgVVh55bWmiTe86uqza95HIY2v36zL0G/W\nZTqOx0+8t9Clb+JJvnIsRl4SspRONacR9gF2MLPPuxpP00yN8SnxOsnTK2Bj4BkK/AJI6iMpG+U6\ngLzUkGZ2A3AqMCwlGAqCoFmQir8KMwpYVtKSkmbBHar/mbZpzZcxlf0euIAiNI0gNLNHcS/vk3hy\nIfA0kIWWXgs4XNKzkp7AM7jtUaDNc4DrgJvSQwuCoAloa1PRVyHMbDKet/pOYBww1MyelXSspK1S\ntUHA85KeAxag6yRlQHNNjTGzY4Fj84o3KlDvC+BHXbSRPT4Od6EHQdAsVBFPbWZ3AN/NKzsm8/46\nXAEqmaYShEEQtAbNtrIkBGEQBA0nBGEQBC1PV0vouoMQhEEQNJ6mcdM6IQiDIGg4oREGQdDyhI0w\nCIKWp8kUwtYWhL/ed926tr/FPEXjOGvC7R/PPBvsTJ5c/4w9zTYtq4Yttvhu8UpNSGiEQRAETfZj\nFIIwCIKG09kSuu4iBGEQBI0nwmeCIGh1ms1O22RyOQiCVqDOyZsWT0mbcsndtig2ntAIgyBoOOpR\nmUaYSd60Mb4h6yhJN5nZc5lqRwJXmdk5klYEbgOW7qrd0AiDIGg4le/LWlLypinAXOn93PhW/V0S\nGmEQBA2nijjCQsmb1s6rcyxwp6Tf4Nkwf1is0abRCCVNzszpH5O0TipfUtKX6dxYSWenckk6TdKY\nlBD+v5KWTOdekTRver+GpJclrdp9dxcEQZYqstiVkrxpCHChmS2Ob+B8WbHxNJNGOMHMVgeQtCme\nlHlQOjfezFaX1AO4V9JgYDZgYTNbJV2zCDAh1bdU1h+4BtjJzJ4iCIKmoJCge/ezF3jvsxeKXVo0\neROwJ54AHjN7JOVB6mdmH3TWaDMJwuyT6Qt8lF/BzCZLeghP8j4ZeCdzLv9hfA/PZLebmT1e++EG\nQVAxBYyAC/X9Lgv1nbpkcMzbtxW6siN5E/793wXXALO8hk+HL07Oklm7EoLQXIJw9pSIaXZgIabN\nVSIASb1xb9FRwFjgAUkb4FntLzOz0Zn6NwK7m9nDDRp/EAQlUmkYYVKGcsmb2oDzc8mbgFFmdgvw\nW+A8SQfjjpPpErvl00yC8MvM1Hgd4FJg5XRumSQkDbjRzIalesvjAnNj4G5JO5nZfemau4G9JA0z\ns0KZ8IIg6CYqDZ+BkpI3PQusX06bzSQIO0jz+n6S+qWi8TkhmVdvEjAMz138HjAYuA8XmPsD5wBn\nA3sX6ue446YmvGtvb6e9fVAtbyMIZkhGjBzByJEj6tpHs60saSZB2PFkJK2Aq70fAn0o4CmSNAB4\n18zeSUGW/YHs1HgKbju4Q9Kx2V+MHEcfPV1RELQ87QPbaR/Y3nF84okn1LyP2Iarc2ZL09/cE/qp\nmVn65Sg0tV0AtwPkErc/CpyZ3huAmX2TPMzDJb1rZmfXb/hBEJRKkymEzSMIzaxXJ+Wv4dpefvkw\nfFpc6JrvZN5/Bkw3rQ6CoPtQj6YJYQaaSBAGQdA6hEYYBEHQZJIwBGEQBA0nvMZBELQ81cQR1oMQ\nhEEQNJwmUwhDEAZB0HgijjAIgqDJVMIQhEEQNJy2sBE2D/X2XN3+8R/q2n6OjXv9se59DPvqqLr3\nAdCzZ4+G9DOz0KPJApNLporvnqTNgX8wdfeZU/LO/w3YEF9h1geY38zm7arNlhaEQRB0D5XKwVKS\nN5nZIZn6+wOrFWt3Bv05CYJgRqatR1vRVyeUkrwpyxDgyqLjKfsOgiAIqkUlvApTKHnTogW7kJYA\nlsI3bu6SmBoHQdBwqgifKSV5U45dgGtL2Zg5BGEQBA2nkKPyzfee4c33nyl2aSnJm3LsAuxbynhC\nEAZB0HAKLbFbfJGVWHyRlTqOHx13XaFLS0nehKTvAnOb2SOljCdshEEQNBxJRV+FMLPJeBqOO4Fx\nwNBc8iZJW2Wq7oI7Ukqi4RqhpAXxGKA1gU+A94CDgaeA54BZgJFmtm+S+s+mcuG2gLWBeYHzgcWB\nXsArZrZVqn9LJtfxXsCvgY3N7NPG3WUQBF1SxRK7Ysmb0vGxlEF3TI1vwLPQDwGQtAqwIIWTuD9J\ngcRNko4D7jSzM9LxypnTueTuPwH2AzYMIRgEzUWTrbBr7NRY0obAN2Z2Xq7MzMaQcYcn1TeXxB0K\ne4kWxo2muWvGTtuNdgIOBzYxs49rdwdBENQC9Wgr+mokjbYRrgw83sm5/CTuY1L5MpKeSK8zUtmZ\nwAWS7pH0f5IWzrSzJHAGsKmZ/a/2txAEQbVUaiOsF83kNZ4uiXuy+U03NTazOyUtDWwObAk8kZke\n/w9PA7ozbosMgqDJUJO5aRstCMcBO3ZyrmAS984ws09wr9BQSTcDA4EngAnAFsCDkt43sys6a+PY\nvATvgyLBexAwYsRwRoyIBO91w8zulXSipD3N7HzocJb07eKyQsndNwQeMbOvJM0JLAO8njttZh+m\nHSruk/SBmd1ZqOFjIsF7EExHe/sg2jNKwfEnHF/zPpptq/7uUFC3AzaVNF7SGOBPwLtd1C+0PGYN\n4DFJo4EHgXPN7PFsfTN7FV+Mfb6ktWo1+CAIqqflbYRm9i5uv8unUBL3zpK7/wX4S7H6ZvY0HmsY\nBEEzEVv1B0HQ6rS0jTAIggCaz0YYgjAIgoYTGmEQBC1Pk8nB2H0mCILGU80SO0mbS3pO0guSjuik\nzo8ljZM0RtJlxcYTGmEQBA2n0h2qS0neJGlZ4AhgXTP7TFK/Yu2GRhgEQeOpPGdJKcmb9gLONLPP\nAMzsg2LDCUEYBEHDqSKgupTkTcsD35X0gKSHJG1WbDwxNZ4JaETy9c1mr/0yq0LcM+mPDelnZqHZ\nvK+l0kW6zmKUkrypJ76N30A8v8n9klbKaYiFCEEYBEHjKSDOXnn1KV597aliV5aSvOlN4GEzmwK8\nKul5YDk63wKwPEEoqS+wqJkVTTUVBEHQGYU02e8svRrfWXq1juMRIws6e0tJ3nRjKrskOUqWA17u\najxF9dO0+elckuYBRgOXSjq12HVBEASdIRV/FaKU5E1mNgz4UNI44B7gt8V2qi9FI5w3uaD3BC4z\ns6MkPQ0cVupNB0EQZGmrf/KmQ4FDSx5PCXV6Spof2Am4udSGgyAIOqNSjbBelCIITwRGAK+b2aOS\nvgO8Ut9hBUEwMzPD7UdoZkPJJEo2s5eZPoAxCIKgZJot6qcUZ8lJyVnSU9IwSe9J2rURgwuCYOak\nrU1FXw0dTwl1tkiBiFvh8Tor4uv4aoakBSRdnrbvHyXpQUnbSmqX9ElK5fmkpDtT/eUl3ZfKxkn6\nVypvT4mccu2eIOl2Sb1qOd4gCKpDJfxrJKV4jXN1tgSuMbOPJBXKI1INNwIXmtluAJIWB7YBPgFG\nmtk2efVPB/5qZrek+itlzlkq+wOwLi7IJ9V4vEEQVMEMNzUGbpc0Fvg+cFcKUPy6VgOQtBHwtZmd\nlyszszfM7MxclQKXLQS8lak/btomdQie83hrM/umVmMNgqA2NNvUuBRnyWEpgPojM/tW0kRg+xqO\nYSU8H3FnbJASv4NrpCfhidvvk/QgcBeuTX6a6vwAX3S9hpl9WcNxBkFQI5pNIyx1id28wPqSZsuU\ndZo4vRok/RNYH/gGD9qebmpsZhdJugPX+gYDv5K0ajo9Hpgb2Ay4rqu+IsF7EEzP8AYkeG82SVhU\nEEo6EtgUWAEYhguYB6idIBwH7JA7MLP9Jc0HPEbhnMa5eu8CFwEXpfzIK6dT7wK7AvdK+tDMhnfW\nRiR4D4LpGdQ+aBql4Pjjj6t5H00mB0uyEe4MbAi8Y2Y/AVYF+tRqAGZ2LzCrpF9nivswVQhO98gk\nbSapZ3q/EK6xZm2G4/Hp+6UZTTEIgiah2WyEpQjCr9JC528lzYlrXEvWeByDgUGSXpL0CHAhHqIj\nCmuFmwJjJT0J3I4vqn4/W8HMHgN+AdwkaekajzcIgiqY4VaWAE9Kmhu4AJ+ufgY8WstBmNl7TL+V\nTo7pjBWdLag2sxHZ+mZ2F7BUbUYZBEGtqEbOSdocd5i2Aeeb2Sl55/cATsX3JQT4p5ld0FWbpXiN\nc1PWMyUNA+Yys668vEEQBF1SqRwsJXlTYqiZ/abUdjsVhJL6d3LqW0n9zezpUjsJgiDIUoUNsCN5\nE4CkXPKmfEFYVgddaYRndnHO8HwAQRAEZVOFDbBQ8qa1C9TbXtIGwAvAIWb2ZoE6HXQqCM1sg0pG\nGQRBUIwqbISlJG/6D3CFmU1K0SgX41PpTikljnBvfL79STqeB9jJzM4tadhBEAR5FNIIn3/hCV54\nsaj7oWjyprxt+c8DpnGmFKIUr/HeZvavbCeS9gFCEAZBUBFtBQL3VlxhdVZcYfWO41tuK+joLZq8\nSdJCacEFuP2waLK5UgRhj7xO2oDY1ioIgoqp1EZoZpMl5ZI35cJnnpV0LDAq7Uj1G0nbAJOAj4Cf\nFWu3FEF4l6QrgX/hc/F9gLsruosgCAKqiyMslrzJzP4P+L9y2ixFEB6GC7+DcUPlncA55XTSqkyc\n2JhtEGebrf4K+j2T/lj3PgC2WvDkuvdx09uH170PqC5TW6k0egVGrWi2cZcSUD0ZD2D8Z/2HEwRB\nK6AGryUuRqnbcAVBENSMGU4jDIIgqDVNJgdLF4SSZjWzmm3RHwRB69LobbaKUUo6z7XTxqcvpuNV\nJZ1R95EFQTDT0mzbcJWyH+HpeCrPDwHM7Cl8o9YgCIKKaDZBWMrUuM3MXssb2OQ6jScIghag2WyE\npWiEb0haGzBJPSQdhO/oUDWSJqfk7WMkXZVNDiVpO0lTJC2fKVsylR2bKZtP0jeSTs9re8dUd3WC\nIGgq2nq0FX01dDwl1NkHOARf6PwesE4qqwUTzGx1M1sFXw6zd+bcLsD96f8sL+NT9Rw7AWOzFSTN\nARwAPFKjcQZBUEOk4q9GUlQQmtn7ZraLmfVLr13M7IM6jOV+YFkASX2A9YA9mX4L/6+AZzOa3s7A\n1Xl1jsd3nAgvdxA0ITOcjVDSeRRIoGRmv6pB/0p99AS2wBMxgSdzusPMxkv6UNJqZjY6c91QYIik\n94Bv8W14FkltDQAWM7PbJB1WgzEGQVBjZkQb4d3APen1ILAAtdO0Zpf0BJ4M6jXg/FQ+BBd2AFfh\neYpzGHAHsEmqdxVTBaqAvzFtYqcme+RBELS1tRV9dYakzSU9J+kFSUd0Ua9kP0Epa42vymv8UjzB\ney340symGaSkeYGNgJUkGb4NmAEdK+XN7FtJj+O2y5WAbdKpOfFE78OTUFwIT+e5TaGEU8ce1+Fz\nob29fZqk1kHQqgwfMZwRI6ZLHllTKtUIS03eVK6foJIldksDC1ZwXSEKPY6dgIvNrMMhI+k+ST/A\nd6fNXfNXYHjaKBYAM/sMmD97HZ6v4MlCnR9z9DGFioOgpRnUPmgapeD444+rfSeVz41LTd6U8xOU\nZB4rZWXJx5I+Sq9PgLuA35cz8i4olLx9Z+CGvLLrmTo9NgAze8bMLi2h/ZgaB0GTUYWzpFDypkXz\n2l6N5CcodTxdaoRperkq8FYqmmJmhYRXRZjZXAXKNipQll3SN12aUTO7GE/QUrStIAi6n7YeFesn\nXSZvSjLr78AeRa6Zhi4FoZmZpNvMbOVSRxkEQVCMQgrfmDGPMmbMqGKXFkveNCfuNyjJT5CjFBvh\naEmrd9VIEARBORSa+vbv/3369/9+x/HQoWcVurTL5E3JT7BApp8u/QQ5OhWEknqa2bfAAOBRSS8B\nE3A10/K9vUEQBKVS5+RN01xClVPjR4HVmRqaEgRBUBOq2Y+wWPKmvPKS/ARdCUKlhl4qdYBBEASl\nMCNt1T+/pEM6O2lmf6vDeIIgaAGaTA52KQh7AHMQcXhBENSYrpbQdQddCcJ3zKwOIeVBELQ6M5JG\n2GRDrT1ffD6xru3PMedsxSsF03DLe7+rex833ji2eKUaMP+Cc9a9j5VXXKB4pSZkRsprvHHDRhEE\nQUsxw2iEZvZRIwcSBEHrMCN5jYMgCOpCCMIgCFqeJpODIQiDIGg8oREGQdDyVLPErh6EIAyCoOE0\nmUJYUvKmqpC0qKQbU6KV8ZJOl9Qrc/40SW/mXbNHSrqyYaYsl/B9+3S8n6QXU5L4efOuHyTpSUlj\n0zY8QRA0EdWk8yyWvEnSryU9nWTASEkrFBtPI9a5XA9cb2bLA8sBvYFToWM32cHA65IG5l33NNPm\nNN4ZyKb0fACPdXwte5GkvsCZwFZpQ9mdancrQRDUgkoTvGeSN22Gb8A6pICgu9zM+pvZAFzW/L3Y\neOoqCCVtBHxlZpeAb2IIHAz8VFJvYENgDHA206bsBBd0a0vqkRK+L0tGEJrZU2b2OtOvgNkVuM7M\n3kr16pGMPgiCKmiTir46oSN5k5lNwtP+bputYGZfZA7nAKYUHU+F91EqKwGPZwvM7HPgFVywDQGu\nAG4EfiSpR7YqnlN5c/xGbyqxz+WBeVPmu1GSflLdLQRBUGsq1QgpIXmTt699JY0HTgZ+U2w89RaE\nonCmujZgVmBL4KYkHB8FNs3UMVza74JPi6+ktPXPPfENZbfAhehRkpat9AaCIKg9VdgIu0ze1FFg\ndpaZLQscARxVbDz19hqPA3bIFkiaC88psDDQFxiTbIWz46kAbs/VNbPHJK0MTDCz8Z08nPyH8Cbw\nPzObCEyUNBLPxDc+/8KTTj6x4/3662/ABuvnmymDoPV44MGRPPjg/XXto1D4zGOPPcTjjz9c7NJi\nyZvyuQr4V7FGVcPsnIU7kB4FTjezy9LU92x8arwKrg1eler1TuVL4hrgGmb2G0mbARPNbISkC4Gb\nzez6TPuvAGua2YfpeAXgDFwbnBX4L7CzmT2TNy775KMJdb332H2mOYndZ8pjvvnnwMxqFvAiyR5/\n/M2i9dZYY7Hp+k0y5HncUfoOPpMcYmbPZuosa2bj0/utgaPMbO2u+mqE13g7YCdJLwAfAJOBf+DT\n4FtzlczsS+B+YOvsxWY2zMxG5A5z5ZIOkPQGbh94StK5qf5zwDDc6/wIcG6+EAyCoHupdGpsZpOB\nXPKmccDQXPImSVulavun0LkngIOYNsdx4fHUWyOcpjNpHdzWt32x9HoNGEtohC1KaITlUQ+N8Ikn\n3ypab/UBi9a0365o6MoSM3sEWLqRfQZB0HzEErsgCFqe2HQhCIKWp7nEYAjCIAi6gdAIgyBoecJG\nGARBy9NkCmEIwiAIGk8IwiAIWp6wETYRs/eepbuHEHQDk76Z3JB+Hn/k9br3sd46SxSv1IQ0m42w\nEUvsgiAImpqW1giDIOgeYmocBEHL02RyMARhEASNp9kEYdgIgyBoOCrhX6fXFs9id7CkcZJGS7pL\n0uLFxhOCMAiCxqMSXoUuKy2L3RP4xs6rAdeRsmZ2RQjCIAgaTp2z2I1IqTrAN2eeLrnTdOOp4l6C\nIAgqo0KNkBKz2GXYk0wepM6ou7NE0qJ4wvXv4YL3NuDQJM2RdBqwg5ktlrlmD+BCYGMzuy+VbYer\nuTvmcpZIOhHYEfgWONvM/plpYy3gYeDH2RwnQRB0P4Xk3MMPP8AjjzxQyaUFt9mXtDuwBtBerNFG\neI2vB840s8EpW915+Jz9oHQ8GHhd0kAzG5m57mk87/F96XhnMgneJf0cWNTMvpuO+2XOteH5TO+o\n320FQVApheII11tvA9Zbb4OO43+c9udCl5aUxU7SD4HfAwNzSldX1HVqLGkj4CszuwTAPEHKwcBP\nU9a6DYExeGa7XfMufwBYW1IPSX3whPCjM+f3Bo7LHZjZB5lzBwDXAu/X9o6CIKgFVSR4HwUsK2lJ\nSbPgec//M23bGoCn8Nwml92yGPW2Ea4EPJ4tSMncX8EF2xDgCuBG4EcpVV9HVeBuPC3ntsBNeW0v\nA+wiaZSkW3NJ3NNUfDD+IJosWikIAqh7Frs/A32AayQ9KenGYuOp99RYFJ6/t+E5h7cEDjKzCSn/\n8aZMNWwa7hE6EJgLOBT4Q6aNWYEvzWytZD+8ABgI/B04wswsPcxOheHxx3colAwc2E57e1FTQhDM\n9IwYMZwRI0YUr9hNmNkdwHfzyo7JvN+k3DbrLQjHATtkCyTNBSwALAz0BcYkW+HswAQyHh4ze0zS\nysAEMxuf9yvxBm5/xMxukHRBKl8TGJra7AdsIWmSmU2jPgMcddTRtbnLIJiJaG8fRHv7oI7j4084\nvuZ9tNTKEjO7B5g9eW9yWer/ggdE7gLsaWbfMbOlge8Am0nKTwb8O6bVBHPciGe7R9Ig4IXU53cy\nbV4L7FtWoUtpAAAZJ0lEQVRICAZB0H1UOjWuF42II9wO2EnSC8AHwGTgH/g0+NZcJTP7Ergf2Dp7\nsZkNM7Ocnp6dZp8C7CDpaeBE4JcF+m5c9vogCEqmCmdJXah7+IyZvUWK/Ja0DnAlcK6Z9StQd8fM\n4cUFzv8i8/5TYKv8Op3VD4KgeehqLXF30NDdZ8zsEWDpRvYZBEET0lxyMLbhCoKg8TTZTv0hCIMg\n6AaazG0cgjAIgobTXGIwBGEQBN1AkymEIQiDIGg8kbwpCIKWp8nkYAjCIAi6g+aShC0tCG+++Zm6\ntj948Mp1bT+H725WX5ptKlMN223fmL9LI57ZWWc8VPc+6kE1j0bS5vjqtDbgfDM7Je/8Bul8f2Dn\nUjZmjq36gyBoOJUusSsxedNrwB7A5aWOp6U1wiAIuouKVcKO5E0AknLJm57LVTCz19O5kqdKoREG\nQdBwqth0odzkTSURGmEQBI2ngKC7//6RPPDAyOlPFL2y+l2mQhAGQdBwCu0+M3CDdgZuMHWX+JNP\n+VOhS0tK3lQuMTUOgmBGomjypjxKMkaGIAyCoOFUaiMsJXmTpDUlvYHnPP+XpDHFxtMUU+NOksD/\nFlgXz173EjAbcJWZHSdpdjw/cn9c4n8MbG5mX0r63MzmTO1uiSdz2tjM3mzwbQVB0BlVBBKWkLzp\nMWDxctpsFo3weuB6M1seWA7ojafkAxhpZmsAawG7p5ylBwLvmll/M1sF2BPIJXE2AEkbA6cBm4UQ\nDILmQiW8Gkm3a4SFksBLOhgPirwzVy9pe4/j+YwXAl7PnHtx2ia1PnAOsIWZvVr/uwiCoCyabKFS\nM2iEnSWBfxXXDgGQNB/wfdwucCFwhKQHJR2fS+6emBXPcDc4T0AGQdAkNJtG2AyCsLMk8LnygUkT\nvAM4ycyeNbOn8NwnpwLzAo9KytkMJgEPUTirXRAEzUCTpbHr9qkxXSeBfx63EW6Tf1FK/3kjcKOk\nKcCWqf5k4MfAPZJ+b2YnddbxVVef3fF+pZXWZOWV1qr+boJgBufF8U8y/qUn69pHk82Mu18Qmtk9\nkk6StLuZXZZJAn8GMJECz0zSesAzZvZJiiX6HnBv7rSZTUyu9JGS3jOzCwr1vfOP96nLPQXBjMxy\nyw5guWUHdBzfcedFte+kySRhM0yNoUASeDM7OZ0rNG1eBhgh6SncvjjKzG7I1jezj4EtgD9I2rpA\nG0EQdBOSir4aSbdrhFA4CbykAWY2AhhRoP6lwKWdtDVX5v2buNAMgqCJaDKFsDkEYZZIAh8ELUCT\nScKmE4RBELQCzSUJQxAGQdBwmi3zQwjCIAgaTpPJwabxGs8QjB03qu59DB8xvO59jGhAH9CYe2nI\n8xo5nb+uPv2MqH8/L46vb3xgyVQRUC1pc0nPSXpB0hEFzs8iaaikFyU9LGmJQu1kCUFYBuPGPVb3\nPhrxZWhEH43qpxF9jGyQIGxEP/UOlK43JSZv2hP4yMyWw7PZ/ZkihCAMgqDhVKEQdiRvMrNJQC55\nU5ZtgYvT+2uBjYuNJwRhEAQNp4qA6lKSN3XUSRu5fiJp3i7H04jk4M1IOan+gqDVMbOa+TckvQos\nWULV98xsobxrdwQ2NbNfpePdgbXM7MBMnbGpztvpeHyq83FnHbWs17iWf9ggCErHzJaq4vJSkje9\nge9Q/Xbau2CuroQgxNQ4CIIZi1KSN90M7JHe78TUDVk6pWU1wiAIZjzMbLKkXPKmNuD8XPImfPOV\nW4DzgUslvQh8iAvLLmlZG2EQBEGOmBpXgaS5G9DHAEnz1LufvD7rYj9N9pogaDpCEFaIpHWBEyS1\npSDPWrcvSbMBVzCtcbhuSBooaQmrwzQhbab7j3RfdXNUNeLHqdFI2rWU1REVtn2KpMXq0faMRAjC\nylkK6G1mU6jD0skkjCYDE/C8zXUlCd3fAfPXuN3cZ2wtYKIlatlHpq+1gbGSfiCpIfZvSeekEI56\ntf9D4DJgsKTlitUvs+0+wDpM73VtOUIQlomkBdPbKUAv6AjarGUfa0maJ0XOf4inLEBSzzpqU5OB\nOYBZa6zh5jbK/Yb6O+d6AXPiS6zWqvdUXNLFwIK4l7Ie7QsPFxkH9MeF4RKZc9UyO54ad4F6aukz\nAiEIy0DSkvjW/5sDXwFfpvJZMnVq8Uz3Be5KtkEB8wCY2be11qaS9rRNErqfAp+b2ZRafDEkLQVc\nljIMfgD0S+X1+tI9DVwEvAP8EVhK0lIpGVhNSW3OZmaDzezTZMtdV9LstfohScrzc7h55Ho8N8/W\nko4GBnR5cddjP1vS9mb2AZ71cUrKJ94jU6elBGOEz5RImjr+D59GfB+YD5grLfieLOkV/HkuiCen\nr6SP7wEvmNnPJZ0H3IJn8ztQ0kTgM+B9oA/wpJndXeVtgdsfT5L0DfAsLuCpVuCmL9L7wMPAsbhw\nyj2XeSV9bmbfJM234qm/pIXM7N10OAvQO/W3FXAlvoJhEP7saomAFSStAqyLx619i+fjPh8YWXHD\nPh1+xMy+SJ+7VYBbgSOBe4C++BrbSnkQuEjSV8DdgCVTwpRMnZ64kGwJQhCWQNIAB+F5lM8G9sLT\nhy4PLIsnjJqIf0A/l7StmX1YQR+nA78ChpvZXpL+hNvtLsE/pHMCK+JR89dVeU9rAK+b2ZWSvgb+\nmtpeVtI7wHv4VPNb4CEzu6uMtjfGhcPJwLl4UOsfgX6SlgHWAz6S9BHQS9ImZvZ1BfewMfBvSSea\n2b/N7ENJL+NrTUfjdtzXgSmSetTKhCGpLWmB5+EL/PsDm5jZl5JOwP+GFQlCSVfiduEnJU1IGRmv\nBBYBhgCfA4/i0+RLMj8CpbR9OHBFyhb5Of4Zmi21vSTwQfoszI8L3cZsu9MMmFm8unjhAm8cvu1P\nn1TWFzgAOAv4CS6gZsMTRfWroI9BwFhgowLn/oont5+txvf0HC6g2lLZtvjSpDuArYEDgdPwbYy+\nV0bbmwHPADsCc6Sy+YGDgOHABun5LZ1ei1dxH+vhGvrlwCGpbCf8C/w8sEnq92rcsVXtc1u3wN/t\nAuAJYI1U1hufxlbyOdgLuDWvTMD6uKY+IpWtCPy6zLbPxbXJZYGeqWzD1O5huDBcFdgI2LVWn7UZ\n5dXtA2jmFz4t/S+wfjqeBeiRvtgCfgP8HdixwvbbUjt/Bg5OZXPjGsZBwDqp7O9JUM6djlXFPQ0C\nngS+X+DcNsAYYGCFba+A2+kGpuMemefWJz2v6/IFSpV/n4uB3wPHA3vjWuwNwI8z9coWSgX6ugbX\nyn9W4HleBPwNT0t7DXBOhX3sBRyT3h+Q2rwE13DXBmYvcE3Rz0J6Ntfllc2W/t8Uj0rYutDnsxZ/\npxnhFc6SrukJfGNmD0jqDRyKr2scDpxsZqfjdrABkuYst3Ezm2L+iRsDrChPSv8v/Iu9F7C3pP3M\n7ODUZ990Xdn2u4zxez3gGjP7r6S5JK0n6aRkl3oAOAq4QtJm5faBaxcjzWykpAWA/SVdDTyET5Uv\nxoXwAZJmq8QgL2nN3NjM7H3gPmBz4CXclrYH/sN0taRZU70PKriXbJ/fx+3Dg4HfSdozd87MhgN/\nwf8+7cBYM/t1uq6k+9PUgPl3gD6SVgO2x23Ez+PP7DMz+0pSr+y1JX4WegE3pr7a5UvURkraD7gf\n2BW4SdKqeW1Pma6lmZRYYlcAScviHuH3cbvgpvjU9378Q3kLcBcurB7DNZ+PyuyjHfgRbu/pjf/q\n74lPTS/HE9fvCqxpZvvX4J5WMLPnJP0at23eDfwStwEuAnwBXG9m50kaDDxtZi+X2PZmuHngflww\n3QzsjE9Rx6RqB+Axa19SwfNK/SyIT98Nn7Zfi9sAf4jbNHvjU/PXzezkctvvpM/eeOjP8mb2jKT1\ncYH+JzM7P69uL3Pve86OWFSQSLoEty//EbcN3os/o9PM7NpU5yTg8dxxGWNfwMzel3QI/jdeADff\njMLDpfoB/zWzsyStZWb1z0XRrHS3StpsL1y7eAYPWRiOG5E3Bn6Mf9Fy072/AT+qsI/NcGP+ibj3\n72hgYWDBdD73A7UXPtXqTXXT4c1xgbFgup/z0r39kzRNxafFtwKzltn2psBTJPsmHuKxT3r1zdQb\nSoHpeAX3sjWuYY7Etb+78R+lY9P5nXENbZ4a9HVJelZL5JX/AHgZ2CUdHwrMmzlf0t8q/V1vwH9M\nDwDmxYXV8+l55Wx5dwA/KXPsZwLDcLPKj9Nn6SJ8Kr9IqvMz4Oy8z1zLTIeneV7dPYBmeuHG9TG4\ncXqOjKDqkVdvJ1wzXKaCPvrjtqacHW1dPMRkrbx6v0p9rFTlPW2VhMbGeeU5x0/uC7Arbr8r2amQ\nhOAbQP90vAiwXIF6P8FtnIvW4G8k/IfkSWCHJHivxUNW+uJBwnPWoJ+skNoXWLHA33E88ApwQRX9\n7Am8iDszDscD0OcHbsdnI3cB55XZ5r9xJ84S6bmcDvQqUO8a0g9Iq7+6fQDN9EpC79LM8ZrpA5oT\nFgvjhuexlQqoJGCvBy7PlF0LbJXez5e+4COAlau4F+Haxae4PRNcGxyaFVZJcPwCn4qvUkb7s+LO\nj9FJAPXBp8ZbZ+qsCBxS5fPaIrWxcl75dmQ87cB8dfg8ZIXUwfj0OHt+LHBJ9pmX2O6GZLRMPO7x\nj8CF+Oxg7vR3WQxoz9Qrqq3h5pYvmarp90l/o++n4954WNHNWQFb6thn1lc4S/ANFCT9CNeI5pd0\nTDq1E24bzBm938W/GDuY2bgy++gnaV4z+wLfH80kXS3pVNyreheAefzhSGA7Mxtb6T2Z8z4+fRyY\nDOMXAg+Y2YtpTLPgRvntgT3MbEynDU57L+vjMW3P47a66/AQkgvMLLvc7EP8i7hjuc8r9dOGC8Ij\n8RU9l0haQNIcZnYDLkD+KmmIlRm32UWfGyotYzO3AV6Bh+j0B3ZUWu+bYhhvM7Of5sZqSaIUaX8/\nPIzl35IOlTQ7voxudLqfJYH9cEH5ppmNSNfJSnNePI57zw+TtLKZTcCDyb9K59vwWcgoM9urnLHP\nzLS8s0TSNsAJ+JT4czzm7Df4r/IUPPfBt9UE5EraEv/FfxXPwPUHSXMA5+CeyHnMV1nMZmYTa3BP\ng/BYwSdww/jSuCaY/eL2TPfVB5jFSlzdkQK/T8bjG1/Dv8C/An6KC7wX5Eu1zHypXtnPLX3pLb3f\nAjgGf04n4BruHMBJZvZq8rQfke73i2q+0ElInYHbHYfhcaK74x7j0bhH/UV8SvlKTjCV6hhJdVfD\nn1U/3HFxKR5buQFuy/0WD6f6t/kmo6WO/RR8NtGGC+438ZnFosBfzOyCTN1ZzOybcsc+U9PdKml3\nvvAPzjDStAv3Bg7CA0tvwb9gs5BnIyyzj83xsJRtgdXwD/7s6dws6fhyCthwKuwv64i5GvgTboTf\nBrerbZepW9Z94eEh48lzeqTyHfHQoh/kZFgV99Az7/hq4Kj0/kDcu/oEcFL6e00XX1dhv6sxNXbv\nQVyzuhx3NH0P97bfSIGYuzL7WQ+f7v8Tn8r+ON1PzjxSVpA5run/B7dxD8Y19X+nv/3TJFNI/nON\nV+YZdvcAuvXm3bY1Mn2J58IN37elD+hF+BTmVDIewTLbnxfXKrdLx2vjsWJnAeemslnSh/jSGtzP\nCkzriFmHjCMmCeMngCEVtn8QcGBe2Z/x0JXjkrAdgYf8VHoPm+BrhH8HDE5l6+K22W1xb+36wOq4\n5r5YjT8TNRVS6ZoTgTXI2DFxz/NxuId79vRZ6Zt3XSnB0psAd+aVLY5rtecw9QeqvZbPaWZ7tbSN\n0Mw+xT1qv8dzIFxgZlsCN+G7pZyGO0gq2s7JPFZua+DoFKx6Im54PwlYVdJQ8ynKEFz7rBhJA/DY\nsP/goRKY2SPAW3jYDGZ2U+p7P0lzlhHwm6u3DJn9CtO0dSFcC9kdf1YX4oKxknvYHH9GD+G2xW0l\nrY5vBrE+7mT6pZk9YGZPAGeZ2ZuV9JXp80RJa0iaD8DMHsJXE32EOzVuxuMU70/n30jXlfrsVsPD\na04ADkrBzJjZg7ht1XAh3zd9HjuwJNVK4M3UV69k8ngDtw2vC3yCP881SmyrNeluSdwML3ybq1NJ\nv/qp7CbSNK8G7W+Oa2q/y5TNgWucVXs7U/ujcefO0rg2e026p/+Qt06ZtAa4gn42xp06q6fjXrh9\nEeD/8Bi+iswITNWet07HiwNX4Y4pcHPFncDCNfy7r4YHM9+OC6P9M+dWTc/vL8DSVfZzBR4LuCEe\njvNX3H4nfO3v36hwfS8+CxhNWo6ZynKhUZfgzpeW9giX8mppjTCHuaPgXmAHSZsmB8riuDZVi/bv\nwG13P9fUreR3wqdE31TTdlqhcgawl5ldY2avAPvjX/B9cQfGRPl2TrnxfFFhd4/gtrNdJK1tZpPM\nnTxD8HjFR61Ch5JN1Z5PljSXuVYzCd+xRrhj5mPgB5Uszeukz9G4lin87/8zSX+VtANuWzuHqV7W\nsskt8cOF7JvAw2a2Jm5COBp3ZK0MXGZmV1R4G8/jpoSdk/aJuacYPHzqFNzz3nJ7DJZDy3uNcyQB\n9VP8l3oicLiZPVXjPrbAtYyz8BCafa2KEJnU5iHAZDM7LW+JV5/Uj4A9c+XVIim3FHAj3PnyFW6H\nGmxmz9Sg/S1wc8UwPEB7NzP7Kp3bFRcmr9Sgn1nN7GtJK+JT1/3TD8aLeBzeJHw6+7r5NLyctk/G\nTQg98XCWS/GVHlfhYTg/NLN2Sb8DPjazc9J1Hd7yMvtbGA+5+S6u3Y7C7Y/z4NP8C8zs+XLbbSVC\nEOYh3zxBZlbrjTxz7W+FayEDrILYukw7MjOTdAbwqZkdmf9FSjFvpwJfmdmQqgc/td3ZcWfFJrjW\nPNxSbGKN2v8hPg1eyHytbG8z+7JGbddVSEm6EI9GOB13wOV++N7Cp8hPm9lqtbiXvH7nxVf6/AZf\n8vilmR1a635mVkIQdgM1/mJvhNvnjjCzx1MQMuYxfL/EvYdfmVlFDozuImmGfwE2NA8Mr0WbdRVS\nkjYBDjOzTTNlS+K2untxB8wnZnZprWJGC4yhI0YwHUecYAnEDtXdQK2EYOK/eJzizpIws8cBJO2C\nT5fumNGEIICZ3Z5WvtwhaU3SYplK20tCatE8IfU4U4XUgbiHlSqFVIcHN435NUm74XGpDwCbSrqy\nHkIw0WECKWM1SssTgnAGx8wmyLeM3xP4m6RRuI1zR9xRUlV4SXdiZjdJuqeGX+Z6C6k3gNUlrWMe\nuoSkPmb2pqQncKfJaDP7tvpbKUz2x6KaH45WI7zGMwFm9hY+zfsDvq/gG8A21TpimoEqPNz5ZIXU\nJEvLC9MPRU5I/blKIdWVB3cxPGzmbehYRx00CWEjDFqCFDpyOB4AfnEKncmduxPfhPcKM7utGrta\neHBnTEIQBi1Do4RUeHBnPEIQBi1FI4VUeHBnHEIQBi1JI4RUNvaw0mDpoDGEIAxakhBSQZYQhEEQ\ntDzhwg+CoOUJQRgEQcsTgjAIgpYnBGEQBC1PCMIWRtJkSU9IGiPpquzmrRW01S7p5vR+a0mHd1G3\nr6R9KujjmLT/Yqn1Py+3j6A1CUHY2kwws9XNbBV815K98yuUuauxAZjZzWb25y7qzYPvnl1vIiQi\nKIkQhEGO+4FlJS0p6TlJF0saAywmaRNJD0l6LGmOvcGTLUl6VtJjeJJ4UvkeacNY5AnZr5c0WtKT\nktbBE0gtk7TRU1K930p6NNU7JtPWHyQ9L2kkvjRuOjrpA3x3biT1kXR3Gv9T8lQMSOot6ZZ0zdOS\ndkrlJ0sal9rrSqAHMwmxDVdrkxMUPfG8Fren8uWAn5jZKHl2tyOBjc3sqzTlPUTSqXhGvkFm9rKk\nq/Lazmljp+M7WG+ftMs58FSdK5nZ6qn/TfDcu2unOv+RtD6+Zf6P8Z2jZ8F3iXmswH0U6iM7hol4\nKoEv0v08gie12hx4y8y2SuOYU9I8qe4KqWyuch5oMGMSgrC1mT3tkweuEZ4PLAq8amajUvk6eHLz\nB5OQ6YXnSl4BeNnMXk71LiOlEc1jI+An0LE/3udpvW+WTYFN0liEp/JcDt9F+gYz+xr4WtJ/OrmP\n6frIOy/gJEkD8Ux5i0haABgDnCrpJOBWM3tAUg/gq7TH4234XoXBTE4Iwtbmy5xWliOZBCdki/AE\n4rvl1Vu1xD5KsdMJOMnMzsvr48ASry9WZzegH54nZoqkV/AUpy9KWgPYEjhB0t1mdoKktfHUpTvh\nGQE3LmEMwQxM2Ahbm84cIdnyR/AUmsuAJ26SJ4V6DlhK0tKpXmfJoe4hOUYktcmTY30OzJmpMwz4\nhTzzHpIWkTQ/MBLYTtKs6bqtS+wjNzXO3Udf4P0kBDcElkh1F8bzuVyBb2y7erJ/zm2egvUQfFoe\nzOSERtjadKZJZbd7/0DSz4Ar5Xl6DTgyaVO/Bm6TNAGfWs9RoK2DgHMl7Ql8C+xjZv9NzpengdvN\n7Ah5Ws2Hk0b6ObC7mT0p6Wo8x/B7wKOdjHe6PvD9BXP3cTlws6SncBvjc6l8FXxqPAXPL70PPh2/\nKRNKdHAnfQYzEbHpQhAELU9MjYMgaHlCEAZB0PKEIAyCoOUJQRgEQcsTgjAIgpYnBGEQBC1PCMIg\nCFqeEIRBELQ8/w8YBZL5bTauFAAAAABJRU5ErkJggg==\n", 411 | "text/plain": [ 412 | "" 413 | ] 414 | }, 415 | "metadata": {}, 416 | "output_type": "display_data" 417 | } 418 | ], 419 | "source": [ 420 | "# Confusion Matrix\n", 421 | "\n", 422 | "with tf.Session() as sess:\n", 423 | " saver.restore(sess, path)\n", 424 | " Z = logits.eval(feed_dict = {X : X_test[18]})\n", 425 | " predicted_18dB = np.argmax(Z, axis = 1)\n", 426 | " \n", 427 | "from sklearn.metrics import confusion_matrix\n", 428 | "%matplotlib inline\n", 429 | "\n", 430 | "classes = ['8PSK', 'BPSK', 'CPFSK', 'GFSK', 'PAM4', 'QAM16', 'QAM64', 'QPSK']\n", 431 | "conf_matrix = confusion_matrix(predicted_18dB, y_test[18]) \n", 432 | "\n", 433 | "conf_matrix = conf_matrix.astype('float') / conf_matrix.sum(axis=1)[:, np.newaxis]\n", 434 | "conf_matrix = conf_matrix.round(decimals = 2)\n", 435 | "\n", 436 | "import pandas as pd\n", 437 | "\n", 438 | "df = pd.DataFrame(data = conf_matrix, columns = classes, index = classes) \n", 439 | "print(\"Confusion Matrix\")\n", 440 | "print(df)\n", 441 | "\n", 442 | "plt.imshow(conf_matrix, interpolation = 'nearest', cmap = plt.cm.Purples)\n", 443 | "ticks = np.arange(len(classes))\n", 444 | "plt.title(\"Confusion Matrix\")\n", 445 | "plt.xticks(ticks, classes, rotation=45)\n", 446 | "plt.yticks(ticks, classes)\n", 447 | "\n", 448 | "plt.ylabel('True class')\n", 449 | "plt.xlabel('Predicted class')\n", 450 | "\n", 451 | "plt.tight_layout()\n", 452 | "plt.colorbar()\n", 453 | "plt.show()" 454 | ] 455 | }, 456 | { 457 | "cell_type": "code", 458 | "execution_count": null, 459 | "metadata": { 460 | "collapsed": true 461 | }, 462 | "outputs": [], 463 | "source": [] 464 | } 465 | ], 466 | "metadata": { 467 | "anaconda-cloud": {}, 468 | "kernelspec": { 469 | "display_name": "Python [default]", 470 | "language": "python", 471 | "name": "python3" 472 | }, 473 | "language_info": { 474 | "codemirror_mode": { 475 | "name": "ipython", 476 | "version": 3 477 | }, 478 | "file_extension": ".py", 479 | "mimetype": "text/x-python", 480 | "name": "python", 481 | "nbconvert_exporter": "python", 482 | "pygments_lexer": "ipython3", 483 | "version": "3.5.2" 484 | } 485 | }, 486 | "nbformat": 4, 487 | "nbformat_minor": 1 488 | } 489 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repo contains the implementation of various Machine Learning classifiers to solve the task of Digital Modulation Classification. data_feature-engineering.ipynb does feature engineering on raw data- dataset taken from https://www.deepsig.io/datasets; contains 8 classes of digital modulation- '8PSK', 'BPSK', 'CPFSK', 'GFSK', 'PAM4', 'QAM16', 'QAM64', 'QPSK'. 2 | 3 | Dependencies- 4 | Python v3.6.3, NumPy v1.14.0, TensorFlow v1.4.0, scikit-learn v0.19.1, matplotlib v2.1.0, xgboost v0.6 5 | 6 | K Nearest Neighbors, Support Vector Classifiers, Decision Trees, Decision Tree Ensembles and Extreme Gradient Boosting were implemented using scikit-learn. 7 | 8 | Deep Neural Networks (DNNs)- fully connected and Convolutional Neural Networks (CNNs) were implemented using TensorFlow. 9 | -------------------------------------------------------------------------------- /data_feature-engineering.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Feature Engineering\n", 8 | "\n", 9 | "Create features that help the machine learning algorithms find patterns in the data, and therefore perform the classification task better than when the algorithms are trained on raw data. \n", 10 | " \n", 11 | "Feature engineering transforms the raw data into a set of designed features. Cyclic-moment based features are widely used for the purpose of modulation recognition. A total of 32 features are designed in this notebook. The first 16 features are based on 0 cyclic time lag and the next 16 features are based on 8 cyclic time lag. The features are of the form \n", 12 | "\n", 13 | "\\begin{equation}\n", 14 | "s_{mn} = f_m\\big(\\left\\{x_i^nx_{i+T}^n\\right\\}\\big).\n", 15 | "\\end{equation}\n", 16 | "which is the the $m$th order statistic on the $n$th power of the instantaneous or time delayed received signal $x_i$." 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 1, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "#Import the required modules\n", 26 | "\n", 27 | "import numpy as np\n", 28 | "import pickle \n", 29 | "import sklearn\n", 30 | "from sklearn import metrics\n", 31 | "from sklearn.preprocessing import StandardScaler\n", 32 | "import os,random\n", 33 | "import sys, math, cmath\n", 34 | "from time import time\n", 35 | "from IPython.display import Markdown, display\n", 36 | "from collections import defaultdict" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "## Get the data" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 2, 49 | "metadata": {}, 50 | "outputs": [ 51 | { 52 | "name": "stdout", 53 | "output_type": "stream", 54 | "text": [ 55 | "**Original dataset**\n", 56 | "Dataset has modulation types ['8PSK', 'AM-DSB', 'AM-SSB', 'BPSK', 'CPFSK', 'GFSK', 'PAM4', 'QAM16', 'QAM64', 'QPSK', 'WBFM']\n", 57 | "and SNR values [-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]\n", 58 | " \n", 59 | "**New dataset**\n", 60 | "Limit dataset to 8 digital modulation schemes: ['8PSK', 'BPSK', 'CPFSK', 'GFSK', 'PAM4', 'QAM16', 'QAM64', 'QPSK']\n" 61 | ] 62 | } 63 | ], 64 | "source": [ 65 | "#Load the dataset\n", 66 | "\n", 67 | "with open(\"RML2016.10a_dict.dat\",'rb') as f:\n", 68 | " Xd = pickle.load(f, encoding='latin1')\n", 69 | "#we tell pickle.load() how to convert Python bytestring data to Python 3 strings, \n", 70 | "#or you can tell pickle to leave them as bytes.Setting the encoding to latin1 allows you to import the data directly\n", 71 | "\n", 72 | "snrs,mods = map(lambda j: sorted(list(set(map(lambda x: x[j], Xd.keys())))), [1,0])\n", 73 | "# in map(function, input) format, input = Xd.keys(); we feed to variable x, one key at a time\n", 74 | "# then we apply another map; from above, we got a list = [(mod type, SNR)]\n", 75 | "# so to each pair; when we do (mod type, SNR)[0] we get the mod type; (mod type, SNR)[1] gives the SNR value\n", 76 | "print('**Original dataset**')\n", 77 | "print(\"Dataset has modulation types\", mods)\n", 78 | "print(\"and SNR values\", snrs)\n", 79 | "\n", 80 | "#delete analogue modulation and keep only digital modulation schemes\n", 81 | "\n", 82 | "mods_to_rmv = ['AM-DSB', 'AM-SSB', 'WBFM'] #mod names we need to remove\n", 83 | "keys_to_rmv = [key for key in Xd.keys() if key[0] in mods_to_rmv] #keys corresponding to all these mods\n", 84 | "# we remove each key containing each of the analog mod types\n", 85 | "Xd_digital = {key: Xd[key] for key in Xd if key not in keys_to_rmv} #new dictionary containing only digital mod types\n", 86 | "snrs,mods = map(lambda j: sorted(list(set(map(lambda x: x[j], Xd_digital.keys())))), [1,0])\n", 87 | "print(\" \")\n", 88 | "print('**New dataset**')\n", 89 | "print(\"Limit dataset to\",len(list(mods)), \"digital modulation schemes:\", mods)" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 3, 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "name": "stdout", 99 | "output_type": "stream", 100 | "text": [ 101 | "**Samples in dataset**\n", 102 | "Dictionary contains 160 keys, meaning 160 (mod, SNR) pairs\n", 103 | "Each key or (mod,SNR) pair is assigned {(1000, 2, 128)} array\n", 104 | "This results in a total of 1000 samples per (mod, SNR) pair, with each sample a (2, 128) array\n" 105 | ] 106 | } 107 | ], 108 | "source": [ 109 | "#Check samples assigned to keys - each (mod, SNR) pair in dictionary \n", 110 | "\n", 111 | "print('**Samples in dataset**')\n", 112 | "array_shape = []\n", 113 | "print(\"Dictionary contains\", len(Xd_digital), \"keys, meaning\",len(Xd_digital),\"(mod, SNR) pairs\" )\n", 114 | "for k,v in Xd_digital.items():\n", 115 | " array_shape.append(v.shape)\n", 116 | "print(\"Each key or (mod,SNR) pair is assigned\",set(array_shape), \"array\") \n", 117 | "print(\"This results in a total of\",array_shape[0][0], \"samples per (mod, SNR) pair, with each sample a\",\n", 118 | " array_shape[0][1:3], \"array\")" 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "## Separate training and test samples" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": 4, 131 | "metadata": {}, 132 | "outputs": [ 133 | { 134 | "name": "stdout", 135 | "output_type": "stream", 136 | "text": [ 137 | "**Separate samples for training and testing**\n", 138 | "Training:Test set ratio = 0.5\n", 139 | "Each key in training set is assigned {(500, 2, 128)} array\n", 140 | "Each key in test set is assigned {(500, 2, 128)} array\n", 141 | "This results in:\n", 142 | " training set: a total of 500 samples per (mod, SNR) pair\n", 143 | " test set: a total of 500 samples per (mod, SNR) pair\n" 144 | ] 145 | } 146 | ], 147 | "source": [ 148 | "#Separate samples for training and test sets\n", 149 | "\n", 150 | "from sklearn.utils import shuffle\n", 151 | "\n", 152 | "print('**Separate samples for training and testing**')\n", 153 | "\n", 154 | "Xd_shuffled = dict()\n", 155 | " \n", 156 | "#Randomize the samples assigned to each key \n", 157 | "# we take each key: (mod type, snr) pair, and shuffle the samples within this group of values\n", 158 | "for k,v in Xd_digital.items():\n", 159 | " v = shuffle(v, random_state=0)\n", 160 | " Xd_shuffled.update({k : v})\n", 161 | "# So Xd_shuffled is just Xd_digital with samples belonging to each key shuffled \n", 162 | "#set train:test set ratio\n", 163 | "train_test = 0.5\n", 164 | "dict_test = dict()\n", 165 | "dict_train = dict()\n", 166 | "test_array_shape = []\n", 167 | "train_array_shape = []\n", 168 | "\n", 169 | "#extract the first 'train_test' fraction of samples to form test set and the rest to form training set\n", 170 | "for k,v in Xd_shuffled.items(): \n", 171 | " dict_test.update({k : v[:int(v.shape[0]*0.5), :]}) \n", 172 | " dict_train.update({k : v[int(v.shape[0]*0.5):, :]})\n", 173 | "# Take each (mod type, SNR) key. From these 1000 samples assigned to the key, take the first half and put them in test set\n", 174 | "# (we already shuffled these samples earlier)\n", 175 | "\n", 176 | "#check samples assgined to each key in dictionary dict_test and dict_train\n", 177 | "for k,v in dict_test.items(): test_array_shape.append(v.shape) \n", 178 | "for k,v in dict_train.items(): train_array_shape.append(v.shape)\n", 179 | "\n", 180 | "print(\"Training:Test set ratio = \", train_test)\n", 181 | "print(\"Each key in training set is assigned\",set(train_array_shape), \"array\")\n", 182 | "print(\"Each key in test set is assigned\",set(test_array_shape), \"array\")\n", 183 | "print(\"This results in:\")\n", 184 | "print(\" training set: a total of\",train_array_shape[0][0], \"samples per (mod, SNR) pair\")\n", 185 | "print(\" test set: a total of\",test_array_shape[0][0], \"samples per (mod, SNR) pair\")" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": {}, 191 | "source": [ 192 | "From every (modulation, SNR) pair, randomly pick half the samples for training set" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 5, 198 | "metadata": {}, 199 | "outputs": [ 200 | { 201 | "name": "stdout", 202 | "output_type": "stream", 203 | "text": [ 204 | "**Training data (raw data)**\n", 205 | "(80000, 2, 128) training data, (80000,) labels\n" 206 | ] 207 | } 208 | ], 209 | "source": [ 210 | "snrs,mods = map(lambda j: sorted(list(set(map(lambda x: x[j], dict_train.keys())))), [1,0])\n", 211 | "X_train = [] \n", 212 | "labels_train = []\n", 213 | "for mod in mods:\n", 214 | " for snr in snrs:\n", 215 | " X_train.append(dict_train[(mod,snr)])\n", 216 | " for i in range(dict_train[(mod,snr)].shape[0]): \n", 217 | " labels_train.append((mod,snr))\n", 218 | "X_train = np.vstack(X_train)\n", 219 | "n_samples_train = X_train.shape[0]\n", 220 | "y_train = np.array(list(map(lambda x: mods.index(labels_train[x][0]), range(n_samples_train))))\n", 221 | "\n", 222 | "print(\"**Training data (raw data)**\")\n", 223 | "print(X_train.shape,\"training data, \", y_train.shape, \"labels\")" 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "metadata": {}, 229 | "source": [ 230 | "## First 16 features based on 0 cyclic time lag\n", 231 | "Design features to transform raw data- each sample (2, 128) to feature vector of length 16" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": 6, 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "#Form expert features \n", 241 | "\n", 242 | "def form_features(X):\n", 243 | " \n", 244 | " #Form array of complex numbers; convert each (2,128) sample to a (128,) sample\n", 245 | " \n", 246 | " n_samples = X.shape[0]\n", 247 | " rows = X.shape[1]\n", 248 | " vec_len = X.shape[2]\n", 249 | " X_complex = []\n", 250 | " X_complex = [complex(X[samp_num,0,column],X[samp_num,1,column]) \n", 251 | " for samp_num in range(n_samples) for column in range(vec_len)]\n", 252 | " \n", 253 | " X_complex = np.vstack(X_complex)\n", 254 | " X_complex = np.reshape(X_complex, [n_samples,vec_len])\n", 255 | " X_complex_sqr = np.square(X_complex)\n", 256 | " X_complex_angl = np.angle(X_complex)\n", 257 | " \n", 258 | " #Form features: set of 16 expert features based on 0 cyclic time lag\n", 259 | "\n", 260 | " dict_16features = {}\n", 261 | " \n", 262 | " #Feature 1\n", 263 | " dict_16features['f1'] = np.array([np.mean(X_complex, axis=1)]).T\n", 264 | "\n", 265 | " #Feature 2\n", 266 | " dict_16features['f2'] = np.array([np.mean(abs(X_complex),axis = 1)]).T\n", 267 | " \n", 268 | " #Feature 3\n", 269 | " dict_16features['f3'] = np.array([np.mean(X_complex_angl, axis = 1)]).T\n", 270 | "\n", 271 | " #Feature 4\n", 272 | " dict_16features['f4'] = np.array([np.mean(abs(X_complex_angl), axis = 1)]).T\n", 273 | "\n", 274 | " #Feature 5\n", 275 | " dict_16features['f5'] = np.array([np.mean(X_complex_sqr, axis = 1)]).T\n", 276 | "\n", 277 | " #Feature 6\n", 278 | " dict_16features['f6'] = np.array([np.mean(np.square(abs(X_complex)), axis = 1)]).T\n", 279 | "\n", 280 | " #Feature 7\n", 281 | " dict_16features['f7'] = np.array([np.mean(np.square(X_complex_angl), axis = 1)]).T\n", 282 | "\n", 283 | " #Feature 8\n", 284 | " dict_16features['f8'] = np.array([np.mean(np.square(abs(X_complex_angl)), axis = 1)]).T\n", 285 | "\n", 286 | " #Feature 9\n", 287 | " dict_16features['f9'] = np.array([(np.mean(X_complex_sqr,axis = 1)) - \n", 288 | " ((1/vec_len**2)*np.square(np.sum(X_complex, axis = 1)))]).T\n", 289 | "\n", 290 | " #Feature 10\n", 291 | " dict_16features['f10'] = np.array([(np.mean(np.square(abs(X_complex)), axis = 1)) - \n", 292 | " ((1/vec_len**2)*np.square(np.sum(abs(X_complex), axis = 1)))]).T\n", 293 | "\n", 294 | " #Feature 11\n", 295 | " dict_16features['f11'] = np.array([(np.mean(np.square(X_complex_angl),axis = 1)) - \n", 296 | " ((1/vec_len**2)*np.square(np.sum(X_complex_angl, axis = 1)))]).T\n", 297 | "\n", 298 | " #Feature 12\n", 299 | " dict_16features['f12'] = np.array([(np.mean(np.square(abs(X_complex_angl)), axis = 1)) - \n", 300 | " ((1/vec_len**2)* np.square(np.sum(abs(X_complex_angl), axis = 1)))]).T\n", 301 | "\n", 302 | " #Feature 13\n", 303 | " dict_16features['f13'] = np.array([(np.mean(np.power(X_complex,4), axis = 1)) - \n", 304 | " ((1/vec_len**2)*(np.sum(X_complex_sqr,1))**2)]).T\n", 305 | "\n", 306 | " #Feature 14\n", 307 | " dict_16features['f14'] = np.array([(np.mean(np.power(abs(X_complex),4), axis = 1)) - \n", 308 | " ((1/vec_len**2)*(np.sum(np.square(abs(X_complex)), axis = 1))**2)]).T\n", 309 | "\n", 310 | " #Feature 15\n", 311 | " dict_16features['f15'] = np.array([(np.mean(np.power(X_complex_angl,4), axis =1)) - \n", 312 | " ((1/vec_len**2)*(np.sum(np.square(X_complex_angl),axis = 1))**2)]).T\n", 313 | "\n", 314 | " #Feature 16\n", 315 | " dict_16features['f16'] = np.array([(np.mean(np.power(abs(X_complex_angl),4), axis =1) - \n", 316 | " ((1/vec_len**2)*(np.sum(np.square(abs(X_complex_angl)),axis = 1))**2))]).T \n", 317 | "\n", 318 | " #Concatenate 16 feature arrays\n", 319 | " X_16 = []\n", 320 | " X_16 += dict_16features.values()\n", 321 | " X_16 = abs(np.hstack(np.array(X_16)))\n", 322 | " \n", 323 | " return X_16" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": 7, 329 | "metadata": {}, 330 | "outputs": [ 331 | { 332 | "name": "stdout", 333 | "output_type": "stream", 334 | "text": [ 335 | "**Training data after preprocessing**\n", 336 | " - samples have 16 features\n", 337 | "(80000, 16) training data, (80000,) labels\n" 338 | ] 339 | } 340 | ], 341 | "source": [ 342 | "#Preprocess the training data\n", 343 | "\n", 344 | "#shuffle the samples\n", 345 | "X_train, y_train = shuffle(X_train, y_train)\n", 346 | "\n", 347 | "#form features \n", 348 | "X_16_train = form_features(X_train)\n", 349 | "\n", 350 | "#standardize the features\n", 351 | "sc = StandardScaler()\n", 352 | "sc.fit(X_16_train)\n", 353 | "X_train_std = sc.transform(X_16_train)\n", 354 | "\n", 355 | "print(\"**Training data after preprocessing**\")\n", 356 | "print(\" - samples have\", X_train_std.shape[1], \"features\")\n", 357 | "print(X_train_std.shape,\"training data, \", y_train.shape, \"labels\")" 358 | ] 359 | }, 360 | { 361 | "cell_type": "markdown", 362 | "metadata": {}, 363 | "source": [ 364 | "## Create features for the test data\n", 365 | "Use the same function for creating the test set. But unlike the training set, we keep track of the SNR for each sample in case of test set. This is because the performance/ accuracy of the trained ML algorithm depends on the SNR of the signal, and later an SNR vs. accuracy plot depicts how the algorithm does on samples corresponding to various SNRs. " 366 | ] 367 | }, 368 | { 369 | "cell_type": "code", 370 | "execution_count": 8, 371 | "metadata": {}, 372 | "outputs": [ 373 | { 374 | "name": "stdout", 375 | "output_type": "stream", 376 | "text": [ 377 | "**Test data**\n", 378 | "Separate arrays for samples corresponding to different SNRs\n", 379 | "Total 20 (4000, 16) arrays for SNR values [-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]\n" 380 | ] 381 | } 382 | ], 383 | "source": [ 384 | "#Form and preprocess test data\n", 385 | "\n", 386 | "# new defaultdict with keys = SNR values and values = (2,128) samples \n", 387 | "test_data = defaultdict(list)\n", 388 | "test_labels = defaultdict(list)\n", 389 | "\n", 390 | "# Extract all samples corresponding to each SNR value\n", 391 | "# dict_test had keys of the form (mod type, SNR); new dict test_data has keys (SNR)\n", 392 | "def form_test_data(snr):\n", 393 | " for k,v in dict_test.items():\n", 394 | " if k[1] == snr: \n", 395 | " test_data[snr].append(v)\n", 396 | " for x in range(v.shape[0]): \n", 397 | " test_labels[snr].append(k[0]) \n", 398 | " test_data[snr] = np.vstack(test_data[snr])\n", 399 | " test_labels[snr] = np.vstack(test_labels[snr])\n", 400 | " n_samples_test = test_data[snr].shape[0]\n", 401 | " test_labels[snr] = np.array(list(map(lambda x: mods.index(test_labels[snr][x]), range(n_samples_test))))\n", 402 | " return test_data[snr], test_labels[snr]\n", 403 | " \n", 404 | "X_test = defaultdict(list)\n", 405 | "X_test16 = defaultdict(list)\n", 406 | "y_test = defaultdict(list)\n", 407 | "X_test_std = defaultdict(list)\n", 408 | "\n", 409 | "# Extract samples and labels for each SNR \n", 410 | "for snr in snrs:\n", 411 | " data, labels = form_test_data(snr) # extract all samples belonging to this SNR, from dict_test\n", 412 | " X_test[snr].append(data)\n", 413 | " X_test[snr] = np.vstack(X_test[snr])\n", 414 | " y_test[snr].append(labels) # extract the corresponding labels belonging to this SNR, from dict_test\n", 415 | " y_test[snr] = np.hstack(y_test[snr])\n", 416 | " X_test[snr], y_test[snr] = shuffle(X_test[snr], y_test[snr]) #shuffle the samples (2, 128)\n", 417 | " X_test16[snr] = form_features(X_test[snr]) #form features; each sample is now (16,) feature vector \n", 418 | " X_test_std[snr] = sc.transform(X_test16[snr]) #standardize the features\n", 419 | " \n", 420 | "print(\"**Test data**\")\n", 421 | "print(\"Separate arrays for samples corresponding to different SNRs\")\n", 422 | "print(\"Total\", len(snrs), X_test_std[18].shape, \"arrays for SNR values\", snrs)" 423 | ] 424 | }, 425 | { 426 | "cell_type": "markdown", 427 | "metadata": {}, 428 | "source": [ 429 | "### Store variables in Jupyter's database" 430 | ] 431 | }, 432 | { 433 | "cell_type": "code", 434 | "execution_count": 9, 435 | "metadata": {}, 436 | "outputs": [ 437 | { 438 | "name": "stdout", 439 | "output_type": "stream", 440 | "text": [ 441 | "Stored 'snrs' (list)\n", 442 | "Stored 'X_train_std' (ndarray)\n", 443 | "Stored 'X_test_std' (defaultdict)\n", 444 | "Stored 'y_train' (ndarray)\n", 445 | "Stored 'y_test' (defaultdict)\n" 446 | ] 447 | } 448 | ], 449 | "source": [ 450 | "%store snrs\n", 451 | "%store X_train_std\n", 452 | "%store X_test_std\n", 453 | "%store y_train\n", 454 | "%store y_test" 455 | ] 456 | }, 457 | { 458 | "cell_type": "markdown", 459 | "metadata": {}, 460 | "source": [ 461 | "## Next 16 features based on 8 cyclic time lag\n", 462 | "Design next 16 features to transform raw data- each sample (2, 128) to feature vector of length 16 and then conmbine the previous 16 and these 16 features to form feature set consisting of 32 features" 463 | ] 464 | }, 465 | { 466 | "cell_type": "code", 467 | "execution_count": 10, 468 | "metadata": {}, 469 | "outputs": [], 470 | "source": [ 471 | "#Form expert features \n", 472 | "\n", 473 | "def form_next16_features(X):\n", 474 | " \n", 475 | " #Form array of complex numbers; convert each (2,128) sample to a (128,) sample\n", 476 | " \n", 477 | " n_samples = X.shape[0]\n", 478 | " rows = X.shape[1]\n", 479 | " vec_len = X.shape[2]\n", 480 | " X_complex = []\n", 481 | " X_complex = [complex(X[samp_num,0,column],X[samp_num,1,column]) \n", 482 | " for samp_num in range(n_samples) for column in range(vec_len)]\n", 483 | " \n", 484 | " X_complex = np.vstack(X_complex)\n", 485 | " X_complex = np.reshape(X_complex, [n_samples,vec_len])\n", 486 | " \n", 487 | " #Form array to use in features based on 8 cyclic time lag\n", 488 | "\n", 489 | " X_complex_8lag = np.zeros((X_complex.shape), dtype=complex)\n", 490 | " for samp_num in range(n_samples):\n", 491 | " for clmn in range(vec_len):\n", 492 | " shift_by = (clmn + 8)%vec_len\n", 493 | " X_complex_8lag[samp_num,clmn] = (X_complex[samp_num,clmn])*(X_complex[samp_num,shift_by])\n", 494 | " \n", 495 | " X_complex8_sqr = np.square(X_complex_8lag)\n", 496 | " X_complex8_angl = np.angle(X_complex_8lag)\n", 497 | " \n", 498 | " #16 expert features based on 8 cyclic time lag\n", 499 | " \n", 500 | " dict_16features = {}\n", 501 | " \n", 502 | " #Feature 17\n", 503 | " dict_16features['f17'] = np.array([np.mean(X_complex_8lag, axis = 1)]).T\n", 504 | "\n", 505 | " #Feature 18\n", 506 | " dict_16features['f18'] = np.array([np.mean(abs(X_complex_8lag),axis = 1)]).T\n", 507 | "\n", 508 | " #Feature 19\n", 509 | " dict_16features['f19'] = np.array([np.mean(X_complex8_angl, axis = 1)]).T\n", 510 | "\n", 511 | " #Feature 20\n", 512 | " dict_16features['f20'] = np.array([np.mean(abs(X_complex8_angl), axis = 1)]).T\n", 513 | "\n", 514 | " #Feature 21\n", 515 | " dict_16features['f21'] = np.array([np.mean(X_complex8_sqr, axis = 1)]).T\n", 516 | "\n", 517 | " #Feature 22\n", 518 | " dict_16features['f22'] = np.array([np.mean(np.square(abs(X_complex_8lag)), axis = 1)]).T\n", 519 | "\n", 520 | " #Feature 23\n", 521 | " dict_16features['f23'] = np.array([np.mean(np.square(X_complex8_angl), axis = 1)]).T\n", 522 | "\n", 523 | " #Feature 24\n", 524 | " dict_16features['f24'] = np.array([np.mean(np.square(abs(X_complex8_angl)), axis = 1)]).T\n", 525 | "\n", 526 | " #Feature 25\n", 527 | " dict_16features['f25'] = np.array([(np.mean(X_complex8_sqr,axis = 1)) - \n", 528 | " ((1/vec_len**2)*np.square(np.sum(X_complex_8lag, axis = 1)))]).T\n", 529 | "\n", 530 | " #Feature 26\n", 531 | " dict_16features['f26'] = np.array([(np.mean(np.square(abs(X_complex_8lag)), axis = 1)) -\n", 532 | " ((1/vec_len**2)*np.square(np.sum(abs(X_complex_8lag), axis = 1)))]).T\n", 533 | "\n", 534 | " #Feature 27\n", 535 | " dict_16features['f27'] = np.array([(np.mean(np.square(X_complex8_angl),axis = 1)) -\n", 536 | " ((1/vec_len**2)*np.square(np.sum(X_complex8_angl, axis = 1)))]).T\n", 537 | "\n", 538 | " #Feature 28\n", 539 | " dict_16features['f28'] = np.array([(np.mean(np.square(abs(X_complex8_angl)), axis = 1)) - \n", 540 | " ((1/vec_len**2)* np.square(np.sum(abs(X_complex8_angl), axis = 1)))]).T\n", 541 | "\n", 542 | " #Feature 29\n", 543 | " dict_16features['f29'] = np.array([(np.mean(np.power(X_complex_8lag,4), axis = 1)) - \n", 544 | " ((1/vec_len**2)*(np.sum(X_complex8_sqr,1))**2)]).T\n", 545 | "\n", 546 | " #Feature 30\n", 547 | " dict_16features['f30'] = np.array([(np.mean(np.power(abs(X_complex_8lag),4), axis = 1)) - \n", 548 | " ((1/vec_len**2)*(np.sum(np.square(abs(X_complex_8lag)), axis = 1))**2)]).T\n", 549 | "\n", 550 | " #Feature 31\n", 551 | " dict_16features['f31'] = np.array([((1/vec_len)* np.sum(np.power(X_complex8_angl,4), axis =1)) - \n", 552 | " ((1/vec_len**2)*(np.sum(np.square(X_complex8_angl),axis = 1))**2)]).T\n", 553 | "\n", 554 | " #Feature 32\n", 555 | " dict_16features['f32'] = np.array([(np.mean(np.power(abs(X_complex8_angl),4), axis =1) - \n", 556 | " ((1/vec_len**2)*(np.sum(np.square(abs(X_complex8_angl)),axis = 1))**2))]).T\n", 557 | "\n", 558 | " #Concatenate 16 feature arrays\n", 559 | " X_16 = []\n", 560 | " X_16 += dict_16features.values()\n", 561 | " X_16 = abs(np.hstack(np.array(X_16)))\n", 562 | " \n", 563 | " return X_16" 564 | ] 565 | }, 566 | { 567 | "cell_type": "code", 568 | "execution_count": 11, 569 | "metadata": {}, 570 | "outputs": [ 571 | { 572 | "name": "stdout", 573 | "output_type": "stream", 574 | "text": [ 575 | "**Training data after preprocessing**\n", 576 | " - samples have 32 features\n", 577 | "(80000, 32) training data, (80000,) labels\n" 578 | ] 579 | } 580 | ], 581 | "source": [ 582 | "#Preprocess the training data\n", 583 | "\n", 584 | "#form features \n", 585 | "X_next16_train = form_next16_features(X_train)\n", 586 | "\n", 587 | "# combine the previous 16 features with these next 16 features, to create (n_samples, 32) data\n", 588 | "X_32_train = np.concatenate((X_16_train, X_next16_train), axis = 1)\n", 589 | "\n", 590 | "#standardize the features\n", 591 | "sc = StandardScaler()\n", 592 | "sc.fit(X_32_train)\n", 593 | "X_32train_std = sc.transform(X_32_train)\n", 594 | "\n", 595 | "print(\"**Training data after preprocessing**\")\n", 596 | "print(\" - samples have\", X_32train_std.shape[1], \"features\")\n", 597 | "print(X_32train_std.shape,\"training data, \", y_train.shape, \"labels\")" 598 | ] 599 | }, 600 | { 601 | "cell_type": "code", 602 | "execution_count": 15, 603 | "metadata": {}, 604 | "outputs": [ 605 | { 606 | "name": "stdout", 607 | "output_type": "stream", 608 | "text": [ 609 | "**Test data**\n", 610 | "Separate arrays for samples corresponding to different SNRs\n", 611 | "Total 20 (4000, 32) arrays for SNR values [-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]\n" 612 | ] 613 | } 614 | ], 615 | "source": [ 616 | "#Form and preprocess test data\n", 617 | " \n", 618 | "X_next16test = defaultdict(list)\n", 619 | "X_32test_std = defaultdict(list)\n", 620 | "X_32test = defaultdict(list)\n", 621 | "\n", 622 | "for snr in snrs:\n", 623 | " X_next16test[snr] = form_next16_features(X_test[snr]) # form the next 16 features\n", 624 | " # concatenate the previous 16 and these next 16 features, so total 32 features\n", 625 | " X_32test[snr] = np.concatenate((X_test16[snr], X_next16test[snr]), axis = 1) \n", 626 | " X_32test_std[snr] = sc.transform(X_32test[snr]) #standardize the features\n", 627 | " \n", 628 | "print(\"**Test data**\")\n", 629 | "print(\"Separate arrays for samples corresponding to different SNRs\")\n", 630 | "print(\"Total\", len(snrs), X_32test_std[18].shape, \"arrays for SNR values\", snrs)" 631 | ] 632 | }, 633 | { 634 | "cell_type": "code", 635 | "execution_count": 16, 636 | "metadata": {}, 637 | "outputs": [], 638 | "source": [ 639 | "y_32_train = y_train\n", 640 | "y_32_test = y_test" 641 | ] 642 | }, 643 | { 644 | "cell_type": "markdown", 645 | "metadata": {}, 646 | "source": [ 647 | "## Store variables in Jupyter's database" 648 | ] 649 | }, 650 | { 651 | "cell_type": "code", 652 | "execution_count": 19, 653 | "metadata": {}, 654 | "outputs": [ 655 | { 656 | "name": "stdout", 657 | "output_type": "stream", 658 | "text": [ 659 | "Stored 'X_32train_std' (ndarray)\n", 660 | "Stored 'X_32test_std' (defaultdict)\n", 661 | "Stored 'y_32_train' (ndarray)\n", 662 | "Stored 'y_32_test' (defaultdict)\n" 663 | ] 664 | } 665 | ], 666 | "source": [ 667 | "%store X_32train_std\n", 668 | "%store X_32test_std\n", 669 | "%store y_32_train\n", 670 | "%store y_32_test" 671 | ] 672 | }, 673 | { 674 | "cell_type": "markdown", 675 | "metadata": {}, 676 | "source": [ 677 | "## View all stored variables" 678 | ] 679 | }, 680 | { 681 | "cell_type": "code", 682 | "execution_count": 20, 683 | "metadata": {}, 684 | "outputs": [ 685 | { 686 | "name": "stdout", 687 | "output_type": "stream", 688 | "text": [ 689 | "Stored variables and their in-db values:\n", 690 | "X_32test_std -> defaultdict(, {-20: array([[-0.45951\n", 691 | "X_32train_std -> array([[ 2.11096968, -1.63913221, 2.21713053, ...\n", 692 | "X_test_std -> defaultdict(, {-20: array([[-4.59517\n", 693 | "X_train_std -> array([[ 2.11096968, -1.63913221, 2.21713053, ...\n", 694 | "snrs -> [-20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, \n", 695 | "y_32_test -> defaultdict(, {-20: array([1, 3, 5, \n", 696 | "y_32_train -> array([4, 4, 6, ..., 1, 7, 0])\n", 697 | "y_test -> defaultdict(, {-20: array([1, 3, 5, \n", 698 | "y_train -> array([4, 4, 6, ..., 1, 7, 0])\n" 699 | ] 700 | } 701 | ], 702 | "source": [ 703 | "%store" 704 | ] 705 | }, 706 | { 707 | "cell_type": "code", 708 | "execution_count": null, 709 | "metadata": {}, 710 | "outputs": [], 711 | "source": [] 712 | } 713 | ], 714 | "metadata": { 715 | "kernelspec": { 716 | "display_name": "Python 3", 717 | "language": "python", 718 | "name": "python3" 719 | }, 720 | "language_info": { 721 | "codemirror_mode": { 722 | "name": "ipython", 723 | "version": 3 724 | }, 725 | "file_extension": ".py", 726 | "mimetype": "text/x-python", 727 | "name": "python", 728 | "nbconvert_exporter": "python", 729 | "pygments_lexer": "ipython3", 730 | "version": "3.6.3" 731 | } 732 | }, 733 | "nbformat": 4, 734 | "nbformat_minor": 2 735 | } 736 | --------------------------------------------------------------------------------