{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"colab":{"provenance":[],"gpuType":"T4"},"accelerator":"GPU"},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import glob\nimport os\nimport pandas as pd\nimport tensorflow as tf\nfeature_description = {\n    'id': tf.io.FixedLenFeature([], tf.string),\n    'class': tf.io.FixedLenFeature([], tf.int64),\n}\n\ndef parse_proto(example_proto):\n    return tf.io.parse_single_example(example_proto, feature_description)\n\ntfrecord_files = glob.glob('/kaggle/input/competitions/tpu-getting-started/tfrecords-jpeg-224x224/train/*tfrec')\n\nids = []\nclasses = []\n\nfor file in tfrecord_files:\n    dataset = tf.data.TFRecordDataset(file)\n    for raw_record in dataset:\n        parsed = parse_proto(raw_record)\n        ids.append(parsed['id'].numpy().decode('utf-8'))\n        classes.append(parsed['class'].numpy())\n\ndf = pd.DataFrame({'image': ids, 'class': classes})\ndf.to_csv('train.csv', index=False)\n\nprint(f'train.csv has been created. It has {len(df)} strings')","metadata":{"id":"wE_opq0fJjyc","outputId":"c66e2229-147c-4778-eb62-4f85b3cdd893","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:05:05.908530Z","iopub.execute_input":"2026-07-06T12:05:05.908842Z","iopub.status.idle":"2026-07-06T12:05:38.080182Z","shell.execute_reply.started":"2026-07-06T12:05:05.908805Z","shell.execute_reply":"2026-07-06T12:05:38.079395Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport glob\nimport tensorflow as tf\nfeature_description = {\n    'image': tf.io.FixedLenFeature([], tf.string),\n    'id': tf.io.FixedLenFeature([], tf.string),\n}\n\ndef parse_proto(example_proto):\n    return tf.io.parse_single_example(example_proto, feature_description)\noutput_dir = '/kaggle/working/dataset/images/train'\nos.makedirs(output_dir, exist_ok=True)\n\ntfrecord_files = glob.glob('/kaggle/input/competitions/tpu-getting-started/tfrecords-jpeg-224x224/train/*tfrec')\n\n\ncount = 0\nfor file in tfrecord_files:\n    dataset = tf.data.TFRecordDataset(file)\n    for raw_record in dataset:\n        parsed = parse_proto(raw_record)\n\n        img_id = parsed['id'].numpy().decode('utf-8')\n        img_bytes = parsed['image'].numpy()\n\n        img_path = f'{output_dir}/{img_id}.jpeg'\n        with open(img_path, 'wb') as f:\n            f.write(img_bytes)\n\n        count += 1\n\nprint(f\"We extracted {count} the actual images into the folder {output_dir}\")","metadata":{"id":"Gy_7H3ROXFvS","outputId":"e6b3aead-9556-4f70-a4fd-13525220819a","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:11:18.491553Z","iopub.execute_input":"2026-07-06T12:11:18.492304Z","iopub.status.idle":"2026-07-06T12:11:31.090613Z","shell.execute_reply.started":"2026-07-06T12:11:18.492272Z","shell.execute_reply":"2026-07-06T12:11:31.089760Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport glob\nimport tensorflow as tf\n\nfeature_description = {\n    'image': tf.io.FixedLenFeature([], tf.string),\n    'id': tf.io.FixedLenFeature([], tf.string),\n}\n\ndef parse_proto(example_proto):\n    return tf.io.parse_single_example(example_proto, feature_description)\n\ndef extract_folder(mode):\n    base_out_dir = '/kaggle/working/dataset/images'\n    output_dir = f'{base_out_dir}/{mode}'\n    os.makedirs(output_dir, exist_ok=True)\n    input_pattern = f'/kaggle/input/competitions/tpu-getting-started/tfrecords-jpeg-224x224/{mode}/*.tfrec'\n    files = glob.glob(input_pattern)\n    \n    print(f\"Extracting {mode} images...\")\n    \n    count = 0\n    for file in files:\n        dataset = tf.data.TFRecordDataset(file)\n        for raw_record in dataset:\n            parsed = parse_proto(raw_record)\n            img_id = parsed['id'].numpy().decode('utf-8')\n            \n            img_path = f'{output_dir}/{img_id}.jpeg'\n            with open(img_path, 'wb') as f:\n                f.write(parsed['image'].numpy())\n            \n            count += 1\n            \n    print(f\"Extracted {count} images into {output_dir}\")\n\nextract_folder('val')\nextract_folder('test')\nprint(\"All data has been extracted on disk\")","metadata":{"id":"ss5dizsoYkKv","outputId":"93435136-d98f-450c-bc80-92e2ca7c5af9","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:17:29.564493Z","iopub.execute_input":"2026-07-06T12:17:29.564956Z","iopub.status.idle":"2026-07-06T12:17:43.162911Z","shell.execute_reply.started":"2026-07-06T12:17:29.564924Z","shell.execute_reply":"2026-07-06T12:17:43.162284Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport glob\nimport pandas as pd\nimport tensorflow as tf\n\nfeature_desc = {\n    'id': tf.io.FixedLenFeature([], tf.string),\n    'class': tf.io.FixedLenFeature([], tf.int64)\n}\n\nids, classes = [], []\ntfrecord_files = glob.glob('/kaggle/input/competitions/tpu-getting-started/tfrecords-jpeg-224x224/val/*.tfrec')\n\nfor file in tfrecord_files:\n    dataset = tf.data.TFRecordDataset(file)\n    for raw in dataset:\n        parsed = tf.io.parse_single_example(raw, feature_desc)\n        ids.append(parsed['id'].numpy().decode('utf-8'))\n        classes.append(parsed['class'].numpy())\ndf = pd.DataFrame({'image': ids, 'class': classes})\ndf.to_csv('/kaggle/working/val.csv', index=False)\n\nprint(\"val.csv has been created!\")","metadata":{"id":"eH8v07tlZGGc","outputId":"2d7e4375-4c80-43bf-c425-5e2d7f5bba13","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:18:40.065736Z","iopub.execute_input":"2026-07-06T12:18:40.066556Z","iopub.status.idle":"2026-07-06T12:18:43.331391Z","shell.execute_reply.started":"2026-07-06T12:18:40.066525Z","shell.execute_reply":"2026-07-06T12:18:43.330617Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### **Data preparing**","metadata":{"id":"vauAA8nVKDoU"}},{"cell_type":"code","source":"import os\nimport pandas as pd\nfrom PIL import Image\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nimport torch.nn as nn\nimport torchvision.models as models\nimport numpy as np","metadata":{"id":"1BYE7GUGKXv_","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:20:27.081026Z","iopub.execute_input":"2026-07-06T12:20:27.081941Z","iopub.status.idle":"2026-07-06T12:20:35.615430Z","shell.execute_reply.started":"2026-07-06T12:20:27.081903Z","shell.execute_reply":"2026-07-06T12:20:35.614644Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_DIR = '/kaggle/working/dataset/images'\nTRAIN_CSV = '/kaggle/working/train.csv'\nVAL_CSV = '/kaggle/working/val.csv'","metadata":{"id":"M2yFugtkHW0u","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:21:14.759109Z","iopub.execute_input":"2026-07-06T12:21:14.760018Z","iopub.status.idle":"2026-07-06T12:21:14.763936Z","shell.execute_reply.started":"2026-07-06T12:21:14.759988Z","shell.execute_reply":"2026-07-06T12:21:14.762977Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_transforms = transforms.Compose([\n    transforms.RandomResizedCrop(224),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n\nval_transforms = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n","metadata":{"id":"tfuU8uc3KPTI","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:21:17.934806Z","iopub.execute_input":"2026-07-06T12:21:17.935451Z","iopub.status.idle":"2026-07-06T12:21:17.940841Z","shell.execute_reply.started":"2026-07-06T12:21:17.935420Z","shell.execute_reply":"2026-07-06T12:21:17.939982Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class FlowerDataset(Dataset):\n  def __init__(self, csv_file, img_dir, mode='train', transform= None):\n    self.df = pd.read_csv(csv_file)\n    self.img_dir = img_dir\n    self.mode = mode\n    self.transform = transform\n\n  def __len__(self):\n    return len(self.df)\n\n  def __getitem__(self,idx):\n    img_id = self.df.iloc[idx]['image']\n    label = self.df.iloc[idx]['class']\n\n    img_path = os.path.join(self.img_dir, self.mode, f'{img_id}.jpeg')\n    image = Image.open(img_path).convert('RGB')\n\n    if self.transform:\n      image = self.transform(image)\n\n    return image, label\n\n\ntrain_dataset = FlowerDataset(csv_file=TRAIN_CSV, img_dir=DATA_DIR, transform=train_transforms)\ntrain_loader = DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=2)\n\nval_dataset = FlowerDataset(csv_file=VAL_CSV, img_dir=DATA_DIR, mode='val', transform=val_transforms)\nval_loader = DataLoader(val_dataset, batch_size=64, shuffle=False, num_workers=2)\n\nprint(f'Length of  train dataset: {len(train_dataset)}')\nprint(f'Length of val dataset: {len(val_dataset)}')","metadata":{"id":"3bJfhB-YNJHm","outputId":"729f86ac-5dc4-47ff-feb0-80f479342058","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:21:21.575825Z","iopub.execute_input":"2026-07-06T12:21:21.576504Z","iopub.status.idle":"2026-07-06T12:21:21.597602Z","shell.execute_reply.started":"2026-07-06T12:21:21.576471Z","shell.execute_reply":"2026-07-06T12:21:21.596799Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class FlowerTestDataset(Dataset):\n  def __init__(self, img_dir, transform = None):\n    self.img_dir = img_dir\n    self.transform = transform\n    self.img_names = [f.split('.')[0] for f in os.listdir(os.path.join(img_dir, 'test')) if f.endswith('.jpeg')]\n\n  def __len__(self):\n    return len(self.img_names)\n\n  def __getitem__(self, idx):\n    img_id = self.img_names[idx]\n    img_path = os.path.join(self.img_dir, 'test', f'{img_id}.jpeg')\n    image = Image.open(img_path).convert('RGB')\n\n    if self.transform:\n      image = self.transform(image)\n\n    return image, img_id\n\ntest_dataset = FlowerTestDataset(img_dir=DATA_DIR, transform=val_transforms)\ntest_loader = DataLoader(test_dataset, batch_size=64, shuffle=False, num_workers=2)\n\nprint(f'Length of  test dataset: {len(test_dataset)}')","metadata":{"id":"LAxJ3OT-YU3I","outputId":"1a449707-5ebb-4d06-fe39-df489bc33b44","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:21:24.962926Z","iopub.execute_input":"2026-07-06T12:21:24.963807Z","iopub.status.idle":"2026-07-06T12:21:24.978593Z","shell.execute_reply.started":"2026-07-06T12:21:24.963776Z","shell.execute_reply":"2026-07-06T12:21:24.977751Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"images, labels = next(iter(train_loader))\nprint(f'Image batch size: {images.shape}')\nprint(f'Label batch size: {labels.shape}')\n\nimages, labels = next(iter(val_loader))\nprint(f'Image batch size: {images.shape}')\nprint(f'Label batch size: {labels.shape}')\n\nimages, img_ids = next(iter(test_loader))\nprint(f'Image batch size: {images.shape}')","metadata":{"id":"zGZmgauNUQdy","outputId":"1b43de31-1cf2-4cff-fc60-390a5054709f","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:21:28.222085Z","iopub.execute_input":"2026-07-06T12:21:28.222926Z","iopub.status.idle":"2026-07-06T12:21:30.012467Z","shell.execute_reply.started":"2026-07-06T12:21:28.222896Z","shell.execute_reply":"2026-07-06T12:21:30.011183Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### **Model creating**","metadata":{"id":"zrA-Z7o2g6ru"}},{"cell_type":"code","source":"model = models.resnet50(weights=models.ResNet50_Weights.DEFAULT)\nnum_features = model.fc.in_features\nmodel.fc = nn.Linear(num_features, 104)\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel = model.to(device)\nprint(f'Model is ready on device {device}')","metadata":{"id":"quOvn8Ajg9sE","outputId":"68f856e7-7831-48a2-9b89-2538a7ca8efe","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:47:01.739022Z","iopub.execute_input":"2026-07-06T12:47:01.739749Z","iopub.status.idle":"2026-07-06T12:47:02.134332Z","shell.execute_reply.started":"2026-07-06T12:47:01.739718Z","shell.execute_reply":"2026-07-06T12:47:02.133373Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)","metadata":{"id":"COIrCYTXjIqh","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:47:04.229123Z","iopub.execute_input":"2026-07-06T12:47:04.229633Z","iopub.status.idle":"2026-07-06T12:47:04.234702Z","shell.execute_reply.started":"2026-07-06T12:47:04.229602Z","shell.execute_reply":"2026-07-06T12:47:04.233722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=1)","metadata":{"id":"0EHxh1tLkEwy","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:47:18.213836Z","iopub.execute_input":"2026-07-06T12:47:18.214343Z","iopub.status.idle":"2026-07-06T12:47:18.219956Z","shell.execute_reply.started":"2026-07-06T12:47:18.214311Z","shell.execute_reply":"2026-07-06T12:47:18.219220Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class EarlyStopping:\n\n  def __init__(self,patience=3, min_delta=0.0):\n    self.patience = patience\n    self.min_delta = min_delta\n    self.counter = 0\n    self.best_loss = None\n    self.early_stop = False\n\n  def __call__(self, val_loss, model):\n    if self.best_loss is None:\n      self.best_loss = val_loss\n      self.save_checkpoint(model)\n    elif val_loss > self.best_loss - self.min_delta:\n      self.counter += 1\n      print(f'There is no progress. Counter {self.counter} out of {self.patience}')\n      if self.counter >= self.patience:\n        self.early_stop = True\n    else:\n      print(f'New best epoch, loss decreased from {self.best_loss} to {val_loss}')\n      self.best_loss = val_loss\n      self.save_checkpoint(model)\n      self.counter = 0\n\n  def save_checkpoint(self, model):\n    torch.save(model.state_dict(), 'best_model.pth')\n    print(f'Checkpoint is saved')\n\n\nearly_stopper = EarlyStopping(patience=3, min_delta=0.0)","metadata":{"id":"HmVBwpeTlHdP","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T12:47:20.100032Z","iopub.execute_input":"2026-07-06T12:47:20.100495Z","iopub.status.idle":"2026-07-06T12:47:20.106991Z","shell.execute_reply.started":"2026-07-06T12:47:20.100463Z","shell.execute_reply":"2026-07-06T12:47:20.106101Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### **Training loop**","metadata":{"id":"ojZLQNJupzfb"}},{"cell_type":"code","source":"import torch\n\nepochs = 20\n\nprint(\"Training loop is starting...\")\n\nfor epoch in range(epochs):\n\n    model.train()\n    train_loss = 0.0\n    train_correct = 0\n    train_total = 0\n\n    for images, labels in train_loader:\n        images, labels = images.to(device), labels.to(device)\n\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        train_loss += loss.item() * images.size(0)\n        _, predicted = torch.max(outputs, 1)\n        train_correct += (predicted == labels).sum().item()\n        train_total += labels.size(0)\n\n    epoch_train_loss = train_loss / train_total\n    epoch_train_acc = (train_correct / train_total) * 100\n\n\n    model.eval()\n    val_loss = 0.0\n    val_correct = 0\n    val_total = 0\n\n    with torch.no_grad():\n        for images, labels in val_loader:\n            images, labels = images.to(device), labels.to(device)\n\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n\n            val_loss += loss.item() * images.size(0)\n            _, predicted = torch.max(outputs, 1)\n            val_correct += (predicted == labels).sum().item()\n            val_total += labels.size(0)\n\n    epoch_val_loss = val_loss / val_total\n    epoch_val_acc = (val_correct / val_total) * 100\n\n    print(f\"\\n Epoch [{epoch+1}/{epochs}]\")\n    print(f\"   Train -> Loss: {epoch_train_loss:.4f} | Accuracy: {epoch_train_acc:.2f}%\")\n    print(f\"   Val   -> Loss: {epoch_val_loss:.4f} | Accuracy: {epoch_val_acc:.2f}%\")\n\n    scheduler.step(epoch_val_loss)\n\n    early_stopper(epoch_val_loss, model)\n\n    if early_stopper.early_stop:\n        print(\"\\n Early stopping triggered. Training has been stopped.\")\n        break\n\nprint(\"\\n Training loop completed!\")\n\nmodel.load_state_dict(torch.load('best_model.pth'))\nprint(\"Best model weights have been loaded\")","metadata":{"id":"IzbXxGD5p3YE","outputId":"9888462b-531a-44aa-a497-04ee76a6a99b","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T13:35:13.813486Z","iopub.execute_input":"2026-07-06T13:35:13.814022Z","iopub.status.idle":"2026-07-06T13:46:23.836697Z","shell.execute_reply.started":"2026-07-06T13:35:13.813975Z","shell.execute_reply":"2026-07-06T13:46:23.835517Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport torch\n\nmodel.eval()\n\ntest_ids = []\ntest_preds = []\n\nprint(\"Starting inference for the test set...\")\n\nwith torch.no_grad():\n    for images, ids in test_loader:\n        images = images.to(device)\n\n        outputs = model(images)\n        _, predicted = torch.max(outputs, 1)\n\n        test_ids.extend(ids)\n        test_preds.extend(predicted.cpu().numpy())\n\nsubmission_df = pd.DataFrame({\n    'id': test_ids,\n    'label': test_preds\n})\n\nsubmission_path = '/kaggle/working/submission.csv'\nsubmission_df.to_csv(submission_path, index=False)\n\nprint(f\"Submission dataframe created successfully. Total rows: {len(submission_df)}\")\nprint(f\"File saved to: {submission_path}\")","metadata":{"id":"t5zFHh8W3e_7","outputId":"36e06152-51e3-407c-ee64-11b82ef73ddf","trusted":true,"execution":{"iopub.status.busy":"2026-07-06T14:39:29.782244Z","iopub.execute_input":"2026-07-06T14:39:29.782682Z","iopub.status.idle":"2026-07-06T14:40:00.136982Z","shell.execute_reply.started":"2026-07-06T14:39:29.782645Z","shell.execute_reply":"2026-07-06T14:40:00.135753Z"}},"outputs":[],"execution_count":null}]}