{"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":"gpu","dataSources":[{"sourceId":21154,"databundleVersionId":1243559,"sourceType":"competition"}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:29:05.811836Z","iopub.execute_input":"2025-07-20T06:29:05.812068Z","iopub.status.idle":"2025-07-20T06:29:07.002324Z","shell.execute_reply.started":"2025-07-20T06:29:05.812044Z","shell.execute_reply":"2025-07-20T06:29:07.000503Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pip install ultralytics","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport glob\nimport random\nimport io\nimport tensorflow as tf\nfrom PIL import Image\nfrom collections import defaultdict\nimport yaml\nimport ultralytics\nfrom ultralytics import YOLO\nimport torch\nimport pandas as pd\n\n\nTFRECORD_DIR = '/kaggle/input/tpu-getting-started/tfrecords-jpeg-224x224/train/*.tfrec'\nTEST_TFRECORD_DIR = '/kaggle/input/tpu-getting-started/tfrecords-jpeg-224x224/test/*.tfrec'\nOUTPUT_DIR = '/kaggle/working'  \nTRAIN_RATIO = 0.8\nMAX_CLASSES = 104\n\n\nos.makedirs(OUTPUT_DIR, exist_ok=True)\nfor split in ['train', 'val']:\n    for cls in range(MAX_CLASSES):\n        os.makedirs(os.path.join(OUTPUT_DIR, split, f'class{cls}'), exist_ok=True)\n\n\ndef parse_tfrecord(pRecord):\n    features = {\n        \"id\": tf.io.FixedLenFeature([], tf.string),\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"class\": tf.io.FixedLenFeature([], tf.int64),\n    }\n    return tf.io.parse_single_example(pRecord, features)\n\ndef parse_test_tfrecord(pRecord):\n    features = {\n        \"id\": tf.io.FixedLenFeature([], tf.string),\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n    }\n    return tf.io.parse_single_example(pRecord, features)\n\ntfrecord_paths = glob.glob(TFRECORD_DIR)\nrandom.shuffle(tfrecord_paths)\nsplit_idx = int(len(tfrecord_paths) * TRAIN_RATIO)\ntrain_paths, val_paths = tfrecord_paths[:split_idx], tfrecord_paths[split_idx:]\n\nused_classes = set()\n\ndef extract_and_save(tfrecord_list, split):\n    for tfrecord in tfrecord_list:\n        dataset = tf.data.TFRecordDataset(tfrecord)\n        for record in dataset:\n            try:\n                sample = parse_tfrecord(record)\n                img_bytes = sample['image'].numpy()\n                class_id = int(sample['class'].numpy())\n                used_classes.add(class_id)\n\n                class_folder = os.path.join(OUTPUT_DIR, split, f'class{class_id}')\n                os.makedirs(class_folder, exist_ok=True)\n\n                image = Image.open(io.BytesIO(img_bytes)).convert(\"RGB\")\n                image_id = sample['id'].numpy().decode('utf-8')\n                image_path = os.path.join(class_folder, f'{image_id}.jpg')\n                image.save(image_path)\n            except Exception as e:\n                print(f\"Error processing a record: {e}\")\n\ntest_image_ids = []\n\ndef extract_test_images(tfrecord_list, output_folder):\n    os.makedirs(output_folder, exist_ok=True)\n    for tfrecord in tfrecord_list:\n        dataset = tf.data.TFRecordDataset(tfrecord)\n        for record in dataset:\n            try:\n                sample = parse_test_tfrecord(record)\n                img_bytes = sample['image'].numpy()\n                image_id = sample['id'].numpy().decode('utf-8')\n                image_path = os.path.join(output_folder, f'{image_id}.jpg')\n                Image.open(io.BytesIO(img_bytes)).convert(\"RGB\").save(image_path)\n                test_image_ids.append(image_id)\n            except Exception as e:\n                print(f\"Error processing a record: {e}\")\n\ntest_paths = glob.glob(TEST_TFRECORD_DIR)\ntest_folder = os.path.join(OUTPUT_DIR, 'test')\nextract_test_images(test_paths, test_folder)\n\n\n\nextract_and_save(train_paths, 'train')\nextract_and_save(val_paths, 'val')\n\n\nused_classes = sorted(list(used_classes))\nnum_classes = len(used_classes)\nclass_names = [f'class{c}' for c in used_classes]\n\nyaml_dict = {\n    'path': OUTPUT_DIR,\n    'train': 'train',\n    'val': 'val',\n    'nc': num_classes,\n    'names': class_names\n}\n\nyaml_path = os.path.join(OUTPUT_DIR, 'dataset.yaml')\nwith open(yaml_path, 'w') as f:\n    yaml.dump(yaml_dict, f)\n\nprint(f\"\\n Dataset ready at: {OUTPUT_DIR}\")\nprint(f\" YAML config saved at: {yaml_path}\")\nprint(f\" Classes detected: {class_names}\")\n\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\nprint(f'Device: {device}')\n\n\nmodel = YOLO('yolov8x-cls.pt') \n\nmodel.train(\n    data= yaml_path,\n    epochs=10,\n    imgsz=224, \n    batch = 256\n)\n\ntrained_model_path = model.model.model_path if hasattr(model.model, 'model_path') else None\nif trained_model_path is None or not os.path.exists(trained_model_path):\n\n    runs_dir = 'runs/classify'\n    latest_run = max(glob.glob(os.path.join(runs_dir, 'train*')), key=os.path.getmtime)\n    trained_model_path = os.path.join(latest_run, 'weights', 'best.pt')\n\nprint(f\"Using trained weights: {trained_model_path}\")\n\nmodel = YOLO(trained_model_path)\n\n\nbatch_size = 128\n\n\ntest_folder = os.path.join(OUTPUT_DIR, 'test')\ntest_images = sorted(glob.glob(os.path.join(test_folder, '*.jpg')))\ntest_image_ids = [os.path.splitext(os.path.basename(p))[0] for p in test_images] \npred_labels = []\n\nfor i in range(0, len(test_images), batch_size):\n    batch_imgs = test_images[i:i+batch_size]\n    results = model.predict(source=batch_imgs, imgsz=224, device=device)\n    for r in results:\n        pred_labels.append(r.probs.top1)\n\n\nassert len(test_image_ids) == len(pred_labels), \"Mismatch between image IDs and predicted labels!\"\n\n\nsubmission_df = pd.DataFrame({\n    'id': test_image_ids,\n    'label': pred_labels\n})\nsubmission_df.to_csv('/kaggle/working/submission.csv', index=False)\nprint(f\"✅ submission.csv saved with {len(submission_df)} rows\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:29:14.343567Z","iopub.execute_input":"2025-07-20T06:29:14.344110Z","iopub.status.idle":"2025-07-20T06:29:27.869924Z","shell.execute_reply.started":"2025-07-20T06:29:14.344069Z","shell.execute_reply":"2025-07-20T06:29:27.868932Z"}},"outputs":[],"execution_count":null}]}