Modify hidden state of LSTM and output

noahw31: <p>Hello everyone,<br>
I want to train a LSTM, but i have some modifications to do to the calculations. I want to perform some calculations on the hidden state, before it gets passed on to the next calculation for the next element in the sequence. Lets say:</p>
<p><code>h' = o * \tanh(c')</code></p>
<p>But i now want to take this <code>h</code>, pass it through a fully connected layer, do some calculations with it to get another value <code>A</code> (which i want to be the actual output of the cell, instead of <code>h</code>) and then pass the modified <code>h</code> to the next calculation. I have tried modifying the <code>nn.LSTMCell</code> but i am not sure if this is even the right place to start. I have trained a net before using the plain <code>nn.LSTM()</code> class and this worked well.</p>
<p>Maybe someone has a recommendation on where and what i should change to achieve that. Thank you in advance</p>

J_Johnson: <p><code>nn.LSTMCell()</code> is just a basic version of <code>nn.LSTM</code> where <code>num_layers = 1</code> and <code>bidircectional = False</code>.</p>
<p>With that said, you can make changes to the hidden state(hx) or cell state(cx) by using a sequence length of 1 at each time step(assuming you wish to make your calculation at every time step).</p>
<pre><code class="lang-auto">rnn = nn.LSTMCell(10, 20)  # (input_size, hidden_size)
input = torch.randn(2, 3, 10)  # (time_steps, batch, input_size)
hx = torch.randn(3, 20)  # (batch, hidden_size)
cx = torch.randn(3, 20)
output = []
for i in range(input.size()[0]):
    hx, cx = rnn(input[i], (hx.detach(), cx.detach()))
    hx = hx*2 #&lt;&lt;&lt;&lt; some calculation &gt;&gt;&gt;&gt;
    output.append(hx)
output = torch.stack(output, dim=0)
</code></pre>
<p>Note, you might not need the <code>.detach()</code> to prevent the graph from getting captured through time steps under more recent torch versions, but I include them by habit and they don’t hurt anything.</p>

noahw31: <p>Thank you for your answer, this definitely makes sense, and i think this solves the problem in general, but:</p>
<p>I have tried this already and had the problem that this was quite slow since i iterate over all the samples from the batch.<br>
When i use the LSTM in a normal setup, it seems that the whole batch is processed with one call. So is there a way to modify the function that really does the computation on the whole batch? I hope its clear what i mean, i try to show an example:</p>
<p>For standard LSTM with batch of 100:</p>
<pre><code class="lang-auto">output, h_c = self.lstm(x.squeeze(), (h.detach(), c.detach()))
</code></pre>
<p>Gives output of batch size</p>
<p>Now what i am trying to do is have the same call, but internally change how the hidden state is calculated. Thanks</p>

J_Johnson: <p>I can’t tell from your code if you mean batch size or sequence length. You can make the batch size any size your RAM can handle. The batch dimension is NOT processed as a sequence. Since the calculations are independent of each other, it is handled asynchronously.</p>
<p>But if you mean sequence length(which is <code>dim = 0</code>, unless you set <code>batch_first = True</code>), as far as I know, the underlying LSTM code in C++ iterates over the sequence length. It is synchronous.</p>

noahw31: <p>Thanks for the reply,<br>
maybe i am not understanding the terms here precisely. From my understanding, giving the lstm() function a tensor of length 100 would mean, the length 100 output is calculated by unfolding the lstm 100 times, internally passing the hidden states for each sample. Using the <code>for</code> loop as you proposed, i do the same but not giving the <code>lstm</code> the whole sequence at once, but sample by sample and manually passing the hidden state as an argument?<br>
Sorry if this is confusing or completely wrong, I am familiar how LSTMs work, but not exactly how they behave in pytorch.</p>

J_Johnson: <p>Please refer here to input, h_0 and c_0:</p>
<p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/3/d/3dcce5108f979710fe70ac8b86de4e3306de96ff.png" data-download-href="https://discuss.pytorch.org/uploads/default/3dcce5108f979710fe70ac8b86de4e3306de96ff" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/3/d/3dcce5108f979710fe70ac8b86de4e3306de96ff_2_571x500.png" alt="image" data-base62-sha1="8OI6RIdbr2p0BPk7VL7mPlqr58j" width="571" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/3/d/3dcce5108f979710fe70ac8b86de4e3306de96ff_2_571x500.png, https://discuss.pytorch.org/uploads/default/optimized/3X/3/d/3dcce5108f979710fe70ac8b86de4e3306de96ff_2_856x750.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/3/d/3dcce5108f979710fe70ac8b86de4e3306de96ff.png 2x" data-dominant-color="F6F6F6"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">960×840 78.5 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div><br>
Link: <a href="https://pytorch.org/docs/stable/generated/torch.nn.LSTM.html" class="inline-onebox" rel="noopener nofollow ugc">LSTM — PyTorch 2.1 documentation</a></p>
<p>Depending on what your dims are will determine whether it’s the batch size or sequence length. For example:</p>
<pre><code class="lang-auto">sequence_length = 100
batch_size = 200
features_dim = 128
lstm_input = torch.rand((sequence_length, batch_size, features_dim))

# or with no batch
lstm_input = torch.rand((sequence_length, features_dim))
</code></pre>