TorchLean API

NN.Spec.Models.Seq2seq

Seq2Seq (spec model) #

Encoder-decoder models for sequence generation.

This file supports both bounded token indices and differentiable token distributions. A bounded index has type Fin vocabularySize, so embedding lookup cannot silently substitute a value for an invalid token. A token distribution uses a vector of length vocabularySize and realizes embedding as a matrix multiplication.

PyTorch analogue:

Scope of this baseline:

The transformer encoder blocks used by the transformer variant come from NN/Spec/Models/Transformer.lean.

References:

PyTorch docs (for API intuition, not semantics):

Implementation status #

No API builder implements an encoder-decoder model. nn.rnn, nn.lstm, and nn.gru build single recurrent layers and NN/API/Models/Recurrent.lean builds sequence models with a per-step linear head, neither of which is this architecture. NN/Spec/Module/Seq2seq.lean wraps this file as a Spec.Module. No theorem is proved about it.

Training + gradients (one-hot inputs) #

Most of this file focuses on architecture variants and forward passes (teacher-forcing, inference-time decoding, optional self-attention in the decoder, etc.).

To make Seq2Seq usable as a first-class baseline, we also provide an explicit training objective and reverse-mode gradients for the differentiable path:

Bounded token indices are intentionally treated as non-differentiable.

Small gradient records #

structure Spec.Seq2SeqEmbeddingGrads (α : Type) [TorchLean.Storage α] (vocabularySize embedDim : ) :

Gradients for a token embedding table E : (vocabularySize × embedDim).

PyTorch analogue: nn.Embedding.weight.grad.

Instances For
    structure Spec.Seq2SeqGrads (α : Type) [TorchLean.Storage α] (srcVocabSize tgtVocabSize embedDim hiddenDim : ) :

    End-to-end gradient record for the differentiable Seq2Seq baseline.

    This bundles gradients for:

    • source/target embeddings,
    • encoder RNN,
    • decoder RNN,
    • decoder output projection,
    • optional decoder self-attention (if enabled in the decoder spec).
    Instances For
      structure Spec.Seq2SeqEmbeddingSpec (α : Type) [TorchLean.Storage α] (vocabularySize embedDim : ) :

      Seq2Seq token embedding specification.

      Parameters:

      • embedding: a lookup table E : (vocabularySize × embedDim).

      PyTorch analogue: nn.Embedding(vocabularySize, embedDim).

      • embedding : TorchLean.Tensor α [vocabularySize, embedDim]

        Embedding table E : (vocabularySize × embedDim).

      Instances For
        def Spec.Seq2SeqEmbeddingSpec.forward {α : Type} [TorchLean.Storage α] {vocabularySize embedDim seqLen : } (embedding : Seq2SeqEmbeddingSpec α vocabularySize embedDim) (tokenIds : TorchLean.Tensor (Fin vocabularySize) [seqLen]) :
        TorchLean.Tensor α [seqLen, embedDim]

        Embedding forward pass for discrete token ids.

        Inputs:

        • tokenIds : (seqLen), a tensor of indices bounded by the vocabulary size.

        Output:

        • y : (seqLen × embedDim), where each timestep selects a row of the embedding table.

        PyTorch analogue: nn.Embedding on an integer tensor. The Fin vocabularySize element type expresses the lookup precondition directly, rather than assigning an arbitrary meaning to an invalid token.

        Instances For
          def Spec.Seq2SeqEmbeddingSpec.forwardOneHot {α : Type} [TorchLean.Storage α] [Context α] {vocabularySize embedDim seqLen : } (embedding : Seq2SeqEmbeddingSpec α vocabularySize embedDim) (tokenOneHot : TorchLean.Tensor α [seqLen, vocabularySize]) :
          TorchLean.Tensor α [seqLen, embedDim]

          Seq2Seq embedding forward pass for one-hot / token distributions.

          This is the usual "embedding lookup as a matrix multiply":

          • if E : (vocabularySize × embedDim) is the embedding table,
          • and x_t : (vocabularySize) is a one-hot / probability vector for time step t,
          • then the embedded vector is y_t = x_tᵀ · E : (embedDim).

          PyTorch analogy: y = x @ E where x is one-hot / a distribution; this matches nn.Embedding when the input is exactly one-hot.

          Instances For
            def Spec.Seq2SeqEmbeddingSpec.backwardOneHot {α : Type} [TorchLean.Storage α] [Context α] {vocabularySize embedDim seqLen : } (embedding : Seq2SeqEmbeddingSpec α vocabularySize embedDim) (tokenOneHot : TorchLean.Tensor α [seqLen, vocabularySize]) (gradOutput : TorchLean.Tensor α [seqLen, embedDim]) :
            Seq2SeqEmbeddingGrads α vocabularySize embedDim × TorchLean.Tensor α [seqLen, vocabularySize]

            Backward pass for Seq2SeqEmbeddingSpec.forwardOneHot.

            This is just a time-distributed linear layer:

            y_t = token_tᵀ · E

            So:

            • dE = Σ_t token_t ⊗ dY_t
            • dToken_t = E · dY_t (not usually needed, but included for completeness)
            Instances For
              structure Spec.Seq2SeqRNNEncoderSpec (α : Type) [TorchLean.Storage α] (embedDim hiddenDim : ) :

              RNN-based encoder specification for Seq2Seq.

              This models an nn.RNN-style encoder over embedded tokens:

              • input is a sequence of embeddings (seqLen × embedDim),
              • output is the full hidden-state sequence plus the final hidden state.

              PyTorch analogue: nn.RNN(..., batch_first=True) (ignoring the batch axis), returning (output, h_n).

              • rnn : RNNSpec α embedDim hiddenDim

                RNN cell parameters.

              Instances For
                def Spec.Seq2SeqRNNEncoderSpec.forward {α : Type} [TorchLean.Storage α] [Context α] {embedDim hiddenDim seqLen : } (encoder : Seq2SeqRNNEncoderSpec α embedDim hiddenDim) (x : TorchLean.Tensor α [seqLen, embedDim]) (h0 : Option (TorchLean.Tensor α [hiddenDim])) :
                TorchLean.Tensor α [seqLen, hiddenDim] × TorchLean.Tensor α [hiddenDim]

                Forward pass for Seq2SeqRNNEncoderSpec.

                Inputs:

                • x : (seqLen × embedDim), embedded source tokens,
                • h0, optional initial hidden state (hiddenDim).

                Returns:

                • (outputs, final_h) where outputs : (seqLen × hiddenDim) is the per-timestep hidden sequence.
                Instances For
                  structure Spec.Seq2SeqLSTMEncoderSpec (α : Type) [TorchLean.Storage α] (embedDim hiddenDim : ) :

                  LSTM-based encoder specification for Seq2Seq.

                  This models an nn.LSTM-style encoder over embedded tokens, returning the full hidden sequence, final hidden state, and final cell state.

                  PyTorch analogue: nn.LSTM(..., batch_first=True) (ignoring the batch axis), returning (output, (h_n, c_n)).

                  • lstm : LSTMSpec α embedDim hiddenDim

                    LSTM cell parameters.

                  Instances For
                    def Spec.Seq2SeqLSTMEncoderSpec.forward {α : Type} [TorchLean.Storage α] [Context α] {embedDim hiddenDim seqLen : } (encoder : Seq2SeqLSTMEncoderSpec α embedDim hiddenDim) (x : TorchLean.Tensor α [seqLen, embedDim]) (h0 c0 : Option (TorchLean.Tensor α [hiddenDim])) :
                    TorchLean.Tensor α [seqLen, hiddenDim] × TorchLean.Tensor α [hiddenDim] × TorchLean.Tensor α [hiddenDim]

                    Forward pass for Seq2SeqLSTMEncoderSpec.

                    Inputs:

                    • x : (seqLen × embedDim), embedded source tokens,
                    • h0, optional initial hidden state (hiddenDim),
                    • c0, optional initial cell state (hiddenDim).

                    Returns:

                    • (outputs, final_h, final_c) where outputs : (seqLen × hiddenDim) is the per-timestep hidden sequence.
                    Instances For
                      structure Spec.Seq2SeqTransformerEncoderSpec (α : Type) [TorchLean.Storage α] [Context α] (embedDim numHeads numLayers : ) :

                      Transformer-based encoder specification for Seq2Seq.

                      This wrapper applies exactly numLayers TransformerEncoderLayers from NN.Spec.Models.Transformer as a left fold.

                      PyTorch analogue: nn.TransformerEncoder(nn.TransformerEncoderLayer(...), num_layers=...) (ignoring dropout and most configuration knobs).

                      Instances For
                        def Spec.Seq2SeqTransformerEncoderSpec.forward {α : Type} [TorchLean.Storage α] [Context α] {embedDim numHeads numLayers seqLen : } (encoder : Seq2SeqTransformerEncoderSpec α embedDim numHeads numLayers) (x : TorchLean.Tensor α [seqLen, embedDim]) (h1 : seqLen > 0) (h2 : embedDim > 0) :
                        TorchLean.Tensor α [seqLen, embedDim]

                        Forward pass for Seq2SeqTransformerEncoderSpec.

                        Input/output shape: (seqLen × embedDim).

                        This uses post-norm transformer layers from NN.Spec.Models.Transformer and does not model dropout; it is meant as a clean semantic reference rather than a full training-ready implementation.

                        Instances For
                          structure Spec.Seq2SeqDecoderSpec (α : Type) [TorchLean.Storage α] (embedDim hiddenDim vocabularySize : ) :

                          RNN decoder specification for Seq2Seq.

                          This decoder consumes a sequence of target-side embeddings and produces vocabulary logits:

                          • an RNNSpec cell updates the hidden state per timestep,
                          • a time-distributed LinearSpec maps hidden states to logits,
                          • optionally, causal self-attention transforms the decoder input embeddings before the RNN. Position i attends to inputs 0, ..., i, in both teacher forcing and greedy decoding.

                          PyTorch analogue: a hand-rolled decoder using nn.RNN and nn.linear, optionally preceded by nn.MultiheadAttention over the target embeddings (note: this is not encoder-decoder cross-attention).

                          • rnn : RNNSpec α embedDim hiddenDim

                            Decoder RNN cell parameters.

                          • attention : Option ((numHeads : ) × MultiHeadAttention α numHeads embedDim (embedDim / numHeads))

                            Optional causal self-attention over decoder inputs, shared by training and inference.

                          • outputProjection : LinearSpec α hiddenDim vocabularySize

                            Output projection (hiddenDim -> vocabularySize) producing per-timestep logits.

                          Instances For
                            def Spec.Seq2SeqDecoderSpec.attendInputs {α : Type} [TorchLean.Storage α] [Context α] {embedDim hiddenDim vocabularySize seqLen : } (decoder : Seq2SeqDecoderSpec α embedDim hiddenDim vocabularySize) (embeddings : TorchLean.Tensor α [seqLen, embedDim]) (hLen : seqLen 0) :
                            TorchLean.Tensor α [seqLen, embedDim]

                            Prepare the RNN inputs from a nonempty sequence of decoder embeddings.

                            With attention enabled, row i uses only rows 0, ..., i. The hard mask gives later positions zero weight, including in the attention backward pass. Without attention, the embeddings pass through unchanged. Teacher forcing and single-step decoding both use this function, so attention has the same parameters, projection order, and mask convention in both paths.

                            Instances For
                              def Spec.Seq2SeqDecoderSpec.forwardTeacherForcing {α : Type} [TorchLean.Storage α] [Context α] {embedDim hiddenDim vocabularySize tgtSeqLen : } (decoder : Seq2SeqDecoderSpec α embedDim hiddenDim vocabularySize) (targetEmbeddings : TorchLean.Tensor α [tgtSeqLen, embedDim]) (h0 : TorchLean.Tensor α [hiddenDim]) (h_len_nonzero : tgtSeqLen 0) :
                              TorchLean.Tensor α [tgtSeqLen, vocabularySize]

                              Teacher-forcing logits for a sequence of decoder inputs.

                              targetEmbeddings has shape (tgtSeqLen × embedDim) and contains the tokens fed to the decoder. For next-token prediction, the caller supplies the start token followed by the preceding target tokens; the labels are one position ahead of these inputs. Causal self-attention prepares each RNN input, then the recurrence starts at h0 and the output projection produces vocabulary logits. Changing a later decoder input cannot create an attention edge into an earlier position.

                              Instances For

                                Decoder backward (teacher forcing) #

                                The decoder is: (optional self-attention) → RNN → time-distributed linear projection.

                                We compute gradients by:

                                1. recomputing the attended embeddings (if any),
                                2. recomputing the decoder hidden sequence,
                                3. backpropagating through the output projection per timestep,
                                4. backpropagating through the RNN sequence,
                                5. optionally backpropagating through self-attention.
                                structure Spec.Seq2SeqDecoderGradients (α : Type) [TorchLean.Storage α] (embedDim hiddenDim vocabularySize tgtSeqLen : ) :

                                Gradients for the decoder parameters, target embeddings, and initial hidden state.

                                The attention field is present exactly when the decoder has an attention block. The final two fields keep the input sequence gradient separate from the gradient passed back to the encoder through its final hidden state.

                                Instances For
                                  def Spec.Seq2SeqDecoderSpec.backwardTeacherForcing {α : Type} [TorchLean.Storage α] [Context α] {embedDim hiddenDim vocabularySize tgtSeqLen : } (decoder : Seq2SeqDecoderSpec α embedDim hiddenDim vocabularySize) (targetEmbeddings : TorchLean.Tensor α [tgtSeqLen, embedDim]) (h0 : TorchLean.Tensor α [hiddenDim]) (h_len_nonzero : tgtSeqLen 0) (gradLogits : TorchLean.Tensor α [tgtSeqLen, vocabularySize]) :
                                  Seq2SeqDecoderGradients α embedDim hiddenDim vocabularySize tgtSeqLen

                                  Backward pass for Seq2SeqDecoderSpec.forwardTeacherForcing.

                                  Returns a Seq2SeqDecoderGradients record.

                                  The attended embeddings and hidden sequence are recomputed with the forward pass's causal mask. The same mask is passed to the attention VJP. An upstream gradient supported on an initial target prefix therefore cannot flow through an attention edge to a later decoder input.

                                  Instances For
                                    def Spec.Seq2SeqDecoderSpec.forwardStep {α : Type} [TorchLean.Storage α] [Context α] {embedDim hiddenDim vocabularySize prefixLen : } (decoder : Seq2SeqDecoderSpec α embedDim hiddenDim vocabularySize) (inputPrefix : TorchLean.Tensor α [prefixLen + 1, embedDim]) (previousHidden : TorchLean.Tensor α [hiddenDim]) :
                                    TorchLean.Tensor α [hiddenDim] × TorchLean.Tensor α [vocabularySize]

                                    Advance the decoder once using a nonempty prefix of input embeddings.

                                    previousHidden is the RNN state after processing all but the last prefix token. Attention sees the whole prefix, and its last row supplies the current RNN input. The earlier RNN steps are not replayed. The result contains the new hidden state and this step's vocabulary logits. Keeping the prefix explicit also lets a caller compare a teacher-forced prefix with a single inference step.

                                    Instances For
                                      def Spec.Seq2SeqDecoderSpec.forwardInference {α : Type} [TorchLean.Storage α] [Context α] {embedDim hiddenDim vocabularySize : } (decoder : Seq2SeqDecoderSpec α embedDim hiddenDim vocabularySize) (h0 : TorchLean.Tensor α [hiddenDim]) (targetEmbedding : TorchLean.Tensor α [vocabularySize, embedDim]) (startToken : Fin vocabularySize) (maxLen : ) :
                                      TorchLean.Tensor α [maxLen, vocabularySize] × TorchLean.Tensor (Fin vocabularySize) [maxLen]

                                      Greedy autoregressive decoding from startToken and the initial hidden state h0.

                                      Each step appends the current token embedding to the input prefix, applies forwardStep, and feeds the argmax token back as the next input. Optional self-attention therefore sees the same prefix as teacher forcing with those input tokens. The RNN state advances once per emitted token. Attention projections are recomputed from the stored prefix; this specification has no key/value cache.

                                      The result contains logits of shape (maxLen × vocabularySize) and maxLen predicted token ids. When maxLen = 0, both outputs are empty and no decoder step runs.

                                      Instances For
                                        structure Spec.Seq2SeqSpec (α : Type) [TorchLean.Storage α] (srcVocabSize tgtVocabSize embedDim hiddenDim : ) :

                                        Complete Seq2Seq model specification (baseline).

                                        This bundles:

                                        • source and target embedding tables,
                                        • an RNN encoder,
                                        • an RNN decoder with output projection (and optional decoder self-attention).

                                        PyTorch analogue: a small encoder-decoder model built from nn.Embedding, nn.RNN, and nn.linear.

                                        Instances For
                                          def Spec.Seq2SeqSpec.forwardTraining {α : Type} [TorchLean.Storage α] [Context α] {srcVocabSize tgtVocabSize embedDim hiddenDim srcSeqLen tgtSeqLen : } (model : Seq2SeqSpec α srcVocabSize tgtVocabSize embedDim hiddenDim) (sourceTokens : TorchLean.Tensor (Fin srcVocabSize) [srcSeqLen]) (targetTokens : TorchLean.Tensor (Fin tgtVocabSize) [tgtSeqLen]) (hTarget : tgtSeqLen 0) :
                                          TorchLean.Tensor α [tgtSeqLen, tgtVocabSize]

                                          Teacher-forcing logits from discrete source and decoder input tokens.

                                          sourceTokens supplies the encoder sequence. targetTokens supplies the decoder inputs: for next-token prediction, these are the start token followed by the preceding target tokens. The caller pairs the returned (tgtSeqLen × tgtVocabSize) logits with labels one position ahead. The function embeds these inputs as given; it does not insert a start token or shift the sequence.

                                          The encoder's final hidden state initializes the decoder. Optional decoder self-attention is causal, and embedding lookup treats the bounded token ids as discrete inputs without token-id gradients.

                                          Instances For
                                            def Spec.Seq2SeqSpec.forwardInference {α : Type} [TorchLean.Storage α] [Context α] {srcVocabSize tgtVocabSize embedDim hiddenDim srcSeqLen : } (maxTgtLen : ) (model : Seq2SeqSpec α srcVocabSize tgtVocabSize embedDim hiddenDim) (sourceTokens : TorchLean.Tensor (Fin srcVocabSize) [srcSeqLen]) (startToken : Fin tgtVocabSize) :
                                            TorchLean.Tensor α [maxTgtLen, tgtVocabSize] × TorchLean.Tensor (Fin tgtVocabSize) [maxTgtLen]

                                            Encode the source once and generate maxTgtLen target tokens greedily.

                                            The encoder's final hidden state initializes the decoder, and startToken supplies its first input. Each predicted token becomes the next decoder input. Optional causal self-attention uses that growing input prefix, with the same attention parameters as teacher forcing. The returned pair contains (maxTgtLen × tgtVocabSize) logits and maxTgtLen bounded token ids.

                                            Instances For

                                              Differentiable training + backward (one-hot inputs) #

                                              This is the “full” training interface for the Seq2Seq baseline.

                                              def Spec.Seq2SeqSpec.forwardTrainingOneHot {α : Type} [TorchLean.Storage α] [Context α] {srcVocabSize tgtVocabSize embedDim hiddenDim srcSeqLen tgtSeqLen : } (model : Seq2SeqSpec α srcVocabSize tgtVocabSize embedDim hiddenDim) (srcOneHot : TorchLean.Tensor α [srcSeqLen, srcVocabSize]) (tgtOneHot : TorchLean.Tensor α [tgtSeqLen, tgtVocabSize]) (hTgt : tgtSeqLen 0) :
                                              TorchLean.Tensor α [tgtSeqLen, tgtVocabSize]

                                              Differentiable forward pass for training (teacher forcing) using one-hot/token-distribution inputs.

                                              This is the same computation as Seq2SeqSpec.forwardTraining, except that embedding lookup is expressed as a matrix multiplication (forwardOneHot), so gradients can flow into the embedding tables and back into upstream token distributions. tgtOneHot contains the decoder inputs, in the same start-token/preceding-token order as the discrete path. For next-token prediction, the labels must be supplied separately to the loss, one position ahead of these inputs.

                                              Instances For
                                                def Spec.Seq2SeqSpec.crossEntropyLossOneHot {α : Type} [TorchLean.Storage α] [Context α] {srcVocabSize tgtVocabSize embedDim hiddenDim srcSeqLen tgtSeqLen : } [Shape.HasNonemptyAxis 1 (Shape.dim tgtSeqLen (Shape.dim tgtVocabSize Shape.scalar))] (model : Seq2SeqSpec α srcVocabSize tgtVocabSize embedDim hiddenDim) (srcOneHot : TorchLean.Tensor α [srcSeqLen, srcVocabSize]) (tgtOneHot : TorchLean.Tensor α [tgtSeqLen, tgtVocabSize]) (hTgt : tgtSeqLen 0) :
                                                α

                                                Per-timestep cross-entropy loss for the differentiable Seq2Seq baseline.

                                                Computes:

                                                1. logits via Seq2SeqSpec.forwardTrainingOneHot,
                                                2. probabilities via softmax,
                                                3. cross-entropy against the target token distribution at each timestep.

                                                PyTorch analogue: nn.CrossEntropyLoss applied per timestep (with probabilities represented as one-hot).

                                                Instances For
                                                  def Spec.Seq2SeqSpec.crossEntropyGradOneHot {α : Type} [TorchLean.Storage α] [Context α] {srcVocabSize tgtVocabSize embedDim hiddenDim srcSeqLen tgtSeqLen : } [Shape.HasNonemptyAxis 1 (Shape.dim tgtSeqLen (Shape.dim tgtVocabSize Shape.scalar))] (model : Seq2SeqSpec α srcVocabSize tgtVocabSize embedDim hiddenDim) (srcOneHot : TorchLean.Tensor α [srcSeqLen, srcVocabSize]) (tgtOneHot : TorchLean.Tensor α [tgtSeqLen, tgtVocabSize]) (hTgt : tgtSeqLen 0) :
                                                  α × Seq2SeqGrads α srcVocabSize tgtVocabSize embedDim hiddenDim

                                                  Compute (loss, grads) for the Seq2Seq baseline under per-timestep cross-entropy.

                                                  This returns gradients for:

                                                  • both embedding tables,
                                                  • the encoder RNN,
                                                  • the decoder RNN,
                                                  • the decoder output projection,
                                                  • and decoder self-attention (if present).
                                                  Instances For
                                                    structure Spec.AttentionSeq2SeqSpec (α : Type) [TorchLean.Storage α] (srcVocabSize tgtVocabSize embedDim hiddenDim : ) :

                                                    Attention-augmented Seq2Seq specification (simple encoder-output attention).

                                                    This record extends the baseline with an additional projection matrix used by the helper attention functions below (computeAttentionWeightsSpec / applyAttentionSpec).

                                                    Note: this file includes these attention helpers as a building block; the main baseline forward passes above do not integrate encoder-decoder cross-attention by default.

                                                    • sourceEmbedding : Seq2SeqEmbeddingSpec α srcVocabSize embedDim

                                                      Source embedding table.

                                                    • targetEmbedding : Seq2SeqEmbeddingSpec α tgtVocabSize embedDim

                                                      Target embedding table.

                                                    • encoder : Seq2SeqRNNEncoderSpec α embedDim hiddenDim

                                                      Encoder RNN parameters.

                                                    • decoder : Seq2SeqDecoderSpec α embedDim hiddenDim tgtVocabSize

                                                      Decoder parameters (RNN + output projection + optional self-attention).

                                                    • attentionWeights : TorchLean.Tensor α [hiddenDim, hiddenDim]

                                                      Attention projection matrix used to score encoder outputs against the decoder hidden state.

                                                    Instances For
                                                      def Spec.computeAttentionWeightsSpec {α : Type} [TorchLean.Storage α] [Context α] {hiddenDim seqLen : } (attentionWeights : TorchLean.Tensor α [hiddenDim, hiddenDim]) (decoderHidden : TorchLean.Tensor α [hiddenDim]) (encoderOutputs : TorchLean.Tensor α [seqLen, hiddenDim]) (h1 : hiddenDim 0) (_h2 : seqLen 0) :

                                                      Compute attention weights over encoder outputs for a single decoder hidden state.

                                                      This is a simple dot-product style attention:

                                                      1. project the decoder hidden state (attention_weights · decoder_hidden),
                                                      2. score each encoder hidden vector by an elementwise product + sum,
                                                      3. normalize scores with softmax over the sequence axis.

                                                      It is inspired by classic encoder-decoder attention mechanisms (Bahdanau-style), and this spec keeps the scoring rule compact.

                                                      Instances For
                                                        def Spec.applyAttentionSpec {α : Type} [TorchLean.Storage α] [Context α] {hiddenDim seqLen : } (attentionWeights : TorchLean.Tensor α [seqLen]) (encoderOutputs : TorchLean.Tensor α [seqLen, hiddenDim]) (h1 : seqLen 0) (_h2 : hiddenDim 0) :
                                                        TorchLean.Tensor α [hiddenDim]

                                                        Apply attention weights to encoder outputs (weighted sum / context vector).

                                                        Given attention weights a : (seqLen) and encoder outputs H : (seqLen × hiddenDim), returns the context vector c = Σ_i a_i · H_i : (hiddenDim).

                                                        Instances For