{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":3004,"databundleVersionId":861823}],"dockerImageVersionId":31328,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## **DIGIT RECOGONIZER**\nconvolutional neural network (CNN) classifier to classify images of handwritten digits in the MNIST dataset and testing classifier on high-resolution hand-written digits from outside the dataset.","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"markdown","source":"### importing libraries","metadata":{"execution":{"iopub.status.busy":"2026-05-11T05:22:39.486965Z","iopub.execute_input":"2026-05-11T05:22:39.487527Z","iopub.status.idle":"2026-05-11T05:22:39.496018Z","shell.execute_reply.started":"2026-05-11T05:22:39.487494Z","shell.execute_reply":"2026-05-11T05:22:39.494319Z"}}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense\n# Commonly used modules\nimport numpy as np\nimport os\nimport sys\n\n# Images, plots, display, and visualization\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\nimport cv2\nimport IPython\nfrom six.moves import urllib\n\nprint(tf.__version__)\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:01:27.196718Z","iopub.execute_input":"2026-05-11T06:01:27.197173Z","iopub.status.idle":"2026-05-11T06:01:27.206672Z","shell.execute_reply.started":"2026-05-11T06:01:27.197137Z","shell.execute_reply":"2026-05-11T06:01:27.204732Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"this_repo_url = 'https://github.com/arunkumarramanan/mit-deep-learning/raw/master/'\nthis_tutorial_url = this_repo_url + 'tutorial_deep_learning_basics'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:01:27.211039Z","iopub.execute_input":"2026-05-11T06:01:27.211567Z","iopub.status.idle":"2026-05-11T06:01:27.249006Z","shell.execute_reply.started":"2026-05-11T06:01:27.211523Z","shell.execute_reply":"2026-05-11T06:01:27.246595Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"(train_images, train_labels), (test_images, test_labels) = keras.datasets.mnist.load_data()\n\n# reshape images to specify that it's a single channel\ntrain_images = train_images.reshape(train_images.shape[0], 28, 28, 1)\ntest_images = test_images.reshape(test_images.shape[0], 28, 28, 1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:01:27.251876Z","iopub.execute_input":"2026-05-11T06:01:27.252369Z","iopub.status.idle":"2026-05-11T06:01:27.796929Z","shell.execute_reply.started":"2026-05-11T06:01:27.252331Z","shell.execute_reply":"2026-05-11T06:01:27.794557Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def preprocess_images(imgs): # should work for both a single image and multiple images\n    sample_img = imgs if len(imgs.shape) == 2 else imgs[0]\n    assert sample_img.shape in [(28, 28, 1), (28, 28)], sample_img.shape # make sure images are 28x28 and single-channel (grayscale)\n    return imgs / 255.0\n\ntrain_images = preprocess_images(train_images)\ntest_images = preprocess_images(test_images)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:01:27.798925Z","iopub.execute_input":"2026-05-11T06:01:27.799903Z","iopub.status.idle":"2026-05-11T06:01:27.982631Z","shell.execute_reply.started":"2026-05-11T06:01:27.799607Z","shell.execute_reply":"2026-05-11T06:01:27.980873Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(10,2))\nfor i in range(10):\n    plt.subplot(1,10,i+1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.grid(False)\n    plt.imshow(train_images[i].reshape(28, 28), cmap='viridis')\n    plt.xlabel(train_labels[i])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:01:27.985494Z","iopub.execute_input":"2026-05-11T06:01:27.986097Z","iopub.status.idle":"2026-05-11T06:01:28.354510Z","shell.execute_reply.started":"2026-05-11T06:01:27.986055Z","shell.execute_reply":"2026-05-11T06:01:28.353247Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = keras.Sequential()\n# 32 convolution filters used each of size 3x3\nmodel.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)))\n# 64 convolution filters used each of size 3x3\nmodel.add(Conv2D(64, (3, 3), activation='relu'))\n# choose the best features via pooling\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n# randomly turn neurons on and off to improve convergence\nmodel.add(Dropout(0.25))\n# flatten since too many dimensions, we only want a classification output\nmodel.add(Flatten())\n# fully connected to get all relevant data\nmodel.add(Dense(128, activation='relu'))\n# one more dropout\nmodel.add(Dropout(0.5))\n# output a softmax to squash the matrix into output probabilities\nmodel.add(Dense(10, activation='softmax'))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:01:28.356252Z","iopub.execute_input":"2026-05-11T06:01:28.357100Z","iopub.status.idle":"2026-05-11T06:01:28.462326Z","shell.execute_reply.started":"2026-05-11T06:01:28.357057Z","shell.execute_reply":"2026-05-11T06:01:28.461218Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(optimizer='adam', \n              loss='sparse_categorical_crossentropy',\n              metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:04:59.110422Z","iopub.execute_input":"2026-05-11T06:04:59.110780Z","iopub.status.idle":"2026-05-11T06:04:59.127935Z","shell.execute_reply.started":"2026-05-11T06:04:59.110748Z","shell.execute_reply":"2026-05-11T06:04:59.126888Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = model.fit(train_images, train_labels, epochs=5)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:09:39.679674Z","iopub.execute_input":"2026-05-11T06:09:39.680057Z","iopub.status.idle":"2026-05-11T06:17:37.216037Z","shell.execute_reply.started":"2026-05-11T06:09:39.680025Z","shell.execute_reply":"2026-05-11T06:17:37.214668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(test_images.shape)\ntest_loss, test_acc = model.evaluate(test_images, test_labels)\n\nprint('Test accuracy:', test_acc)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:21:16.318967Z","iopub.execute_input":"2026-05-11T06:21:16.319845Z","iopub.status.idle":"2026-05-11T06:21:20.902452Z","shell.execute_reply.started":"2026-05-11T06:21:16.319794Z","shell.execute_reply":"2026-05-11T06:21:20.901315Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mnist_dream_path = 'images/mnist_dream.mp4'\nmnist_prediction_path = 'images/mnist_dream_predicted.mp4'\n\n# download the video if running in Colab\nif not os.path.isfile(mnist_dream_path): \n    print('downloading the sample video...')\n    vid_url = this_tutorial_url + '/' + mnist_dream_path\n    \n    mnist_dream_path = urllib.request.urlretrieve(vid_url)[0]\n                                                                                                  \ndef cv2_imshow(img):\n    ret = cv2.imencode('.png', img)[1].tobytes() \n    img_ip = IPython.display.Image(data=ret)\n    IPython.display.display(img_ip)\n\ncap = cv2.VideoCapture(mnist_dream_path) \nvw = None\nframe = -1 # counter for debugging (mostly), 0-indexed\n\n# go through all the frames and run our classifier on the high res MNIST images as they morph from number to number\nwhile True: # should 481 frames\n    frame += 1\n    ret, img = cap.read()\n    if not ret: break\n               \n    assert img.shape[0] == img.shape[1] # should be a square\n    if img.shape[0] != 720:\n        img = cv2.resize(img, (720, 720))\n       \n    #preprocess the image for prediction\n    img_proc = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    img_proc = cv2.resize(img_proc, (28, 28))\n    img_proc = preprocess_images(img_proc)\n    img_proc = 1 - img_proc # inverse since training dataset is white text with black background\n\n    net_in = np.expand_dims(img_proc, axis=0) # expand dimension to specify batch size of 1\n    net_in = np.expand_dims(net_in, axis=3) # expand dimension to specify number of channels\n    \n    preds = model.predict(net_in)[0]\n    guess = np.argmax(preds)\n    perc = np.rint(preds * 100).astype(int)\n    \n    img = 255 - img\n    pad_color = 0\n    img = np.pad(img, ((0,0), (0,1280-720), (0,0)), mode='constant', constant_values=(pad_color))  \n    \n    line_type = cv2.LINE_AA\n    font_face = cv2.FONT_HERSHEY_SIMPLEX\n    font_scale = 1.3        \n    thickness = 2\n    x, y = 740, 60\n    color = (255, 255, 255)\n    \n    text = \"Neural Network Output:\"\n    cv2.putText(img, text=text, org=(x, y), fontScale=font_scale, fontFace=font_face, thickness=thickness,\n                    color=color, lineType=line_type)\n    \n    text = \"Input:\"\n    cv2.putText(img, text=text, org=(30, y), fontScale=font_scale, fontFace=font_face, thickness=thickness,\n                    color=color, lineType=line_type)   \n        \n    y = 130\n    for i, p in enumerate(perc):\n        if i == guess: color = (255, 218, 158)\n        else: color = (100, 100, 100)\n            \n        rect_width = 0\n        if p > 0: rect_width = int(p * 3.3)\n        \n        rect_start = 180\n        cv2.rectangle(img, (x+rect_start, y-5), (x+rect_start+rect_width, y-20), color, -1)\n\n        text = '{}: {:>3}%'.format(i, int(p))\n        cv2.putText(img, text=text, org=(x, y), fontScale=font_scale, fontFace=font_face, thickness=thickness,\n                    color=color, lineType=line_type)\n        y += 60\n    \n    # if you don't want to save the output as a video, set this to False\n    save_video = True\n    \n    if save_video:\n        if vw is None:\n            codec = cv2.VideoWriter_fourcc(*'DIVX')\n            vid_width_height = img.shape[1], img.shape[0]\n            vw = cv2.VideoWriter(mnist_prediction_path, codec, 30, vid_width_height)\n        # 15 fps above doesn't work robustly so we right frame twice at 30 fps\n        vw.write(img)\n        vw.write(img)\n    \n    # scale down image for display\n    img_disp = cv2.resize(img, (0,0), fx=0.5, fy=0.5)\n    cv2_imshow(img_disp)\n    IPython.display.clear_output(wait=True)\n        \ncap.release()\nif vw is not None:\n    vw.release()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-11T06:38:27.804586Z","iopub.execute_input":"2026-05-11T06:38:27.805477Z","iopub.status.idle":"2026-05-11T06:39:22.791316Z","shell.execute_reply.started":"2026-05-11T06:38:27.805433Z","shell.execute_reply":"2026-05-11T06:39:22.790376Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}