LSTM应用场景以及pytorch实例
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false},
{left: '\\(', right: '\\)', display: false},
{left: '\\[', right: '\\]', display: true}
],
throwOnError : false
});
});
</script>
<p>在去年介绍的一篇paper中,应用了多任务RNN来解决问题,当时RNN指的即是LSTM。本文介绍LSTM实现以及应用。</p>
<h2 id="1-lstm简介" class="relative group">1. LSTM简介 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#1-lstm%e7%ae%80%e4%bb%8b" aria-label="Anchor">#</a></span></h2><p>循环神经网络要点在于可以将上一时刻的信息传递给下一时刻,但是在需要长程信息依赖的场景,训练一个好的RNN十分困难,存在梯度爆炸和梯度消失的情况。LSTM通过刻意的设计来解决该问题。</p>
<p>简单的RNN网络中重复的模块只有一个简单的结构,例如一个<code>relu</code>层,而在LSTM中重复的模块拥有4个不同的结构相互交互来完成。</p>
<p>
<figure><img src="https://youngforever.tech/images/LSTM/LSTM.jpg" alt="LSTM" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<h3 id="11-首先决定从cell中丢弃什么信息" class="relative group">1.1 首先决定从cell中丢弃什么信息 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#11-%e9%a6%96%e5%85%88%e5%86%b3%e5%ae%9a%e4%bb%8ecell%e4%b8%ad%e4%b8%a2%e5%bc%83%e4%bb%80%e4%b9%88%e4%bf%a1%e6%81%af" aria-label="Anchor">#</a></span></h3><p>$$f_t = \sigma(W_f*[h_{t-1}, X_t] + b_f) \tag1$$
sigma函数在0到1选择代表丢弃与否</p>
<h3 id="12-什么样的新信息存放到cell中" class="relative group">1.2 什么样的新信息存放到cell中 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#12-%e4%bb%80%e4%b9%88%e6%a0%b7%e7%9a%84%e6%96%b0%e4%bf%a1%e6%81%af%e5%ad%98%e6%94%be%e5%88%b0cell%e4%b8%ad" aria-label="Anchor">#</a></span></h3><p>$$i_t = \sigma(W_i*[h_{t-1}, x_t] + b_i) \tag2$$</p>
<p>$$\widetilde{C_t} = tanh(W_c*[h_{t-1}, x_t] + b_c) \tag3$$</p>
<p>$$C_t = f_t*C_{t-1} + {i_t} * \widetilde{C_{t}} \tag4$$</p>
<p>4式中旧状态与$f_t$相乘,丢弃确定需要丢弃的信息,加上新的候选值。可以看到假如遗忘门一直为1,就可以保持以前的信息$C_{t-1}$</p>
<h3 id="13-输出结果" class="relative group">1.3 输出结果 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#13-%e8%be%93%e5%87%ba%e7%bb%93%e6%9e%9c" aria-label="Anchor">#</a></span></h3><p>$$o_t = \sigma(W_o[h_{t-1}, x_t] + b_o)\tag5$$
$$h_t = o_t*tanh(C_t)\tag6$$</p>
<h2 id="2-lstm实例以及pytorch实现" class="relative group">2. LSTM实例以及Pytorch实现 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#2-lstm%e5%ae%9e%e4%be%8b%e4%bb%a5%e5%8f%8apytorch%e5%ae%9e%e7%8e%b0" aria-label="Anchor">#</a></span></h2><p>循环神经网络可以应用到以下场景。</p>
<p>
<figure><img src="https://youngforever.tech/images/LSTM/examples.jpg" alt="examples" class="mx-auto my-0 rounded-md" />
</figure>
</p>
<ul>
<li>点对点(单个图片(文字)被分类;图像分类)</li>
<li>点对序列(单个图像(文字)被分为多个类;图像输出文字)</li>
<li>序列分析(一系列图片(文字)被分类;情感分析)</li>
<li>不等长序列对序列(机器翻译)</li>
<li>等长序列对序列(视频帧分类)</li>
</ul>
<p>举两个例子:图像分类以及时间序列预测</p>
<h3 id="21-lstm图像分类" class="relative group">2.1 LSTM图像分类 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#21-lstm%e5%9b%be%e5%83%8f%e5%88%86%e7%b1%bb" aria-label="Anchor">#</a></span></h3><p>关于图片分类常用卷积神经网络,侧重空间上处理;而循环神经网络侧重序列处理。但是也能用来图片分类。第一个例子以常用的mnist手写字体识别为例。</p>
<h4 id="211-导入所需用到的包以及超参数设置等" class="relative group">2.1.1 导入所需用到的包以及超参数设置等 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#211-%e5%af%bc%e5%85%a5%e6%89%80%e9%9c%80%e7%94%a8%e5%88%b0%e7%9a%84%e5%8c%85%e4%bb%a5%e5%8f%8a%e8%b6%85%e5%8f%82%e6%95%b0%e8%ae%be%e7%bd%ae%e7%ad%89" aria-label="Anchor">#</a></span></h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># Setup</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">torch</span> <span class="kn">import</span> <span class="n">nn</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">torch.utils.data</span> <span class="kn">import</span> <span class="n">DataLoader</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torchvision.datasets</span> <span class="k">as</span> <span class="nn">dsets</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torchvision.transforms</span> <span class="k">as</span> <span class="nn">transforms</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">manual_seed</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Device configuration</span>
</span></span><span class="line"><span class="cl"><span class="n">device</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">device</span><span class="p">(</span><span class="s1">'cuda'</span> <span class="k">if</span> <span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">is_available</span><span class="p">()</span> <span class="k">else</span> <span class="s1">'cpu'</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="212-导入数据集" class="relative group">2.1.2 导入数据集 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#212-%e5%af%bc%e5%85%a5%e6%95%b0%e6%8d%ae%e9%9b%86" aria-label="Anchor">#</a></span></h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># Mnist手写数字</span>
</span></span><span class="line"><span class="cl"><span class="n">train_data</span> <span class="o">=</span> <span class="n">dsets</span><span class="o">.</span><span class="n">MNIST</span><span class="p">(</span><span class="n">root</span><span class="o">=</span><span class="s1">'./mnist/'</span><span class="p">,</span> <span class="c1"># 保存或者提取位置</span>
</span></span><span class="line"><span class="cl"> <span class="n">train</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="c1"># this is tra`ining data</span>
</span></span><span class="line"><span class="cl"> <span class="n">transform</span><span class="o">=</span><span class="n">transforms</span><span class="o">.</span><span class="n">ToTensor</span><span class="p">(),</span> <span class="c1"># 转换 PIL.Image or numpy.ndarray 成</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># torch.FloatTensor (C x H x W), 训练的时候 normalize 成 [0.0, 1.0] 区间</span>
</span></span><span class="line"><span class="cl"> <span class="n">download</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="c1"># 没下载就下载, 下载了就不用再下了改成False</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">test_data</span> <span class="o">=</span> <span class="n">dsets</span><span class="o">.</span><span class="n">MNIST</span><span class="p">(</span><span class="n">root</span><span class="o">=</span><span class="s1">'./mnist/'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">train</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">transform</span><span class="o">=</span><span class="n">transforms</span><span class="o">.</span><span class="n">ToTensor</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Dataloader</span>
</span></span><span class="line"><span class="cl"><span class="c1"># PyTorch中数据读取的一个重要接口,该接口定义在dataloader.py中,只要是用PyTorch来训练模型基本都会用到该接口(除非用户重写…),</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 该接口的目的:将自定义的Dataset根据batch size大小、是否shuffle等封装成一个Batch Size大小的Tensor,用于后面的训练。</span>
</span></span><span class="line"><span class="cl"><span class="n">train_loader</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span><span class="n">dataset</span><span class="o">=</span><span class="n">train_data</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">batch_size</span><span class="o">=</span><span class="n">batch_size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">shuffle</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># 在每个epoch开始的时候,对数据重新打乱进行训练。在这里其实没啥用,因为只训练了一次</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">test_loader</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span><span class="n">dataset</span><span class="o">=</span><span class="n">test_data</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">batch_size</span><span class="o">=</span><span class="n">batch_size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">shuffle</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="213-建立模型" class="relative group">2.1.3 建立模型 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#213-%e5%bb%ba%e7%ab%8b%e6%a8%a1%e5%9e%8b" aria-label="Anchor">#</a></span></h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># LSTM</span>
</span></span><span class="line"><span class="cl"><span class="c1"># __init__ is basically a function which will "initialize"/"activate" the properties of the class for a specific object</span>
</span></span><span class="line"><span class="cl"><span class="c1"># self represents that object which will inherit those properties</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">simpleLSTM</span><span class="p">(</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_size</span><span class="p">,</span> <span class="n">hidden_size</span><span class="p">,</span> <span class="n">num_layers</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="nb">super</span><span class="p">(</span><span class="n">simpleLSTM</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">hidden_size</span> <span class="o">=</span> <span class="n">hidden_size</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span> <span class="o">=</span> <span class="n">num_layers</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">lstm</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">LSTM</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="n">hidden_size</span><span class="p">,</span> <span class="n">num_layers</span><span class="p">,</span> <span class="n">batch_first</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">fc</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span><span class="n">hidden_size</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># x shape (batch, time_step, input_size)</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># out shape (batch, time_step, output_size)</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># h_n shape (n_layers, batch, hidden_size)</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># h_c shape (n_layers, batch, hidden_size)</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># 初始化hidden和memory cell参数</span>
</span></span><span class="line"><span class="cl"> <span class="n">h0</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span><span class="p">,</span> <span class="n">x</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">hidden_size</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">c0</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span><span class="p">,</span> <span class="n">x</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">hidden_size</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># forward propagate lstm</span>
</span></span><span class="line"><span class="cl"> <span class="n">out</span><span class="p">,</span> <span class="p">(</span><span class="n">h_n</span><span class="p">,</span> <span class="n">h_c</span><span class="p">)</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">lstm</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="p">(</span><span class="n">h0</span><span class="p">,</span> <span class="n">c0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># 选取最后一个时刻的输出</span>
</span></span><span class="line"><span class="cl"> <span class="n">out</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fc</span><span class="p">(</span><span class="n">out</span><span class="p">[:,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="p">:])</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">out</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">simpleLSTM</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="n">hidden_size</span><span class="p">,</span> <span class="n">num_layers</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># loss and optimizer</span>
</span></span><span class="line"><span class="cl"><span class="n">criterion</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">CrossEntropyLoss</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">Adam</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="214-训练模型" class="relative group">2.1.4 训练模型 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#214-%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b" aria-label="Anchor">#</a></span></h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># train the model</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 关于reshape(-1)的解释 https://www.zhihu.com/question/52684594</span>
</span></span><span class="line"><span class="cl"><span class="c1"># view()和reshape()区别的解释 https://stackoverflow.com/questions/49643225/whats-the-difference-between-reshape-and-view-in-pytorch</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Hyper Parameters</span>
</span></span><span class="line"><span class="cl"><span class="n">epochs</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># 训练整批数据多少次, 为了节约时间, 我们只训练一次</span>
</span></span><span class="line"><span class="cl"><span class="n">batch_size</span> <span class="o">=</span> <span class="mi">64</span>
</span></span><span class="line"><span class="cl"><span class="n">time_step</span> <span class="o">=</span> <span class="mi">28</span> <span class="c1"># rnn 时间步数 / 图片高度</span>
</span></span><span class="line"><span class="cl"><span class="n">input_size</span> <span class="o">=</span> <span class="mi">28</span> <span class="c1"># rnn 每步输入值 / 图片每行像素</span>
</span></span><span class="line"><span class="cl"><span class="n">hidden_size</span> <span class="o">=</span> <span class="mi">64</span>
</span></span><span class="line"><span class="cl"><span class="n">num_layers</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">num_classes</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="n">lr</span> <span class="o">=</span> <span class="mf">0.01</span> <span class="c1"># learning rate</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">total_step</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">train_loader</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">epoch</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">epochs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="p">(</span><span class="n">images</span><span class="p">,</span> <span class="n">labels</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">train_loader</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">images</span> <span class="o">=</span> <span class="n">images</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">time_step</span><span class="p">,</span> <span class="n">input_size</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">labels</span> <span class="o">=</span> <span class="n">labels</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># forward pass</span>
</span></span><span class="line"><span class="cl"> <span class="n">outputs</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">images</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">loss</span> <span class="o">=</span> <span class="n">criterion</span><span class="p">(</span><span class="n">outputs</span><span class="p">,</span> <span class="n">labels</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># backward and optimize</span>
</span></span><span class="line"><span class="cl"> <span class="n">optimizer</span><span class="o">.</span><span class="n">zero_grad</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="n">loss</span><span class="o">.</span><span class="n">backward</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="n">optimizer</span><span class="o">.</span><span class="n">step</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">100</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s1">'Epoch [</span><span class="si">{}</span><span class="s1">/</span><span class="si">{}</span><span class="s1">], Step [</span><span class="si">{}</span><span class="s1">/</span><span class="si">{}</span><span class="s1">], Loss: </span><span class="si">{:.4f}</span><span class="s1">'</span>
</span></span><span class="line"><span class="cl"> <span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">epoch</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">epochs</span><span class="p">,</span> <span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">total_step</span><span class="p">,</span> <span class="n">loss</span><span class="o">.</span><span class="n">item</span><span class="p">()))</span>
</span></span></code></pre></div><h4 id="215-测试模型" class="relative group">2.1.5 测试模型 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#215-%e6%b5%8b%e8%af%95%e6%a8%a1%e5%9e%8b" aria-label="Anchor">#</a></span></h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># Test the model</span>
</span></span><span class="line"><span class="cl"><span class="c1"># https://stackoverflow.com/questions/55627780/evaluating-pytorch-models-with-torch-no-grad-vs-model-eval</span>
</span></span><span class="line"><span class="cl"><span class="c1"># torch.max()用法。https://blog.csdn.net/weixin_43255962/article/details/84402586</span>
</span></span><span class="line"><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">eval</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="n">torch</span><span class="o">.</span><span class="n">no_grad</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">correct</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"> <span class="n">total</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">images</span><span class="p">,</span> <span class="n">labels</span> <span class="ow">in</span> <span class="n">test_loader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">images</span> <span class="o">=</span> <span class="n">images</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">time_step</span><span class="p">,</span> <span class="n">input_size</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">labels</span> <span class="o">=</span> <span class="n">labels</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">outputs</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">images</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">_</span><span class="p">,</span> <span class="n">predicted</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">outputs</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">total</span> <span class="o">+=</span> <span class="n">labels</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">correct</span> <span class="o">+=</span> <span class="p">(</span><span class="n">predicted</span> <span class="o">==</span> <span class="n">labels</span><span class="p">)</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span><span class="o">.</span><span class="n">item</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s1">'Test Accuracy of the model on the 10000 test images: </span><span class="si">{}</span><span class="s1"> %'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="mi">100</span> <span class="o">*</span> <span class="n">correct</span> <span class="o">/</span> <span class="n">total</span><span class="p">))</span>
</span></span></code></pre></div><h3 id="22-时间序列预测" class="relative group">2.2 时间序列预测 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#22-%e6%97%b6%e9%97%b4%e5%ba%8f%e5%88%97%e9%a2%84%e6%b5%8b" aria-label="Anchor">#</a></span></h3><p>Todo</p>
<h3 id="23-图像输出文字" class="relative group">2.3 图像输出文字 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#23-%e5%9b%be%e5%83%8f%e8%be%93%e5%87%ba%e6%96%87%e5%ad%97" aria-label="Anchor">#</a></span></h3><p>Todo</p>
<h2 id="补充" class="relative group">补充 <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e8%a1%a5%e5%85%85" aria-label="Anchor">#</a></span></h2><ol>
<li>
<p>在原始发表文献用的图示是类似于下图的这种,看起来比较好容易理解当初形成LSTM的原因
<figure><img src="https://youngforever.tech/images/LSTM/LSTM_O.jpg" alt="LSTM_O" class="mx-auto my-0 rounded-md" />
</figure>
</p>
</li>
<li>
<p>pytorch lstm函数用法示例</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">rnn</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">LSTM</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="c1"># input_size, hidden_size, num_layers</span>
</span></span><span class="line"><span class="cl"><span class="nb">input</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span> <span class="c1"># time_step, batch, input_size(这里input_size即features)</span>
</span></span><span class="line"><span class="cl"><span class="n">h0</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span> <span class="c1"># num_layers, batch, hidden_size</span>
</span></span><span class="line"><span class="cl"><span class="n">c0</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span> <span class="c1"># num_layers, batch, hidden_size</span>
</span></span><span class="line"><span class="cl"><span class="n">output</span><span class="p">,</span> <span class="p">(</span><span class="n">hn</span><span class="p">,</span> <span class="n">cn</span><span class="p">)</span> <span class="o">=</span> <span class="n">rnn</span><span class="p">(</span><span class="nb">input</span><span class="p">,</span> <span class="p">(</span><span class="n">h0</span><span class="p">,</span> <span class="n">c0</span><span class="p">))</span> <span class="c1"># output包含从最后一层lstm中输出的ht。shape: time_step, batch, hidden_size</span>
</span></span></code></pre></div><ul>
<li>
<p><code>hidden_size</code> is the number of units of your LSTM cell. This means all the layers (input, forget, etc.) will have this size</p>
</li>
<li>
<p>hidden_size即pytorch隐含层每个结构中含有的隐含cell数目</p>
</li>
</ul>
<ol start="3">
<li>lstm函数中加入<code>bidirectional=True</code>参数即双向神经网络</li>
</ol>
<h2 id="reference" class="relative group">Reference <span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"><a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#reference" aria-label="Anchor">#</a></span></h2><ol>
<li>理解LSTM(<a href="http://colah.github.io/posts/2015-08-Understanding-LSTMs/" target="_blank" rel="noreferrer">http://colah.github.io/posts/2015-08-Understanding-LSTMs/</a>)</li>
<li>高效RNN(<a href="http://karpathy.github.io/2015/05/21/rnn-effectiveness/" target="_blank" rel="noreferrer">http://karpathy.github.io/2015/05/21/rnn-effectiveness/</a>)</li>
<li>Hochreiter & Schmidhuber (1997) LSTM</li>
<li>Pytorch LSTM官方文档(<a href="https://pytorch.org/docs/stable/nn.html#lstm" target="_blank" rel="noreferrer">https://pytorch.org/docs/stable/nn.html#lstm</a>)</li>
</ol>