{"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":"none","dataSources":[{"sourceId":113558,"databundleVersionId":14174843,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<h1 style=\"text-align:center; color:#3C91E6; font-size:2.2em; margin-bottom:0;\">🧠 Recod.ai/LUC - Scientific Image Forgery Detection</h1>\n<h2 style=\"text-align:center; color:#555; font-weight:400; margin-top:5px;\">A Comprehensive Guide and Educational Notebook</h2>\n\n<hr style=\"border:1px solid #ccc; margin:20px 0;\">\n\n<section>\n  <h2 style=\"color:#3C91E6;\">1. Competition Overview</h2>\n  <p>\n    This notebook serves as a <strong>comprehensive guide</strong> for the \n    <em>\"Recod.ai/LUC - Scientific Image Forgery Detection\"</em> competition.\n    The primary goal is to develop a robust model capable of \n    <strong>detecting and segmenting copy-move forgeries</strong> \n    in biomedical research images at the pixel level.\n  </p>\n\n  <div style=\"background-color:#f8f9fa; border-left:4px solid #3C91E6; padding:10px 20px; margin:15px 0;\">\n    <h3 style=\"color:#3C91E6;\">📘 Through this notebook, you will find:</h3>\n    <ul>\n      <li>A complete <strong>Exploratory Data Analysis (EDA)</strong> to understand dataset structure and challenges.</li>\n      <li>A review of <strong>effective model architectures</strong> from recent literature, focused on segmentation and forgery detection.</li>\n      <li>A detailed, step-by-step <strong>implementation pipeline</strong> — from preprocessing to model training and inference.</li>\n      <li>A <strong>submission-ready system</strong> aligned with competition requirements.</li>\n    </ul>\n  </div>\n\n  <p>\n    The goal is not just to build a model, but to create an <strong>educational resource</strong> \n    that explains the <em>why</em> and <em>how</em> — making advanced image forensics \n    methods understandable for all participants.\n  </p>\n</section>\n\n<hr style=\"border:1px solid #ccc; margin:30px 0;\">\n\n<section>\n  <h2 style=\"color:#3C91E6;\">2. Scientific Context</h2>\n  <p>\n    The <strong>integrity of scientific imagery</strong> is fundamental to credible research. \n    Images in publications should represent genuine data — yet manipulation persists. \n    A common and damaging practice is <strong>copy-move forgery</strong>, \n    where regions of an image are duplicated to fabricate or reinforce results.\n  </p>\n\n  <p>\n    The consequences are far-reaching:\n  </p>\n  <ul>\n    <li>It <strong>misleads researchers</strong>, wasting valuable time and funding.</li>\n    <li>It <strong>undermines public trust</strong> in scientific institutions.</li>\n    <li>It can even <strong>endanger lives</strong> when flawed clinical data informs real-world decisions.</li>\n  </ul>\n\n  <p>\n    This competition uses a <strong>realistic benchmark dataset</strong> derived from \n    hundreds of confirmed forgeries across over 2,000 retracted scientific papers — \n    making it one of the most detailed datasets in the field of image forensics.\n  </p>\n</section>\n\n<hr style=\"border:1px solid #ccc; margin:30px 0;\">\n\n<section>\n  <h2 style=\"color:#3C91E6;\">3. Link to Real-World Retracted Research</h2>\n  <p>\n    Retractions are not abstract — they represent a growing crisis in scientific publishing. \n    The following table summarizes insights from studies on retracted research, \n    emphasizing the urgency of tools like this competition aims to build.\n  </p>\n\n  <table style=\"width:100%; border-collapse:collapse; margin:15px 0; font-size:0.95em;\">\n    <thead style=\"background-color:#3C91E6; color:#fff;\">\n      <tr>\n        <th style=\"padding:10px; text-align:left;\">Aspect</th>\n        <th style=\"padding:10px; text-align:left;\">Findings from Recent Research</th>\n        <th style=\"padding:10px; text-align:left;\">Relevance to this Competition</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr style=\"background-color:#f8f9fa;\">\n        <td style=\"padding:10px;\">Retraction Scale & Impact</td>\n        <td style=\"padding:10px;\">Thousands of retracted papers have been analyzed using ML. One study examined 764 retracted AI papers.</td>\n        <td style=\"padding:10px;\">Provides a rich foundation of real-world fraudulent cases for training detection models.</td>\n      </tr>\n      <tr>\n        <td style=\"padding:10px;\">Persistence of Flawed Work</td>\n        <td style=\"padding:10px;\">96% of citations to a retracted clinical trial failed to note its retraction.</td>\n        <td style=\"padding:10px;\">Highlights the importance of detecting manipulation <em>before</em> publication.</td>\n      </tr>\n      <tr style=\"background-color:#f8f9fa;\">\n        <td style=\"padding:10px;\">Common Reasons for Retraction</td>\n        <td style=\"padding:10px;\">In AI and biomedical fields, causes include data falsification and image manipulation.</td>\n        <td style=\"padding:10px;\">Copy-move forgery detection targets one of the root causes directly.</td>\n      </tr>\n      <tr>\n        <td style=\"padding:10px;\">AI’s Role in the Problem</td>\n        <td style=\"padding:10px;\">AI systems sometimes reuse content from retracted papers without warning.</td>\n        <td style=\"padding:10px;\">Shows the need for reliable, ethical AI systems that safeguard research integrity.</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <div style=\"background-color:#eaf5ff; border-left:4px solid #3C91E6; padding:15px 20px; margin-top:20px;\">\n    <p style=\"font-size:1.05em; color:#333;\">\n      These studies confirm that the issue this competition tackles is <strong>real, urgent, and impactful</strong>. \n      By contributing here, you help develop technologies that can \n      <strong>protect the integrity of scientific discovery</strong>.\n    </p>\n  </div>\n</section>\n\n<hr style=\"border:1px solid #ccc; margin:30px 0;\">\n\n<section style=\"text-align:center;\">\n  <h2 style=\"color:#3C91E6;\">🚀 Let's Keep Science Honest — One Pixel at a Time</h2>\n  \n</section>\n","metadata":{}},{"cell_type":"markdown","source":"# Data Deep Dive (EDA)","metadata":{}},{"cell_type":"code","source":"\nimport os\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom PIL import Image\nimport cv2\nfrom collections import Counter\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Set up plotting style\nplt.style.use('seaborn-v0_8')\nsns.set_palette(\"husl\")\n\n# Paths\nBASE_PATH = \"/kaggle/input/recodai-luc-scientific-image-forgery-detection\"\nTRAIN_AUTHENTIC_PATH = os.path.join(BASE_PATH, \"train_images/authentic\")\nTRAIN_FORGED_PATH = os.path.join(BASE_PATH, \"train_images/forged\")\nTRAIN_MASKS_PATH = os.path.join(BASE_PATH, \"train_masks\")\nTEST_IMAGES_PATH = os.path.join(BASE_PATH, \"test_images\")\n\nprint(\"🔍 Exploring Dataset Structure...\")\nprint(f\"Base path: {BASE_PATH}\")\nprint(f\"Authentic images: {TRAIN_AUTHENTIC_PATH}\")\nprint(f\"Forged images: {TRAIN_FORGED_PATH}\")\nprint(f\"Masks path: {TRAIN_MASKS_PATH}\")\nprint(f\"Test images: {TEST_IMAGES_PATH}\")\n\n# Check what files exist\ndef explore_directory_structure():\n    \"\"\"Explore and count files in each directory\"\"\"\n    print(\"\\n\" + \"=\"*50)\n    print(\"📁 DIRECTORY STRUCTURE ANALYSIS\")\n    print(\"=\"*50)\n    \n    directories = {\n        'Authentic Train': TRAIN_AUTHENTIC_PATH,\n        'Forged Train': TRAIN_FORGED_PATH,\n        'Train Masks': TRAIN_MASKS_PATH,\n        'Test Images': TEST_IMAGES_PATH\n    }\n    \n    file_counts = {}\n    file_extensions = {}\n    \n    for dir_name, dir_path in directories.items():\n        if os.path.exists(dir_path):\n            files = os.listdir(dir_path)\n            file_counts[dir_name] = len(files)\n            \n            # Count file extensions\n            extensions = Counter([os.path.splitext(f)[1] for f in files])\n            file_extensions[dir_name] = extensions\n            \n            print(f\"{dir_name}: {len(files)} files\")\n            print(f\"  Extensions: {dict(extensions)}\")\n        else:\n            print(f\"{dir_name}: Directory not found!\")\n            file_counts[dir_name] = 0\n    \n    return file_counts, file_extensions\n\nfile_counts, file_extensions = explore_directory_structure()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T12:47:41.975528Z","iopub.execute_input":"2025-10-25T12:47:41.975754Z","iopub.status.idle":"2025-10-25T12:47:46.768575Z","shell.execute_reply.started":"2025-10-25T12:47:41.975733Z","shell.execute_reply":"2025-10-25T12:47:46.767556Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create summary dataframe\nsummary_df = pd.DataFrame({\n    'Dataset': list(file_counts.keys()),\n    'Count': list(file_counts.values())\n})\n\nprint(\"\\n\" + \"=\"*50)\nprint(\"📊 DATASET SUMMARY\")\nprint(\"=\"*50)\nprint(summary_df)\n\n# Visualize dataset distribution\nplt.figure(figsize=(10, 6))\nbars = plt.bar(summary_df['Dataset'], summary_df['Count'], color=['skyblue', 'lightcoral', 'lightgreen', 'gold'])\nplt.title('Dataset Distribution Across Categories', fontsize=16, fontweight='bold')\nplt.ylabel('Number of Files', fontsize=12)\nplt.xticks(rotation=45)\nplt.grid(axis='y', alpha=0.3)\n\n# Add value labels on bars\nfor bar in bars:\n    height = bar.get_height()\n    plt.text(bar.get_x() + bar.get_width()/2., height,\n             f'{int(height)}', ha='center', va='bottom')\n\nplt.tight_layout()\nplt.show()\n\n# Analyze image properties\ndef analyze_image_properties(image_paths, category_name):\n    \"\"\"Analyze basic properties of images\"\"\"\n    print(f\"\\n🔬 Analyzing {category_name} Images...\")\n    \n    heights = []\n    widths = []\n    aspect_ratios = []\n    sizes_kb = []\n    modes = []\n    \n    for img_path in image_paths[:500]:  # Sample first 500 images for efficiency\n        try:\n            with Image.open(img_path) as img:\n                width, height = img.size\n                mode = img.mode\n                \n                heights.append(height)\n                widths.append(width)\n                aspect_ratios.append(width / height)\n                sizes_kb.append(os.path.getsize(img_path) / 1024)\n                modes.append(mode)\n        except Exception as e:\n            print(f\"Error reading {img_path}: {e}\")\n            continue\n    \n    if not heights:  # If no images were processed\n        return None\n    \n    properties = {\n        'heights': heights,\n        'widths': widths,\n        'aspect_ratios': aspect_ratios,\n        'sizes_kb': sizes_kb,\n        'modes': modes\n    }\n    \n    # Create summary statistics\n    stats_df = pd.DataFrame({\n        'Property': ['Height', 'Width', 'Aspect Ratio', 'Size (KB)'],\n        'Mean': [np.mean(heights), np.mean(widths), np.mean(aspect_ratios), np.mean(sizes_kb)],\n        'Std': [np.std(heights), np.std(widths), np.std(aspect_ratios), np.std(sizes_kb)],\n        'Min': [np.min(heights), np.min(widths), np.min(aspect_ratios), np.min(sizes_kb)],\n        'Max': [np.max(heights), np.max(widths), np.max(aspect_ratios), np.max(sizes_kb)],\n        'Median': [np.median(heights), np.median(widths), np.median(aspect_ratios), np.median(sizes_kb)]\n    })\n    \n    print(f\"Sample size: {len(heights)} images\")\n    print(f\"Color modes: {Counter(modes)}\")\n    print(f\"\\nSummary Statistics for {category_name}:\")\n    print(stats_df.round(2))\n    \n    return properties, stats_df\n\n# Get sample image paths\ndef get_sample_image_paths(directory, sample_size=500):\n    \"\"\"Get sample image paths from directory\"\"\"\n    if os.path.exists(directory):\n        all_files = [os.path.join(directory, f) for f in os.listdir(directory) \n                    if f.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff'))]\n        return all_files[:sample_size]\n    return []\n\n# Analyze authentic and forged images\nauthentic_samples = get_sample_image_paths(TRAIN_AUTHENTIC_PATH)\nforged_samples = get_sample_image_paths(TRAIN_FORGED_PATH)\n\nauth_props, auth_stats = analyze_image_properties(authentic_samples, \"Authentic\")\nforge_props, forge_stats = analyze_image_properties(forged_samples, \"Forged\")\n\n# Visualize image properties comparison\ndef plot_image_properties_comparison(auth_props, forge_props):\n    \"\"\"Create comparison plots for image properties\"\"\"\n    if auth_props is None or forge_props is None:\n        print(\"No image data to plot\")\n        return\n    \n    fig, axes = plt.subplots(2, 2, figsize=(15, 12))\n    \n    # Height distribution\n    axes[0,0].hist(auth_props['heights'], bins=50, alpha=0.7, label='Authentic', color='skyblue')\n    axes[0,0].hist(forge_props['heights'], bins=50, alpha=0.7, label='Forged', color='lightcoral')\n    axes[0,0].set_xlabel('Height (pixels)')\n    axes[0,0].set_ylabel('Frequency')\n    axes[0,0].set_title('Image Height Distribution')\n    axes[0,0].legend()\n    axes[0,0].grid(alpha=0.3)\n    \n    # Width distribution\n    axes[0,1].hist(auth_props['widths'], bins=50, alpha=0.7, label='Authentic', color='skyblue')\n    axes[0,1].hist(forge_props['widths'], bins=50, alpha=0.7, label='Forged', color='lightcoral')\n    axes[0,1].set_xlabel('Width (pixels)')\n    axes[0,1].set_ylabel('Frequency')\n    axes[0,1].set_title('Image Width Distribution')\n    axes[0,1].legend()\n    axes[0,1].grid(alpha=0.3)\n    \n    # Aspect ratio distribution\n    axes[1,0].hist(auth_props['aspect_ratios'], bins=50, alpha=0.7, label='Authentic', color='skyblue')\n    axes[1,0].hist(forge_props['aspect_ratios'], bins=50, alpha=0.7, label='Forged', color='lightcoral')\n    axes[1,0].set_xlabel('Aspect Ratio (Width/Height)')\n    axes[1,0].set_ylabel('Frequency')\n    axes[1,0].set_title('Aspect Ratio Distribution')\n    axes[1,0].legend()\n    axes[1,0].grid(alpha=0.3)\n    \n    # File size distribution\n    axes[1,1].hist(auth_props['sizes_kb'], bins=50, alpha=0.7, label='Authentic', color='skyblue')\n    axes[1,1].hist(forge_props['sizes_kb'], bins=50, alpha=0.7, label='Forged', color='lightcoral')\n    axes[1,1].set_xlabel('File Size (KB)')\n    axes[1,1].set_ylabel('Frequency')\n    axes[1,1].set_title('File Size Distribution')\n    axes[1,1].legend()\n    axes[1,1].grid(alpha=0.3)\n    \n    plt.tight_layout()\n    plt.show()\n\nplot_image_properties_comparison(auth_props, forge_props)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T12:47:46.770699Z","iopub.execute_input":"2025-10-25T12:47:46.771093Z","iopub.status.idle":"2025-10-25T12:47:55.882578Z","shell.execute_reply.started":"2025-10-25T12:47:46.771070Z","shell.execute_reply":"2025-10-25T12:47:55.881525Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Analyze mask properties\ndef analyze_masks(masks_path):\n    \"\"\"Analyze the mask files (.npy)\"\"\"\n    print(\"\\n\" + \"=\"*50)\n    print(\"🎭 MASK ANALYSIS\")\n    print(\"=\"*50)\n    \n    if not os.path.exists(masks_path):\n        print(\"Masks directory not found!\")\n        return None\n    \n    mask_files = [f for f in os.listdir(masks_path) if f.endswith('.npy')]\n    print(f\"Found {len(mask_files)} mask files\")\n    \n    if not mask_files:\n        return None\n    \n    mask_properties = {\n        'num_masks_per_file': [],\n        'mask_shapes': [],\n        'mask_areas': [],\n        'coverage_ratios': []\n    }\n    \n    # Analyze sample of masks\n    for mask_file in mask_files[:200]:  # Sample for efficiency\n        try:\n            mask_path = os.path.join(masks_path, mask_file)\n            mask_data = np.load(mask_path)\n            \n            # Handle different mask formats\n            if mask_data.ndim == 2:\n                # Single mask\n                mask_properties['num_masks_per_file'].append(1)\n                mask_properties['mask_shapes'].append(mask_data.shape)\n                area = np.sum(mask_data > 0)  # Assuming binary mask\n                mask_properties['mask_areas'].append(area)\n                if mask_data.size > 0:\n                    mask_properties['coverage_ratios'].append(area / mask_data.size)\n            elif mask_data.ndim == 3:\n                # Multiple masks\n                num_masks = mask_data.shape[0] if mask_data.shape[0] > 1 else 1\n                mask_properties['num_masks_per_file'].append(num_masks)\n                for i in range(num_masks):\n                    single_mask = mask_data[i] if mask_data.shape[0] > 1 else mask_data\n                    mask_properties['mask_shapes'].append(single_mask.shape)\n                    area = np.sum(single_mask > 0)\n                    mask_properties['mask_areas'].append(area)\n                    if single_mask.size > 0:\n                        mask_properties['coverage_ratios'].append(area / single_mask.size)\n                    \n        except Exception as e:\n            print(f\"Error loading mask {mask_file}: {e}\")\n            continue\n    \n    if mask_properties['mask_areas']:\n        print(f\"\\nMask Analysis Summary (sample size: {len(mask_properties['mask_areas'])})\")\n        print(f\"Number of masks per file: {Counter(mask_properties['num_masks_per_file'])}\")\n        print(f\"Average mask area: {np.mean(mask_properties['mask_areas']):.2f} pixels\")\n        print(f\"Average coverage ratio: {np.mean(mask_properties['coverage_ratios']):.4f}\")\n        print(f\"Min coverage: {np.min(mask_properties['coverage_ratios']):.6f}\")\n        print(f\"Max coverage: {np.max(mask_properties['coverage_ratios']):.4f}\")\n    \n    return mask_properties\n\nmask_props = analyze_masks(TRAIN_MASKS_PATH)\n\n# Visualize sample images and masks\ndef visualize_samples(authentic_path, forged_path, masks_path, num_samples=5):\n    \"\"\"Visualize sample authentic images, forged images, and their masks\"\"\"\n    print(\"\\n\" + \"=\"*50)\n    print(\"🖼️ SAMPLE VISUALIZATION\")\n    print(\"=\"*50)\n    \n    # Get sample files\n    authentic_files = [f for f in os.listdir(authentic_path) if f.lower().endswith(('.png', '.jpg', '.jpeg'))][:num_samples]\n    forged_files = [f for f in os.listdir(forged_path) if f.lower().endswith(('.png', '.jpg', '.jpeg'))][:num_samples]\n    \n    fig, axes = plt.subplots(3, num_samples, figsize=(4*num_samples, 12))\n    \n    if num_samples == 1:\n        axes = axes.reshape(3, 1)\n    \n    # Plot authentic images\n    for i, img_file in enumerate(authentic_files):\n        img_path = os.path.join(authentic_path, img_file)\n        img = Image.open(img_path)\n        axes[0, i].imshow(img)\n        axes[0, i].set_title(f'Authentic: {img_file[:15]}...')\n        axes[0, i].axis('off')\n    \n    # Plot forged images\n    for i, img_file in enumerate(forged_files):\n        img_path = os.path.join(forged_path, img_file)\n        img = Image.open(img_path)\n        axes[1, i].imshow(img)\n        axes[1, i].set_title(f'Forged: {img_file[:15]}...')\n        axes[1, i].axis('off')\n        \n        # Try to find corresponding mask\n        mask_name = os.path.splitext(img_file)[0] + '.npy'\n        mask_path = os.path.join(masks_path, mask_name)\n        if os.path.exists(mask_path):\n            try:\n                mask = np.load(mask_path)\n                if mask.ndim == 3:\n                    mask = mask[0]  # Take first mask if multiple\n                axes[2, i].imshow(mask, cmap='hot')\n                axes[2, i].set_title(f'Mask: {mask_name[:15]}...')\n                coverage = np.sum(mask > 0) / mask.size if mask.size > 0 else 0\n                axes[2, i].set_xlabel(f'Coverage: {coverage:.4f}')\n            except Exception as e:\n                axes[2, i].text(0.5, 0.5, f'Mask Error\\n{e}', \n                               ha='center', va='center', transform=axes[2, i].transAxes)\n        else:\n            axes[2, i].text(0.5, 0.5, 'Mask Not Found', \n                           ha='center', va='center', transform=axes[2, i].transAxes)\n        axes[2, i].axis('off')\n    \n    plt.tight_layout()\n    plt.show()\n\n# Display samples\nvisualize_samples(TRAIN_AUTHENTIC_PATH, TRAIN_FORGED_PATH, TRAIN_MASKS_PATH, num_samples=5)\n\n# Analyze class distribution\nprint(\"\\n\" + \"=\"*50)\nprint(\"📈 CLASS DISTRIBUTION ANALYSIS\")\nprint(\"=\"*50)\n\ntotal_train_images = file_counts['Authentic Train'] + file_counts['Forged Train']\nauthentic_ratio = file_counts['Authentic Train'] / total_train_images\nforged_ratio = file_counts['Forged Train'] / total_train_images\n\nprint(f\"Total training images: {total_train_images}\")\nprint(f\"Authentic images: {file_counts['Authentic Train']} ({authentic_ratio:.2%})\")\nprint(f\"Forged images: {file_counts['Forged Train']} ({forged_ratio:.2%})\")\n\n# Plot class distribution\nplt.figure(figsize=(8, 6))\nclasses = ['Authentic', 'Forged']\ncounts = [file_counts['Authentic Train'], file_counts['Forged Train']]\ncolors = ['lightgreen', 'lightcoral']\n\nplt.pie(counts, labels=classes, colors=colors, autopct='%1.1f%%', startangle=90)\nplt.title('Class Distribution in Training Set', fontsize=14, fontweight='bold')\nplt.show()\n\n# Summary statistics\nprint(\"\\n\" + \"=\"*50)\nprint(\"📋 EDA SUMMARY\")\nprint(\"=\"*50)\nprint(\"✓ Dataset structure verified\")\nprint(\"✓ Image properties analyzed (dimensions, aspect ratios, file sizes)\")\nprint(\"✓ Class distribution calculated\")\nprint(\"✓ Mask properties explored\")\nprint(\"✓ Sample visualization completed\")\n\nif auth_props and forge_props:\n    print(f\"\\nKey Insights:\")\n    print(f\"- Authentic images analyzed: {len(auth_props['heights'])}\")\n    print(f\"- Forged images analyzed: {len(forge_props['heights'])}\")\n    print(f\"- Average image dimensions: {np.mean(auth_props['widths']):.0f}x{np.mean(auth_props['heights']):.0f} pixels\")\n    print(f\"- Class balance: {authentic_ratio:.1%} authentic vs {forged_ratio:.1%} forged\")\n\nif mask_props and mask_props['coverage_ratios']:\n    print(f\"- Average mask coverage: {np.mean(mask_props['coverage_ratios']):.4f}\")\n    print(f\"- This indicates the typical proportion of image area that is forged\")\n\nprint(\"\\n🎯 Next steps: Use these insights to guide preprocessing and model selection!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T12:47:55.883560Z","iopub.execute_input":"2025-10-25T12:47:55.883784Z","iopub.status.idle":"2025-10-25T12:48:02.261932Z","shell.execute_reply.started":"2025-10-25T12:47:55.883765Z","shell.execute_reply":"2025-10-25T12:48:02.261037Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Evaluation Metrics","metadata":{}},{"cell_type":"markdown","source":"### Why Accuracy Can Be Misleading in Image Forgery Detection In medical image segmentation tasks like forgery detection, accuracy is often a deceptive metric that can lead to false confidence. Here's why:","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import accuracy_score, f1_score, jaccard_score\n\n# Demonstration of why accuracy can be misleading\ndef demonstrate_accuracy_paradox():\n    # Simulate a biomedical image scenario\n    # Typical case: 95% background, 5% forged regions\n    y_true = np.random.choice([0, 1], size=10000, p=[0.95, 0.05])\n    \n    # Naive model that predicts everything as background\n    y_pred_naive = np.zeros_like(y_true)\n    \n    # Good model with 90% recall on forged regions\n    y_pred_good = y_true.copy()\n    forged_indices = np.where(y_true == 1)[0]\n    # Simulate 10% false negatives in forged regions\n    false_negatives = np.random.choice(forged_indices, size=int(0.1 * len(forged_indices)), replace=False)\n    y_pred_good[false_negatives] = 0\n    \n    # Calculate metrics\n    acc_naive = accuracy_score(y_true, y_pred_naive)\n    acc_good = accuracy_score(y_true, y_pred_good)\n    f1_naive = f1_score(y_true, y_pred_naive)\n    f1_good = f1_score(y_true, y_pred_good)\n    \n    print(\"📊 The Accuracy Paradox in Medical Image Segmentation\")\n    print(\"=\"*60)\n    print(f\"Scenario: 95% background pixels, 5% forged region pixels\")\n    print(f\"\\nNaive Model (always predicts background):\")\n    print(f\"  Accuracy: {acc_naive:.4f} ({acc_naive*100:.2f}%)\")\n    print(f\"  F1 Score: {f1_naive:.4f}\")\n    \n    print(f\"\\nGood Model (90% recall on forged regions):\")\n    print(f\"  Accuracy: {acc_good:.4f} ({acc_good*100:.2f}%)\")\n    print(f\"  F1 Score: {f1_good:.4f}\")\n    \n    print(f\"\\nKey Insight:\")\n    print(f\"  The naive model appears to have excellent accuracy ({acc_naive*100:.2f}%)\")\n    print(f\"  but completely fails at the actual task (F1 = 0)\")\n    print(f\"  The good model has slightly lower accuracy but actually detects forgeries!\")\n\ndemonstrate_accuracy_paradox()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T12:48:02.263031Z","iopub.execute_input":"2025-10-25T12:48:02.263346Z","iopub.status.idle":"2025-10-25T12:48:02.495135Z","shell.execute_reply.started":"2025-10-25T12:48:02.263315Z","shell.execute_reply":"2025-10-25T12:48:02.493985Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Core Evaluation Metrics for Segmentation","metadata":{}},{"cell_type":"markdown","source":"### 1. Intersection over Union (IoU) / Jaccard Index\n","metadata":{}},{"cell_type":"code","source":"def calculate_iou(mask1, mask2):\n    \"\"\"\n    Calculate Intersection over Union between two binary masks\n    \n    IoU = |A ∩ B| / |A ∪ B|\n    \n    Where:\n    - A ∩ B: Intersection (pixels where both masks are 1)\n    - A ∪ B: Union (pixels where either mask is 1)\n    \"\"\"\n    intersection = np.logical_and(mask1, mask2).sum()\n    union = np.logical_or(mask1, mask2).sum()\n    \n    if union == 0:\n        return 1.0  # Both masks are empty\n    return intersection / union\n\n# Example calculation\ndef demonstrate_iou():\n    # Example masks\n    y_true = np.array([\n        [0, 0, 0, 0, 0],\n        [0, 1, 1, 1, 0],\n        [0, 1, 1, 1, 0],\n        [0, 0, 0, 0, 0]\n    ])\n    \n    y_pred = np.array([\n        [0, 0, 0, 0, 0],\n        [0, 1, 1, 0, 0],\n        [0, 1, 1, 0, 0],\n        [0, 0, 0, 0, 0]\n    ])\n    \n    iou = calculate_iou(y_true, y_pred)\n    \n    print(f\"\\n🎯 Intersection over Union (IoU) Example\")\n    print(\"=\"*40)\n    print(\"Ground Truth Mask:\")\n    print(y_true)\n    print(\"\\nPredicted Mask:\")\n    print(y_pred)\n    print(f\"\\nIoU = {iou:.4f}\")\n    \n    # Visualization\n    plt.figure(figsize=(12, 4))\n    \n    plt.subplot(1, 3, 1)\n    plt.imshow(y_true, cmap='Blues')\n    plt.title('Ground Truth')\n    plt.colorbar()\n    \n    plt.subplot(1, 3, 2)\n    plt.imshow(y_pred, cmap='Reds')\n    plt.title('Prediction')\n    plt.colorbar()\n    \n    plt.subplot(1, 3, 3)\n    intersection = np.logical_and(y_true, y_pred)\n    union = np.logical_or(y_true, y_pred)\n    plt.imshow(union.astype(int) - intersection.astype(int), cmap='RdYlBu')\n    plt.title('Union - Intersection\\n(Blue: Union only)')\n    plt.colorbar()\n    \n    plt.tight_layout()\n    plt.show()\n    \n    return iou\n\niou_score = demonstrate_iou()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T12:48:02.496111Z","iopub.execute_input":"2025-10-25T12:48:02.496413Z","iopub.status.idle":"2025-10-25T12:48:03.243757Z","shell.execute_reply.started":"2025-10-25T12:48:02.496391Z","shell.execute_reply":"2025-10-25T12:48:03.242700Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 2. Dice Coefficient / F1 Score\n","metadata":{}},{"cell_type":"code","source":"def calculate_dice_coefficient(mask1, mask2):\n    \"\"\"\n    Calculate Dice Coefficient (F1 Score for segmentation)\n    \n    Dice = (2 * |A ∩ B|) / (|A| + |B|)\n    \n    This is equivalent to the F1 score where:\n    - True Positives: |A ∩ B|\n    - False Positives: |B - A|\n    - False Negatives: |A - B|\n    \"\"\"\n    intersection = np.logical_and(mask1, mask2).sum()\n    mask1_sum = mask1.sum()\n    mask2_sum = mask2.sum()\n    \n    if mask1_sum + mask2_sum == 0:\n        return 1.0  # Both masks are empty\n    \n    return (2.0 * intersection) / (mask1_sum + mask2_sum)\n\ndef demonstrate_dice_vs_iou():\n    \"\"\"\n    Show relationship between Dice and IoU\n    \"\"\"\n    # Create sample masks\n    y_true = np.random.randint(0, 2, (100, 100))\n    y_pred = np.random.randint(0, 2, (100, 100))\n    \n    dice = calculate_dice_coefficient(y_true, y_pred)\n    iou = calculate_iou(y_true, y_pred)\n    \n    print(f\"\\n🎲 Dice Coefficient vs IoU\")\n    print(\"=\"*40)\n    print(f\"Dice Coefficient: {dice:.4f}\")\n    print(f\"IoU Score: {iou:.4f}\")\n    \n    # Mathematical relationship\n    if dice > 0:\n        calculated_iou = dice / (2 - dice)\n        print(f\"Mathematical relationship: IoU = Dice / (2 - Dice)\")\n        print(f\"Calculated IoU from Dice: {calculated_iou:.4f}\")\n    \n    return dice, iou\n\ndice_score, iou_score = demonstrate_dice_vs_iou()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T12:48:03.246162Z","iopub.execute_input":"2025-10-25T12:48:03.246467Z","iopub.status.idle":"2025-10-25T12:48:03.256513Z","shell.execute_reply.started":"2025-10-25T12:48:03.246443Z","shell.execute_reply":"2025-10-25T12:48:03.255521Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 3. Competition-Specific F1 Variant\n","metadata":{}},{"cell_type":"code","source":"import pandas as pd\ndef competition_f1_variant(y_true, y_pred, beta=1):\n    \"\"\"\n    This competition uses a variant of F1 score\n    Typically includes run-length encoding and specific handling\n    \n    Fβ = (1 + β²) * (precision * recall) / (β² * precision + recall)\n    \"\"\"\n    # Convert to binary if needed\n    y_true = (y_true > 0.5).astype(np.uint8)\n    y_pred = (y_pred > 0.5).astype(np.uint8)\n    \n    # Calculate TP, FP, FN\n    tp = np.sum((y_true == 1) & (y_pred == 1))\n    fp = np.sum((y_true == 0) & (y_pred == 1))\n    fn = np.sum((y_true == 1) & (y_pred == 0))\n    \n    # Calculate precision and recall\n    precision = tp / (tp + fp + 1e-7)\n    recall = tp / (tp + fn + 1e-7)\n    \n    # F-beta score\n    f_beta = (1 + beta**2) * (precision * recall) / ((beta**2 * precision) + recall + 1e-7)\n    \n    return f_beta, precision, recall\n\ndef analyze_metric_sensitivity():\n    \"\"\"\n    Analyze how different metrics respond to various prediction scenarios\n    \"\"\"\n    scenarios = {\n        'Perfect Prediction': (np.ones(100), np.ones(100)),\n        'All Wrong': (np.ones(100), np.zeros(100)),\n        'Partial Overlap': (np.concatenate([np.ones(50), np.zeros(50)]), \n                           np.concatenate([np.ones(30), np.zeros(70)])),\n        'Empty Masks': (np.zeros(100), np.zeros(100))\n    }\n    \n    results = []\n    \n    for scenario, (true_mask, pred_mask) in scenarios.items():\n        accuracy = accuracy_score(true_mask, pred_mask)\n        dice = calculate_dice_coefficient(true_mask, pred_mask)\n        iou = calculate_iou(true_mask, pred_mask)\n        f1, precision, recall = competition_f1_variant(true_mask, pred_mask)\n        \n        results.append({\n            'Scenario': scenario,\n            'Accuracy': accuracy,\n            'Dice/F1': dice,\n            'IoU': iou,\n            'Competition_F1': f1,\n            'Precision': precision,\n            'Recall': recall\n        })\n    \n    # Create results table\n    results_df = pd.DataFrame(results)\n    print(f\"\\n📈 Metric Sensitivity Analysis\")\n    print(\"=\"*60)\n    print(results_df.round(4).to_string(index=False))\n    \n    return results_df\n\nmetric_analysis = analyze_metric_sensitivity()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T12:48:03.257703Z","iopub.execute_input":"2025-10-25T12:48:03.257950Z","iopub.status.idle":"2025-10-25T12:48:03.286680Z","shell.execute_reply.started":"2025-10-25T12:48:03.257930Z","shell.execute_reply":"2025-10-25T12:48:03.285764Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Practical Implementation for the Competition\n","metadata":{}},{"cell_type":"code","source":"# Complete evaluation metric implementation\nclass ForgeryDetectionMetrics:\n    def __init__(self, threshold=0.5):\n        self.threshold = threshold\n        self.scores = {}\n    \n    def rle_decode(self, mask_rle, shape):\n        \"\"\"\n        Decode run-length encoded mask\n        \"\"\"\n        if mask_rle == 'authentic' or pd.isna(mask_rle):\n            return np.zeros(shape, dtype=np.uint8)\n        \n        s = mask_rle.split()\n        starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n        starts -= 1\n        ends = starts + lengths\n        mask = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n        \n        for lo, hi in zip(starts, ends):\n            mask[lo:hi] = 1\n        \n        return mask.reshape(shape)\n    \n    def calculate_metrics(self, y_true_masks, y_pred_masks):\n        \"\"\"\n        Calculate all relevant metrics for the competition\n        \"\"\"\n        dice_scores = []\n        iou_scores = []\n        f1_scores = []\n        \n        for true_mask, pred_mask in zip(y_true_masks, y_pred_masks):\n            # Ensure binary masks\n            true_binary = (true_mask > self.threshold).astype(np.uint8)\n            pred_binary = (pred_mask > self.threshold).astype(np.uint8)\n            \n            dice = calculate_dice_coefficient(true_binary, pred_binary)\n            iou = calculate_iou(true_binary, pred_binary)\n            f1, precision, recall = competition_f1_variant(true_binary, pred_binary)\n            \n            dice_scores.append(dice)\n            iou_scores.append(iou)\n            f1_scores.append(f1)\n        \n        self.scores = {\n            'dice_mean': np.mean(dice_scores),\n            'dice_std': np.std(dice_scores),\n            'iou_mean': np.mean(iou_scores),\n            'iou_std': np.std(iou_scores),\n            'f1_mean': np.mean(f1_scores),\n            'f1_std': np.std(f1_scores),\n            'individual_dice': dice_scores,\n            'individual_iou': iou_scores\n        }\n        \n        return self.scores\n    \n    def plot_metric_distribution(self):\n        \"\"\"\n        Plot distribution of metrics across test samples\n        \"\"\"\n        fig, axes = plt.subplots(1, 2, figsize=(12, 5))\n        \n        # Dice distribution\n        axes[0].hist(self.scores['individual_dice'], bins=20, alpha=0.7, color='skyblue')\n        axes[0].axvline(self.scores['dice_mean'], color='red', linestyle='--', label=f'Mean: {self.scores[\"dice_mean\"]:.3f}')\n        axes[0].set_xlabel('Dice Coefficient')\n        axes[0].set_ylabel('Frequency')\n        axes[0].set_title('Distribution of Dice Scores')\n        axes[0].legend()\n        axes[0].grid(alpha=0.3)\n        \n        # IoU distribution\n        axes[1].hist(self.scores['individual_iou'], bins=20, alpha=0.7, color='lightcoral')\n        axes[1].axvline(self.scores['iou_mean'], color='red', linestyle='--', label=f'Mean: {self.scores[\"iou_mean\"]:.3f}')\n        axes[1].set_xlabel('IoU Score')\n        axes[1].set_ylabel('Frequency')\n        axes[1].set_title('Distribution of IoU Scores')\n        axes[1].legend()\n        axes[1].grid(alpha=0.3)\n        \n        plt.tight_layout()\n        plt.show()\n\n# Example usage\nmetrics_calculator = ForgeryDetectionMetrics()\n\nprint(\"\\n🎯 Key Takeaways for the Competition:\")\nprint(\"=\"*50)\nprint(\"1. ✅ USE: Dice/F1 Score & IoU - They handle class imbalance well\")\nprint(\"2. ✅ USE: Competition's F1 variant - Follows official evaluation\")\nprint(\"3. ❌ AVOID: Raw Accuracy - Misleading with imbalanced data\")\nprint(\"4. 📊 MONITOR: Both Precision and Recall - Balance detection quality\")\nprint(\"5. 🔍 ANALYZE: Metric distributions - Don't just look at averages\")\n\nprint(\"\\nFor this competition, focus on optimizing the Dice/F1 score as it\")\nprint(\"directly measures how well your model detects and segments forgeries,\")\nprint(\"ignoring the easy background predictions that inflate accuracy.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T12:48:03.287641Z","iopub.execute_input":"2025-10-25T12:48:03.287910Z","iopub.status.idle":"2025-10-25T12:48:03.312720Z","shell.execute_reply.started":"2025-10-25T12:48:03.287887Z","shell.execute_reply":"2025-10-25T12:48:03.311651Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### This comprehensive metrics section explains why traditional accuracy is problematic for this task and provides practical implementations of the appropriate metrics for evaluating your forgery detection models.","metadata":{}},{"cell_type":"markdown","source":"<h1 style=\"text-align:center; color:#3C91E6; font-size:2.2em; margin-bottom:0;\">🧠 Image Segmentation for Forgery Detection</h1>\n\n<p style=\"text-align:center; color:#6C757D;\">Comprehensive review of image segmentation techniques, from traditional to deep learning approaches.</p>\n\n<hr>\n\n<h2>🏛️ Traditional Segmentation Methods</h2>\n\n<p>Before the rise of deep learning, image segmentation relied on mathematical models and low-level features like intensity and texture. The following table summarizes their key characteristics, which are useful for understanding the fundamentals of image analysis:</p>\n\n<table style=\"width:100%; border-collapse:collapse; text-align:left;\">\n  <thead style=\"background-color:#E8F0FE;\">\n    <tr>\n      <th style=\"padding:8px; border:1px solid #ccc;\">Method Type</th>\n      <th style=\"padding:8px; border:1px solid #ccc;\">Key Idea</th>\n      <th style=\"padding:8px; border:1px solid #ccc;\">Strengths</th>\n      <th style=\"padding:8px; border:1px solid #ccc;\">Weaknesses in Medical/Forgery Context</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Thresholding</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Converts a grayscale image to binary based on a pixel value threshold.</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Computationally efficient, simple to implement.</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Struggles with intensity variations, noise, and complex structures.</td>\n    </tr>\n    <tr>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Edge-Based</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Detects boundaries between regions by finding sharp intensity changes.</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Good at identifying clear contours.</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Sensitive to noise; struggles with discontinuous or blurred edges common in medical images.</td>\n    </tr>\n    <tr>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Region-Based</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Groups pixels with similar properties into contiguous regions.</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Can produce coherent regions.</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Often requires manual seed points; performance depends on initial choices.</td>\n    </tr>\n    <tr>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Clustering</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Groups pixels into clusters based on feature similarity (e.g., K-Means).</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Unsupervised; no need for labeled data.</td>\n      <td style=\"padding:8px; border:1px solid #ccc;\">Struggles with complex shapes and high variability of forged regions.</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2>🧠 Deep Learning Revolution</h2>\n\n<p>Deep learning, particularly Convolutional Neural Networks (CNNs), has dramatically improved segmentation performance by automatically learning hierarchical features from data.</p>\n\n<p>Fully Convolutional Networks (FCNs) were a pivotal step, demonstrating that networks could perform dense pixel-wise prediction, which is the foundation of modern segmentation models.</p>\n\n<h2>🔬 Key Deep Learning Architectures</h2>\n\n<ul>\n  <li><strong>U-Net and its Variants:</strong> The U-Net architecture, with its encoder-decoder structure and skip connections, has become a cornerstone in medical image segmentation. It is highly effective even with limited training data.</li>\n  <li><strong>VANet:</strong> Designed for polyp segmentation in colonoscopy images, it enhances boundary perception, a critical feature for precise forgery masking.</li>\n  <li><strong>VM-UNet and Mamba-UNet:</strong> Recent architectures integrating Vision Transformers or state-space models to capture global context better.</li>\n  <li><strong>Generative Adversarial Networks (GANs):</strong> Used to generate synthetic data and improve segmentation, especially in limited annotated datasets.</li>\n  <li><strong>Transformers:</strong> Excel at modeling long-range dependencies, valuable for identifying large or context-dependent forgeries.</li>\n  <li><strong>Segment Anything Model (SAM):</strong> A foundational model capable of generalizing to new objects with minimal prompts. Adapted versions like DeSAM enhance medical segmentation efficiency.</li>\n</ul>\n\n<h2>⚙️ Optimization Methods for Training</h2>\n\n<p>Choosing the right optimizer is crucial for efficiently training these deep models. While Stochastic Gradient Descent (SGD) is a classic choice, adaptive optimizers are often preferred:</p>\n\n<ul>\n  <li><strong>Adam:</strong> Combines momentum and adaptive learning rates for each parameter.</li>\n  <li><strong>AdamW:</strong> Decouples weight decay from gradient update for better generalization.</li>\n  <li><strong>NovoGrad:</strong> A layer-wise adaptive optimizer, more stable and memory-efficient.</li>\n</ul>\n\n<h2>📊 Practical Considerations for the Competition</h2>\n\n<ul>\n  <li><strong>Leverage Pre-trained Models and Benchmarks:</strong> Use PyTorch or TensorFlow frameworks and pre-trained models. Benchmarks like MedSegBench provide robust standards for evaluation.</li>\n  <li><strong>Address the \"Black Box\" Problem with XAI:</strong> Apply Explainable AI (XAI) methods to visualize and interpret model decisions for trust and transparency.</li>\n  <li><strong>Start Simple and Iterate:</strong> Begin with U-Net as a baseline, then explore advanced architectures like Vision Transformers or U-Net++ to optimize performance.</li>\n</ul>\n\n<hr>\n\n\n","metadata":{}},{"cell_type":"markdown","source":"<h2 style=\"text-align:center; color:#3C91E6; font-size:2em; margin-top:10px;\">⚔️ U-Net vs Mask R-CNN: Which Model Should You Choose?</h2>\n\n<p style=\"font-size:1.05em; color:#444; text-align:justify;\">\nBased on current research and benchmarking studies, both <strong>U-Net</strong> and <strong>Mask R-CNN</strong> are top-tier candidates for segmentation in this competition. \nU-Net often achieves <strong>higher pixel-level accuracy</strong>, while Mask R-CNN offers the flexibility of <strong>instance-level detection</strong>. \nThe table below highlights their main differences to help you make an informed choice.\n</p>\n\n<table style=\"width:100%; border-collapse:collapse; text-align:left; margin-top:15px;\">\n  <thead style=\"background-color:#E8F0FE;\">\n    <tr>\n      <th style=\"padding:10px; border:1px solid #ccc;\">Feature</th>\n      <th style=\"padding:10px; border:1px solid #ccc;\">U-Net <span style=\"color:#3C91E6;\">(Recommended)</span></th>\n      <th style=\"padding:10px; border:1px solid #ccc;\">Mask R-CNN</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Architecture Type</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Semantic Segmentation</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Instance Segmentation</td>\n    </tr>\n    <tr>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Core Strength</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Pixel-level classification with highly precise boundaries</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Distinguishes between individual object instances</td>\n    </tr>\n    <tr>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Ideal For</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">This competition's goal — detecting forged or manipulated regions</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Scenes with multiple, distinct objects</td>\n    </tr>\n    <tr>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Key Advantage</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Superior Dice/IoU scores in biomedical and forgery detection tasks</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Provides both bounding boxes and segmentation masks</td>\n    </tr>\n    <tr>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Performance (Example)</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Dice: 0.96, IoU: 0.97 <br><small>(Panoramic Radiographs)</small></td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Dice: 0.87, IoU: 0.74 <br><small>(Panoramic Radiographs)</small></td>\n    </tr>\n    <tr>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Computational Cost</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Generally lower — lightweight and fast</td>\n      <td style=\"padding:10px; border:1px solid #ccc;\">Higher — more complex due to multi-stage detection</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 style=\"margin-top:30px; color:#3C91E6;\">🛠️ How to Implement U-Net (Step-by-Step)</h3>\n\n<p style=\"color:#444; text-align:justify;\">\nFor the highest segmentation accuracy, <strong>start with a standard U-Net</strong> implementation. Once it’s working reliably, you can enhance it with modern variants such as <strong>U-Net++</strong>, <strong>Attention U-Net</strong>, or <strong>ResUNet</strong> for improved boundary precision and generalization.\n</p>\n\n<h4 style=\"color:#333;\">Option 1: Build a Standard U-Net</h4>\n\n<p style=\"color:#555;\">This foundational approach constructs the classic encoder–decoder structure with skip connections that preserve fine spatial details:</p>\n\n\n","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.layers import *\nfrom tensorflow.keras.models import Model\n\ndef build_unet(input_size=(128, 128, 1)):\n    inputs = Input(input_size)\n    \n    # Encoder (Contracting Path)\n    c1 = Conv2D(64, (3, 3), activation='relu', padding='same')(inputs)\n    c1 = Conv2D(64, (3, 3), activation='relu', padding='same')(c1)\n    p1 = MaxPooling2D((2, 2))(c1)\n\n    c2 = Conv2D(128, (3, 3), activation='relu', padding='same')(p1)\n    c2 = Conv2D(128, (3, 3), activation='relu', padding='same')(c2)\n    p2 = MaxPooling2D((2, 2))(c2)\n\n    # Bottleneck\n    b = Conv2D(256, (3, 3), activation='relu', padding='same')(p2)\n    b = Conv2D(256, (3, 3), activation='relu', padding='same')(b)\n\n    # Decoder (Expanding Path)\n    u1 = Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(b)\n    u1 = concatenate([u1, c2])\n    u1 = Conv2D(128, (3, 3), activation='relu', padding='same')(u1)\n    u1 = Conv2D(128, (3, 3), activation='relu', padding='same')(u1)\n\n    u2 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(u1)\n    u2 = concatenate([u2, c1])\n    u2 = Conv2D(64, (3, 3), activation='relu', padding='same')(u2)\n    u2 = Conv2D(64, (3, 3), activation='relu', padding='same')(u2)\n\n    outputs = Conv2D(1, (1, 1), activation='sigmoid')(u2)\n    \n    model = Model(inputs=[inputs], outputs=[outputs])\n    return model\n\n# Build and compile the model\nmodel = build_unet()\nmodel.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T12:48:03.313931Z","iopub.execute_input":"2025-10-25T12:48:03.314260Z","iopub.status.idle":"2025-10-25T12:48:21.992722Z","shell.execute_reply.started":"2025-10-25T12:48:03.314231Z","shell.execute_reply":"2025-10-25T12:48:21.991870Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<!-- Advanced U-Net Strategies — ready to paste into a Markdown (text) cell in your Kaggle notebook -->\n<section>\n  <h2 style=\"color:#1F6FEB; margin-bottom:0.2em;\">Option 2: Advanced U-Net with Modern Enhancements</h2>\n  <p style=\"color:#333; font-size:1em; line-height:1.45;\">\n    To push a U-Net baseline toward state-of-the-art performance on the forgery detection task, combine loss, pretraining and architectural improvements from recent literature.  \n    Below are practical, research-backed recommendations with short explanations and implementation tips.\n  </p>\n\n  <div style=\"margin-top:0.8em; padding:12px; background:#F6FBFF; border-left:4px solid #1F6FEB; border-radius:8px;\">\n    <strong style=\"color:#1F6FEB;\">Summary — What to try</strong>\n    <ul style=\"margin-top:8px; color:#333;\">\n      <li>Optimize with a <strong>Dice (or Dice + BCE) loss</strong> to match the competition metric.</li>\n      <li>Use <strong>masked pretraining</strong> (self-supervised reconstruction) to leverage unlabeled data and improve feature learning.</li>\n      <li>Experiment with modern U-Net variants such as <strong>MS-UNet</strong> and <strong>U-Tunnel-Net</strong> for better feature preservation and efficiency.</li>\n    </ul>\n  </div>\n\n  <h3 style=\"color:#0B66C3; margin-top:1em;\">1) Loss: Dice (and Combo) — Why and how</h3>\n  <p style=\"color:#333; line-height:1.45;\">\n    Dice directly measures overlap between predicted and ground-truth masks and correlates with the competition F1-style metric. In practice, combining Dice with a pixel-wise loss (BCE) stabilizes training:\n  </p>\n\n  <pre style=\"background:#F8F9FA; padding:12px; border-radius:8px; overflow:auto; font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, 'Roboto Mono', monospace;\">\n# PyTorch: simple combined Dice + BCE loss\nimport torch\nimport torch.nn.functional as F\n\ndef dice_loss(pred, target, eps=1e-6):\n    # pred: logits or probabilities\n    pred = torch.sigmoid(pred).view(-1)\n    target = target.view(-1).float()\n    intersection = (pred * target).sum()\n    return 1 - (2. * intersection + eps) / (pred.sum() + target.sum() + eps)\n\ndef bce_dice_loss(logits, target, bce_weight=0.5):\n    bce = F.binary_cross_entropy_with_logits(logits, target.float())\n    d_loss = dice_loss(logits, target)\n    return bce_weight * bce + (1 - bce_weight) * d_loss\n  </pre>\n\n  <h3 style=\"color:#0B66C3; margin-top:1em;\">2) Masked Pretraining (Self-Supervised) — What & Why</h3>\n  <p style=\"color:#333; line-height:1.45;\">\n    Masked pretraining asks the network to reconstruct randomly masked image patches. This forces the encoder and decoder to learn strong context and texture priors without labels. Benefits:\n  </p>\n  <ul style=\"color:#333;\">\n    <li>Improves sample efficiency when labeled masks are scarce.</li>\n    <li>Helps the model learn domain-specific textures typical of biomedical images (microscopy, gels, charts).</li>\n    <li>Often yields measurable gains after fine-tuning on the labeled task.</li>\n  </ul>\n\n  <p style=\"color:#333;\">\n    <strong>Practical recipe:</strong> pretrain the U-Net to predict the original pixels for randomly masked patches (e.g., 25–50% of pixels masked). Use L1 or L2 reconstruction loss. Then fine-tune with the segmentation loss on labeled masks.\n  </p>\n\n  <h3 style=\"color:#0B66C3; margin-top:1em;\">3) Modern U-Net Variants to Try</h3>\n  <p style=\"color:#333; line-height:1.45;\">\n    Replace or augment the vanilla U-Net building blocks with these modern ideas to improve receptive field, boundary accuracy, and parameter efficiency:\n  </p>\n\n  <table style=\"width:100%; border-collapse:collapse; margin-top:0.6em;\">\n    <thead style=\"background:#EEF6FF;\">\n      <tr>\n        <th style=\"padding:8px; text-align:left; border:1px solid #E1ECFF;\">Variant</th>\n        <th style=\"padding:8px; text-align:left; border:1px solid #E1ECFF;\">Core Idea</th>\n        <th style=\"padding:8px; text-align:left; border:1px solid #E1ECFF;\">Why it helps</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td style=\"padding:8px; border:1px solid #E1ECFF;\">MS-UNet</td>\n        <td style=\"padding:8px; border:1px solid #E1ECFF;\">Multi-scale feature fusion across encoder/decoder levels</td>\n        <td style=\"padding:8px; border:1px solid #E1ECFF;\">Captures both fine details and global context with fewer parameters</td>\n      </tr>\n      <tr>\n        <td style=\"padding:8px; border:1px solid #E1ECFF;\">U-Tunnel-Net</td>\n        <td style=\"padding:8px; border:1px solid #E1ECFF;\">Improved feature preservation via enhanced skip-path design and residual tunnels</td>\n        <td style=\"padding:8px; border:1px solid #E1ECFF;\">Better restoration of subtle textures and boundaries — ideal for small forged patches</td>\n      </tr>\n      <tr>\n        <td style=\"padding:8px; border:1px solid #E1ECFF;\">Attention U-Net</td>\n        <td style=\"padding:8px; border:1px solid #E1ECFF;\">Gates that reweight encoder features before skip connections</td>\n        <td style=\"padding:8px; border:1px solid #E1ECFF;\">Focuses model capacity on relevant regions, reducing false positives</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <h3 style=\"color:#0B66C3; margin-top:1em;\">4) Implementation Tips & Workflow</h3>\n  <ol style=\"color:#333;\">\n    <li><strong>Pretrain</strong> with masked reconstruction on all available images (train + unlabeled data) for several epochs.</li>\n    <li><strong>Initialize</strong> the segmentation U-Net with encoder weights from the pretrained model.</li>\n    <li><strong>Train</strong> with the combined Dice + BCE loss, using strong augmentations (copy-paste, elastic, brightness/contrast) that preserve biological plausibility.</li>\n    <li><strong>Post-process</strong> predictions with morphological ops (open/close) and small-object removal to reduce noise.</li>\n    <li><strong>Calibrate</strong> the probability threshold on a validation split to balance false positives vs false negatives (important for \"authentic\" images).</li>\n  </ol>\n\n  <div style=\"margin-top:0.8em; padding:12px; background:#FFF8E8; border-left:4px solid #F5A623; border-radius:8px;\">\n    <strong>Quick practical note:</strong> if GPU memory is limited, prefer MS-UNet or attention modules over very deep transformer blocks — they give strong gains with lower compute cost.\n  </div>\n\n  <p style=\"color:#333; margin-top:1em;\">\n    If you want, I can now generate:\n    <ul>\n      <li>an editable PyTorch notebook cell that implements masked pretraining for U-Net,</li>\n      <li>a ready-to-run training loop using the combined Dice+BCE loss, or</li>\n      <li>code templates for MS-UNet and U-Tunnel-Net you can plug into your Kaggle notebook.</li>\n    </ul>\n  </p>\n</section>\n","metadata":{}},{"cell_type":"markdown","source":"<h3>🚀 Step-by-Step Implementation Guide</h3>\n\n<ol>\n  <li>\n    <strong>1️⃣ Data Preparation</strong><br>\n    - Organize your dataset into <code>train</code>, <code>validation</code>, and <code>test</code> folders.<br>\n    - Apply data augmentation techniques (flips, rotations, brightness adjustments) to improve generalization.<br>\n    - Normalize pixel values to the [0, 1] range for stable training.\n  </li>\n  \n  <li>\n    <strong>2️⃣ Model Construction</strong><br>\n    - Build your U-Net architecture using PyTorch or TensorFlow.<br>\n    - Implement skip connections to preserve spatial features.<br>\n    - Optionally, use pretrained encoders like <code>ResNet34</code> or <code>EfficientNet-B0</code> for faster convergence.\n  </li>\n  \n  <li>\n    <strong>3️⃣ Loss Function & Metrics</strong><br>\n    - Combine <code>Dice Loss</code> with <code>Binary Cross-Entropy</code> for balanced learning.<br>\n    - Track metrics such as <strong>Dice Score</strong>, <strong>IoU</strong>, and <strong>Precision</strong> after each epoch.<br>\n    - Implement early stopping based on validation Dice score.\n  </li>\n\n  <li>\n    <strong>4️⃣ Training Strategy</strong><br>\n    - Start with a small learning rate (e.g., <code>1e-4</code>) and use a scheduler like <code>ReduceLROnPlateau</code>.<br>\n    - Train for 30–50 epochs depending on dataset size.<br>\n    - Monitor loss and metrics using <code>TensorBoard</code> or <code>Weights & Biases</code> for better visualization.\n  </li>\n\n  <li>\n    <strong>5️⃣ Post-Processing</strong><br>\n    - Apply thresholding (e.g., 0.5) to convert predicted masks into binary form.<br>\n    - Use morphological operations (opening/closing) to remove small artifacts.<br>\n    - Optionally, smooth boundaries with Gaussian filtering for clean segmentation results.\n  </li>\n\n  <li>\n    <strong>6️⃣ Evaluation & Comparison</strong><br>\n    - Compare results between <strong>Standard U-Net</strong> and <strong>Enhanced U-Net</strong> variants.<br>\n    - Visualize sample predictions with overlayed ground truth masks.<br>\n    - Report <strong>Dice</strong>, <strong>IoU</strong>, and <strong>F1-score</strong> in a summary table for clarity.\n  </li>\n\n  \n</ol>\n\n<p><strong>💡 Pro Tip:</strong> Always validate results on unseen data and monitor overfitting. Visual inspection is key in segmentation tasks — numbers alone don't tell the full story!</p>\n","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}