{
  "id": 579768,
  "title": "10th_solution_text_only",
  "url": "/competitions/el-hackathon-2025/writeups/ding-yang-wang-10th-solution-text-only",
  "author_name": "",
  "post_date": "2025-05-20T08:23:25.644663300Z",
  "votes": 7,
  "comment_count": 6,
  "views": 0,
  "content": "<p><a href=\"https://github.com/Dewey-Wang/HEVisum/tree/main\" target=\"_blank\">https://github.com/Dewey-Wang/HEVisum/tree/main</a><br>\nYou can see my whole solution within my github</p>\n<p>This is my original file. I will also post my solution and integrate code later on the repo. If you want to know my solution, stay tune! Feel free to ask me any question!</p>\n<hr>\n<h1>1. Search Studies</h1>\n<ul>\n<li><a href=\"https://www.nature.com/articles/s41467-025-56618-y\" target=\"_blank\">Benchmarking the translational potential of spatial gene expression prediction from histology</a>  </li>\n<li><a href=\"https://www.medrxiv.org/content/10.1101/2025.02.09.25321567v1\" target=\"_blank\">DeepSpot: Leveraging Spatial Context for Enhanced Spatial Transcriptomics Prediction from H&amp;E Images</a>  </li>\n</ul>\n<blockquote>\n  <p>These papers survey state-of-the-art techniques for predicting spatial gene expression from H&amp;E histology images.</p>\n</blockquote>\n<hr>\n<h1>2. Exploratory Data Analysis (EDA)</h1>\n<ul>\n<li><a href=\"https://www.kaggle.com/code/tarundirector/histology-eda-spotnet-visual-spatial-dl\" target=\"_blank\">https://www.kaggle.com/code/tarundirector/histology-eda-spotnet-visual-spatial-dl</a>  </li>\n<li><a href=\"https://www.kaggle.com/code/dalloliogm/eda-exploring-cell-type-abundance\" target=\"_blank\">https://www.kaggle.com/code/dalloliogm/eda-exploring-cell-type-abundance</a>  </li>\n<li><a href=\"https://www.kaggle.com/code/prajwaldongreonly-eda-you-need-to-understand-this-data\" target=\"_blank\">https://www.kaggle.com/code/prajwaldongreonly-eda-you-need-to-understand-this-data</a>  </li>\n</ul>\n<blockquote>\n  <p>Use these notebooks to visualize spot distributions, cell-type abundances, and other spatial features.</p>\n</blockquote>\n<hr>\n<h1>3. Data Preprocessing</h1>\n<h2>3.1 Image Data</h2>\n<ol>\n<li><strong>Stain normalization</strong>  (One of the most important step) <ul>\n<li>Essential for reducing color variability across slides.  </li>\n<li>Sample patches from all images to compute stable normalization parameters.  </li></ul></li>\n<li><strong>Background masking</strong>  <ul>\n<li>Grayscale: <code>gray = rgb2gray(image)</code>  </li>\n<li>Threshold: <code>mask = gray &lt;= mean_threshold</code>  </li>\n<li>Closing: <code>closing(mask, disk(2))</code>  </li>\n<li>Fill holes: <code>remove_small_holes(..., area_threshold=5000)</code>  </li>\n<li><strong>Output:</strong> clean binary tissue mask  </li></ul></li>\n</ol>\n<h2>3.2 Spot Data</h2>\n<ol>\n<li><strong>Expression ranking</strong>  (One of the most important step) <ul>\n<li>Replace raw counts with rank values. (I also check UMAP with them to see which combination or replacement would be better to let the ML to predict. In the end replace with rank us the most promising one.)</li></ul></li>\n<li><strong>Spot realignment</strong>  <ul>\n<li>Minor effect if background spots are already filtered out.</li></ul></li>\n</ol>\n<hr>\n<h1>4. Model Preparation</h1>\n<h2>4.1 Encoder</h2>\n<h3>DeepTileEncoder</h3>\n<ul>\n<li><strong>Input size:</strong> <code>[B, 3, 78, 78]</code>  </li>\n<li><strong>Purpose:</strong> Processes the entire 78×78 tile (from spot coordinates).  </li>\n<li><strong>Residual blocks:</strong> Stacked <code>ResidualBlock</code>s (two 3×3 Conv + BN + SiLU; 1×1 Conv shortcut if needed)  </li>\n<li><strong>Multi-scale pooling:</strong>  <ul>\n<li>Global: <code>AdaptiveAvgPool2d(1×1)</code> → <code>[B,256]</code>  </li>\n<li>Mid-scale: <code>AdaptiveAvgPool2d(3×3)</code> → <code>[B,256×3×3]</code>  </li></ul></li>\n<li><strong>MLP (3 layers):</strong>  </li>\n</ul>\n<h3>SubtileEncoder</h3>\n<ul>\n<li><strong>Input size:</strong> <code>[B, 9, 3, 26, 26]</code>  </li>\n<li><strong>Purpose:</strong> Captures local details from 9 subtiles.  </li>\n<li><strong>Residual blocks:</strong> Applied after reshaping to <code>[B×9, 3, 26, 26]</code>  </li>\n<li><strong>Multi-scale pooling (per patch):</strong>  <ul>\n<li>Global 1×1 → <code>[B×9,128]</code>  </li>\n<li>Mid 2×2 → <code>[B×9,128×2×2]</code>  </li>\n<li>Large 3×3 → <code>[B×9,128×3×3]</code>  </li></ul></li>\n<li><strong>Aggregation:</strong>  <ol>\n<li>Reshape to <code>[B, 9, total_dim]</code>  </li>\n<li>Average over 9 → <code>[B, total_dim]</code>  </li></ol></li>\n<li><strong>MLP (2 layers):</strong>  </li>\n</ul>\n<h3>CenterSubtileEncoder</h3>\n<ul>\n<li><strong>Input size:</strong> <code>[B, 3, 26, 26]</code>  </li>\n<li><strong>Purpose:</strong> Focuses on the single central patch.  </li>\n<li><strong>Structure:</strong> Same as SubtileEncoder but only for the center.  </li>\n<li><strong>Multi-scale pooling:</strong> 1×1, 2×2, 3×3 → concatenate → Flatten  </li>\n<li><strong>MLP (2 layers):</strong> </li>\n</ul>\n<hr>\n<h2>4.2 Decoder</h2>\n<ol>\n<li><strong>Concatenate:</strong> <code>[tile_dim] + [subtile_dim] + [subtile_dim]</code> → <code>[B, tile_dim+2×subtile_dim]</code>  </li>\n<li><strong>Four-layer MLP:</strong>  </li>\n<li><strong>Output:</strong> Multi-task prediction vector of length <code>output_dim</code>, which is 35.</li>\n</ol>\n<p><strong>Loss function:</strong> Mean Squared Error (MSE)</p>\n<hr>\n<h1>5. Training Strategy</h1>\n<h2>5.1 Leave-One-Out (LOO) Cross-Validation</h2>\n<ul>\n<li>Six folds → six models.</li>\n</ul>\n<h2>5.2 Model Stacking</h2>\n<ol>\n<li>Use each of the six models to predict on all samples → produce a dataframe of shape <code>(spots_n, 35 × 6)</code>.  </li>\n<li>Train a small MLP on this dataframe → final output <code>(spots_n, 35)</code>.  <ul>\n<li>Learns to weight each fold’s prediction adaptively.</li></ul></li>\n</ol>\n<hr>\n<h1>Optimization Notes</h1>\n<ol>\n<li><strong>Model structure:</strong> Residual + multi-scale design proved most stable.  </li>\n<li><strong>Input size:</strong> 78×78 tile + 9×26×26 subtiles + center 26×26 gave best results.  </li>\n<li><strong>Patch size choice:</strong> Mean spot spacing ≈ 26 px, so 3×26 covers full receptive field. That's why I use 26*3 as the global vision for input and 26 as the local vesion.</li>\n</ol>\n<h1>Future Improvements</h1>\n<ul>\n<li>Diversify stacked models to increase ensemble variance.  </li>\n</ul>",
  "messages": [
    {
      "id": "3205686",
      "postDate": "05/20/2025 08:23:25",
      "content": "<p><a href=\"https://github.com/Dewey-Wang/HEVisum/tree/main\" target=\"_blank\">https://github.com/Dewey-Wang/HEVisum/tree/main</a><br>\nYou can see my whole solution within my github</p>\n<p>This is my original file. I will also post my solution and integrate code later on the repo. If you want to know my solution, stay tune! Feel free to ask me any question!</p>\n<hr>\n<h1>1. Search Studies</h1>\n<ul>\n<li><a href=\"https://www.nature.com/articles/s41467-025-56618-y\" target=\"_blank\">Benchmarking the translational potential of spatial gene expression prediction from histology</a>  </li>\n<li><a href=\"https://www.medrxiv.org/content/10.1101/2025.02.09.25321567v1\" target=\"_blank\">DeepSpot: Leveraging Spatial Context for Enhanced Spatial Transcriptomics Prediction from H&amp;E Images</a>  </li>\n</ul>\n<blockquote>\n  <p>These papers survey state-of-the-art techniques for predicting spatial gene expression from H&amp;E histology images.</p>\n</blockquote>\n<hr>\n<h1>2. Exploratory Data Analysis (EDA)</h1>\n<ul>\n<li><a href=\"https://www.kaggle.com/code/tarundirector/histology-eda-spotnet-visual-spatial-dl\" target=\"_blank\">https://www.kaggle.com/code/tarundirector/histology-eda-spotnet-visual-spatial-dl</a>  </li>\n<li><a href=\"https://www.kaggle.com/code/dalloliogm/eda-exploring-cell-type-abundance\" target=\"_blank\">https://www.kaggle.com/code/dalloliogm/eda-exploring-cell-type-abundance</a>  </li>\n<li><a href=\"https://www.kaggle.com/code/prajwaldongreonly-eda-you-need-to-understand-this-data\" target=\"_blank\">https://www.kaggle.com/code/prajwaldongreonly-eda-you-need-to-understand-this-data</a>  </li>\n</ul>\n<blockquote>\n  <p>Use these notebooks to visualize spot distributions, cell-type abundances, and other spatial features.</p>\n</blockquote>\n<hr>\n<h1>3. Data Preprocessing</h1>\n<h2>3.1 Image Data</h2>\n<ol>\n<li><strong>Stain normalization</strong>  (One of the most important step) <ul>\n<li>Essential for reducing color variability across slides.  </li>\n<li>Sample patches from all images to compute stable normalization parameters.  </li></ul></li>\n<li><strong>Background masking</strong>  <ul>\n<li>Grayscale: <code>gray = rgb2gray(image)</code>  </li>\n<li>Threshold: <code>mask = gray &lt;= mean_threshold</code>  </li>\n<li>Closing: <code>closing(mask, disk(2))</code>  </li>\n<li>Fill holes: <code>remove_small_holes(..., area_threshold=5000)</code>  </li>\n<li><strong>Output:</strong> clean binary tissue mask  </li></ul></li>\n</ol>\n<h2>3.2 Spot Data</h2>\n<ol>\n<li><strong>Expression ranking</strong>  (One of the most important step) <ul>\n<li>Replace raw counts with rank values. (I also check UMAP with them to see which combination or replacement would be better to let the ML to predict. In the end replace with rank us the most promising one.)</li></ul></li>\n<li><strong>Spot realignment</strong>  <ul>\n<li>Minor effect if background spots are already filtered out.</li></ul></li>\n</ol>\n<hr>\n<h1>4. Model Preparation</h1>\n<h2>4.1 Encoder</h2>\n<h3>DeepTileEncoder</h3>\n<ul>\n<li><strong>Input size:</strong> <code>[B, 3, 78, 78]</code>  </li>\n<li><strong>Purpose:</strong> Processes the entire 78×78 tile (from spot coordinates).  </li>\n<li><strong>Residual blocks:</strong> Stacked <code>ResidualBlock</code>s (two 3×3 Conv + BN + SiLU; 1×1 Conv shortcut if needed)  </li>\n<li><strong>Multi-scale pooling:</strong>  <ul>\n<li>Global: <code>AdaptiveAvgPool2d(1×1)</code> → <code>[B,256]</code>  </li>\n<li>Mid-scale: <code>AdaptiveAvgPool2d(3×3)</code> → <code>[B,256×3×3]</code>  </li></ul></li>\n<li><strong>MLP (3 layers):</strong>  </li>\n</ul>\n<h3>SubtileEncoder</h3>\n<ul>\n<li><strong>Input size:</strong> <code>[B, 9, 3, 26, 26]</code>  </li>\n<li><strong>Purpose:</strong> Captures local details from 9 subtiles.  </li>\n<li><strong>Residual blocks:</strong> Applied after reshaping to <code>[B×9, 3, 26, 26]</code>  </li>\n<li><strong>Multi-scale pooling (per patch):</strong>  <ul>\n<li>Global 1×1 → <code>[B×9,128]</code>  </li>\n<li>Mid 2×2 → <code>[B×9,128×2×2]</code>  </li>\n<li>Large 3×3 → <code>[B×9,128×3×3]</code>  </li></ul></li>\n<li><strong>Aggregation:</strong>  <ol>\n<li>Reshape to <code>[B, 9, total_dim]</code>  </li>\n<li>Average over 9 → <code>[B, total_dim]</code>  </li></ol></li>\n<li><strong>MLP (2 layers):</strong>  </li>\n</ul>\n<h3>CenterSubtileEncoder</h3>\n<ul>\n<li><strong>Input size:</strong> <code>[B, 3, 26, 26]</code>  </li>\n<li><strong>Purpose:</strong> Focuses on the single central patch.  </li>\n<li><strong>Structure:</strong> Same as SubtileEncoder but only for the center.  </li>\n<li><strong>Multi-scale pooling:</strong> 1×1, 2×2, 3×3 → concatenate → Flatten  </li>\n<li><strong>MLP (2 layers):</strong> </li>\n</ul>\n<hr>\n<h2>4.2 Decoder</h2>\n<ol>\n<li><strong>Concatenate:</strong> <code>[tile_dim] + [subtile_dim] + [subtile_dim]</code> → <code>[B, tile_dim+2×subtile_dim]</code>  </li>\n<li><strong>Four-layer MLP:</strong>  </li>\n<li><strong>Output:</strong> Multi-task prediction vector of length <code>output_dim</code>, which is 35.</li>\n</ol>\n<p><strong>Loss function:</strong> Mean Squared Error (MSE)</p>\n<hr>\n<h1>5. Training Strategy</h1>\n<h2>5.1 Leave-One-Out (LOO) Cross-Validation</h2>\n<ul>\n<li>Six folds → six models.</li>\n</ul>\n<h2>5.2 Model Stacking</h2>\n<ol>\n<li>Use each of the six models to predict on all samples → produce a dataframe of shape <code>(spots_n, 35 × 6)</code>.  </li>\n<li>Train a small MLP on this dataframe → final output <code>(spots_n, 35)</code>.  <ul>\n<li>Learns to weight each fold’s prediction adaptively.</li></ul></li>\n</ol>\n<hr>\n<h1>Optimization Notes</h1>\n<ol>\n<li><strong>Model structure:</strong> Residual + multi-scale design proved most stable.  </li>\n<li><strong>Input size:</strong> 78×78 tile + 9×26×26 subtiles + center 26×26 gave best results.  </li>\n<li><strong>Patch size choice:</strong> Mean spot spacing ≈ 26 px, so 3×26 covers full receptive field. That's why I use 26*3 as the global vision for input and 26 as the local vesion.</li>\n</ol>\n<h1>Future Improvements</h1>\n<ul>\n<li>Diversify stacked models to increase ensemble variance.  </li>\n</ul>",
      "rawMarkdown": "https://github.com/Dewey-Wang/HEVisum/tree/main\nYou can see my whole solution within my github\n\nThis is my original file. I will also post my solution and integrate code later on the repo. If you want to know my solution, stay tune! Feel free to ask me any question!\n\n---\n\n# 1. Search Studies\n\n- [Benchmarking the translational potential of spatial gene expression prediction from histology](https://www.nature.com/articles/s41467-025-56618-y)  \n- [DeepSpot: Leveraging Spatial Context for Enhanced Spatial Transcriptomics Prediction from H&E Images](https://www.medrxiv.org/content/10.1101/2025.02.09.25321567v1)  \n\n> These papers survey state-of-the-art techniques for predicting spatial gene expression from H&E histology images.\n\n---\n\n# 2. Exploratory Data Analysis (EDA)\n\n- https://www.kaggle.com/code/tarundirector/histology-eda-spotnet-visual-spatial-dl  \n- https://www.kaggle.com/code/dalloliogm/eda-exploring-cell-type-abundance  \n- https://www.kaggle.com/code/prajwaldongreonly-eda-you-need-to-understand-this-data  \n\n> Use these notebooks to visualize spot distributions, cell-type abundances, and other spatial features.\n\n---\n\n# 3. Data Preprocessing\n\n## 3.1 Image Data  \n1. **Stain normalization**  (One of the most important step) \n   - Essential for reducing color variability across slides.  \n   - Sample patches from all images to compute stable normalization parameters.  \n2. **Background masking**  \n   - Grayscale: `gray = rgb2gray(image)`  \n   - Threshold: `mask = gray <= mean_threshold`  \n   - Closing: `closing(mask, disk(2))`  \n   - Fill holes: `remove_small_holes(..., area_threshold=5000)`  \n   - **Output:** clean binary tissue mask  \n\n## 3.2 Spot Data  \n1. **Expression ranking**  (One of the most important step) \n   - Replace raw counts with rank values. (I also check UMAP with them to see which combination or replacement would be better to let the ML to predict. In the end replace with rank us the most promising one.)\n2. **Spot realignment**  \n   - Minor effect if background spots are already filtered out.\n\n---\n\n# 4. Model Preparation\n\n## 4.1 Encoder\n\n### DeepTileEncoder  \n- **Input size:** `[B, 3, 78, 78]`  \n- **Purpose:** Processes the entire 78×78 tile (from spot coordinates).  \n- **Residual blocks:** Stacked `ResidualBlock`s (two 3×3 Conv + BN + SiLU; 1×1 Conv shortcut if needed)  \n- **Multi-scale pooling:**  \n  - Global: `AdaptiveAvgPool2d(1×1)` → `[B,256]`  \n  - Mid-scale: `AdaptiveAvgPool2d(3×3)` → `[B,256×3×3]`  \n- **MLP (3 layers):**  \n\n\n### SubtileEncoder  \n- **Input size:** `[B, 9, 3, 26, 26]`  \n- **Purpose:** Captures local details from 9 subtiles.  \n- **Residual blocks:** Applied after reshaping to `[B×9, 3, 26, 26]`  \n- **Multi-scale pooling (per patch):**  \n  - Global 1×1 → `[B×9,128]`  \n  - Mid 2×2 → `[B×9,128×2×2]`  \n  - Large 3×3 → `[B×9,128×3×3]`  \n- **Aggregation:**  \n  1. Reshape to `[B, 9, total_dim]`  \n  2. Average over 9 → `[B, total_dim]`  \n- **MLP (2 layers):**  \n\n\n### CenterSubtileEncoder  \n- **Input size:** `[B, 3, 26, 26]`  \n- **Purpose:** Focuses on the single central patch.  \n- **Structure:** Same as SubtileEncoder but only for the center.  \n- **Multi-scale pooling:** 1×1, 2×2, 3×3 → concatenate → Flatten  \n- **MLP (2 layers):** \n\n---\n\n## 4.2 Decoder\n\n1. **Concatenate:** `[tile_dim] + [subtile_dim] + [subtile_dim]` → `[B, tile_dim+2×subtile_dim]`  \n2. **Four-layer MLP:**  \n3. **Output:** Multi-task prediction vector of length `output_dim`, which is 35.\n\n**Loss function:** Mean Squared Error (MSE)\n\n---\n\n# 5. Training Strategy\n\n## 5.1 Leave-One-Out (LOO) Cross-Validation  \n- Six folds → six models.\n\n## 5.2 Model Stacking  \n1. Use each of the six models to predict on all samples → produce a dataframe of shape `(spots_n, 35 × 6)`.  \n2. Train a small MLP on this dataframe → final output `(spots_n, 35)`.  \n   - Learns to weight each fold’s prediction adaptively.\n\n---\n\n# Optimization Notes\n\n1. **Model structure:** Residual + multi-scale design proved most stable.  \n2. **Input size:** 78×78 tile + 9×26×26 subtiles + center 26×26 gave best results.  \n3. **Patch size choice:** Mean spot spacing ≈ 26 px, so 3×26 covers full receptive field. That's why I use 26*3 as the global vision for input and 26 as the local vesion.\n\n# Future Improvements\n\n- Diversify stacked models to increase ensemble variance.",
      "votes": null
    },
    {
      "id": "3205939",
      "postDate": "05/20/2025 15:21:40",
      "content": "<p>Solid modelling. Did you apply normalization after converting targets to ranks? If not, I'm curious how MSE handles this. Also, could you share the CV scores?</p>",
      "rawMarkdown": "Solid modelling. Did you apply normalization after converting targets to ranks? If not, I'm curious how MSE handles this. Also, could you share the CV scores?",
      "votes": null
    },
    {
      "id": "3205941",
      "postDate": "05/20/2025 15:34:17",
      "content": "<p>I do not apply normalization after converting targets to ranks. The output depends on your final activation function. For me, I used linear so it could handle this. The idea is that ML is predicting the rank of the cell-type, not the actually value. MSE makes the ML learn the ture ranking of the cells.</p>\n<p>Leave S_1 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2Fef7970a5a62e4ca44b1ed0987a40a0c3%2Floss_curve.png?generation=1747755187590888&amp;alt=media\" alt=\"Leave S_1\"></p>\n<p>Leave S_2 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F89328b07369e0c601748f70da0c484a2%2Floss_curve.png?generation=1747755202604313&amp;alt=media\" alt=\"Leave S_2\"></p>\n<p>Leave S_3 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F06e4379ff6df0a6a152e50f4b28fcb76%2Floss_curve.png?generation=1747755211553051&amp;alt=media\" alt=\"Leave S_3\"></p>\n<p>Leave S_4 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2Fcbc4ce3442fb8b8bb0af12557136d95b%2Floss_curve.png?generation=1747755219211013&amp;alt=media\" alt=\"Leave S_4\"></p>\n<p>Leave S_5 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F6448bec704feebc87000f1171eb177e6%2Floss_curve.png?generation=1747755226463273&amp;alt=media\" alt=\"Leave S_5\"></p>\n<p>Leave S_6 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F710c7807263ef452b8f9d3b430e44172%2Floss_curve.png?generation=1747755234674488&amp;alt=media\" alt=\"Leave S_6\"></p>",
      "rawMarkdown": "I do not apply normalization after converting targets to ranks. The output depends on your final activation function. For me, I used linear so it could handle this. The idea is that ML is predicting the rank of the cell-type, not the actually value. MSE makes the ML learn the ture ranking of the cells.\n\n\n\n \n\nLeave S_1 ![Leave S_1](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2Fef7970a5a62e4ca44b1ed0987a40a0c3%2Floss_curve.png?generation=1747755187590888&alt=media)\n \nLeave S_2 ![Leave S_2](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F89328b07369e0c601748f70da0c484a2%2Floss_curve.png?generation=1747755202604313&alt=media)\n\nLeave S_3 ![Leave S_3](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F06e4379ff6df0a6a152e50f4b28fcb76%2Floss_curve.png?generation=1747755211553051&alt=media)\n\nLeave S_4 ![Leave S_4](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2Fcbc4ce3442fb8b8bb0af12557136d95b%2Floss_curve.png?generation=1747755219211013&alt=media)\n\nLeave S_5 ![Leave S_5](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F6448bec704feebc87000f1171eb177e6%2Floss_curve.png?generation=1747755226463273&alt=media)\n\nLeave S_6 ![Leave S_6](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F710c7807263ef452b8f9d3b430e44172%2Floss_curve.png?generation=1747755234674488&alt=media)",
      "votes": null
    },
    {
      "id": "3205946",
      "postDate": "05/20/2025 15:42:04",
      "content": "<p>The accuracy in S_7 is</p>\n<p>Private Score, Public Score<br>\nLeave S_1:   0.54364.       , 0.55496<br>\nLeave S_2:  0.48656        , 0.54707<br>\nLeave S_3:  0.61194          , 0.69921<br>\nLeave S_4:  0.47258         , 0.49559<br>\nLeave S_5:  0.58700         , 0.66151<br>\nLeave S_6:  0.65420         , 0.68142</p>",
      "rawMarkdown": "The accuracy in S_7 is\n\nPrivate Score, Public Score\nLeave S_1:   0.54364.       , 0.55496\nLeave S_2:  0.48656        , 0.54707\nLeave S_3:  0.61194          , 0.69921\nLeave S_4:  0.47258         , 0.49559\nLeave S_5:  0.58700         , 0.66151\nLeave S_6:  0.65420         , 0.68142",
      "votes": null
    },
    {
      "id": "3206935",
      "postDate": "05/22/2025 01:24:28",
      "content": "<p>thank you very much</p>",
      "rawMarkdown": "thank you very much",
      "votes": null
    },
    {
      "id": "3207492",
      "postDate": "05/22/2025 20:14:18",
      "content": "<p>No worries! I will post my whole code on my github soon! Feel free to check later!</p>",
      "rawMarkdown": "No worries! I will post my whole code on my github soon! Feel free to check later!",
      "votes": null
    },
    {
      "id": "3215777",
      "postDate": "06/02/2025 16:23:25",
      "content": "<p>Your work was incredibly helpful and insightful. I truly appreciate the time and effort you put into making your approach clear and accessible to others. It made a big difference in my understanding of the problem. Thanks</p>",
      "rawMarkdown": "Your work was incredibly helpful and insightful. I truly appreciate the time and effort you put into making your approach clear and accessible to others. It made a big difference in my understanding of the problem. Thanks",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3205939,
      "author_name": "mertbayraktar",
      "author_url": "",
      "post_date": "05/20/2025 15:21:40",
      "content": "<p>Solid modelling. Did you apply normalization after converting targets to ranks? If not, I'm curious how MSE handles this. Also, could you share the CV scores?</p>",
      "votes": null,
      "replies": [
        {
          "id": 3205941,
          "author_name": "dingyangwang",
          "author_url": "",
          "post_date": "05/20/2025 15:34:17",
          "content": "<p>I do not apply normalization after converting targets to ranks. The output depends on your final activation function. For me, I used linear so it could handle this. The idea is that ML is predicting the rank of the cell-type, not the actually value. MSE makes the ML learn the ture ranking of the cells.</p>\n<p>Leave S_1 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2Fef7970a5a62e4ca44b1ed0987a40a0c3%2Floss_curve.png?generation=1747755187590888&amp;alt=media\" alt=\"Leave S_1\"></p>\n<p>Leave S_2 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F89328b07369e0c601748f70da0c484a2%2Floss_curve.png?generation=1747755202604313&amp;alt=media\" alt=\"Leave S_2\"></p>\n<p>Leave S_3 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F06e4379ff6df0a6a152e50f4b28fcb76%2Floss_curve.png?generation=1747755211553051&amp;alt=media\" alt=\"Leave S_3\"></p>\n<p>Leave S_4 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2Fcbc4ce3442fb8b8bb0af12557136d95b%2Floss_curve.png?generation=1747755219211013&amp;alt=media\" alt=\"Leave S_4\"></p>\n<p>Leave S_5 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F6448bec704feebc87000f1171eb177e6%2Floss_curve.png?generation=1747755226463273&amp;alt=media\" alt=\"Leave S_5\"></p>\n<p>Leave S_6 <img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F710c7807263ef452b8f9d3b430e44172%2Floss_curve.png?generation=1747755234674488&amp;alt=media\" alt=\"Leave S_6\"></p>",
          "votes": null,
          "replies": [
            {
              "id": 3205946,
              "author_name": "dingyangwang",
              "author_url": "",
              "post_date": "05/20/2025 15:42:04",
              "content": "<p>The accuracy in S_7 is</p>\n<p>Private Score, Public Score<br>\nLeave S_1:   0.54364.       , 0.55496<br>\nLeave S_2:  0.48656        , 0.54707<br>\nLeave S_3:  0.61194          , 0.69921<br>\nLeave S_4:  0.47258         , 0.49559<br>\nLeave S_5:  0.58700         , 0.66151<br>\nLeave S_6:  0.65420         , 0.68142</p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 3206935,
      "author_name": "isharaekanayaka",
      "author_url": "",
      "post_date": "05/22/2025 01:24:28",
      "content": "<p>thank you very much</p>",
      "votes": null,
      "replies": [
        {
          "id": 3207492,
          "author_name": "dingyangwang",
          "author_url": "",
          "post_date": "05/22/2025 20:14:18",
          "content": "<p>No worries! I will post my whole code on my github soon! Feel free to check later!</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 3215777,
      "author_name": "sun9sun9",
      "author_url": "",
      "post_date": "06/02/2025 16:23:25",
      "content": "<p>Your work was incredibly helpful and insightful. I truly appreciate the time and effort you put into making your approach clear and accessible to others. It made a big difference in my understanding of the problem. Thanks</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "3205686": "https://github.com/Dewey-Wang/HEVisum/tree/main\nYou can see my whole solution within my github\n\nThis is my original file. I will also post my solution and integrate code later on the repo. If you want to know my solution, stay tune! Feel free to ask me any question!\n\n---\n\n# 1. Search Studies\n\n- [Benchmarking the translational potential of spatial gene expression prediction from histology](https://www.nature.com/articles/s41467-025-56618-y)  \n- [DeepSpot: Leveraging Spatial Context for Enhanced Spatial Transcriptomics Prediction from H&E Images](https://www.medrxiv.org/content/10.1101/2025.02.09.25321567v1)  \n\n> These papers survey state-of-the-art techniques for predicting spatial gene expression from H&E histology images.\n\n---\n\n# 2. Exploratory Data Analysis (EDA)\n\n- https://www.kaggle.com/code/tarundirector/histology-eda-spotnet-visual-spatial-dl  \n- https://www.kaggle.com/code/dalloliogm/eda-exploring-cell-type-abundance  \n- https://www.kaggle.com/code/prajwaldongreonly-eda-you-need-to-understand-this-data  \n\n> Use these notebooks to visualize spot distributions, cell-type abundances, and other spatial features.\n\n---\n\n# 3. Data Preprocessing\n\n## 3.1 Image Data  \n1. **Stain normalization**  (One of the most important step) \n   - Essential for reducing color variability across slides.  \n   - Sample patches from all images to compute stable normalization parameters.  \n2. **Background masking**  \n   - Grayscale: `gray = rgb2gray(image)`  \n   - Threshold: `mask = gray <= mean_threshold`  \n   - Closing: `closing(mask, disk(2))`  \n   - Fill holes: `remove_small_holes(..., area_threshold=5000)`  \n   - **Output:** clean binary tissue mask  \n\n## 3.2 Spot Data  \n1. **Expression ranking**  (One of the most important step) \n   - Replace raw counts with rank values. (I also check UMAP with them to see which combination or replacement would be better to let the ML to predict. In the end replace with rank us the most promising one.)\n2. **Spot realignment**  \n   - Minor effect if background spots are already filtered out.\n\n---\n\n# 4. Model Preparation\n\n## 4.1 Encoder\n\n### DeepTileEncoder  \n- **Input size:** `[B, 3, 78, 78]`  \n- **Purpose:** Processes the entire 78×78 tile (from spot coordinates).  \n- **Residual blocks:** Stacked `ResidualBlock`s (two 3×3 Conv + BN + SiLU; 1×1 Conv shortcut if needed)  \n- **Multi-scale pooling:**  \n  - Global: `AdaptiveAvgPool2d(1×1)` → `[B,256]`  \n  - Mid-scale: `AdaptiveAvgPool2d(3×3)` → `[B,256×3×3]`  \n- **MLP (3 layers):**  \n\n\n### SubtileEncoder  \n- **Input size:** `[B, 9, 3, 26, 26]`  \n- **Purpose:** Captures local details from 9 subtiles.  \n- **Residual blocks:** Applied after reshaping to `[B×9, 3, 26, 26]`  \n- **Multi-scale pooling (per patch):**  \n  - Global 1×1 → `[B×9,128]`  \n  - Mid 2×2 → `[B×9,128×2×2]`  \n  - Large 3×3 → `[B×9,128×3×3]`  \n- **Aggregation:**  \n  1. Reshape to `[B, 9, total_dim]`  \n  2. Average over 9 → `[B, total_dim]`  \n- **MLP (2 layers):**  \n\n\n### CenterSubtileEncoder  \n- **Input size:** `[B, 3, 26, 26]`  \n- **Purpose:** Focuses on the single central patch.  \n- **Structure:** Same as SubtileEncoder but only for the center.  \n- **Multi-scale pooling:** 1×1, 2×2, 3×3 → concatenate → Flatten  \n- **MLP (2 layers):** \n\n---\n\n## 4.2 Decoder\n\n1. **Concatenate:** `[tile_dim] + [subtile_dim] + [subtile_dim]` → `[B, tile_dim+2×subtile_dim]`  \n2. **Four-layer MLP:**  \n3. **Output:** Multi-task prediction vector of length `output_dim`, which is 35.\n\n**Loss function:** Mean Squared Error (MSE)\n\n---\n\n# 5. Training Strategy\n\n## 5.1 Leave-One-Out (LOO) Cross-Validation  \n- Six folds → six models.\n\n## 5.2 Model Stacking  \n1. Use each of the six models to predict on all samples → produce a dataframe of shape `(spots_n, 35 × 6)`.  \n2. Train a small MLP on this dataframe → final output `(spots_n, 35)`.  \n   - Learns to weight each fold’s prediction adaptively.\n\n---\n\n# Optimization Notes\n\n1. **Model structure:** Residual + multi-scale design proved most stable.  \n2. **Input size:** 78×78 tile + 9×26×26 subtiles + center 26×26 gave best results.  \n3. **Patch size choice:** Mean spot spacing ≈ 26 px, so 3×26 covers full receptive field. That's why I use 26*3 as the global vision for input and 26 as the local vesion.\n\n# Future Improvements\n\n- Diversify stacked models to increase ensemble variance.",
    "3205939": "Solid modelling. Did you apply normalization after converting targets to ranks? If not, I'm curious how MSE handles this. Also, could you share the CV scores?",
    "3205941": "I do not apply normalization after converting targets to ranks. The output depends on your final activation function. For me, I used linear so it could handle this. The idea is that ML is predicting the rank of the cell-type, not the actually value. MSE makes the ML learn the ture ranking of the cells.\n\n\n\n \n\nLeave S_1 ![Leave S_1](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2Fef7970a5a62e4ca44b1ed0987a40a0c3%2Floss_curve.png?generation=1747755187590888&alt=media)\n \nLeave S_2 ![Leave S_2](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F89328b07369e0c601748f70da0c484a2%2Floss_curve.png?generation=1747755202604313&alt=media)\n\nLeave S_3 ![Leave S_3](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F06e4379ff6df0a6a152e50f4b28fcb76%2Floss_curve.png?generation=1747755211553051&alt=media)\n\nLeave S_4 ![Leave S_4](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2Fcbc4ce3442fb8b8bb0af12557136d95b%2Floss_curve.png?generation=1747755219211013&alt=media)\n\nLeave S_5 ![Leave S_5](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F6448bec704feebc87000f1171eb177e6%2Floss_curve.png?generation=1747755226463273&alt=media)\n\nLeave S_6 ![Leave S_6](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8174444%2F710c7807263ef452b8f9d3b430e44172%2Floss_curve.png?generation=1747755234674488&alt=media)",
    "3205946": "The accuracy in S_7 is\n\nPrivate Score, Public Score\nLeave S_1:   0.54364.       , 0.55496\nLeave S_2:  0.48656        , 0.54707\nLeave S_3:  0.61194          , 0.69921\nLeave S_4:  0.47258         , 0.49559\nLeave S_5:  0.58700         , 0.66151\nLeave S_6:  0.65420         , 0.68142",
    "3206935": "thank you very much",
    "3207492": "No worries! I will post my whole code on my github soon! Feel free to check later!",
    "3215777": "Your work was incredibly helpful and insightful. I truly appreciate the time and effort you put into making your approach clear and accessible to others. It made a big difference in my understanding of the problem. Thanks"
  },
  "source": "meta"
}