关于LSTM网络编程中的一些坑

本次出现的问题:

在神经网络的forward方法中,对于输出的隐藏状态和记忆体,采用了直观粗暴的函数形参回代的方式进行更新。造成了梯度清空。

    def forward(self,inp):
        to_in = self.flat(inp)
        f,_ = self.lstm(to_in,(self.h0,self.c0))
        (self.h0,self.c0) = _
        return self.model1(f)


RuntimeError: Trying to backward through the graph a second time (or directly access saved variables after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved variables after calling backward.

 

  • 在解决问题一的过程中,看到了网上的一个解决方案,让将loss.backward()中的retain_graph参数设置为true,理由是在LSTM网络的逆向求梯度过程中,每个记忆细胞会涉及到两次求梯度,因为其同时是本轮的LSTM层输出,同时是下一轮LSTM层输入,而backward方法会默认在本轮计算完成之后清除掉其梯度值,无法在下一轮中再求一次。因此应设置为True。

但一方面,当时没想到其作为输出时间并未参与下一层的运算于是不必参与本轮求梯度,自然不牵扯两次backward,(为证明这个说法,只需要设计一个实验——将记忆细胞同时作为下面全连接层的输入值,测试其能否在retain_graph=False时支持loss正常backward,如果不能,这个说法就是正确的。),其实不必设置保留计算图(retain_graph);

RuntimeError: CUDA out of memory. Tried to allocate 20.00 MiB (GPU 0; 11.00 GiB total capacity; 9.64 GiB already allocated; 0 bytes free; 9.65 GiB reserved in total by PyTorch)

另一方面,设置了保留计算图,阻止了一批批计算中梯度信息的自动释放,却没有在之后自主地释放它,就造成了存储空间的堆积。或许保留计算图在这个训练中是不需要的,但我之后要搞清楚什么时候会用到它并搞清楚自主释放梯度信息的时机与方法

  • LSTM神经元的输出中,除了预测值,还包含着时刻状态记忆细胞,同时每个神经元的输入也要包含上次输入的状态和记忆细胞。直觉上,如果要进行这两个参数的更新,就需要输出这两个参数并进行回传。但在使用Pytorch时,如果细究其逆传播优化的原理,就会发现,对于所有参数的迭代都是由优化器完成的,在forward函数中设计前向传播即可。反之,如果在forward函数中设置参数迭代,就会使一个参数被迭代多次,不但破坏了“参数版本”的连续性,同时要多次求梯度,使默认的retain_graph为false不可行。

你可能感兴趣的:(lstm,深度学习,人工智能)