{
  "id": 669562,
  "title": "6th place solution",
  "url": "/competitions/physionet-ecg-image-digitization/writeups/6th-place-solution",
  "author_name": "",
  "post_date": "2026-01-23T03:57:52.183Z",
  "votes": 30,
  "comment_count": 5,
  "views": 0,
  "content": "<h2>Acknowledgments</h2>\n<p>I would like to express my sincere gratitude to Kaggle and the competition organizers for providing this invaluable opportunity. Special thanks to <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> for sharing his strong baseline, which served as a crucial foundation for my work.</p>\n<h2>Summary</h2>\n<p>My solution focuses on optimizing Stage 2 of the baseline provided by <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a>. The key insight is to directly regress the lead signal, bypassing the traditional pipeline of \"segmentation followed by post-processing.\" By treating this as a direct regression task, the model learns the signal features more effectively and reduces the cumulative error often introduced during the post-processing stage.</p>\n<h2>Overall Pipeline</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5483160%2F478068740d14fb19934fb2f237a9deca%2F1.png?generation=1769161443528035&amp;alt=media\" alt=\"\"></p>\n<h3>Resample</h3>\n<p>The training dataset contains ECG signals with diverse sampling rates, ranging from <code>2.5 kHz</code> to <code>10 kHz</code>. To ensure high-quality ground truth and maintain optimal Signal-to-Noise Ratio (SNR), a consistent resampling strategy is required. I implemented a benchmarking framework to evaluate the fidelity of various resampling algorithms—including <code>polyphase, linear, cubic spline, and FFT-based methods</code>. The performance was measured using a transformation:</p>\n<ol>\n<li>Up/Down-sample: Resample the original signal to a target length (e.g., 2560, 5120, or 10250). </li>\n<li>Restore: Resample the signal back to its original length.</li>\n<li>Evaluate: Calculate the SNR by comparing the \"Restored\" signal against the \"Original\" ground truth.</li>\n</ol>\n<p>The key observations is</p>\n<ul>\n<li>scipy.signal.resample (FFT-based) yields significantly superior results compared to torch.nn.functional.interpolate (Linear/Bilinear) for this signal processing task.</li>\n<li>fidelity is positively correlated with the intermediate sampling density; higher intermediate lengths (10250 &gt; 5120 &gt; 2560) result in substantially lower information loss.</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5483160%2F2af8c00564301f404ea7b900bf715442%2F1.png?generation=1769138986791210&amp;alt=media\" alt=\"\"></p>\n<p>Moreover, to accelerate image resampling and integrate it into the training process, I use <code>resample_torch</code></p>\n<pre><code>def resample_torch(self, x, num, dim=-1):\n        dim = (x.dim() + dim) if dim &lt; 0 else dim\n        X = torch.fft.fft(x, dim=dim)\n        Nx = X.shape[dim]\n\n        sl = [slice(None)] * X.ndim\n        newshape = list(X.shape)\n        newshape[dim] = num\n        Y = torch.zeros(newshape, dtype=X.dtype, device=X.device)\n\n        N = min(num, Nx)\n        sl[dim] = slice(0, (N + 1) // 2)\n        Y[sl] = X[sl]\n        sl[dim] = slice(-(N - 1) // 2, None)\n        Y[sl] = X[sl]\n\n        if N % 2 == 0:\n            if N &lt; Nx:\n                sl[dim] = slice(N//2, N//2+1)\n                Y[sl] += X[sl]\n            elif N &lt; num:\n                sl[dim] = slice(num-N//2, num-N//2+1)\n                Y[sl] /= 2\n                temp = Y[sl]\n                sl[dim] = slice(N//2, N//2+1)\n                Y[sl] = temp\n\n        y = torch.fft.ifft(Y, dim=dim).real * (float(num) / float(Nx))\n        return y\n</code></pre>\n<h3>Signal Regression Head</h3>\n<p>This module converts 2D feature embeddings into precise physical voltage values for ECG leads by using a Soft-Argmax mechanism to estimate vertical coordinates.</p>\n<pre><code># Signal Regression Head\nclass MaskEmbeddingToLeadSignalSoftArgmax(nn.Module):\n    def __init__(self, n_leads=4, embedding_dim=32, temperature=0.5):\n        super().__init__()\n\n        self.n_leads = n_leads\n        self.temperature = temperature\n        self.lead_y_logits = nn.Conv2d(embedding_dim, n_leads, kernel_size=1)\n\n        self.register_buffer('zero_mv', torch.tensor([703.5, 987.5, 1271.5, 1531.5]).view(1, 4, 1))\n        self.register_buffer('mv_to_pixel', torch.tensor(79.0))\n\n    def forward(self, masked_feat):\n        B, C, H, W = masked_feat.shape\n        device = masked_feat.device\n        dtype = masked_feat.dtype\n\n        y_logits = self.lead_y_logits(masked_feat)\n        prob = torch.softmax(y_logits / self.temperature, dim=2)\n\n        y_coord = torch.arange(H, device=device, dtype=dtype).view(1,1,H,1)\n        y_pixel = (prob * y_coord).sum(dim=2)  # [B, L, W]\n\n        pred_mv = (self.zero_mv - y_pixel) / self.mv_to_pixel\n        return pred_mv, prob\n</code></pre>\n<h2>Experimental Results</h2>\n<table>\n<thead>\n<tr>\n<th>Signal Length</th>\n<th>TTA (hflip)</th>\n<th>Epochs</th>\n<th>LB Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>2560</td>\n<td>False</td>\n<td>60</td>\n<td>21.36</td>\n</tr>\n<tr>\n<td>5120</td>\n<td>False</td>\n<td>100</td>\n<td>22.20</td>\n</tr>\n<tr>\n<td>5120</td>\n<td>True</td>\n<td>100</td>\n<td>22.36</td>\n</tr>\n<tr>\n<td>5120</td>\n<td>True</td>\n<td>150</td>\n<td>22.43</td>\n</tr>\n</tbody>\n</table>\n<h2>Code:</h2>\n<p><a href=\"https://github.com/GWwangshuo/Kaggle-2025-PhysioNet/tree/main\" target=\"_blank\">Training Code </a></p>",
  "messages": [
    {
      "id": "3395478",
      "postDate": "01/23/2026 03:57:42",
      "content": "<h2>Acknowledgments</h2>\n<p>I would like to express my sincere gratitude to Kaggle and the competition organizers for providing this invaluable opportunity. Special thanks to <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> for sharing his strong baseline, which served as a crucial foundation for my work.</p>\n<h2>Summary</h2>\n<p>My solution focuses on optimizing Stage 2 of the baseline provided by <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a>. The key insight is to directly regress the lead signal, bypassing the traditional pipeline of \"segmentation followed by post-processing.\" By treating this as a direct regression task, the model learns the signal features more effectively and reduces the cumulative error often introduced during the post-processing stage.</p>\n<h2>Overall Pipeline</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5483160%2F478068740d14fb19934fb2f237a9deca%2F1.png?generation=1769161443528035&amp;alt=media\" alt=\"\"></p>\n<h3>Resample</h3>\n<p>The training dataset contains ECG signals with diverse sampling rates, ranging from <code>2.5 kHz</code> to <code>10 kHz</code>. To ensure high-quality ground truth and maintain optimal Signal-to-Noise Ratio (SNR), a consistent resampling strategy is required. I implemented a benchmarking framework to evaluate the fidelity of various resampling algorithms—including <code>polyphase, linear, cubic spline, and FFT-based methods</code>. The performance was measured using a transformation:</p>\n<ol>\n<li>Up/Down-sample: Resample the original signal to a target length (e.g., 2560, 5120, or 10250). </li>\n<li>Restore: Resample the signal back to its original length.</li>\n<li>Evaluate: Calculate the SNR by comparing the \"Restored\" signal against the \"Original\" ground truth.</li>\n</ol>\n<p>The key observations is</p>\n<ul>\n<li>scipy.signal.resample (FFT-based) yields significantly superior results compared to torch.nn.functional.interpolate (Linear/Bilinear) for this signal processing task.</li>\n<li>fidelity is positively correlated with the intermediate sampling density; higher intermediate lengths (10250 &gt; 5120 &gt; 2560) result in substantially lower information loss.</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5483160%2F2af8c00564301f404ea7b900bf715442%2F1.png?generation=1769138986791210&amp;alt=media\" alt=\"\"></p>\n<p>Moreover, to accelerate image resampling and integrate it into the training process, I use <code>resample_torch</code></p>\n<pre><code>def resample_torch(self, x, num, dim=-1):\n        dim = (x.dim() + dim) if dim &lt; 0 else dim\n        X = torch.fft.fft(x, dim=dim)\n        Nx = X.shape[dim]\n\n        sl = [slice(None)] * X.ndim\n        newshape = list(X.shape)\n        newshape[dim] = num\n        Y = torch.zeros(newshape, dtype=X.dtype, device=X.device)\n\n        N = min(num, Nx)\n        sl[dim] = slice(0, (N + 1) // 2)\n        Y[sl] = X[sl]\n        sl[dim] = slice(-(N - 1) // 2, None)\n        Y[sl] = X[sl]\n\n        if N % 2 == 0:\n            if N &lt; Nx:\n                sl[dim] = slice(N//2, N//2+1)\n                Y[sl] += X[sl]\n            elif N &lt; num:\n                sl[dim] = slice(num-N//2, num-N//2+1)\n                Y[sl] /= 2\n                temp = Y[sl]\n                sl[dim] = slice(N//2, N//2+1)\n                Y[sl] = temp\n\n        y = torch.fft.ifft(Y, dim=dim).real * (float(num) / float(Nx))\n        return y\n</code></pre>\n<h3>Signal Regression Head</h3>\n<p>This module converts 2D feature embeddings into precise physical voltage values for ECG leads by using a Soft-Argmax mechanism to estimate vertical coordinates.</p>\n<pre><code># Signal Regression Head\nclass MaskEmbeddingToLeadSignalSoftArgmax(nn.Module):\n    def __init__(self, n_leads=4, embedding_dim=32, temperature=0.5):\n        super().__init__()\n\n        self.n_leads = n_leads\n        self.temperature = temperature\n        self.lead_y_logits = nn.Conv2d(embedding_dim, n_leads, kernel_size=1)\n\n        self.register_buffer('zero_mv', torch.tensor([703.5, 987.5, 1271.5, 1531.5]).view(1, 4, 1))\n        self.register_buffer('mv_to_pixel', torch.tensor(79.0))\n\n    def forward(self, masked_feat):\n        B, C, H, W = masked_feat.shape\n        device = masked_feat.device\n        dtype = masked_feat.dtype\n\n        y_logits = self.lead_y_logits(masked_feat)\n        prob = torch.softmax(y_logits / self.temperature, dim=2)\n\n        y_coord = torch.arange(H, device=device, dtype=dtype).view(1,1,H,1)\n        y_pixel = (prob * y_coord).sum(dim=2)  # [B, L, W]\n\n        pred_mv = (self.zero_mv - y_pixel) / self.mv_to_pixel\n        return pred_mv, prob\n</code></pre>\n<h2>Experimental Results</h2>\n<table>\n<thead>\n<tr>\n<th>Signal Length</th>\n<th>TTA (hflip)</th>\n<th>Epochs</th>\n<th>LB Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>2560</td>\n<td>False</td>\n<td>60</td>\n<td>21.36</td>\n</tr>\n<tr>\n<td>5120</td>\n<td>False</td>\n<td>100</td>\n<td>22.20</td>\n</tr>\n<tr>\n<td>5120</td>\n<td>True</td>\n<td>100</td>\n<td>22.36</td>\n</tr>\n<tr>\n<td>5120</td>\n<td>True</td>\n<td>150</td>\n<td>22.43</td>\n</tr>\n</tbody>\n</table>\n<h2>Code:</h2>\n<p><a href=\"https://github.com/GWwangshuo/Kaggle-2025-PhysioNet/tree/main\" target=\"_blank\">Training Code </a></p>",
      "rawMarkdown": "## Acknowledgments\nI would like to express my sincere gratitude to Kaggle and the competition organizers for providing this invaluable opportunity. Special thanks to @hengck23 for sharing his strong baseline, which served as a crucial foundation for my work.\n\n## Summary\nMy solution focuses on optimizing Stage 2 of the baseline provided by @hengck23. The key insight is to directly regress the lead signal, bypassing the traditional pipeline of \"segmentation followed by post-processing.\" By treating this as a direct regression task, the model learns the signal features more effectively and reduces the cumulative error often introduced during the post-processing stage.\n\n## Overall Pipeline\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5483160%2F478068740d14fb19934fb2f237a9deca%2F1.png?generation=1769161443528035&alt=media)\n\n\n### Resample\n\nThe training dataset contains ECG signals with diverse sampling rates, ranging from `2.5 kHz` to `10 kHz`. To ensure high-quality ground truth and maintain optimal Signal-to-Noise Ratio (SNR), a consistent resampling strategy is required. I implemented a benchmarking framework to evaluate the fidelity of various resampling algorithms—including `polyphase, linear, cubic spline, and FFT-based methods`. The performance was measured using a transformation:\n1. Up/Down-sample: Resample the original signal to a target length (e.g., 2560, 5120, or 10250). \n2. Restore: Resample the signal back to its original length.\n3. Evaluate: Calculate the SNR by comparing the \"Restored\" signal against the \"Original\" ground truth.\n\nThe key observations is\n- scipy.signal.resample (FFT-based) yields significantly superior results compared to torch.nn.functional.interpolate (Linear/Bilinear) for this signal processing task.\n- fidelity is positively correlated with the intermediate sampling density; higher intermediate lengths (10250 > 5120 > 2560) result in substantially lower information loss.\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5483160%2F2af8c00564301f404ea7b900bf715442%2F1.png?generation=1769138986791210&alt=media)\n\nMoreover, to accelerate image resampling and integrate it into the training process, I use `resample_torch`\n\n```python\ndef resample_torch(self, x, num, dim=-1):\n        dim = (x.dim() + dim) if dim < 0 else dim\n        X = torch.fft.fft(x, dim=dim)\n        Nx = X.shape[dim]\n\n        sl = [slice(None)] * X.ndim\n        newshape = list(X.shape)\n        newshape[dim] = num\n        Y = torch.zeros(newshape, dtype=X.dtype, device=X.device)\n\n        N = min(num, Nx)\n        sl[dim] = slice(0, (N + 1) // 2)\n        Y[sl] = X[sl]\n        sl[dim] = slice(-(N - 1) // 2, None)\n        Y[sl] = X[sl]\n\n        if N % 2 == 0:\n            if N < Nx:\n                sl[dim] = slice(N//2, N//2+1)\n                Y[sl] += X[sl]\n            elif N < num:\n                sl[dim] = slice(num-N//2, num-N//2+1)\n                Y[sl] /= 2\n                temp = Y[sl]\n                sl[dim] = slice(N//2, N//2+1)\n                Y[sl] = temp\n\n        y = torch.fft.ifft(Y, dim=dim).real * (float(num) / float(Nx))\n        return y\n```\n\n### Signal Regression Head\nThis module converts 2D feature embeddings into precise physical voltage values for ECG leads by using a Soft-Argmax mechanism to estimate vertical coordinates.\n\n```python\n# Signal Regression Head\nclass MaskEmbeddingToLeadSignalSoftArgmax(nn.Module):\n    def __init__(self, n_leads=4, embedding_dim=32, temperature=0.5):\n        super().__init__()\n        \n        self.n_leads = n_leads\n        self.temperature = temperature\n        self.lead_y_logits = nn.Conv2d(embedding_dim, n_leads, kernel_size=1)\n        \n        self.register_buffer('zero_mv', torch.tensor([703.5, 987.5, 1271.5, 1531.5]).view(1, 4, 1))\n        self.register_buffer('mv_to_pixel', torch.tensor(79.0))\n\n    def forward(self, masked_feat):\n        B, C, H, W = masked_feat.shape\n        device = masked_feat.device\n        dtype = masked_feat.dtype\n\n        y_logits = self.lead_y_logits(masked_feat)\n        prob = torch.softmax(y_logits / self.temperature, dim=2)\n\n        y_coord = torch.arange(H, device=device, dtype=dtype).view(1,1,H,1)\n        y_pixel = (prob * y_coord).sum(dim=2)  # [B, L, W]\n        \n        pred_mv = (self.zero_mv - y_pixel) / self.mv_to_pixel\n        return pred_mv, prob\n```\n\n\n## Experimental Results\n| Signal Length | TTA (hflip) | Epochs | LB Score | \n|---------------|-------------|--------|----------|\n| 2560          | False       | 60     | 21.36    |\n| 5120          | False       | 100    | 22.20    |\n| 5120          | True        | 100    | 22.36    |\n| 5120          | True        | 150    | 22.43    |\n\n\n## Code:\n[Training Code ](https://github.com/GWwangshuo/Kaggle-2025-PhysioNet/tree/main)",
      "votes": null
    },
    {
      "id": "3395503",
      "postDate": "01/23/2026 05:09:45",
      "content": "<p><a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> is the goat. he does a lot in simplifying complex stuff</p>",
      "rawMarkdown": "hengck23 is the goat. he does a lot in simplifying complex stuff",
      "votes": null
    },
    {
      "id": "3395569",
      "postDate": "01/23/2026 08:41:09",
      "content": "<p>If i may ask, how did you train on such a big dataset? Hardware config? and how long did it take?</p>",
      "rawMarkdown": "If i may ask, how did you train on such a big dataset? Hardware config? and how long did it take?",
      "votes": null
    },
    {
      "id": "3395573",
      "postDate": "01/23/2026 08:45:10",
      "content": "<p>It takes approximately 10 hours to complete full training (without validation) using 24 NVIDIA RTX 3090 GPUs (24 GB each).</p>",
      "rawMarkdown": "It takes approximately 10 hours to complete full training (without validation) using 24 NVIDIA RTX 3090 GPUs (24 GB each).",
      "votes": null
    },
    {
      "id": "3395719",
      "postDate": "01/23/2026 14:42:02",
      "content": "<p>SImple but effective, nice solution. Do you have a measure of how much <code>scipy.signal.resample</code> improved CV/LB over <code>torch.nn.functional.interpolate</code>?</p>",
      "rawMarkdown": "SImple but effective, nice solution. Do you have a measure of how much `scipy.signal.resample` improved CV/LB over `torch.nn.functional.interpolate`?",
      "votes": null
    },
    {
      "id": "3421680",
      "postDate": "03/16/2026 04:32:26",
      "content": "<p>Nice work! Do you mean you used 24 GPUs for parallel training? </p>",
      "rawMarkdown": "Nice work! Do you mean you used 24 GPUs for parallel training?",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3395503,
      "author_name": "samu2505",
      "author_url": "",
      "post_date": "01/23/2026 05:09:45",
      "content": "<p><a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> is the goat. he does a lot in simplifying complex stuff</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 3395569,
      "author_name": "jaiaaryan",
      "author_url": "",
      "post_date": "01/23/2026 08:41:09",
      "content": "<p>If i may ask, how did you train on such a big dataset? Hardware config? and how long did it take?</p>",
      "votes": null,
      "replies": [
        {
          "id": 3395573,
          "author_name": "sjtuwangshuo",
          "author_url": "",
          "post_date": "01/23/2026 08:45:10",
          "content": "<p>It takes approximately 10 hours to complete full training (without validation) using 24 NVIDIA RTX 3090 GPUs (24 GB each).</p>",
          "votes": null,
          "replies": [
            {
              "id": 3421680,
              "author_name": "mancyw",
              "author_url": "",
              "post_date": "03/16/2026 04:32:26",
              "content": "<p>Nice work! Do you mean you used 24 GPUs for parallel training? </p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 3395719,
      "author_name": "brendanartley",
      "author_url": "",
      "post_date": "01/23/2026 14:42:02",
      "content": "<p>SImple but effective, nice solution. Do you have a measure of how much <code>scipy.signal.resample</code> improved CV/LB over <code>torch.nn.functional.interpolate</code>?</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "3395478": "## Acknowledgments\nI would like to express my sincere gratitude to Kaggle and the competition organizers for providing this invaluable opportunity. Special thanks to @hengck23 for sharing his strong baseline, which served as a crucial foundation for my work.\n\n## Summary\nMy solution focuses on optimizing Stage 2 of the baseline provided by @hengck23. The key insight is to directly regress the lead signal, bypassing the traditional pipeline of \"segmentation followed by post-processing.\" By treating this as a direct regression task, the model learns the signal features more effectively and reduces the cumulative error often introduced during the post-processing stage.\n\n## Overall Pipeline\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5483160%2F478068740d14fb19934fb2f237a9deca%2F1.png?generation=1769161443528035&alt=media)\n\n\n### Resample\n\nThe training dataset contains ECG signals with diverse sampling rates, ranging from `2.5 kHz` to `10 kHz`. To ensure high-quality ground truth and maintain optimal Signal-to-Noise Ratio (SNR), a consistent resampling strategy is required. I implemented a benchmarking framework to evaluate the fidelity of various resampling algorithms—including `polyphase, linear, cubic spline, and FFT-based methods`. The performance was measured using a transformation:\n1. Up/Down-sample: Resample the original signal to a target length (e.g., 2560, 5120, or 10250). \n2. Restore: Resample the signal back to its original length.\n3. Evaluate: Calculate the SNR by comparing the \"Restored\" signal against the \"Original\" ground truth.\n\nThe key observations is\n- scipy.signal.resample (FFT-based) yields significantly superior results compared to torch.nn.functional.interpolate (Linear/Bilinear) for this signal processing task.\n- fidelity is positively correlated with the intermediate sampling density; higher intermediate lengths (10250 > 5120 > 2560) result in substantially lower information loss.\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5483160%2F2af8c00564301f404ea7b900bf715442%2F1.png?generation=1769138986791210&alt=media)\n\nMoreover, to accelerate image resampling and integrate it into the training process, I use `resample_torch`\n\n```python\ndef resample_torch(self, x, num, dim=-1):\n        dim = (x.dim() + dim) if dim < 0 else dim\n        X = torch.fft.fft(x, dim=dim)\n        Nx = X.shape[dim]\n\n        sl = [slice(None)] * X.ndim\n        newshape = list(X.shape)\n        newshape[dim] = num\n        Y = torch.zeros(newshape, dtype=X.dtype, device=X.device)\n\n        N = min(num, Nx)\n        sl[dim] = slice(0, (N + 1) // 2)\n        Y[sl] = X[sl]\n        sl[dim] = slice(-(N - 1) // 2, None)\n        Y[sl] = X[sl]\n\n        if N % 2 == 0:\n            if N < Nx:\n                sl[dim] = slice(N//2, N//2+1)\n                Y[sl] += X[sl]\n            elif N < num:\n                sl[dim] = slice(num-N//2, num-N//2+1)\n                Y[sl] /= 2\n                temp = Y[sl]\n                sl[dim] = slice(N//2, N//2+1)\n                Y[sl] = temp\n\n        y = torch.fft.ifft(Y, dim=dim).real * (float(num) / float(Nx))\n        return y\n```\n\n### Signal Regression Head\nThis module converts 2D feature embeddings into precise physical voltage values for ECG leads by using a Soft-Argmax mechanism to estimate vertical coordinates.\n\n```python\n# Signal Regression Head\nclass MaskEmbeddingToLeadSignalSoftArgmax(nn.Module):\n    def __init__(self, n_leads=4, embedding_dim=32, temperature=0.5):\n        super().__init__()\n        \n        self.n_leads = n_leads\n        self.temperature = temperature\n        self.lead_y_logits = nn.Conv2d(embedding_dim, n_leads, kernel_size=1)\n        \n        self.register_buffer('zero_mv', torch.tensor([703.5, 987.5, 1271.5, 1531.5]).view(1, 4, 1))\n        self.register_buffer('mv_to_pixel', torch.tensor(79.0))\n\n    def forward(self, masked_feat):\n        B, C, H, W = masked_feat.shape\n        device = masked_feat.device\n        dtype = masked_feat.dtype\n\n        y_logits = self.lead_y_logits(masked_feat)\n        prob = torch.softmax(y_logits / self.temperature, dim=2)\n\n        y_coord = torch.arange(H, device=device, dtype=dtype).view(1,1,H,1)\n        y_pixel = (prob * y_coord).sum(dim=2)  # [B, L, W]\n        \n        pred_mv = (self.zero_mv - y_pixel) / self.mv_to_pixel\n        return pred_mv, prob\n```\n\n\n## Experimental Results\n| Signal Length | TTA (hflip) | Epochs | LB Score | \n|---------------|-------------|--------|----------|\n| 2560          | False       | 60     | 21.36    |\n| 5120          | False       | 100    | 22.20    |\n| 5120          | True        | 100    | 22.36    |\n| 5120          | True        | 150    | 22.43    |\n\n\n## Code:\n[Training Code ](https://github.com/GWwangshuo/Kaggle-2025-PhysioNet/tree/main)",
    "3395503": "hengck23 is the goat. he does a lot in simplifying complex stuff",
    "3395569": "If i may ask, how did you train on such a big dataset? Hardware config? and how long did it take?",
    "3395573": "It takes approximately 10 hours to complete full training (without validation) using 24 NVIDIA RTX 3090 GPUs (24 GB each).",
    "3395719": "SImple but effective, nice solution. Do you have a measure of how much `scipy.signal.resample` improved CV/LB over `torch.nn.functional.interpolate`?",
    "3421680": "Nice work! Do you mean you used 24 GPUs for parallel training?"
  },
  "source": "meta"
}