{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":30732,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## ALL of \"Gen AI solutions\" or \"Modern AI solutions\" are made up of same building block \"NEURAL NETWORK\"\n## The Process to train ANY and ALL neural networks is a \"4 Stage Pipeline\" \n## 4 Stages of Pipline\n1. Getting the Data to learn from\n2. Wrirint Model Structure / Architecture\n3. Minimizing error of Model prediction by using the \"Data\"\n4. Using the trained Model\n","metadata":{}},{"cell_type":"markdown","source":"# 1. Simple Dataset reading pipeline\n- On Kaggle,the Dataset is already downloaded. Hence this read takes <1 minutes compared to 20+ minutes from huggingface datasets\n- We standardize Image Size to a \"Standard Size\". Common sizes are (224 pixels * 224 pixels) or (256 pixels * 256 pixels)","metadata":{}},{"cell_type":"code","source":"!pip install lightning torchmetrics","metadata":{"execution":{"iopub.status.busy":"2024-10-16T07:10:50.465360Z","iopub.execute_input":"2024-10-16T07:10:50.465747Z","iopub.status.idle":"2024-10-16T07:11:05.451935Z","shell.execute_reply.started":"2024-10-16T07:10:50.465716Z","shell.execute_reply":"2024-10-16T07:11:05.450976Z"},"_kg_hide-output":true,"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision, torchinfo, torchmetrics\nimport torchvision\nimport os, glob, zipfile\nfrom tqdm import tqdm\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\n\nclass Custom_Dataset(torch.utils.data.Dataset):\n    def __init__(self,file_list):\n        self.file_list = file_list\n        self.transform = torchvision.transforms.Compose(\n            [\n                torchvision.transforms.Resize((224, 224)), # IMPORTANT SIZE OF IMAGE (224, 224) or (256,256)\n                torchvision.transforms.ToTensor(),\n            ])\n\n    def __len__(self):\n        self.filelength = len(self.file_list)\n        return self.filelength\n\n    def __getitem__(self,idx):\n        img_path        = self.file_list[idx]\n        img             = Image.open(img_path)\n        img_transformed = self.transform(img)\n\n        label = img_path.split('/')[-1].split('.')[0]\n        if label == 'dog':\n            label=1\n        elif label == 'cat':\n            label=0\n\n        return img_transformed,label\n\nzip_files = ['train.zip', 'test.zip']\nfor zip_file in zip_files:\n    with zipfile.ZipFile(\"../input/dogs-vs-cats-redux-kernels-edition/{}\".format(zip_file),\"r\") as z:\n        z.extractall(\".\")\n        print(\"{} unzipped\".format(zip_file))\n\ntrain_file_names_list = glob.glob(os.path.join(\"../working/train\",'*.jpg'))\ntest_file_names_list  = glob.glob(os.path.join(\"../working/test\", '*.jpg'))\n\n\ntrain_list, val_list  = train_test_split(train_file_names_list, test_size=0.2)\n\ntrain_dataset = Custom_Dataset(train_list)\nval_dataset   = Custom_Dataset(val_list)\ntest_dataset  = Custom_Dataset(test_file_names_list)\n\ntraining_dataloader    = torch.utils.data.DataLoader(dataset = train_dataset, batch_size=32, shuffle=True )\nvalidation_dataloader  = torch.utils.data.DataLoader(dataset = val_dataset  , batch_size=32, shuffle=True)\ntest_dataloader        = torch.utils.data.DataLoader(dataset = test_dataset , batch_size=1 , shuffle=False)\n\n\nassert next(iter(training_dataloader))   is not None\nassert next(iter(validation_dataloader)) is not None","metadata":{"_uuid":"96aafc3f-9cae-4abf-959b-f4d218b0cff9","_cell_guid":"8cff02e3-9730-4536-a8d7-06c0d6d206c5","collapsed":false,"jupyter":{"outputs_hidden":false},"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-10-16T07:09:39.349687Z","iopub.execute_input":"2024-10-16T07:09:39.350529Z","iopub.status.idle":"2024-10-16T07:10:05.734871Z","shell.execute_reply.started":"2024-10-16T07:09:39.350497Z","shell.execute_reply":"2024-10-16T07:10:05.733858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. Simple Model Training Pipeline","metadata":{}},{"cell_type":"code","source":"import lightning\nimport torchmetrics\n\nclass Lightning_Module(lightning.LightningModule):\n    def __init__(self, model):\n        super().__init__()\n        \n        self.model = model\n        self.automatic_optimization = False\n        self.training_accuracy   = torchmetrics.Accuracy(task=\"multiclass\", num_classes=10)\n        self.validation_accuracy = torchmetrics.Accuracy(task=\"multiclass\", num_classes=10)\n  \n    def training_step (self, batch, batch_idx):\n        images_actual, labels_actual        = batch\n        predicted_logits  = self.model(images_actual)\n        labels_predicted  = torch.argmax(predicted_logits, dim = 1)\n\n        loss              = torch.nn.functional.cross_entropy(predicted_logits, labels_actual)\n        \n        optimizer         = self.optimizers()\n        optimizer.zero_grad()\n        self.manual_backward(loss)\n        optimizer.step()\n        \"\"\"\n        for individual_parameter in self.parameters():\n            individual_parameter = individual_parameter - individual_parameter.grad * learning_rate\n        \"\"\"\n        self.training_accuracy(labels_predicted, labels_actual)\n        self.log(\"train_loss\"     , loss                   , prog_bar = True)\n        self.log(\"train_accuracy\" , self.training_accuracy , prog_bar = True)\n        \n        return loss\n\n    def validation_step (self, batch, batch_idx):\n        images_actual, labels_actual        = batch\n        predicted_logits  = self.model(images_actual)\n        labels_predicted  = torch.argmax(predicted_logits, dim = 1)\n\n        loss = torch.nn.functional.cross_entropy(predicted_logits, labels_actual)\n        self.validation_accuracy(labels_predicted, labels_actual)\n        self.log(\"validation_loss\"     , loss                     , prog_bar= False)\n        self.log(\"validation_accuracy\" , self.validation_accuracy , prog_bar= True)\n    \n    def configure_optimizers(self):\n        optimizer = torch.optim.Adam(self.model.parameters(), lr=1e-3)\n        return optimizer","metadata":{"_uuid":"ad119a64-e8f5-4201-8bce-f9f155b0f03e","_cell_guid":"e2dbe369-27ac-4420-ab3a-56f720b3825b","collapsed":false,"jupyter":{"outputs_hidden":false},"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-10-16T07:11:13.521572Z","iopub.execute_input":"2024-10-16T07:11:13.521958Z","iopub.status.idle":"2024-10-16T07:11:14.095841Z","shell.execute_reply.started":"2024-10-16T07:11:13.521924Z","shell.execute_reply":"2024-10-16T07:11:14.095039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. Model Architecture Experiments","metadata":{}},{"cell_type":"markdown","source":"## Experiment 1","metadata":{}},{"cell_type":"code","source":"feature_extractor = nn.Sequential(\n    # Standard Input Size: 3, 224, 224\n    # Filter: UV Light filter on glasses is looking for UV lights to filter out or Filter in water purification, is looking for impurities\n    nn.Conv2d                           ( in_channels =  3, out_channels = 50, kernel_size = (3,3), padding=\"same\"), \n    nn.ReLU(), nn.MaxPool2d ((2,2), 2),                                           \n    # 112, 112\n    nn.Conv2d                           ( in_channels = 50, out_channels = 50, kernel_size = (3,3), padding=\"same\"),\n    nn.ReLU(), nn.MaxPool2d ((2,2), 2),\n    # 56, 56\n    nn.Conv2d                           ( in_channels = 50, out_channels = 50, kernel_size = (3,3), padding=\"same\"),\n    nn.ReLU(), nn.MaxPool2d ((2,2), 2),\n    # 28, 28\n    nn.Conv2d                           ( in_channels = 50, out_channels = 50, kernel_size = (3,3), padding=\"same\"),\n    nn.ReLU(), nn.MaxPool2d ((2,2), 2),\n    # 14, 14\n    nn.Conv2d                           ( in_channels = 50, out_channels = 512, kernel_size = (3,3), padding=\"same\"),\n    nn.ReLU(), nn.MaxPool2d ((2,2), 2),\n    # Standard Output Size: 512, 7, 7\n    # Total Features = 512 images of 7*7 pixel\n)\n\ndecision_maker = nn.Sequential(\n    nn.Flatten(start_dim=1),\n    nn.Linear(in_features = 512*7*7 , out_features = 50), nn.ReLU(),\n    nn.Linear(in_features = 50      , out_features = 2) # 1 Neuron is for detecting Cat and 2nd Neuron is for detecting Dog\n)\n\nmodel = nn.Sequential(\n  feature_extractor,\n  decision_maker\n)","metadata":{"_uuid":"286f8f56-e799-4852-9693-1717f7edca01","_cell_guid":"f1f536f5-f079-4c94-984d-7b56e01f79fd","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-10-16T07:11:19.312225Z","iopub.execute_input":"2024-10-16T07:11:19.312591Z","iopub.status.idle":"2024-10-16T07:11:19.341087Z","shell.execute_reply.started":"2024-10-16T07:11:19.312560Z","shell.execute_reply":"2024-10-16T07:11:19.340262Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs            = 1\nlightning_model   = Lightning_Module(model)\nlightning_trainer = lightning.Trainer(accelerator='cuda', max_epochs= epochs)\n\nlightning_trainer.fit(model=lightning_model, train_dataloaders= training_dataloader, val_dataloaders= validation_dataloader)","metadata":{"execution":{"iopub.status.busy":"2024-10-16T07:11:27.385876Z","iopub.execute_input":"2024-10-16T07:11:27.386522Z","iopub.status.idle":"2024-10-16T07:13:30.854457Z","shell.execute_reply.started":"2024-10-16T07:11:27.386480Z","shell.execute_reply":"2024-10-16T07:13:30.853465Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs            = 1\nlightning_model   = Lightning_Module(model)\nlightning_trainer = lightning.Trainer(accelerator='cpu', max_epochs= epochs)\n\nlightning_trainer.fit(model=lightning_model, train_dataloaders= training_dataloader, val_dataloaders= validation_dataloader)","metadata":{"execution":{"iopub.status.busy":"2024-10-16T07:37:46.624734Z","iopub.execute_input":"2024-10-16T07:37:46.625601Z","iopub.status.idle":"2024-10-16T08:07:28.318009Z","shell.execute_reply.started":"2024-10-16T07:37:46.625567Z","shell.execute_reply":"2024-10-16T08:07:28.317097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Model Save & Load\n```python\ntorch.save(model.state_dict(), 'trained_model_parameter_values.pth')\nmodel.load_state_dict(torch.load(filename))\n```","metadata":{}},{"cell_type":"code","source":"import tqdm\nimport pandas as pd\n\nfile_ids         = []\npredicted_labels = []\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\nfor images_actual, file_id in tqdm.tqdm(test_dataloader):\n    images_actual.to(device)\n    \n    predicted_logits  = model(images_actual)\n    predicted_probs   = torch.nn.functional.softmax(predicted_logits, dim=1)\n    predicted_label   = torch.argmax(predicted_probs, axis = 1).item()\n    \n    predicted_labels.append(predicted_label)\n    file_ids.        append(file_id[0])\n\nprediction_df = pd.DataFrame({'id': file_ids, 'label': predicted_labels})\nprediction_df.to_csv(\"dogs_vs_cats.csv\", index = False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install gradio --upgrade","metadata":{"execution":{"iopub.status.busy":"2024-09-23T05:44:58.271702Z","iopub.execute_input":"2024-09-23T05:44:58.272137Z","iopub.status.idle":"2024-09-23T05:45:14.651257Z","shell.execute_reply.started":"2024-09-23T05:44:58.272105Z","shell.execute_reply":"2024-09-23T05:45:14.649718Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport gradio as gr\n\n# Assuming your trained model is already defined as `model`\n\ndef predict_cat_dog(image):\n  # Preprocess the image (resize, convert to tensor)\n  # ... (same logic as your Custom_Dataset transform)\n\n  # Send image to device (CPU or GPU)\n  image = image.to(torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\"))\n\n  # Use the trained model to get predictions\n  predicted_logits = model(image)\n  predicted_probs = torch.nn.functional.softmax(predicted_logits, dim=1)\n  predicted_label = torch.argmax(predicted_prob, axis=1).item()\n\n  # Return the predicted class (cat or dog)\n  return \"Cat\" if predicted_label == 0 else \"Dog\"\n\n# Define the Gradio interface\ninterface = gr.Interface(\n  fn=predict_cat_dog,\n  inputs=\"image\",\n  outputs=\"text\",\n  title=\"Cat vs Dog Classifier\",\n  description=\"Upload an image of a cat or dog to see if the model can predict it correctly!\"\n)\n\n# Launch the interface (set share=True for a public link)\ninterface.launch(share=True)","metadata":{"execution":{"iopub.status.busy":"2024-09-23T05:45:33.394311Z","iopub.execute_input":"2024-09-23T05:45:33.394766Z","iopub.status.idle":"2024-09-23T05:45:33.775192Z","shell.execute_reply.started":"2024-09-23T05:45:33.394731Z","shell.execute_reply":"2024-09-23T05:45:33.773582Z"},"trusted":true},"execution_count":null,"outputs":[]}]}