{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"c10a5237","cell_type":"markdown","source":"# 🐶 Dogs vs Cats Classification with TensorFlow\n\n## A Beginner-Friendly Step-by-Step Guide\n\nThis notebook uses the original Kaggle **Dogs vs Cats** competition dataset.\n\nIt is designed to run from top to bottom on Kaggle without requiring manual file organization.","metadata":{}},{"id":"36479f99","cell_type":"markdown","source":"# Notebook Outline\n\n1. Import Libraries\n2. Set Configuration\n3. Extract Dataset\n4. Create DataFrame\n5. Train / Validation Split\n6. Build TensorFlow Data Pipeline\n7. Visualize Images\n8. Data Augmentation\n9. Build EfficientNetB0 Model\n10. Train\n11. Evaluate\n12. Predict Test Images\n13. Create Submission","metadata":{}},{"id":"c3adf52c","cell_type":"markdown","source":"## 1. Import Libraries\nWe begin by importing the libraries used throughout the notebook.","metadata":{}},{"id":"4f49b750","cell_type":"code","source":"import os\nimport zipfile\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.applications import EfficientNetB0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:06:38.509524Z","iopub.execute_input":"2026-07-15T07:06:38.509987Z","iopub.status.idle":"2026-07-15T07:06:38.652109Z","shell.execute_reply.started":"2026-07-15T07:06:38.509953Z","shell.execute_reply":"2026-07-15T07:06:38.651245Z"}},"outputs":[],"execution_count":null},{"id":"65361668","cell_type":"markdown","source":"## 2. Configuration\nSet image size, batch size and random seed.","metadata":{}},{"id":"0d646a10","cell_type":"code","source":"IMAGE_SIZE=(224,224)\nBATCH_SIZE=32\nSEED=42\ntf.keras.utils.set_random_seed(SEED)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:06:38.653889Z","iopub.execute_input":"2026-07-15T07:06:38.654455Z","iopub.status.idle":"2026-07-15T07:06:38.658845Z","shell.execute_reply.started":"2026-07-15T07:06:38.654426Z","shell.execute_reply":"2026-07-15T07:06:38.658018Z"}},"outputs":[],"execution_count":null},{"id":"004c51b3","cell_type":"markdown","source":"## 3. Extract Dataset\nThe competition provides `train.zip` and `test1.zip`. We extract them if necessary.","metadata":{}},{"id":"5e9b7442","cell_type":"code","source":"INPUT='/kaggle/input/competitions/dogs-vs-cats'\n\nfor name in ['train.zip','test1.zip']:\n    z=os.path.join(INPUT,name)\n    out=os.path.join('/kaggle/working',name.replace('.zip',''))\n    if os.path.exists(z) and not os.path.exists(out):\n        with zipfile.ZipFile(z) as f:\n            f.extractall('/kaggle/working')\n\nTRAIN_DIR='/kaggle/working/train'\nTEST_DIR='/kaggle/working/test1'\n\nprint('Train images:',len(os.listdir(TRAIN_DIR)))\nprint('Test images:',len(os.listdir(TEST_DIR)))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:06:38.659776Z","iopub.execute_input":"2026-07-15T07:06:38.660036Z","iopub.status.idle":"2026-07-15T07:06:53.046254Z","shell.execute_reply.started":"2026-07-15T07:06:38.659990Z","shell.execute_reply":"2026-07-15T07:06:53.045487Z"}},"outputs":[],"execution_count":null},{"id":"265c20f3","cell_type":"markdown","source":"## 4. Create a DataFrame\nThe label is encoded in the filename (`cat.xxx.jpg` or `dog.xxx.jpg`).","metadata":{}},{"id":"2fde0ad0","cell_type":"code","source":"files=os.listdir(TRAIN_DIR)\n\ndf=pd.DataFrame({\n    'filename':files\n})\n\ndf['filepath']=df['filename'].apply(lambda x: os.path.join(TRAIN_DIR,x))\ndf['label']=df['filename'].str.split('.').str[0]\n\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:06:53.047254Z","iopub.execute_input":"2026-07-15T07:06:53.047551Z","iopub.status.idle":"2026-07-15T07:06:53.144161Z","shell.execute_reply.started":"2026-07-15T07:06:53.047524Z","shell.execute_reply":"2026-07-15T07:06:53.143411Z"}},"outputs":[],"execution_count":null},{"id":"bc80b19e","cell_type":"markdown","source":"## 5. Split the Dataset\nWe reserve 20% of the images for validation.","metadata":{}},{"id":"6408704f","cell_type":"code","source":"train_df,val_df=train_test_split(\n    df,\n    test_size=0.2,\n    random_state=SEED,\n    stratify=df['label']\n)\n\nprint(train_df.shape,val_df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:06:53.145996Z","iopub.execute_input":"2026-07-15T07:06:53.146267Z","iopub.status.idle":"2026-07-15T07:06:53.189100Z","shell.execute_reply.started":"2026-07-15T07:06:53.146242Z","shell.execute_reply":"2026-07-15T07:06:53.188265Z"}},"outputs":[],"execution_count":null},{"id":"77c23cf9","cell_type":"markdown","source":"## 6. Build the TensorFlow Data Pipeline\n`flow_from_dataframe` reads images directly from our DataFrame.","metadata":{}},{"id":"136ed834","cell_type":"code","source":"train_gen=tf.keras.preprocessing.image.ImageDataGenerator(\n    preprocessing_function=tf.keras.applications.efficientnet.preprocess_input,\n    rotation_range=10,\n    zoom_range=0.1,\n    horizontal_flip=True\n)\n\nvalid_gen=tf.keras.preprocessing.image.ImageDataGenerator(\n    preprocessing_function=tf.keras.applications.efficientnet.preprocess_input\n)\n\ntrain_ds=train_gen.flow_from_dataframe(\n    train_df,\n    x_col='filepath',\n    y_col='label',\n    target_size=IMAGE_SIZE,\n    class_mode='binary',\n    batch_size=BATCH_SIZE,\n    shuffle=True,\n    seed=SEED\n)\n\nval_ds=valid_gen.flow_from_dataframe(\n    val_df,\n    x_col='filepath',\n    y_col='label',\n    target_size=IMAGE_SIZE,\n    class_mode='binary',\n    batch_size=BATCH_SIZE,\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:06:53.190214Z","iopub.execute_input":"2026-07-15T07:06:53.190843Z","iopub.status.idle":"2026-07-15T07:06:53.420021Z","shell.execute_reply.started":"2026-07-15T07:06:53.190806Z","shell.execute_reply":"2026-07-15T07:06:53.419304Z"}},"outputs":[],"execution_count":null},{"id":"420c2b40","cell_type":"markdown","source":"## 7. Visualize Sample Images\nLet's inspect a few training images.","metadata":{}},{"id":"7da094ff","cell_type":"code","source":"images,labels=next(train_ds)\n\nplt.figure(figsize=(8,8))\nfor i in range(9):\n    plt.subplot(3,3,i+1)\n    img=(images[i]-images[i].min())/(images[i].max()-images[i].min())\n    plt.imshow(img)\n    plt.title('Dog' if labels[i]==1 else 'Cat')\n    plt.axis('off')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:06:53.421061Z","iopub.execute_input":"2026-07-15T07:06:53.421402Z","iopub.status.idle":"2026-07-15T07:06:54.582810Z","shell.execute_reply.started":"2026-07-15T07:06:53.421377Z","shell.execute_reply":"2026-07-15T07:06:54.581684Z"}},"outputs":[],"execution_count":null},{"id":"9767078c","cell_type":"markdown","source":"## 8. Build the Model\nWe'll use EfficientNetB0 as the feature extractor.","metadata":{}},{"id":"61ce410d","cell_type":"code","source":"base=EfficientNetB0(\n    include_top=False,\n    weights='imagenet',\n    input_shape=(224,224,3)\n)\nbase.trainable=False\n\nmodel=tf.keras.Sequential([\n    base,\n    layers.GlobalAveragePooling2D(),\n    layers.Dropout(0.3),\n    layers.Dense(1,activation='sigmoid')\n])\n\nmodel.compile(\n    optimizer='adam',\n    loss='binary_crossentropy',\n    metrics=['accuracy']\n)\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:06:54.584036Z","iopub.execute_input":"2026-07-15T07:06:54.584327Z","iopub.status.idle":"2026-07-15T07:06:56.741610Z","shell.execute_reply.started":"2026-07-15T07:06:54.584300Z","shell.execute_reply":"2026-07-15T07:06:56.740844Z"}},"outputs":[],"execution_count":null},{"id":"9ff81a48","cell_type":"markdown","source":"## 9. Train the Model","metadata":{}},{"id":"fe7ee7eb","cell_type":"code","source":"callbacks=[\n    tf.keras.callbacks.EarlyStopping(\n        patience=3,\n        restore_best_weights=True\n    )\n]\n\nhistory=model.fit(\n    train_ds,\n    validation_data=val_ds,\n    epochs=10,\n    callbacks=callbacks\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:06:56.742563Z","iopub.execute_input":"2026-07-15T07:06:56.743213Z","iopub.status.idle":"2026-07-15T07:07:18.191394Z","shell.execute_reply.started":"2026-07-15T07:06:56.743183Z","shell.execute_reply":"2026-07-15T07:07:18.190211Z"}},"outputs":[],"execution_count":null},{"id":"cd2ab6bc","cell_type":"markdown","source":"## 10. Evaluate the Training Process","metadata":{}},{"id":"1543e4c3","cell_type":"code","source":"pd.DataFrame(history.history)[['accuracy','val_accuracy']].plot(figsize=(8,4),title='Accuracy')\nplt.show()\n\npd.DataFrame(history.history)[['loss','val_loss']].plot(figsize=(8,4),title='Loss')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:07:18.192143Z","iopub.status.idle":"2026-07-15T07:07:18.192467Z","shell.execute_reply.started":"2026-07-15T07:07:18.192324Z","shell.execute_reply":"2026-07-15T07:07:18.192344Z"}},"outputs":[],"execution_count":null},{"id":"670065b3","cell_type":"markdown","source":"## 11. Predict Test Images","metadata":{}},{"id":"dbfe36dd","cell_type":"code","source":"test_files=sorted(os.listdir(TEST_DIR), key=lambda x:int(x.split('.')[0]))\n\ntest_df=pd.DataFrame({\n    'filepath':[os.path.join(TEST_DIR,f) for f in test_files]\n})\n\ntest_gen=tf.keras.preprocessing.image.ImageDataGenerator(\n    preprocessing_function=tf.keras.applications.efficientnet.preprocess_input\n)\n\ntest_ds=test_gen.flow_from_dataframe(\n    test_df,\n    x_col='filepath',\n    y_col=None,\n    class_mode=None,\n    target_size=IMAGE_SIZE,\n    shuffle=False,\n    batch_size=BATCH_SIZE\n)\n\npred=model.predict(test_ds,verbose=1).ravel()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:07:18.193416Z","iopub.status.idle":"2026-07-15T07:07:18.193683Z","shell.execute_reply.started":"2026-07-15T07:07:18.193554Z","shell.execute_reply":"2026-07-15T07:07:18.193570Z"}},"outputs":[],"execution_count":null},{"id":"b1b34a2e","cell_type":"markdown","source":"## 12. Create Submission File","metadata":{}},{"id":"8c8015a0","cell_type":"code","source":"submission=pd.DataFrame({\n    'id':[int(f.split('.')[0]) for f in test_files],\n    'label':pred\n})\n\nsubmission.to_csv('submission.csv',index=False)\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-15T07:07:18.195109Z","iopub.status.idle":"2026-07-15T07:07:18.195386Z","shell.execute_reply.started":"2026-07-15T07:07:18.195258Z","shell.execute_reply":"2026-07-15T07:07:18.195274Z"}},"outputs":[],"execution_count":null},{"id":"c4a14ece","cell_type":"markdown","source":"# Conclusion\n\nYou have built an end-to-end image classification pipeline using TensorFlow and EfficientNetB0. From here, you can improve performance by:\n\n- Fine-tuning the pretrained model\n- Increasing image resolution\n- Training for more epochs\n- Using Test-Time Augmentation (TTA)\n- Ensembling multiple models","metadata":{}}]}