让网络记住上一道菜:从固定轮换走到当前输入 · znzryb
# 让网络记住上一道菜:从固定轮换走到当前输入
主要参考:[Luis Serrano:A friendly introduction to Recurrent Neural Networks](https://www.youtube.com/watch?v=UNmqTiOnRfg)。这组中文学习笔记结合视频与观看时的截图批注整理,保留 Intro RNN 文件夹中的全部 20 张原图。视频画面版权归原作者所有。
本篇使用第 07—13 张截图。前一篇的网络只处理当前天气;这里先暂时放下天气,让“上一次做了什么”决定下一次,再把天气加回来。
## 循环从哪里来:把上一次结果带到下一步

*截图 07|完整的循环例子:苹果派、汉堡、鸡肉依次出现,再回到苹果派*
先规定一个固定菜单:苹果派之后做汉堡,汉堡之后做鸡肉,鸡肉之后又做苹果派。截图上方展示了完整序列,下方的回路则把“上一道菜成为下一步输入”画了出来。
普通网络处理完一个输入就结束了;这里还要把本步结果带给下一步。于是同一个计算规则可以反复执行,形成随时间变化的序列。
要先给它一个起点,例如苹果派。回路并不是不需要输入就凭空开始,也不是同一时刻无限计算;每走一轮,代表推进一个时间步。
## “下一道菜”仍然可以先用一个矩阵实现

*截图 08|同一个矩阵完成三种转换:苹果派到汉堡,汉堡到鸡肉,鸡肉到苹果派*
沿用食物的 one-hot 编码,把循环矩阵记成 $P$:
$$
P=\begin{bmatrix}0&0&1\\1&0&0\\0&1&0\end{bmatrix}.
$$
第一列是汉堡,所以输入苹果派会得到汉堡;第二列是鸡肉,所以输入汉堡会得到鸡肉;第三列是苹果派,所以输入鸡肉又回到苹果派。仍然只需使用“one-hot 选列”这个直觉。
设 $h_0$ 是初始食物,反复执行 $h_t=Ph_{t-1}$,就能得到这份循环菜单。这里的 $h_t$ 暂时直接用食物向量来表示。

*截图 09|去掉权重为 0 的连线后,循环矩阵的作用更容易看清*
这张图把矩阵转换成圆点连线,并省略了权重为 0 的边。剩下的三条连线恰好把三种食物轮换一遍。
边的多少不等于时间步数。这三条边在描述一次转换;时间上的重复,需要看下一张回路图。

*截图 10|把输出接回输入:下一次继续使用同一套转换规则*
回来的线表示“在下一步使用刚才得到的向量”。每一步复用同一套权重,而不是每天重新发明一个网络。这就是 recurrent(循环、反复出现)在这个例子里的直观含义。
不过,固定轮换很机械。要是今天晴天就想继续做昨天的食物,下雨才换下一道,就必须给网络一个新的当前输入。
## 加入天气:记忆告诉我们是什么,天气告诉我们怎么选

*截图 11|晴天保留上一道菜,雨天沿菜单换下一道*
现在规则改为:晴天做与上一天相同的菜,雨天就沿苹果派、汉堡、鸡肉的顺序往前走一步。
这样,同一个“苹果派”状态会有两个可能结果:遇到晴天仍是苹果派,遇到雨天则是汉堡。只看昨天的菜不够,只看今天的天气也不够;两者必须一起参与计算。

*截图 12|沿每天的天气检查菜单:晴天不变,雨天前进一步*
截图中的菜单是苹果派、苹果派、汉堡、鸡肉、鸡肉、苹果派。把当天的天气理解成相邻两道菜之间的操作,就能逐步核对:保持,前进,前进,保持,前进。
这个例子说明为什么顺序重要:当前结果依赖前面的状态。网络不只是把互不相关的样本逐个分类,还在沿时间积累信息。

*截图 13|一次计算同时接收上一次的食物与这一次的天气*
图中从下方新接入的箭头,是本时间步的天气;回路带来的是上一步留下来的食物。输出本次食物以后,它又成为下一步可用的状态。
为了和通常的 RNN 写法对上,可以把当前天气叫 $x_t$,上一步状态叫 $h_{t-1}$,更新后的状态叫 $h_t$。常见的基本形式是:
$$
h_t=\phi(W_hh_{t-1}+W_xx_t+b).
$$
$W_h$ 处理过去的状态,$W_x$ 处理当前输入,$b$ 是偏置,$\phi$ 是非线性激活函数。这里的公式用来说明两路信息怎样汇合,不代表视频后面手工搭出的每一层都恰好采用这个形式。
**实际 RNN 通常传递的是隐藏状态,不一定是最终预测结果。**隐藏状态可以保存对后续有用的信息;输出还可以由它另行计算。视频把食物向量同时当作状态和结果,是为了让“记住上一轮”容易看懂。
下一篇把这个做饭规则完整算一遍:怎样让天气与旧状态共同选中一道菜,以及 non-linear 为什么不可少。