Iteratively passing elements of different sequences through LSTM

Zador: <p>Hi,</p>
<p>My goal is to use an LSTM in a dataloader. I am filling up a volume in the dataloader with LSTM states. At some iteration, I take a feature vector and assign it to a position in this space. Then I use the h_n and c_n I have assigned to this space (from a previous iteration) as an input to my LSTM in addition to the feature vector. The output I save in the volume as well, and additionally I save the new h_n and c_n in the volume. Then, after this process is complete, I return the final outputs of the lstm.</p>
<p>After loading from the dataloader, I use these outputs as inputs to another NN to make a prediction, and finally, want to backpropogate to update both the prediction NN and the LSTM parameters.</p>
<p>So of course when I am saving the LSTM outputs in a volume, I need to keep its grad_fn, however, must I also save the grad_fn info of h_n and c_n when saving it in my volume and using it as inputs to the LSTM in the upcoming iteration?</p>

ptrblck: <p>I’m not sure why you are moving the LSTM execution to the <code>DataLoader</code> as it would complicate the state assignments. Wouldn’t it work to use the <code>DataLoader</code> in the common way to yield the samples and use the LSTM as well as the other model inside the <code>DataLoader</code> loop?</p>

Zador: <p>Hi, thanks for your response. I am sure I can avoid using a DataLoader but it makes my framework simpler (unless it really does “complicate the state assignments”). Everything in the <code>DataLoader</code> is part of the preprocessing of data and that includes the LSTM. The task is simple; for some point in space, I accumulate information temporally in the forms of vectors. The LSTMs task is to give me one feature vector summarizing this sequence. The result is my training data ready for my actual net responsible for making the predictions. The two main reasons why I want my framework to work as described:</p>
<ol>
<li>
<code>DataLoader</code> makes it convenient to parallelize the preprocessing, and that includes the LSTM.</li>
<li>As this will be computationally intensive, I do not want to load all relevant vectors of the sequences into memory; instead I want to do this incrementally.</li>
</ol>
<p>I believe I have found the answer to my original question. I had not realized what I was looking for was called “Statefule LSTM”, and once I had realized this it was easy to search for examples on how to do this. However, you mentioned that there are difficulties in executing the LSTM in the DataLoader. Is there I way to do this?</p>

ptrblck: <aside class="quote no-group" data-username="Zador" data-post="3" data-topic="140584">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/zador/48/15365_2.png" class="avatar"> Zador:</div>
<blockquote>
<p>However, you mentioned that there are difficulties in executing the LSTM in the DataLoader. Is there I way to do this?</p>
</blockquote>
</aside>
<p>I’m sure the is a way to achieve what you want by writing a custom dataset, sampler, etc.<br>
The main complication I see is that the common workflow of using indices to load and process a data sample wouldn’t work anymore, as your LSTM would need to get the previous states as well.<br>
I.e. assuming you want to use multiple workers in the <code>DataLoader</code>, I guess you want to track and provide the last LSTM state in each copy of the dataset instance or are you woring on a way to use a “global” state and share it between each worker?</p>

Zador: <p>Thanks for your reply! Yes, it is important for me to be able to use multiple workers in the DataLoader. I am not sure I see your point. I will write out what I think is happening so that you can tell me where I am going wrong.</p>
<p>What I imagined:</p>
<ol>
<li>DataLoader workers with LSTM load data [data1, …, datan], and then these tensors would have the LSTM autograd states [LSTM1, …, LSTMn].</li>
<li>DataLoader returns [(data1 w/ LSTM1), …, (datan w/ LSTMn)], where (datai w/ LSTMi) just means LSTMi states are stored in the datai tensor.</li>
<li>Then through SomeNet: [(data1 w/ LSTM1), …, (datan w/ LSTMn)] → [(data1 w/ [LSTM1, SomeNet1]), …, (datan w/ [LSTMn, SomeNetn])</li>
</ol>
<p>So if this works the optimizer optimizing over [LSTM.parameters(), SomeNet.parameters()] should have access to the full history of autograd states. Considering the data generated by each worker get passed independently through SomeNet, it should be okay that the autograd states of datai are independent of those fo dataj. Which step/assumption is incorrect?</p>
<p>Perhaps there was a misunderstanding? When I talked about passing sequences incrementally through an LSTM what I meant was within one worker, I am loading in data incrementally and thus the LSTM must be stateful, and I didn’t mean multiple workers work on different sections of the same sequence.</p>
<p>Looking forward to your reply.</p>

ptrblck: <p>Your general workflow might work, but:</p>
<blockquote>
<p>DataLoader workers with LSTM load data [data1, …, datan], and then these tensors would have the LSTM autograd states [LSTM1, …, LSTMn].</p>
</blockquote>
<p>an LSTM expects the data input as well as the cell and hidden state. If you are not passing the latter ones, they will be initialized with their default values and this wouldn’t match “and thus the LSTM must be stateful”.<br>
So how are you passing the cell and hidden state from the previous iteration to the current forward pass of the LSTM inside each worker?</p>

Zador: <p>Right so here is what I am doing:</p>
<p>I made a custom dataset for my DataLoader; inside the <code>load_file</code> function of this DataLoader I incrementally load batches of a sequence (another DataLoader w/o shuffle). For example, when DataLoader would be loading data-i, inside the dataloder I load [batch-i.1, …, batch-i.m] in a loop. Furthermore, inside the dataset I also initialize two tensors of zeros b and c. Then the pseudo code for the loop looks as follows:</p>
<p>Init: j = 1</p>
<p>Loop:</p>
<ol>
<li>_, (b, c) = LSTM(batch-i.j, (b,c))</li>
<li>j ← j+1</li>
</ol>
<p>while j &lt; m</p>
<p>data1, _ = LSTM(batch-i,m, (b,c))</p>
<p>So hidden states get passed iteratively back into the LSTM and all of this is handled by one worker. What do you think?</p>
<p>About this loop however I did see this post <a href="https://discuss.pytorch.org/t/training-stateful-lstm-in-pytorch-cause-runtime-error/44537" class="inline-onebox">Training Stateful LSTM in Pytorch cause runtime error</a> where the accepted answer says “I think you need to detach both hiddens because the hiddens that are output from the LSTM will require grad.” Wouldn’t you say this information is counterintuitive? If we are removing the gradient states from b and c form previous iterations using .detach(), then how do the gradient states get stored throughout the entire sequence?</p>