{
  "id": 603560,
  "title": "Top 8% Solution with Wavenet",
  "url": "/competitions/cmi-detect-behavior-with-sensor-data/discussion/603560",
  "author_name": "Peter",
  "post_date": "2025-09-03T02:51:01.405000",
  "votes": 8,
  "comment_count": 0,
  "views": 0,
  "content": "<p>First of all, I would like to thank my teemmate <a href=\"https://www.kaggle.com/jaewook704\" target=\"_blank\">@jaewook704</a> and the Child Mind Institute for hosting this competition. It has been a great learning experience for me. I also want to acknowledge and appreciate everyone who dedicated their time and effort over the past three months to participate in this challenge.</p>\n<p>One of my main motivations for joining was to study WaveNet in greater depth. However, during the experiments, I found that temporal 1D CNNs performed better than WaveNet, and as a result, my score was not as high as I had hoped.<br>\nThat said, I would like to take this opportunity to share the model architectures I explored throughout the competition.</p>\n<hr>\n<h3>First Experiment: DilatedInception WaveNet</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F4e6d5e8edfa6c2798f54d583f416c017%2Fmodel1.JPG?generation=1756867480286012&amp;alt=media\" alt=\"\"><br>\nWaveNet is superior at finding patterns in waveforms. Using dilated convolutions, it decomposes a signal into tis different frequency since waves just like the Fourier Transfomer.</p>\n<p>And then I modiy the original dilated convolution to dilated inception convolution. <strong><em>Concretely speaking, instead of using only one kernel size per layer in <code>WaveBlock</code></em></strong> , <strong>this model tries to capture enriched temporal patterns by considering different kernel sizes(2,4,6,8) at the same time.</strong> Futhermore, to restrain model parameters from growing too much, the model narrows down the output channels of convolutions with different kernel sizes. Let out_channels = 64, each dilated convolution with a specific kernel size only outputs 16 channels, then the concatenation along channel dimension is applied to match out_channels = 64</p>\n<ul>\n<li><p><strong></strong></p>\n<pre><code>class (nn.Module):\n    def (self, in_channels, out_channels, dilation_rates, kernel_size, conv_module):\n        (Wave_Block, self).()\n        self.num_rates = dilation_rates\n        self.convs = nn.()\n        self.filter_convs = nn.()\n        self.gate_convs = nn.()\n        self.convs.(nn.(in_channels, out_channels, kernel_size=, bias=True))\n        dilation_rates = [ ** i for iin (dilation_rates)]&lt;pre&gt;&lt;code&gt;    for dilation_ratein dilation_rates:\n        self.filter_convs.(\n            (out_channels, out_channels, kernel_size, dilation_rate)\n        )\n        self.gate_convs.(\n            (out_channels, out_channels, kernel_size, dilation_rate)\n        )\n        self.convs.(\n            nn.(out_channels, out_channels, kernel_size=, bias=True)\n        )\n\n    for iin ((self.convs)):\n        nn.init.(self.convs[i].weight, gain=nn.init.())\n        nn.init.(self.convs[i].bias)\n\n    for min self.filter_convs:\n        for convin m.convs:\n            nn.init.(conv.weight, gain=nn.init.())\n            nn.init.(conv.bias)\n\n    for min self.gate_convs:\n        for convin m.convs:\n            nn.init.(conv.weight, gain=nn.init.())\n            nn.init.(conv.bias)\n\ndef (self,x):\n    x = self.convs[](x)\n    res = x# skip_connectionfor iin (self.num_rates):\n        tanh_out = torch.(self.filter_convs[i](x))\n        sigmoid_out = torch.(self.gate_convs[i](x))\n        x = tanh_out * sigmoid_out\n        x = self.convs[i+](x)\n        res = res + x\n\n    return res\n&lt;/code&gt;&lt;/pre&gt;</code></pre></li>\n<li><p><strong></strong></p>\n<pre><code></code></pre></li>\n</ul>\n<p><strong>If you want to learn more about dilated inception wavenet,</strong></p>\n<p>⇒ <strong><a href=\"https://www.kaggle.com/code/abaojiang/lb-0-46-dilatedinception-wavenet-training\" target=\"_blank\">click here</a></strong></p>\n<hr>\n<h3>Second Experiment: WaveNet + Transformer</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2Fa89dd579f3818cbf2d1d4127f0383f47%2Fmodel2.JPG?generation=1756867550984042&amp;alt=media\" alt=\"\"></p>\n<p>we propose a hybrid architecture that integrates <strong>WaveNet</strong> with a <strong>Transformer encoder</strong> to effecitively capture both <strong><em>local temporal patterns</em></strong> and <strong><em>long-range contextual information</em>.</strong> </p>\n<p>Since the Tranformer architecture does not inherently encode sequential order, it is necessary to inject positional information into the input features. We consider two widely adopted startgies for positional encoding</p>\n<p><strong>Method 1 | Fixed Sinusoidal Encoding</strong></p>\n<p>A deterministic embedding function based on sine and cosine with varying frequencies.</p>\n<pre><code>def (seq_len, feature_dim):\n\n    depth = feature_dim // \n    positions = torch.(seq_len, dtype=torch.float32).()\n\n    depths = torch.(depth, dtype=torch.float32).() / depth\n\n    angle_rates =  / (_000 ** depths)\n    angle_rads = positions @ angle_rates\n\n    pos_encoding = torch.([torch.(angle_rads), torch.(angle_rads)], dim=-) \n\n    return pos_encoding\n</code></pre>\n<p><strong>Method 2 | Learnable Positional Embedding</strong></p>\n<p>A trainable embedding vector assigned to each position index.</p>\n<pre><code></code></pre>\n<p><strong>Feature Extraction via WaveNet</strong></p>\n<p>WaveNet is employed as a feature extractor to model fine-grained temporal dependencies in the input sequence. Its dilated causal convolutional structure enables the network to capture multi-scale temporal patterns without loss of resolution. The output of WaveNet serves as a high-level representation that is subsequently fed into the Transformer encoder.</p>\n<p><em>And then Finally, yon can also try [WaveNet + Transformer + GRU]</em></p>\n<hr>\n<h3>Third Experiment: WaveNet + xLSTM + Attention</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F29c1ec9a3e630d63f1dc1cb343b709ba%2Fmodel3.JPG?generation=1756867571658122&amp;alt=media\" alt=\"\"></p>\n<p><strong>xLSTM</strong></p>\n<p>⇒ xLSTM GitHub: <a href=\"https://github.com/NX-AI/xlstm\" target=\"_blank\">https://github.com/NX-AI/xlstm</a></p>\n<p>⇒ xLSTM Discussion: <a href=\"https://www.kaggle.com/discussions/general/501522\" target=\"_blank\">https://www.kaggle.com/discussions/general/501522</a></p>\n<p>xLSTM is a new Recurrent Neural Network architecture based on ideas of the original LSTM. Through Exponential Gating with appropriate normalization and stabilization techniques and a new Matrix Memory it overcomes the limitations of the original LSTM and shows promising performance on Language Modeling when compared to Transformers or State Space Models.</p>\n<p><strong>Temporal Attention Mechanism</strong></p>\n<p>On top of the xLSTM outputs, an Attention Pooling is applied </p>\n<pre><code></code></pre>\n<p>This hybridization address both <strong>local structure(WaveNet)</strong>, <strong>long-term dependencies(xLSTM)</strong>, and <strong>global context(Attention)</strong>.</p>\n<hr>\n<h3>Fourth Experiment: Hybrid 1D CNN With WaveNet</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F9c5f2eadf06c9ffd19dc8b4a2efc3d23%2Fmodel4.JPG?generation=1756867592334566&amp;alt=media\" alt=\"\"></p>\n<p><strong>1. Data Characteristics and Motivation</strong></p>\n<p>Exploratory Data Analysis(EDA) revealed that each input sequence consists of two distinct phases: <strong>a transition phase</strong> and <strong>a gesture phase</strong>. On average, both phases account for approximately 50% of the total sequence length. The transition phase primarily reflects temporal variations occuring before the execution of a gesture, while the gesture phase encodes discriminative motion patterns corresponding to the performed action.</p>\n<p>This observation motivated us to design a <strong>phase-aware feature extraction strategy</strong>, where the model separately processes the two phase rather than treating the sequence as a homogeneous temporal signal.</p>\n<p><strong>2. Phase-Specific Feature Extraction</strong></p>\n<p>To explicitly leverage the different temporal characteristics of each phase, we divided the sequence into two equal segments.</p>\n<ul>\n<li><p><strong>First 50%(Transition Part):</strong></p>\n<p>This portion contains gradual temporal variations leading to gestures We employed a <strong>WaveNet-based module</strong> due to its ability to capture long-range dependencies and temporal dynamics with dilated causal convolutions. The WaveNet architecture is particularly effective at modeling non-stationary temporal transitions, making it well-suited for this phase.</p></li>\n<li><p><strong>Last 50%(Gesture Part):</strong></p>\n<p>This segment contains the core gesture information with relatively stable temporal structures. We applied a Temporal 1D Convolutional Neural Network(1D - CNN) to capture localied and discriminative motion patterns. The convolutiona filters effectively extract fine-grained temporal features, which are crucial for gesture recognition.</p></li>\n</ul>",
  "messages": [
    {
      "id": 3280677,
      "postDate": "2025-09-03T02:51:01.407Z",
      "content": "<p>First of all, I would like to thank my teemmate <a href=\"https://www.kaggle.com/jaewook704\" target=\"_blank\">@jaewook704</a> and the Child Mind Institute for hosting this competition. It has been a great learning experience for me. I also want to acknowledge and appreciate everyone who dedicated their time and effort over the past three months to participate in this challenge.</p>\n<p>One of my main motivations for joining was to study WaveNet in greater depth. However, during the experiments, I found that temporal 1D CNNs performed better than WaveNet, and as a result, my score was not as high as I had hoped.<br>\nThat said, I would like to take this opportunity to share the model architectures I explored throughout the competition.</p>\n<hr>\n<h3>First Experiment: DilatedInception WaveNet</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F4e6d5e8edfa6c2798f54d583f416c017%2Fmodel1.JPG?generation=1756867480286012&amp;alt=media\" alt=\"\"><br>\nWaveNet is superior at finding patterns in waveforms. Using dilated convolutions, it decomposes a signal into tis different frequency since waves just like the Fourier Transfomer.</p>\n<p>And then I modiy the original dilated convolution to dilated inception convolution. <strong><em>Concretely speaking, instead of using only one kernel size per layer in <code>WaveBlock</code></em></strong> , <strong>this model tries to capture enriched temporal patterns by considering different kernel sizes(2,4,6,8) at the same time.</strong> Futhermore, to restrain model parameters from growing too much, the model narrows down the output channels of convolutions with different kernel sizes. Let out_channels = 64, each dilated convolution with a specific kernel size only outputs 16 channels, then the concatenation along channel dimension is applied to match out_channels = 64</p>\n<ul>\n<li><p><strong></strong></p>\n<pre><code>class (nn.Module):\n    def (self, in_channels, out_channels, dilation_rates, kernel_size, conv_module):\n        (Wave_Block, self).()\n        self.num_rates = dilation_rates\n        self.convs = nn.()\n        self.filter_convs = nn.()\n        self.gate_convs = nn.()\n        self.convs.(nn.(in_channels, out_channels, kernel_size=, bias=True))\n        dilation_rates = [ ** i for iin (dilation_rates)]&lt;pre&gt;&lt;code&gt;    for dilation_ratein dilation_rates:\n        self.filter_convs.(\n            (out_channels, out_channels, kernel_size, dilation_rate)\n        )\n        self.gate_convs.(\n            (out_channels, out_channels, kernel_size, dilation_rate)\n        )\n        self.convs.(\n            nn.(out_channels, out_channels, kernel_size=, bias=True)\n        )\n\n    for iin ((self.convs)):\n        nn.init.(self.convs[i].weight, gain=nn.init.())\n        nn.init.(self.convs[i].bias)\n\n    for min self.filter_convs:\n        for convin m.convs:\n            nn.init.(conv.weight, gain=nn.init.())\n            nn.init.(conv.bias)\n\n    for min self.gate_convs:\n        for convin m.convs:\n            nn.init.(conv.weight, gain=nn.init.())\n            nn.init.(conv.bias)\n\ndef (self,x):\n    x = self.convs[](x)\n    res = x# skip_connectionfor iin (self.num_rates):\n        tanh_out = torch.(self.filter_convs[i](x))\n        sigmoid_out = torch.(self.gate_convs[i](x))\n        x = tanh_out * sigmoid_out\n        x = self.convs[i+](x)\n        res = res + x\n\n    return res\n&lt;/code&gt;&lt;/pre&gt;</code></pre></li>\n<li><p><strong></strong></p>\n<pre><code></code></pre></li>\n</ul>\n<p><strong>If you want to learn more about dilated inception wavenet,</strong></p>\n<p>⇒ <strong><a href=\"https://www.kaggle.com/code/abaojiang/lb-0-46-dilatedinception-wavenet-training\" target=\"_blank\">click here</a></strong></p>\n<hr>\n<h3>Second Experiment: WaveNet + Transformer</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2Fa89dd579f3818cbf2d1d4127f0383f47%2Fmodel2.JPG?generation=1756867550984042&amp;alt=media\" alt=\"\"></p>\n<p>we propose a hybrid architecture that integrates <strong>WaveNet</strong> with a <strong>Transformer encoder</strong> to effecitively capture both <strong><em>local temporal patterns</em></strong> and <strong><em>long-range contextual information</em>.</strong> </p>\n<p>Since the Tranformer architecture does not inherently encode sequential order, it is necessary to inject positional information into the input features. We consider two widely adopted startgies for positional encoding</p>\n<p><strong>Method 1 | Fixed Sinusoidal Encoding</strong></p>\n<p>A deterministic embedding function based on sine and cosine with varying frequencies.</p>\n<pre><code>def (seq_len, feature_dim):\n\n    depth = feature_dim // \n    positions = torch.(seq_len, dtype=torch.float32).()\n\n    depths = torch.(depth, dtype=torch.float32).() / depth\n\n    angle_rates =  / (_000 ** depths)\n    angle_rads = positions @ angle_rates\n\n    pos_encoding = torch.([torch.(angle_rads), torch.(angle_rads)], dim=-) \n\n    return pos_encoding\n</code></pre>\n<p><strong>Method 2 | Learnable Positional Embedding</strong></p>\n<p>A trainable embedding vector assigned to each position index.</p>\n<pre><code></code></pre>\n<p><strong>Feature Extraction via WaveNet</strong></p>\n<p>WaveNet is employed as a feature extractor to model fine-grained temporal dependencies in the input sequence. Its dilated causal convolutional structure enables the network to capture multi-scale temporal patterns without loss of resolution. The output of WaveNet serves as a high-level representation that is subsequently fed into the Transformer encoder.</p>\n<p><em>And then Finally, yon can also try [WaveNet + Transformer + GRU]</em></p>\n<hr>\n<h3>Third Experiment: WaveNet + xLSTM + Attention</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F29c1ec9a3e630d63f1dc1cb343b709ba%2Fmodel3.JPG?generation=1756867571658122&amp;alt=media\" alt=\"\"></p>\n<p><strong>xLSTM</strong></p>\n<p>⇒ xLSTM GitHub: <a href=\"https://github.com/NX-AI/xlstm\" target=\"_blank\">https://github.com/NX-AI/xlstm</a></p>\n<p>⇒ xLSTM Discussion: <a href=\"https://www.kaggle.com/discussions/general/501522\" target=\"_blank\">https://www.kaggle.com/discussions/general/501522</a></p>\n<p>xLSTM is a new Recurrent Neural Network architecture based on ideas of the original LSTM. Through Exponential Gating with appropriate normalization and stabilization techniques and a new Matrix Memory it overcomes the limitations of the original LSTM and shows promising performance on Language Modeling when compared to Transformers or State Space Models.</p>\n<p><strong>Temporal Attention Mechanism</strong></p>\n<p>On top of the xLSTM outputs, an Attention Pooling is applied </p>\n<pre><code></code></pre>\n<p>This hybridization address both <strong>local structure(WaveNet)</strong>, <strong>long-term dependencies(xLSTM)</strong>, and <strong>global context(Attention)</strong>.</p>\n<hr>\n<h3>Fourth Experiment: Hybrid 1D CNN With WaveNet</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F9c5f2eadf06c9ffd19dc8b4a2efc3d23%2Fmodel4.JPG?generation=1756867592334566&amp;alt=media\" alt=\"\"></p>\n<p><strong>1. Data Characteristics and Motivation</strong></p>\n<p>Exploratory Data Analysis(EDA) revealed that each input sequence consists of two distinct phases: <strong>a transition phase</strong> and <strong>a gesture phase</strong>. On average, both phases account for approximately 50% of the total sequence length. The transition phase primarily reflects temporal variations occuring before the execution of a gesture, while the gesture phase encodes discriminative motion patterns corresponding to the performed action.</p>\n<p>This observation motivated us to design a <strong>phase-aware feature extraction strategy</strong>, where the model separately processes the two phase rather than treating the sequence as a homogeneous temporal signal.</p>\n<p><strong>2. Phase-Specific Feature Extraction</strong></p>\n<p>To explicitly leverage the different temporal characteristics of each phase, we divided the sequence into two equal segments.</p>\n<ul>\n<li><p><strong>First 50%(Transition Part):</strong></p>\n<p>This portion contains gradual temporal variations leading to gestures We employed a <strong>WaveNet-based module</strong> due to its ability to capture long-range dependencies and temporal dynamics with dilated causal convolutions. The WaveNet architecture is particularly effective at modeling non-stationary temporal transitions, making it well-suited for this phase.</p></li>\n<li><p><strong>Last 50%(Gesture Part):</strong></p>\n<p>This segment contains the core gesture information with relatively stable temporal structures. We applied a Temporal 1D Convolutional Neural Network(1D - CNN) to capture localied and discriminative motion patterns. The convolutiona filters effectively extract fine-grained temporal features, which are crucial for gesture recognition.</p></li>\n</ul>",
      "rawMarkdown": "First of all, I would like to thank my teemmate @jaewook704 and the Child Mind Institute for hosting this competition. It has been a great learning experience for me. I also want to acknowledge and appreciate everyone who dedicated their time and effort over the past three months to participate in this challenge.\n\nOne of my main motivations for joining was to study WaveNet in greater depth. However, during the experiments, I found that temporal 1D CNNs performed better than WaveNet, and as a result, my score was not as high as I had hoped.\nThat said, I would like to take this opportunity to share the model architectures I explored throughout the competition.\n\n___\n### First Experiment: DilatedInception WaveNet\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F4e6d5e8edfa6c2798f54d583f416c017%2Fmodel1.JPG?generation=1756867480286012&alt=media)\nWaveNet is superior at finding patterns in waveforms. Using dilated convolutions, it decomposes a signal into tis different frequency since waves just like the Fourier Transfomer.\n\nAnd then I modiy the original dilated convolution to dilated inception convolution. ***Concretely speaking, instead of using only one kernel size per layer in `WaveBlock`*** , **this model tries to capture enriched temporal patterns by considering different kernel sizes(2,4,6,8) at the same time.** Futhermore, to restrain model parameters from growing too much, the model narrows down the output channels of convolutions with different kernel sizes. Let out_channels = 64, each dilated convolution with a specific kernel size only outputs 16 channels, then the concatenation along channel dimension is applied to match out_channels = 64\n\n- **<WaveBlock>**\n    \n    ```\n    class Wave_Block(nn.Module):\n        def __init__(self, in_channels, out_channels, dilation_rates, kernel_size, conv_module):\n            super(Wave_Block, self).__init__()\n            self.num_rates = dilation_rates\n            self.convs = nn.ModuleList()\n            self.filter_convs = nn.ModuleList()\n            self.gate_convs = nn.ModuleList()\n            self.convs.append(nn.Conv1d(in_channels, out_channels, kernel_size=1, bias=True))\n            dilation_rates = [2 ** i for iin range(dilation_rates)]\n    \n            for dilation_ratein dilation_rates:\n                self.filter_convs.append(\n                    conv_module(out_channels, out_channels, kernel_size, dilation_rate)\n                )\n                self.gate_convs.append(\n                    conv_module(out_channels, out_channels, kernel_size, dilation_rate)\n                )\n                self.convs.append(\n                    nn.Conv1d(out_channels, out_channels, kernel_size=1, bias=True)\n                )\n    \n            for iin range(len(self.convs)):\n                nn.init.xavier_uniform_(self.convs[i].weight, gain=nn.init.calculate_gain('relu'))\n                nn.init.zeros_(self.convs[i].bias)\n    \n            for min self.filter_convs:\n                for convin m.convs:\n                    nn.init.xavier_uniform_(conv.weight, gain=nn.init.calculate_gain('relu'))\n                    nn.init.zeros_(conv.bias)\n    \n            for min self.gate_convs:\n                for convin m.convs:\n                    nn.init.xavier_uniform_(conv.weight, gain=nn.init.calculate_gain('relu'))\n                    nn.init.zeros_(conv.bias)\n    \n        def forward(self,x):\n            x = self.convs[0](x)\n            res = x# skip_connectionfor iin range(self.num_rates):\n                tanh_out = torch.tanh(self.filter_convs[i](x))\n                sigmoid_out = torch.sigmoid(self.gate_convs[i](x))\n                x = tanh_out * sigmoid_out\n                x = self.convs[i+1](x)\n                res = res + x\n    \n            return res\n    ```\n    \n- **<DilatedInception>**\n    \n    ```\n    class DilatedInception(nn.Module):\n        def __init__(self, in_channels, out_channels, kernel_size, dilation_rate):\n            super().__init__()\n            n_kernels = len(kernel_size)\n            out_channels = out_channels // n_kernels\n    \n            self.convs = nn.ModuleList()\n            for kin kernel_size:\n                self.convs.append(\n                    nn.Conv1d(\n                        in_channels=in_channels,\n                        out_channels=out_channels,\n                        kernel_size=k,\n                        padding='same',\n                        dilation=dilation_rate,\n                    )\n                )\n        def forward(self, x):\n            x_convs = []\n            for convin self.convs:\n                x_conv = conv(x)\n                x_convs.append(x_conv)\n            h = torch.cat(x_convs, dim=1)\n    \n            return h\n    ```\n    \n\n**If you want to learn more about dilated inception wavenet,**\n\n⇒ **[click here](https://www.kaggle.com/code/abaojiang/lb-0-46-dilatedinception-wavenet-training)**\n___\n### Second Experiment: WaveNet + Transformer\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2Fa89dd579f3818cbf2d1d4127f0383f47%2Fmodel2.JPG?generation=1756867550984042&alt=media)\n\nwe propose a hybrid architecture that integrates **WaveNet** with a **Transformer encoder** to effecitively capture both ***local temporal patterns*** and ***long-range contextual information*.** \n\nSince the Tranformer architecture does not inherently encode sequential order, it is necessary to inject positional information into the input features. We consider two widely adopted startgies for positional encoding\n\n**Method 1 | Fixed Sinusoidal Encoding**\n\nA deterministic embedding function based on sine and cosine with varying frequencies.\n\n```\ndef positional_encoding(seq_len, feature_dim):\n\n    depth = feature_dim // 2\n    positions = torch.arange(seq_len, dtype=torch.float32).unsqueeze(1)\n    \n    depths = torch.arange(depth, dtype=torch.float32).unsqueeze(0) / depth\n    \n    angle_rates = 1.0 / (10_000 ** depths)\n    angle_rads = positions @ angle_rates\n    \n    pos_encoding = torch.cat([torch.sin(angle_rads), torch.cos(angle_rads)], dim=-1) \n    \n    return pos_encoding\n```\n\n**Method 2 | Learnable Positional Embedding**\n\nA trainable embedding vector assigned to each position index.\n\n```\nclass PositionalEmbedding(nn.Module):\n    def __init__(self, seq_len, feature_dim):\n        super(PositionalEmbedding, self).__init__()\n        self.pos_embedding = nn.Embedding(seq_len, feature_dim)\n        self.seq_len = seq_len\n\n    def forward(self, x):\n\n        batch_size = x.size(0)\n        device = x.device\n\n        positions = torch.arange(self.seq_len, device=device).unsqueeze(0).expand(batch_size, self.seq_len)# (B, S)pos_emb = self.pos_embedding(positions).permute(0, 2, 1)\n\n        return x + pos_emb\n```\n\n**Feature Extraction via WaveNet**\n\nWaveNet is employed as a feature extractor to model fine-grained temporal dependencies in the input sequence. Its dilated causal convolutional structure enables the network to capture multi-scale temporal patterns without loss of resolution. The output of WaveNet serves as a high-level representation that is subsequently fed into the Transformer encoder.\n\n*And then Finally, yon can also try [WaveNet + Transformer + GRU]*\n\n___\n### Third Experiment: WaveNet + xLSTM + Attention\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F29c1ec9a3e630d63f1dc1cb343b709ba%2Fmodel3.JPG?generation=1756867571658122&alt=media)\n\n**xLSTM**\n\n⇒ xLSTM GitHub: https://github.com/NX-AI/xlstm\n\n⇒ xLSTM Discussion: https://www.kaggle.com/discussions/general/501522\n\nxLSTM is a new Recurrent Neural Network architecture based on ideas of the original LSTM. Through Exponential Gating with appropriate normalization and stabilization techniques and a new Matrix Memory it overcomes the limitations of the original LSTM and shows promising performance on Language Modeling when compared to Transformers or State Space Models.\n\n**Temporal Attention Mechanism**\n\nOn top of the xLSTM outputs, an Attention Pooling is applied \n\n```\nclass TemporalAttentionPooling(nn.Module):\n    def __init__(self, input_channels, hidden_dim=64):\n        super(TemporalAttentionPooling, self).__init__()\n        self.attn = nn.Sequential(\n            nn.Conv1d(input_channels, hidden_dim, kernel_size=1),\n            nn.Tanh(),\n            nn.Conv1d(hidden_dim, 1, kernel_size=1)\n        )\n\n    def forward(self, x):\n        attn_scores = self.attn(x)\n        attn_weights = F.softmax(attn_scores, dim=-1)\n\n        weighted = x * attn_weights\n        pooled = weighted.sum(dim=-1)\n\n        return pooled\n```\n\nThis hybridization address both **local structure(WaveNet)**, **long-term dependencies(xLSTM)**, and **global context(Attention)**.\n\n___\n### Fourth Experiment: Hybrid 1D CNN With WaveNet\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F9c5f2eadf06c9ffd19dc8b4a2efc3d23%2Fmodel4.JPG?generation=1756867592334566&alt=media)\n\n**1. Data Characteristics and Motivation**\n\nExploratory Data Analysis(EDA) revealed that each input sequence consists of two distinct phases: **a transition phase** and **a gesture phase**. On average, both phases account for approximately 50% of the total sequence length. The transition phase primarily reflects temporal variations occuring before the execution of a gesture, while the gesture phase encodes discriminative motion patterns corresponding to the performed action.\n\nThis observation motivated us to design a **phase-aware feature extraction strategy**, where the model separately processes the two phase rather than treating the sequence as a homogeneous temporal signal.\n\n**2. Phase-Specific Feature Extraction**\n\nTo explicitly leverage the different temporal characteristics of each phase, we divided the sequence into two equal segments.\n\n- **First 50%(Transition Part):**\n    \n    This portion contains gradual temporal variations leading to gestures We employed a **WaveNet-based module** due to its ability to capture long-range dependencies and temporal dynamics with dilated causal convolutions. The WaveNet architecture is particularly effective at modeling non-stationary temporal transitions, making it well-suited for this phase.\n    \n- **Last 50%(Gesture Part):**\n    \n    This segment contains the core gesture information with relatively stable temporal structures. We applied a Temporal 1D Convolutional Neural Network(1D - CNN) to capture localied and discriminative motion patterns. The convolutiona filters effectively extract fine-grained temporal features, which are crucial for gesture recognition.",
      "votes": 8
    }
  ],
  "comments": [],
  "raw_markdown_by_id": {
    "3280677": "First of all, I would like to thank my teemmate @jaewook704 and the Child Mind Institute for hosting this competition. It has been a great learning experience for me. I also want to acknowledge and appreciate everyone who dedicated their time and effort over the past three months to participate in this challenge.\n\nOne of my main motivations for joining was to study WaveNet in greater depth. However, during the experiments, I found that temporal 1D CNNs performed better than WaveNet, and as a result, my score was not as high as I had hoped.\nThat said, I would like to take this opportunity to share the model architectures I explored throughout the competition.\n\n___\n### First Experiment: DilatedInception WaveNet\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F4e6d5e8edfa6c2798f54d583f416c017%2Fmodel1.JPG?generation=1756867480286012&alt=media)\nWaveNet is superior at finding patterns in waveforms. Using dilated convolutions, it decomposes a signal into tis different frequency since waves just like the Fourier Transfomer.\n\nAnd then I modiy the original dilated convolution to dilated inception convolution. ***Concretely speaking, instead of using only one kernel size per layer in `WaveBlock`*** , **this model tries to capture enriched temporal patterns by considering different kernel sizes(2,4,6,8) at the same time.** Futhermore, to restrain model parameters from growing too much, the model narrows down the output channels of convolutions with different kernel sizes. Let out_channels = 64, each dilated convolution with a specific kernel size only outputs 16 channels, then the concatenation along channel dimension is applied to match out_channels = 64\n\n- **<WaveBlock>**\n    \n    ```\n    class Wave_Block(nn.Module):\n        def __init__(self, in_channels, out_channels, dilation_rates, kernel_size, conv_module):\n            super(Wave_Block, self).__init__()\n            self.num_rates = dilation_rates\n            self.convs = nn.ModuleList()\n            self.filter_convs = nn.ModuleList()\n            self.gate_convs = nn.ModuleList()\n            self.convs.append(nn.Conv1d(in_channels, out_channels, kernel_size=1, bias=True))\n            dilation_rates = [2 ** i for iin range(dilation_rates)]\n    \n            for dilation_ratein dilation_rates:\n                self.filter_convs.append(\n                    conv_module(out_channels, out_channels, kernel_size, dilation_rate)\n                )\n                self.gate_convs.append(\n                    conv_module(out_channels, out_channels, kernel_size, dilation_rate)\n                )\n                self.convs.append(\n                    nn.Conv1d(out_channels, out_channels, kernel_size=1, bias=True)\n                )\n    \n            for iin range(len(self.convs)):\n                nn.init.xavier_uniform_(self.convs[i].weight, gain=nn.init.calculate_gain('relu'))\n                nn.init.zeros_(self.convs[i].bias)\n    \n            for min self.filter_convs:\n                for convin m.convs:\n                    nn.init.xavier_uniform_(conv.weight, gain=nn.init.calculate_gain('relu'))\n                    nn.init.zeros_(conv.bias)\n    \n            for min self.gate_convs:\n                for convin m.convs:\n                    nn.init.xavier_uniform_(conv.weight, gain=nn.init.calculate_gain('relu'))\n                    nn.init.zeros_(conv.bias)\n    \n        def forward(self,x):\n            x = self.convs[0](x)\n            res = x# skip_connectionfor iin range(self.num_rates):\n                tanh_out = torch.tanh(self.filter_convs[i](x))\n                sigmoid_out = torch.sigmoid(self.gate_convs[i](x))\n                x = tanh_out * sigmoid_out\n                x = self.convs[i+1](x)\n                res = res + x\n    \n            return res\n    ```\n    \n- **<DilatedInception>**\n    \n    ```\n    class DilatedInception(nn.Module):\n        def __init__(self, in_channels, out_channels, kernel_size, dilation_rate):\n            super().__init__()\n            n_kernels = len(kernel_size)\n            out_channels = out_channels // n_kernels\n    \n            self.convs = nn.ModuleList()\n            for kin kernel_size:\n                self.convs.append(\n                    nn.Conv1d(\n                        in_channels=in_channels,\n                        out_channels=out_channels,\n                        kernel_size=k,\n                        padding='same',\n                        dilation=dilation_rate,\n                    )\n                )\n        def forward(self, x):\n            x_convs = []\n            for convin self.convs:\n                x_conv = conv(x)\n                x_convs.append(x_conv)\n            h = torch.cat(x_convs, dim=1)\n    \n            return h\n    ```\n    \n\n**If you want to learn more about dilated inception wavenet,**\n\n⇒ **[click here](https://www.kaggle.com/code/abaojiang/lb-0-46-dilatedinception-wavenet-training)**\n___\n### Second Experiment: WaveNet + Transformer\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2Fa89dd579f3818cbf2d1d4127f0383f47%2Fmodel2.JPG?generation=1756867550984042&alt=media)\n\nwe propose a hybrid architecture that integrates **WaveNet** with a **Transformer encoder** to effecitively capture both ***local temporal patterns*** and ***long-range contextual information*.** \n\nSince the Tranformer architecture does not inherently encode sequential order, it is necessary to inject positional information into the input features. We consider two widely adopted startgies for positional encoding\n\n**Method 1 | Fixed Sinusoidal Encoding**\n\nA deterministic embedding function based on sine and cosine with varying frequencies.\n\n```\ndef positional_encoding(seq_len, feature_dim):\n\n    depth = feature_dim // 2\n    positions = torch.arange(seq_len, dtype=torch.float32).unsqueeze(1)\n    \n    depths = torch.arange(depth, dtype=torch.float32).unsqueeze(0) / depth\n    \n    angle_rates = 1.0 / (10_000 ** depths)\n    angle_rads = positions @ angle_rates\n    \n    pos_encoding = torch.cat([torch.sin(angle_rads), torch.cos(angle_rads)], dim=-1) \n    \n    return pos_encoding\n```\n\n**Method 2 | Learnable Positional Embedding**\n\nA trainable embedding vector assigned to each position index.\n\n```\nclass PositionalEmbedding(nn.Module):\n    def __init__(self, seq_len, feature_dim):\n        super(PositionalEmbedding, self).__init__()\n        self.pos_embedding = nn.Embedding(seq_len, feature_dim)\n        self.seq_len = seq_len\n\n    def forward(self, x):\n\n        batch_size = x.size(0)\n        device = x.device\n\n        positions = torch.arange(self.seq_len, device=device).unsqueeze(0).expand(batch_size, self.seq_len)# (B, S)pos_emb = self.pos_embedding(positions).permute(0, 2, 1)\n\n        return x + pos_emb\n```\n\n**Feature Extraction via WaveNet**\n\nWaveNet is employed as a feature extractor to model fine-grained temporal dependencies in the input sequence. Its dilated causal convolutional structure enables the network to capture multi-scale temporal patterns without loss of resolution. The output of WaveNet serves as a high-level representation that is subsequently fed into the Transformer encoder.\n\n*And then Finally, yon can also try [WaveNet + Transformer + GRU]*\n\n___\n### Third Experiment: WaveNet + xLSTM + Attention\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F29c1ec9a3e630d63f1dc1cb343b709ba%2Fmodel3.JPG?generation=1756867571658122&alt=media)\n\n**xLSTM**\n\n⇒ xLSTM GitHub: https://github.com/NX-AI/xlstm\n\n⇒ xLSTM Discussion: https://www.kaggle.com/discussions/general/501522\n\nxLSTM is a new Recurrent Neural Network architecture based on ideas of the original LSTM. Through Exponential Gating with appropriate normalization and stabilization techniques and a new Matrix Memory it overcomes the limitations of the original LSTM and shows promising performance on Language Modeling when compared to Transformers or State Space Models.\n\n**Temporal Attention Mechanism**\n\nOn top of the xLSTM outputs, an Attention Pooling is applied \n\n```\nclass TemporalAttentionPooling(nn.Module):\n    def __init__(self, input_channels, hidden_dim=64):\n        super(TemporalAttentionPooling, self).__init__()\n        self.attn = nn.Sequential(\n            nn.Conv1d(input_channels, hidden_dim, kernel_size=1),\n            nn.Tanh(),\n            nn.Conv1d(hidden_dim, 1, kernel_size=1)\n        )\n\n    def forward(self, x):\n        attn_scores = self.attn(x)\n        attn_weights = F.softmax(attn_scores, dim=-1)\n\n        weighted = x * attn_weights\n        pooled = weighted.sum(dim=-1)\n\n        return pooled\n```\n\nThis hybridization address both **local structure(WaveNet)**, **long-term dependencies(xLSTM)**, and **global context(Attention)**.\n\n___\n### Fourth Experiment: Hybrid 1D CNN With WaveNet\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F16438831%2F9c5f2eadf06c9ffd19dc8b4a2efc3d23%2Fmodel4.JPG?generation=1756867592334566&alt=media)\n\n**1. Data Characteristics and Motivation**\n\nExploratory Data Analysis(EDA) revealed that each input sequence consists of two distinct phases: **a transition phase** and **a gesture phase**. On average, both phases account for approximately 50% of the total sequence length. The transition phase primarily reflects temporal variations occuring before the execution of a gesture, while the gesture phase encodes discriminative motion patterns corresponding to the performed action.\n\nThis observation motivated us to design a **phase-aware feature extraction strategy**, where the model separately processes the two phase rather than treating the sequence as a homogeneous temporal signal.\n\n**2. Phase-Specific Feature Extraction**\n\nTo explicitly leverage the different temporal characteristics of each phase, we divided the sequence into two equal segments.\n\n- **First 50%(Transition Part):**\n    \n    This portion contains gradual temporal variations leading to gestures We employed a **WaveNet-based module** due to its ability to capture long-range dependencies and temporal dynamics with dilated causal convolutions. The WaveNet architecture is particularly effective at modeling non-stationary temporal transitions, making it well-suited for this phase.\n    \n- **Last 50%(Gesture Part):**\n    \n    This segment contains the core gesture information with relatively stable temporal structures. We applied a Temporal 1D Convolutional Neural Network(1D - CNN) to capture localied and discriminative motion patterns. The convolutiona filters effectively extract fine-grained temporal features, which are crucial for gesture recognition."
  },
  "complete": true,
  "source": "existing_discussion",
  "competition_id": 102335,
  "competition_slug": "cmi-detect-behavior-with-sensor-data",
  "team_id": 13915134,
  "solution_url": "/competitions/cmi-detect-behavior-with-sensor-data/writeups/top-10-solution-with-wavenet"
}