{"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":[{"sourceType":"competition","sourceId":24800,"datasetId":1042002,"databundleVersionId":1831594}],"dockerImageVersionId":30747,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"pip install -q torch torchvision albumentations pydicom\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-08-21T00:43:58.545567Z","iopub.execute_input":"2024-08-21T00:43:58.545873Z","iopub.status.idle":"2024-08-21T00:44:12.435179Z","shell.execute_reply.started":"2024-08-21T00:43:58.545846Z","shell.execute_reply":"2024-08-21T00:44:12.433984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nos.environ['WANDB_MODE'] = 'disabled'","metadata":{"execution":{"iopub.status.busy":"2024-08-21T00:44:12.437324Z","iopub.execute_input":"2024-08-21T00:44:12.437643Z","iopub.status.idle":"2024-08-21T00:44:12.442429Z","shell.execute_reply.started":"2024-08-21T00:44:12.437615Z","shell.execute_reply":"2024-08-21T00:44:12.441449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport shutil\nimport pandas as pd\nfrom tqdm import tqdm\nimport numpy as np\nimport pydicom\nimport cv2\nimport albumentations as A\n\n# Paths for data\nDATA_PATH = '/kaggle/input/vinbigdata-chest-xray-abnormalities-detection'\nTRAIN_CSV_PATH = os.path.join(DATA_PATH, 'train.csv')\nTRAIN_DICOM_DIR = os.path.join(DATA_PATH, 'train')\nIMAGES_DIR = '/kaggle/working/images'\n\n# Create directories for YOLOv8 dataset\nos.makedirs(IMAGES_DIR, exist_ok=True)\nos.makedirs(f'{IMAGES_DIR}/images/train', exist_ok=True)\nos.makedirs(f'{IMAGES_DIR}/images/valid', exist_ok=True)\nos.makedirs(f'{IMAGES_DIR}/labels/train', exist_ok=True)\nos.makedirs(f'{IMAGES_DIR}/labels/valid', exist_ok=True)\n\n# Read the training CSV file\ndf = pd.read_csv(TRAIN_CSV_PATH)\n\n# Preprocess the data\ndf.fillna(0, inplace=True)\ndf.loc[df[\"class_id\"] == 14, ['x_max', 'y_max']] = 1.0\n\n# Assign unique IDs to each image for training and validation\nimage_ids = df['image_id'].unique()\nvalid_ids = image_ids[-3000:]  # Last 3000 images for validation\ntrain_ids = image_ids[:-3000]  # Remaining for training\n\n# Function to convert DICOM images to PNG\ndef convert_dicom_to_png(dicom_path, png_path, transforms=None):\n    dicom = pydicom.dcmread(dicom_path)\n    image = dicom.pixel_array\n    \n    # Rescale intercept and slope\n    intercept = dicom.RescaleIntercept if \"RescaleIntercept\" in dicom else 0.0\n    slope = dicom.RescaleSlope if \"RescaleSlope\" in dicom else 1.0\n    if slope != 1:\n        image = slope * image.astype(np.float64)\n        image = image.astype(np.int16)\n    image += np.int16(intercept)\n    \n    # Normalize and convert to 8-bit\n    image = (image - np.min(image)) / (np.max(image) - np.min(image)) * 255.0\n    image = image.astype(np.uint8)\n    \n    # Apply any augmentation or transformation\n    if transforms:\n        image = transforms(image=image)[\"image\"]\n    \n    # Save the image as PNG\n    cv2.imwrite(png_path, image)\n\n# Data augmentation transforms\ntrain_transforms = A.Compose([\n    A.Flip(p=0.5),\n    A.RandomBrightnessContrast(p=0.2),\n    A.Rotate(limit=15, p=0.5),\n    A.Resize(640, 640),\n])\n\nvalid_transforms = A.Compose([\n    A.Resize(640, 640),\n])\n\n# Create labels for YOLO format\ndef create_yolo_labels(image_id, df, out_dir, image_shape):\n    records = df[df['image_id'] == image_id]\n    h, w = image_shape\n    \n    with open(f'{out_dir}/{image_id}.txt', 'w') as f:\n        for _, row in records.iterrows():\n            class_id = int(row['class_id'])\n            x_center = ((row['x_min'] + row['x_max']) / 2) / w\n            y_center = ((row['y_min'] + row['y_max']) / 2) / h\n            bbox_width = (row['x_max'] - row['x_min']) / w\n            bbox_height = (row['y_max'] - row['y_min']) / h\n            \n            # Write to label file in YOLO format\n            f.write(f'{class_id} {x_center} {y_center} {bbox_width} {bbox_height}\\n')\n\n# Process training and validation images\nfor image_id in tqdm(train_ids):\n    dicom_path = os.path.join(TRAIN_DICOM_DIR, f'{image_id}.dicom')\n    png_path = os.path.join(IMAGES_DIR, 'images/train', f'{image_id}.png')\n    convert_dicom_to_png(dicom_path, png_path, train_transforms)\n    \n    # Create labels\n    create_yolo_labels(image_id, df, f'{IMAGES_DIR}/labels/train', (640, 640))\n\nfor image_id in tqdm(valid_ids):\n    dicom_path = os.path.join(TRAIN_DICOM_DIR, f'{image_id}.dicom')\n    png_path = os.path.join(IMAGES_DIR, 'images/valid', f'{image_id}.png')\n    convert_dicom_to_png(dicom_path, png_path, valid_transforms)\n    \n    # Create labels\n    create_yolo_labels(image_id, df, f'{IMAGES_DIR}/labels/valid', (640, 640))\n","metadata":{"execution":{"iopub.status.busy":"2024-08-21T00:44:12.447823Z","iopub.execute_input":"2024-08-21T00:44:12.448183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Install the ultralytics package for YOLOv8\n!pip install ultralytics\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import yaml\n\n# Define the YAML configuration\ndataset_yaml = {\n    'path': IMAGES_DIR,\n    'train': 'images/train',\n    'val': 'images/valid',\n    'test': '',  # Leave empty if no test data\n    'names': [str(i) for i in range(15)]  # Class names\n}\n\n# Save it to a YAML file\nyaml_path = '/kaggle/working/vinbigdata.yaml'\nwith open(yaml_path, 'w') as f:\n    yaml.dump(dataset_yaml, f)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nfrom ultralytics import YOLO\n\n# Define YOLOv8 configuration\nyolo_cfg = {\n    \"model\": \"yolov8n.pt\",  # YOLOv8 pretrained model (nano version for speed)\n    \"data\": yaml_path,  # Path to the YAML file\n    \"epochs\": 10,  # Number of epochs\n    \"img_size\": 640,  # Image size\n    \"batch\": 16,  # Batch size\n    \"device\": 0 if torch.cuda.is_available() else 'cpu',  # Use GPU if available\n}\n\n# Initialize YOLOv8 model\nmodel = YOLO(yolo_cfg['model'])\n\n# Monkey patch to disable W&B within YOLOv8\ndef disable_wandb(*args, **kwargs):\n    print(\"W&B disabled\")\n    return None\n\n# Override W&B logging\nmodel.wandb_run = disable_wandb\n\n# Train the model with W&B completely disabled\nresults = model.train(\n    data=yolo_cfg['data'],\n    epochs=yolo_cfg['epochs'],\n    imgsz=yolo_cfg['img_size'],\n    batch=yolo_cfg['batch'],\n    device=yolo_cfg['device'],\n    project='runs/train',  # Specify a local directory for logs instead of using W&B\n    name='exp',\n    save_period=1,\n    exist_ok=True,\n)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Validate the model\nvalidation_results = model.val(\n    data=yolo_cfg['data'],\n    imgsz=yolo_cfg['img_size'],\n    device=yolo_cfg['device']\n)\n\n# Extract evaluation metrics\nmetrics = validation_results.metrics\nprint(f\"Validation mAP: {metrics['map']:.4f}\")\nprint(f\"Validation Precision: {metrics['precision']:.4f}\")\nprint(f\"Validation Recall: {metrics['recall']:.4f}\")\n\n# You can also access class-specific metrics if needed\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}