{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":16017,"databundleVersionId":708189,"sourceType":"competition"}],"dockerImageVersionId":31192,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Create and Evaluate a Neural Network for Image Classification\nDawud Ujamaa  \nDecember 07, 2025\n\nDesign a neural network model with at least one hidden layer (NOT using CNN or other derivatives) for image classification, and train it to accurately identify Kannada digits","metadata":{}},{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfrom sklearn import metrics\nfrom sklearn.metrics import confusion_matrix, classification_report\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import roc_curve, auc, RocCurveDisplay\nfrom sklearn.preprocessing import label_binarize\nfrom sklearn.preprocessing import MinMaxScaler\nfrom sklearn.multiclass import OneVsRestClassifier\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers import Dense \n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n\n# Needed for reproducibility\nimport random\nseed = 42 # Set Python's hash seed\nos.environ['PYTHONHASHSEED'] = str(seed)\n# Set random seeds for reproducibility\ntf.random.set_seed(seed)  # For TensorFlow operations\nnp.random.seed(seed)      # For NumPy operations\nrandom.seed(seed)         # For Python's random module","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:13:58.696682Z","iopub.execute_input":"2025-12-04T02:13:58.699515Z","iopub.status.idle":"2025-12-04T02:13:58.739619Z","shell.execute_reply.started":"2025-12-04T02:13:58.699477Z","shell.execute_reply":"2025-12-04T02:13:58.738486Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __1. Load the dataset:__ ","metadata":{}},{"cell_type":"code","source":"df_train = train=pd.read_csv('../input/Kannada-MNIST/train.csv')\ndf_test = pd.read_csv('../input/Kannada-MNIST/test.csv')\ndf_train.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:13:58.741979Z","iopub.execute_input":"2025-12-04T02:13:58.742225Z","iopub.status.idle":"2025-12-04T02:14:01.746254Z","shell.execute_reply.started":"2025-12-04T02:13:58.742207Z","shell.execute_reply":"2025-12-04T02:14:01.74558Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __2. Preprocess the data: Normalize pixel values to the range [0, 1]:__","metadata":{}},{"cell_type":"code","source":"# split into features and target\ny = df_train['label']\nX = df_train.drop('label', axis=1)\n\n# Split Into 80% Training and 20% Test Sets\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n\n# Normalize the features scaling to range between 0 and 1 using Min-Max \nscaler = MinMaxScaler()\nX_train = scaler.fit_transform(X_train) \nX_test = scaler.transform(X_test) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:01.747044Z","iopub.execute_input":"2025-12-04T02:14:01.747296Z","iopub.status.idle":"2025-12-04T02:14:02.746065Z","shell.execute_reply.started":"2025-12-04T02:14:01.747274Z","shell.execute_reply":"2025-12-04T02:14:02.745156Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __3. Build a neural network with at least one hidden layer. Use ReLU as the activation function for the hidden layers and softmax for the output layer__","metadata":{}},{"cell_type":"code","source":"model = keras.Sequential([\n    layers.Input(shape=(X.shape[1],)), # input dimension = 784 (features) \n    # Hidden layer with 512 neurons and ReLU activation function, using kernel_initializer for reproducibility\n    layers.Dense(512, activation=\"relu\", kernel_initializer=keras.initializers.GlorotNormal(seed=seed)), \n    layers.Dense(10, activation=\"softmax\") # Output layer with 10 neurons (for 10 label categories) \n])\n\n# Compile the model \nmodel.compile(loss='sparse_categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy']) \n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:02.747885Z","iopub.execute_input":"2025-12-04T02:14:02.748152Z","iopub.status.idle":"2025-12-04T02:14:02.844546Z","shell.execute_reply.started":"2025-12-04T02:14:02.748131Z","shell.execute_reply":"2025-12-04T02:14:02.843559Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __5. Train the model and monitor the training process (loss and accuracy)__","metadata":{}},{"cell_type":"code","source":"history = model.fit(X_train, y_train, epochs=5, batch_size=128, validation_split=0.1, verbose=1) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:02.845787Z","iopub.execute_input":"2025-12-04T02:14:02.846085Z","iopub.status.idle":"2025-12-04T02:14:15.702349Z","shell.execute_reply.started":"2025-12-04T02:14:02.846063Z","shell.execute_reply":"2025-12-04T02:14:15.701593Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# learning curve\nplt.figure()\nplt.plot(history.history['loss'], label='Training Loss')\nplt.plot(history.history['val_loss'], label='Validation Loss')\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"MSE Loss\")\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:15.703706Z","iopub.execute_input":"2025-12-04T02:14:15.703979Z","iopub.status.idle":"2025-12-04T02:14:15.909104Z","shell.execute_reply.started":"2025-12-04T02:14:15.703952Z","shell.execute_reply":"2025-12-04T02:14:15.908167Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __6. Evaluate model on the test set and record accuracy__","metadata":{}},{"cell_type":"code","source":"# Classification Reports \n\n# Predictions\ny_pred_train = model.predict(X_train).argmax(axis=1)\ny_pred_test = model.predict(X_test).argmax(axis=1)\n\n# generate Classification report on training and test set\nprint( 'Classification Report on Training set')\nprint(classification_report(y_train,y_pred_train, digits=4))\n\nprint( 'Classification Report on Test set')\nprint(classification_report(y_test,y_pred_test, digits=4))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:15.910206Z","iopub.execute_input":"2025-12-04T02:14:15.910467Z","iopub.status.idle":"2025-12-04T02:14:20.580035Z","shell.execute_reply.started":"2025-12-04T02:14:15.910435Z","shell.execute_reply":"2025-12-04T02:14:20.57884Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Confusion matrix on Training set\nmetrics.confusion_matrix(y_train, y_pred_train)\nmetrics.ConfusionMatrixDisplay.from_predictions(y_train, y_pred_train)\nplt.show();","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:20.580869Z","iopub.execute_input":"2025-12-04T02:14:20.581088Z","iopub.status.idle":"2025-12-04T02:14:20.952129Z","shell.execute_reply.started":"2025-12-04T02:14:20.581071Z","shell.execute_reply":"2025-12-04T02:14:20.950866Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Confusion matrix on test\nmetrics.confusion_matrix(y_test, y_pred_test)\nmetrics.ConfusionMatrixDisplay.from_predictions(y_test, y_pred_test)\nplt.show();","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:20.953377Z","iopub.execute_input":"2025-12-04T02:14:20.953849Z","iopub.status.idle":"2025-12-04T02:14:21.317183Z","shell.execute_reply.started":"2025-12-04T02:14:20.953819Z","shell.execute_reply":"2025-12-04T02:14:21.316061Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# One-vs-Rest ROC curve\n\n# Get softmax predictions\ny_pred_probs = model.predict(X_test)\n\n# Binarize the true labels\nnum_classes = len(np.unique(y_test))\ny_test_bin = label_binarize(y_test, classes=list(range(num_classes)))\n\n# Compute ROC and AUC for each class\nfpr = {}   # false positive rate\ntpr = {}   # true positive rate\nroc_auc = {}\n\nfor i in range(num_classes):\n    fpr[i], tpr[i], _ = roc_curve(y_test_bin[:, i], y_pred_probs[:, i])\n    roc_auc[i] = auc(fpr[i], tpr[i])\n\n# Compute micro-average ROC curve\nfpr[\"micro\"], tpr[\"micro\"], _ = roc_curve(\n    y_test_bin.ravel(), \n    y_pred_probs.ravel()\n)\nroc_auc[\"micro\"] = auc(fpr[\"micro\"], tpr[\"micro\"])\n\n# Compute macro-average ROC curve\n# Aggregate all FPR points\nall_fpr = np.unique(np.concatenate([fpr[i] for i in range(num_classes)]))\n\n# Interpolate TPR for each class at these FPR points\nmean_tpr = np.zeros_like(all_fpr)\nfor i in range(num_classes):\n    mean_tpr += np.interp(all_fpr, fpr[i], tpr[i])\n\nmean_tpr /= num_classes\n\nfpr[\"macro\"] = all_fpr\ntpr[\"macro\"] = mean_tpr\nroc_auc[\"macro\"] = auc(fpr[\"macro\"], tpr[\"macro\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:21.320122Z","iopub.execute_input":"2025-12-04T02:14:21.320433Z","iopub.status.idle":"2025-12-04T02:14:22.294444Z","shell.execute_reply.started":"2025-12-04T02:14:21.320384Z","shell.execute_reply":"2025-12-04T02:14:22.293574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Plot the One-vs-Rest ROC curves\nclass_names = [0,1,2,3,4,5,6,7,8,9]\n\nplt.figure(figsize=(10, 5))\n\n# Plot for each class\nfor i in range(num_classes):\n    plt.plot(fpr[i], tpr[i], linewidth=2,\n             label=f\"Class: Rating: {class_names[i]} (AUC = {roc_auc[i]:.3f})\")\n\n# Micro & Macro\nplt.plot(fpr[\"micro\"], tpr[\"micro\"],\n         linestyle='--', linewidth=2,\n         label=f\"micro-average (AUC = {roc_auc['micro']:.3f})\")\n\nplt.plot(fpr[\"macro\"], tpr[\"macro\"],\n         linestyle='--', linewidth=2,\n         label=f\"macro-average (AUC = {roc_auc['macro']:.3f})\")\n\n# Diagonal\nplt.plot([0, 1], [0, 1], 'k--')\n\nplt.xlabel(\"False Positive Rate\")\nplt.ylabel(\"True Positive Rate\")\nplt.title(\"Multi-Class ROC Curve (One-vs-Rest)\")\nplt.legend(loc=\"lower right\")\nplt.grid(True)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:22.295244Z","iopub.execute_input":"2025-12-04T02:14:22.2955Z","iopub.status.idle":"2025-12-04T02:14:22.600366Z","shell.execute_reply.started":"2025-12-04T02:14:22.295481Z","shell.execute_reply":"2025-12-04T02:14:22.599475Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __7. Submit predictions to Kaggle__","metadata":{}},{"cell_type":"code","source":"# train model on full training data and make predictions on competition test dataset\ny_train = df_train['label']\nX = df_train.drop('label', axis=1)\nX_test = df_test.drop('id', axis=1)\nid_test = df_test['id']\n\nscaler = MinMaxScaler()\nX_train = scaler.fit_transform(X) \nX_test = scaler.transform(X_test) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:22.601205Z","iopub.execute_input":"2025-12-04T02:14:22.601584Z","iopub.status.idle":"2025-12-04T02:14:23.313978Z","shell.execute_reply.started":"2025-12-04T02:14:22.601559Z","shell.execute_reply":"2025-12-04T02:14:23.313267Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# train model on full training data\nhistory = model.fit(X_train, y_train, epochs=5, batch_size=128, validation_split=0.1, verbose=1) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:23.314865Z","iopub.execute_input":"2025-12-04T02:14:23.315096Z","iopub.status.idle":"2025-12-04T02:14:38.072062Z","shell.execute_reply.started":"2025-12-04T02:14:23.315078Z","shell.execute_reply":"2025-12-04T02:14:38.070973Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# learning curve on full training set\nplt.figure()\nplt.plot(history.history['loss'], label='Training Loss')\nplt.plot(history.history['val_loss'], label='Validation Loss')\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"MSE Loss\")\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:38.073336Z","iopub.execute_input":"2025-12-04T02:14:38.073711Z","iopub.status.idle":"2025-12-04T02:14:38.251723Z","shell.execute_reply.started":"2025-12-04T02:14:38.073686Z","shell.execute_reply":"2025-12-04T02:14:38.250733Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# make predictions on competition test dataset\nlabel = model.predict(X_test).argmax(axis=1)\nlabel.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:38.252709Z","iopub.execute_input":"2025-12-04T02:14:38.25325Z","iopub.status.idle":"2025-12-04T02:14:38.758335Z","shell.execute_reply.started":"2025-12-04T02:14:38.253221Z","shell.execute_reply":"2025-12-04T02:14:38.757338Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame(id_test)\nsubmission['label'] = label\nsubmission","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:38.759329Z","iopub.execute_input":"2025-12-04T02:14:38.759765Z","iopub.status.idle":"2025-12-04T02:14:38.771158Z","shell.execute_reply.started":"2025-12-04T02:14:38.759739Z","shell.execute_reply":"2025-12-04T02:14:38.770139Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission.to_csv(r'./submission.csv', index = False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T02:14:38.772057Z","iopub.execute_input":"2025-12-04T02:14:38.772314Z","iopub.status.idle":"2025-12-04T02:14:38.794115Z","shell.execute_reply.started":"2025-12-04T02:14:38.772293Z","shell.execute_reply":"2025-12-04T02:14:38.792959Z"}},"outputs":[],"execution_count":null}]}