{"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":3004,"databundleVersionId":861823,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import OneHotEncoder\n\ntrain = pd.read_csv(\"/kaggle/input/digit-recognizer/train.csv\")\ntest = pd.read_csv(\"/kaggle/input/digit-recognizer/test.csv\")\n\nX = train.drop(columns=['label']).values.astype(np.float32) / 255.0\ny = train['label'].values.reshape(-1, 1).astype(int)\n\nencoder = OneHotEncoder(sparse_output=False)\ny_oh = encoder.fit_transform(y)\n\nX_train, X_val, y_train, y_val = train_test_split(X, y_oh, test_size=0.1, random_state=42)\n\n\ndef init_params(input_size=784, hidden_size=256, output_size=10):\n    np.random.seed(42)\n    W1 = np.random.randn(input_size, hidden_size) * np.sqrt(2. / input_size)\n    b1 = np.zeros((1, hidden_size))\n    W2 = np.random.randn(hidden_size, output_size) * np.sqrt(2. / hidden_size)\n    b2 = np.zeros((1, output_size))\n    return W1, b1, W2, b2\n\n\n# Activation functions\ndef relu(Z): return np.maximum(0, Z)\ndef relu_deriv(Z): return (Z > 0).astype(float)\ndef softmax(Z):\n    Z_shift = Z - np.max(Z, axis=1, keepdims=True)\n    expZ = np.exp(Z_shift)\n    return expZ / np.sum(expZ, axis=1, keepdims=True)\n\ndef forward(X, W1, b1, W2, b2):\n    Z1 = X @ W1 + b1\n    A1 = relu(Z1)\n    Z2 = A1 @ W2 + b2\n    A2 = softmax(Z2)\n    return Z1, A1, Z2, A2\n\ndef compute_loss(y_true, y_pred):\n    m = y_true.shape[0]\n    return -np.sum(y_true * np.log(y_pred + 1e-8)) / m\n\ndef backward(X, y_true, Z1, A1, A2, W2):\n    m = X.shape[0]\n    dZ2 = A2 - y_true\n    dW2 = (A1.T @ dZ2) / m\n    db2 = np.sum(dZ2, axis=0, keepdims=True) / m\n    dA1 = dZ2 @ W2.T\n    dZ1 = dA1 * relu_deriv(Z1)\n    dW1 = (X.T @ dZ1) / m\n    db1 = np.sum(dZ1, axis=0, keepdims=True) / m\n    return dW1, db1, dW2, db2\n\ndef accuracy(X, y_true, W1, b1, W2, b2):\n    _, _, _, A2 = forward(X, W1, b1, W2, b2)\n    preds = np.argmax(A2, axis=1)\n    true_labels = np.argmax(y_true, axis=1)\n    return np.mean(preds == true_labels)\n\ndef train_adam(X, y, X_val, y_val, epochs=15, batch_size=128, lr=0.001):\n    W1, b1, W2, b2 = init_params()\n    beta1, beta2, eps = 0.9, 0.999, 1e-8\n    mW1, vW1 = np.zeros_like(W1), np.zeros_like(W1)\n    mB1, vB1 = np.zeros_like(b1), np.zeros_like(b1)\n    mW2, vW2 = np.zeros_like(W2), np.zeros_like(W2)\n    mB2, vB2 = np.zeros_like(b2), np.zeros_like(b2)\n    t = 0\n\n    for epoch in range(epochs):\n        idx = np.random.permutation(X.shape[0])\n        X, y = X[idx], y[idx]\n\n        for i in range(0, X.shape[0], batch_size):\n            X_batch = X[i:i+batch_size]\n            y_batch = y[i:i+batch_size]\n\n            Z1, A1, Z2, A2 = forward(X_batch, W1, b1, W2, b2)\n            dW1, db1, dW2, db2 = backward(X_batch, y_batch, Z1, A1, A2, W2)\n\n            t += 1\n            for param, grad, m, v in zip(\n                [W1, b1, W2, b2],\n                [dW1, db1, dW2, db2],\n                [mW1, mB1, mW2, mB2],\n                [vW1, vB1, vW2, vB2],\n            ):\n                m[:] = beta1 * m + (1 - beta1) * grad\n                v[:] = beta2 * v + (1 - beta2) * (grad ** 2)\n                m_corr = m / (1 - beta1 ** t)\n                v_corr = v / (1 - beta2 ** t)\n                param -= lr * m_corr / (np.sqrt(v_corr) + eps)\n\n        val_acc = accuracy(X_val, y_val, W1, b1, W2, b2)\n        print(f\"Epoch {epoch+1}/{epochs} | Val Acc: {val_acc*100:.2f}%\")\n\n    return W1, b1, W2, b2\n\nW1, b1, W2, b2 = train_adam(X_train, y_train, X_val, y_val, epochs=27, lr=0.001)\n\nfinal_acc = accuracy(X_val, y_val, W1, b1, W2, b2)\nprint(f\"\\n Final validation accuracy: {final_acc*100:.2f}%\")\nprint(f\"\\n\")\n\nm = 5  # small batch size\nX_demo = np.random.randn(m, 784)\nW_demo = np.random.randn(784, 10)\nb_demo = np.random.randn(10)\n\nZ = X_demo @ W_demo + b_demo  # shape (m,10)\nA = np.exp(Z) / np.sum(np.exp(Z), axis=1, keepdims=True)  # softmax\n\ny_true = np.zeros((m, 10))\ny_true[np.arange(m), np.random.randint(0, 10, size=m)] = 1\n\n\nloss = -np.sum(y_true * np.log(A + 1e-8)) / m\n\ndZ = A - y_true\ndW = X_demo.T @ dZ / m\ndb = np.sum(dZ, axis=0) / m\n\nlr = 0.01\nW_demo -= lr * dW\nb_demo -= lr * db\n\nprint(f\"Loss: {loss:.4f}\")\nprint(\"Updated weights shape:\", W_demo.shape)\nprint(\"Updated biases shape:\", b_demo.shape)\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-19T14:23:20.685060Z","iopub.execute_input":"2025-10-19T14:23:20.685378Z","iopub.status.idle":"2025-10-19T14:24:13.123196Z","shell.execute_reply.started":"2025-10-19T14:23:20.685364Z","shell.execute_reply":"2025-10-19T14:24:13.122548Z"}},"outputs":[],"execution_count":null}]}