|
| 1 | +# lstm |
| 2 | + |
| 3 | +Long Short-Term Memory recurrent layer. Preserved as a named `lstm` composite op (mirroring the CoreML MIL `lstm` interface) so the compiler and delegates can recognize the whole recurrent layer instead of a decomposed, unrolled sequence of primitive ops. |
| 4 | + |
| 5 | +Per timestep, for each layer and direction: |
| 6 | + |
| 7 | +$$ |
| 8 | +\begin{aligned} |
| 9 | +i_t &= \sigma(W_{ii} x_t + b_i + W_{hi} h_{t-1}) \\ |
| 10 | +f_t &= \sigma(W_{if} x_t + b_f + W_{hf} h_{t-1}) \\ |
| 11 | +g_t &= \tanh(W_{ig} x_t + b_g + W_{hg} h_{t-1}) \\ |
| 12 | +o_t &= \sigma(W_{io} x_t + b_o + W_{ho} h_{t-1}) \\ |
| 13 | +c_t &= f_t \odot c_{t-1} + i_t \odot g_t \\ |
| 14 | +h_t &= o_t \odot \tanh(c_t) |
| 15 | +\end{aligned} |
| 16 | +$$ |
| 17 | + |
| 18 | +**ATen source:** `aten.lstm.input` |
| 19 | + |
| 20 | +A single composite is emitted per layer. Stacked (multi-layer) LSTMs chain one composite per layer; bidirectional layers use a single composite that also takes the backward weights. Weights are reordered from PyTorch's `[i, f, g, o]` gate layout to MIL's `[i, f, o, g]`, and the input/hidden biases are summed into one `bias`, so the composite inputs match the MIL `lstm` op directly. |
| 21 | + |
| 22 | +## Inputs |
| 23 | + |
| 24 | +| Name | Shape | Description | |
| 25 | +|---|---|---| |
| 26 | +| `x` | `(S, B, I)` | Input sequence (time-major; `batch_first` inputs are transposed before the composite) | |
| 27 | +| `initial_h` | `(B, H)` or `(B, 2H)` | Initial hidden state (forward+reverse packed on the hidden axis when bidirectional) | |
| 28 | +| `initial_c` | `(B, H)` or `(B, 2H)` | Initial cell state | |
| 29 | +| `weight_ih` | `(4H, I)` | Input-hidden weights, `ifog` gate layout | |
| 30 | +| `weight_hh` | `(4H, H)` | Hidden-hidden weights, `ifog` gate layout | |
| 31 | +| `bias` | `(4H,)` | Combined input+hidden bias (zeros when the layer has no bias) | |
| 32 | +| `weight_ih_back` | `(4H, I)` | Backward-direction input-hidden weights (bidirectional only) | |
| 33 | +| `weight_hh_back` | `(4H, H)` | Backward-direction hidden-hidden weights (bidirectional only) | |
| 34 | +| `bias_back` | `(4H,)` | Backward-direction combined bias (bidirectional only) | |
| 35 | + |
| 36 | +## Attributes |
| 37 | + |
| 38 | +| Name | Type | Description | |
| 39 | +|---|---|---| |
| 40 | +| `direction` | `str` | `"forward"` or `"bidirectional"` | |
| 41 | +| `output_sequence` | `bool` | Always `true` — the full per-timestep hidden sequence is returned | |
| 42 | +| `recurrent_activation` | `str` | Gate activation (`"sigmoid"`) | |
| 43 | +| `cell_activation` | `str` | Cell activation (`"tanh"`) | |
| 44 | +| `activation` | `str` | Output activation (`"tanh"`) | |
| 45 | +| `version` | `int` | Composite op version | |
| 46 | + |
| 47 | +## Outputs |
| 48 | + |
| 49 | +| Name | Shape | Description | |
| 50 | +|---|---|---| |
| 51 | +| `output` | `(S, B, DH)` | Hidden state at every timestep (`D` = 2 if bidirectional) | |
| 52 | +| `h_n` | `(B, DH)` | Final hidden state | |
| 53 | +| `c_n` | `(B, DH)` | Final cell state | |
| 54 | + |
| 55 | +The final `output`, `h_n`, and `c_n` returned by the converted graph follow the standard PyTorch `nn.LSTM` layout (`batch_first` reapplied to `output`; states shaped `(num_layers * D, B, H)`). |
| 56 | + |
| 57 | +## Data types |
| 58 | + |
| 59 | +`fp16`, `fp32`, `bf16`. |
| 60 | + |
| 61 | +## Limitations |
| 62 | + |
| 63 | +- The sequence length must be static (known at export time). |
| 64 | +- Packed / variable-length sequences (`aten.lstm.data`, `pack_padded_sequence`) are not supported. |
| 65 | +- Training-time dropout (`train=True`, `dropout>0`, `num_layers>1`) is not supported; a dropout rate configured on an `nn.LSTM` evaluated in inference mode is a no-op and safely ignored. |
| 66 | + |
| 67 | +## PyTorch example |
| 68 | + |
| 69 | +```python |
| 70 | +import torch |
| 71 | + |
| 72 | +lstm = torch.nn.LSTM(input_size=4, hidden_size=3, num_layers=2, batch_first=True).eval() |
| 73 | +x = torch.randn(2, 5, 4) |
| 74 | +h0 = torch.randn(2, 2, 3) |
| 75 | +c0 = torch.randn(2, 2, 3) |
| 76 | +output, (h_n, c_n) = lstm(x, (h0, c0)) |
| 77 | +``` |
| 78 | + |
| 79 | +## Reference |
| 80 | + |
| 81 | +[`torch.nn.LSTM`](https://docs.pytorch.org/docs/stable/generated/torch.nn.LSTM.html) |
0 commit comments