[Quant 1.6] 从数理的角度理解一下RNN (1)
我先放资源
第一个是MIT的一本深度学习教材的RNN章节,作者是Ian Goodfellow & Yoshua Bengio & Aaron Courville
https://www.deeplearningbook.org/contents/rnn.html#pf7
第二个是吴恩达 (Andrew Ng)博士的网课

吴博士的网课主要从NLP的角度出发介绍RNN,里面有帮助的理解的例子。但是它的notation我看不太习惯。然后那本教材我感觉是给更厉害的quant或者数据科学/AI专业的学生读的,细节非常之多,我个人啃起来感觉吃力。这篇想把零零散散的知识点总结一下。(以下内容可能有很多理解错误的地方,后续我发现问题的话会编辑。然后我会有很多中英文穿插着,毕竟面试可能会被问到,我也借这个专栏强化一下记忆。)

1. RNN相比于DNN
神经网络的三个基本元素是模型、损失函数和优化器。在[Quant 1.3] 里面,我们介绍了DNN的基本原理。DNN是由输入层、多个隐藏的全连接层和输出层构成。每个隐藏的全连接层都搭配一个激活函数 (sigmoid, relu, hypobolic tangent)。
训练一个DNN是要先初始化一个神经网络出来,这里面有随机的参数。然后我们分批将训练集中的tensor输入到神经网络中(forward函数),利用输出和标签值计算损失,优化器再进行backward propogation逐步更新参数减小损失。多次迭代之后我们就得到了自己的DNN模型。

DNN可以很好的学习静态的cross-sectional数据。就像我们在逻辑回归[Quant 1.2]中举的例子:给定一个人的身高,体重,臂展,卧推重量等作为输入,训练一个DNN来判断这个人的性别。但是它在学习panel data表格数据的时候会出现一些明显的不足。在判断一个人的性别时,我们的样本中的人是没有顺序的,但是如果我们想要用每一天的因子来预测第二天的股票价格涨跌,样本中的因子则是有时间顺序的。换句话说,人和人之间的关联,只要是随机抽样,一个人的身高,体重,臂展,卧推重量等指标不应该影响到对另一个人的性别的预测。但是,每一天的因子可能不只会影响到第二天股价的涨跌,或许还会影响第三天、第四天或者更长。但是在利用DNN预测股票涨跌时,我们却只用了目标预测日前一天的因子。
为了考虑到每一日的指标对股票价格变动的更长远的影响,我们也对DNN进行了一些改良,例如在输入中加入很多滞后因子,像是昨日的开盘价,前日的收盘价等等。但是这样就非常的主观。在选择滞后的因子时,到底应该选择滞后多少天以内的?如果我们滞后的天数不够多,神经网络学习到的因果关系可能就没那么明显;而如果选择的天数太多,则会加重DNN的计算量。
因此,与其自行筛选这些滞后的因子,不如让神经网络自己来决定如何取舍由近到远的历史数据来优化预测结果。这就是RNN相对于DNN的优势。概括来讲,在处理有序输入的时候,RNN能够通过训练来筛选并利用所有已输入的有序信息来做出预测。

2. 什么时候我们能用上RNN?
当我们的自变量是有顺序的,且顺序靠前的自变量或因变量会影响顺序靠后的因变量时。可以理解为serially correlated。

3. Vanilla RNN的基本结构
我们刚说过了,RNN可以通过训练来筛选并利用已经输入到神经网络内的历史信息来做出预测。那么这个历史信息在神经网络内是如何体现的呢?我们使用状态变量state 来储存历史信息。
RNN的结构可以用两种图来表示,一种叫circuit diagram,另一种叫time-unfolded computational graph。Vanilla RNN (以下简称RNN)是所有RNN中最简单的一类,它没有门结构。
接下来我想介绍三种常见的RNN结构:

下面一种是最典型也是最基础的RNN结构:

左边是circuit diagram,右边是unfolded computational graph。unfolded computational graph相对好理解一些,左边circuit diagram黑色的方框表示:当运算通过方框所在的箭头时,时间+1。也就是说通过W矩阵的线性变换之后,变成了
。两张图对应相同的RNN表达式
这种RNN属于many-to-many,它的一个例子是:是一支股票在第t个时间段内产生的新闻(单位时间内的舆情指数),
是这支股票在第t个时间段的下一个时间段内价格是上涨还是下跌,而
是t时刻对
的预测值。注意这里
是
measurable。
那么和DNN类似的,这个神经网络的训练过程就是:先初始化参数,然后输入
,用上面的一串表达式,我们可以依次计算出
。假如我们用的optimizer是SGD,那么我们需要计算
对
的梯度,再结合我们设定的学习率来更新这些参数。这样,第一个循环就完成了。
第二个循环和第一个循环相似,只不过被求梯度的loss变成了前两次迭代的loss之和。....

下面是第二种RNN结构:

教材中只给了unfolded computational graph。这张图对应的RNN表达式是:
其实和第一种RNN结构非常相似了。只不过没有在每一个time step输出,而只在最后一个timestep输出。所以我们称它为many-to-one的RNN。
这种RNN的一个例子是,我们逐个输入一句话中的每个字/单词,输出这句话对应的情绪评分。如果大家使用过Grammarly的话,会发现它会分析你输入的句子的情绪,可能是开心、愤怒、悲伤、犹豫之类的。从quant的角度,我们可以用这种RNN模型来快速获得market sentiment,对名人的推特或者新闻事件分析来预判资产价格长短期的走向。
参数代入的方式和第一种many-to-many的RNN非常相似,除了只有在最后的time step 才有输出。


第三种RNN。它训练时的表达式是
和前面两种神经网络最明显不同的地方是,这种神经网络的输入不随时间的改变而改变。其次,标签
除了用于和预测值一起计算loss以外,还会用于隐藏变量
的计算。光看这个RNN可能会没什么概念,我们只要用一个例子说明这个RNN的作用就可以理解了。
我们现在想做的事情是描述一张图片的内容,那么我们训练集的构成就是成千上万张图片和他们对应的内容语句。在训练模型的时候,我们在每一个step都将图片作为RNN的输入,除此之外,标签值
既作为上一个step的预测目标,也要作为当前step的输入之一。假如我们现在有一张🍎的图片,它对应的标签是“一个苹果”。训练时在随机初始化好各个参数之后,在第一个迭代内,我们输入🍎图片
,初始化好的state
,而对于
我们需要输入的是标签中的第一个字“一”。而在这次迭代内,我们的预测值是
,而它的训练目标是
,也就是第二个字“个”。同时,
“个”也作为第二次迭代的输入。以此类推。
所以大家可以理解,之所以训练时的标签值既作为上一步的训练目标也作为当前步的输入,是因为我们想让预测时候产出的句子是一个通顺的句子。在模型训练好之后,我们将另一个苹果图片输入进入,这个时候输出的内容会和初始化的参数有关系。因此每一次输入这个新的苹果图片是得到的结果不一定是完全一样的。但是我们会希望结果是"苹果"或者"一个苹果",而不是“苹一个果”这种话。所以这种
和
的联系在这类RNN的应用中是有必要的。
在我们用训练好的模型预测时,测试集的图片都是没有标签的,所以我们要用上一步的预测结果来代替标签,作为这一步的输入。因此测试的时候,表达式就稍微改动的变成了
