def forward(self, x, n_channel_offset=0, perturb=False):
        """
        Forward pass of the BIOT encoder.

        For each channel, the input is transformed into a spectrogram
        and then embedded using a patch embedding. The channel token
        is added to the patch embedding, and then positional encoding
        is applied. The resulting embeddings are concatenated and
        passed through a transformer layer. The mean of the resulting
        embeddings is returned.

        For each channel in channels, the channels are transformed into a
        spectrogram with STFT; The spectrogram representation is permuted
        and passed through a linear layer to learn some representation over
        the frequency domain.

        For each embedding in the sequence, the channel token is added to
        the patch embedding, and then positional encoding is applied.

        The resulting embeddings are concatenated and passed through a
        transformer layer. The mean of the resulting embeddings is returned.

        Parameters
        ----------
        x: Tensor
            (batch_size, n_channels, n_times)
        n_channel_offset: int (default 0)
            The offset term to be added to the channel tokens
        perturb: bool (default False)
            Randomly select a number of time steps and reduce the
            channel embedding to those time steps.

        Returns
        -------
        emb: Tensor
            (batch_size, emb_size)
        """
        emb_seq = []
        for i in range(x.shape[1]):
            # Getting the spectrogram
            channel_spec_emb = self.stft(x[:, i : i + 1, :])
            # Linear layer to learn some representation over the frequency domain
            # with permutation
            channel_spec_emb = self.patch_embedding(channel_spec_emb)
            batch_size, ts, _ = channel_spec_emb.shape
            # (batch_size, ts, emb)
            # Step by step the following lines do the following operations:
            #    - self.channel_tokens(self.index[i + n_channel_offset]):
            #    Fetches the embedding for a channel specified by i + n_channel_offset,
            #    where i is the current index and n_channel_offset adjusts
            #    which channel's embedding is retrieved.
            #    - .unsqueeze(0).unsqueeze(0):
            #    Adds two singleton dimensions to the embedding tensor.
            #    [emb_size] to [1, 1, emb_size] .
            #    - Repeat(batch_size, ts, 1):
            #    Replicates the embedding tensor to match the batch size and
            #    time steps (ts),
            channel_token_emb = (
                self.channel_tokens(self.index[i + n_channel_offset])
                .unsqueeze(0)
                .unsqueeze(0)
                .repeat(batch_size, ts, 1)
            )
            # (batch_size, ts, emb)
            # The positional embedding is explaining with more
            # detail in the _PositionalEncoding class.
            channel_emb = self.positional_encoding(channel_spec_emb + channel_token_emb)
            # In case of perturb, the time steps are randomly selected
            # and the channel embedding is reduced to a random number
            # of time steps.
            if perturb:
                ts = channel_emb.shape[1]
                ts_new = torch.randint(low=ts // 2, high=ts, size=(1,)).item()
                selected_ts = torch.randperm(ts)[:ts_new]
                channel_emb = channel_emb[:, selected_ts]
            emb_seq.append(channel_emb)

        # Concat and transformer
        # (batch_size, 16 * ts, emb)
        emb = torch.cat(emb_seq, dim=1)
        # (batch_size, emb)
        emb = self.transformer(emb).mean(dim=1)
        return emb

        Forward pass of the BIOT encoder.

        For each channel, the input is transformed into a spectrogram
        and then embedded using a patch embedding. The channel token
        is added to the patch embedding, and then positional encoding
        is applied. The resulting embeddings are concatenated and
        passed through a transformer layer. The mean of the resulting
        embeddings is returned.

        For each channel in channels, the channels are transformed into a
        spectrogram with STFT; The spectrogram representation is permuted
        and passed through a linear layer to learn some representation over
        the frequency domain.

        For each embedding in the sequence, the channel token is added to
        the patch embedding, and then positional encoding is applied.

        The resulting embeddings are concatenated and passed through a
        transformer layer. The mean of the resulting embeddings is returned.

        Parameters
        ----------
        x: Tensor
            (batch_size, n_channels, n_times)
        n_channel_offset: int (default 0)
            The offset term to be added to the channel tokens
        perturb: bool (default False)
            Randomly select a number of time steps and reduce the
            channel embedding to those time steps.

        Returns
        -------
        emb: Tensor
            (batch_size, emb_size)
        
braindecode/models/biot.py