欢迎来到雲闪世界。今天,我们将深入探讨循环神经网络。我们将讨论一些熟悉的概念,例如输入、输出和激活函数,但会有一些不同。如果这是您踏上这段旅程的第一站,请务必先阅读之前的文章,尤其是第 1部分和第 2部分。
欢迎来雲闪世界。到今天,我们将深入探讨循环神经网络。我们将讨论一些熟悉的概念,例如输入、输出和激活函数,但会有一些不同。如果这是您踏上这段旅程的第一站,请务必先阅读之前的文章,尤其是第 1部分和第 2部分。
循环神经网络 (RNN) 是专门设计用于处理基于序列的问题的独特模型,其中下一个位置依赖于前一个状态。
用一个简单示例来解释什么是基于序列的问题。想象一个球在特定时间点 tn(来自斯坦福课堂)
如果我们被要求预测球的方向,在没有更多信息的情况下,这只是一个猜谜游戏 — — 球可能会朝任何方向移动。
但是如果我们获得了关于球的先前位置的数据会怎么样呢?
现在我们可以自信地预测球将继续向右移动。
这种预测场景就是我们所说的序列问题,其中答案受到先前数据的强烈影响。这些序列问题无处不在,从根据过去的温度数据预测明天的温度,到包括情绪分析、命名实体识别、机器翻译和语音识别在内的一系列语言模型。今天,我们将解决情绪检测,这是基于序列的问题的一个简单示例。
在情绪检测中,我们会获取一段文本,并确定它传达的是积极情绪还是消极情绪。今天,我们将构建一个 RNN,以电影评论作为输入,并预测其是否是积极的。因此,鉴于这个电影评论……
…我们希望我们的神经网络预测这是一种积极的情绪。
这听起来像是一个简单的分类问题,但标准神经网络在这里面临两个主要挑战。
首先,我们要处理的是可变的输入长度。标准神经网络很难处理不同长度的输入。例如,如果我们用三个字的电影评论训练我们的神经网络,我们的输入大小将固定为 3。但如果我们想输入更长的评论怎么办?
如果输入数量为 12,它就会不知所措,无法处理上述评论。与之前的文章不同,之前的文章中输入的数量是固定的(冰淇淋收入模型有两个输入 — — 温度和星期几),在这种情况下,模型需要灵活,能够适应输入的单词数量。
其次,我们有顺序输入。典型的神经网络不能完全理解输入的方向性,而这一点在这里至关重要。两个句子可能包含完全相同的单词,但顺序不同,它们可以传达完全相反的含义。
面对这些挑战,我们需要一种方法来按顺序处理动态数量的输入。这就是 RNN 的闪光点。
我们解决这个问题的方法是首先处理评论的第一个词“that”:
然后使用此信息来处理第二个单词“was”:
最后,使用以上所有信息来处理最后一个词“phenomenal”,并对评论的情绪进行预测:
在开始构建神经网络之前,我们需要讨论一下输入。神经网络的输入必须是数字。但是,这里的输入是单词,所以我们需要将这些单词转换为数字。有几种方法可以做到这一点,但今天我们将使用一种基本方法。
请继续关注即将发布的文章,我们将在其中探讨更复杂的方法来应对这一挑战。
现在,让我们假设我们有一本包含 10,000 个单词的大词典。我们(天真地)假设评论中出现的任何单词都可以在这本包含 10,000 个单词的词典中找到。每个单词都映射到相应的数字。
为了将单词“ that ”转换为一串数字,我们需要确定“ that ”映射到的数字……
…然后将其表示为由 10,000 个 0 组成的矩阵,但第 8600 个元素为 1:
类似地,接下来两个单词“was”(字典中的第 9680 个单词)和“phenomenal”(字典中的第 4242 个单词)的数字表示将是:
这就是我们如何将一个单词转换成神经网络友好的输入。
现在让我们把注意力转向神经网络的设计。为了简单起见,我们假设我们的网络有 10,000 个输入(= 1 个单词)、一个由一个神经元组成的隐藏层和一个输出神经元。
当然,如果这是一个完全训练的神经网络,那么每个输入都会有相关的权重,并且神经元会有偏差项。
在这个网络中,输入权重被标记为wᵢ,其中i表示输入。隐藏层神经元中的偏差项是 bₕ。连接隐藏层和输出神经元的权重是 wₕᵧ。最后,输出神经元中的偏差用 bᵧ 表示,因为y表示我们的输出。
我们将使用双曲正切函数(tanh)作为隐藏神经元的激活函数。
作为对第一篇文章的回顾,tanh 接受输入并产生在 -1 到 1 范围内的输出。较大的正输入趋向于 1,而较大的负输入接近 -1。
为了确定文本的情绪,我们可以在输出神经元中使用 S 型激活函数。此函数从隐藏层获取输出并输出 0 到 1 之间的值,表示积极情绪的概率。接近 1 的预测表示正面评价,而接近 0 的预测表示不太可能是正面评价。
虽然这种方法目前有效,但还有一种更复杂的方法可以产生更好的结果! 如果你坚持到文章的最后,你会看到一个新的、强大的、无处不在的激活函数 — — Softmax Activation — — 可以更好地解决这个问题。
通过这些激活函数,我们的神经网络看起来如下:
这个神经网络接受一个文本输入,并预测其具有积极情绪的概率。在上面的例子中,网络处理输入“that”并预测其具有积极情绪的可能性。诚然,“that”这个词本身并没有提供太多关于情绪的暗示。现在,我们需要弄清楚如何将下一个单词合并到网络中。这时,循环神经网络的循环方面就会发挥作用,从而导致基本结构的修改。
我们通过创建上述神经网络的精确副本来输入评论的第二个单词“was” 。但是,我们不使用“that”作为输入,而是使用“was”:
神经网络的精确副本,输入为“was”
记住,我们还想在这个神经网络中使用前一个单词“this”的信息。因此,我们从前一个神经网络的隐藏层获取输出,并将其传递到当前网络的隐藏层:
这是很关键的一步,我们来慢慢分解一下。
从第一篇文章中,我们了解到每个神经元的处理由两个步骤组成:求和和激活函数(如果您不确定这些术语的含义,请阅读第一篇文章)。让我们看看这在我们的第一个神经网络中是什么样子的。
在第一个神经网络的隐藏层神经元中,第一步是求和:
在这里,我们将每个输入乘以其相应的权重,并将偏差项添加到所有乘积的总和中:
为了简化这个等式,我们这样表示,其中wₓ表示输入权重,x表示输入:
接下来,在步骤 2 中,我们将这个总和传递给激活函数 tanh:
这将从第一个神经网络的隐藏层产生输出h₁ 。从这里,我们有两个选择 — — 将h1传递给输出神经元或将其传递给下一个神经网络的隐藏层。
(选项 1)如果我们只想要“that”的情绪预测,那么我们可以取h₁并将其传递给输出神经元:
对于输出神经元,我们执行求和步骤……
…然后将 S 型函数应用于这个总和…
…这给出了我们预测的积极情绪值:
所以这个y₁_hat给了我们“that”具有积极情绪的预测概率。
(选项 2)但这不是我们想要的。因此,我们不会将h₁传递给输出神经元,而是将这些信息传递给下一个神经网络,如下所示:
与神经网络中具有输入权重的其他部分类似,我们也有一个输入权重 wₕₕ,用于从一个隐藏层到另一个隐藏层的输入。隐藏层通过将h₁和 wₕₕ的乘积添加到隐藏神经元中的求和步骤来合并h₁ 。因此,第二个神经网络神经元的隐藏神经元中更新的求和步骤将是:
需要注意的关键一点是 — — 整个网络中的所有偏差和权重项都保持不变,因为它们只是从之前的网络复制而来。
然后将该总和通过 tanh 函数传递……
…产生 h₂,这是第二个神经网络隐藏层的输出:
从这里,我们可以再次通过将h₂传递到输出神经元来获得情绪预测:
这里,y₂_hat给出了“那是”具有积极情绪的预测概率。
但我们知道这并不是复习的结束。因此,我们将复制此过程,再次克隆此网络,但输入为“phenomenal”,并将前一个隐藏层输出传递到当前隐藏层。
我们处理隐藏层神经元……
…输出 h₃:
由于这是评论中的最后一个字,因此也是最终的输入,我们将这些数据传递给外部神经元……
…给我们一个情绪的最终预测:
而这个y₃_hat就是我们想要的电影评论的情感,也是我们如何实现我们一开始所画的!
正式代表
如果我们详细阐述上面的图表,那么我们将得到如下结果:
该过程的每个阶段都涉及一个输入x,它穿过隐藏层生成输出h。然后,此输出要么移至下一个神经网络的隐藏层,要么产生情绪预测,表示为y_hat。每个阶段都包含权重和偏差项(偏差未在图中显示)。需要强调的关键一点是,我们将所有隐藏层合并到一个紧凑的盒子中。虽然我们的模型只包含一个隐藏层中只有一个神经元的层,但更复杂的模型可能包含多个隐藏层和大量神经元,所有这些神经元都压缩到这个盒子中,称为隐藏状态。这个隐藏状态封装了隐藏层的抽象概念。
本质上,这是该神经网络的简化版本:
还值得注意的是,为了简单起见,我们可以在这个简化图中表示所有这些:
这个过程的本质是将隐藏层的输出循环反馈到自身,这就是它被称为循环神经网络的原因。教科书中通常用这种方式来描述神经网络。
从数学的角度看,我们可以将其归结为两个基本方程:
第一个方程概括了隐藏状态下发生的完整线性变换。在我们的例子中,这种变换是单个神经元内的 tanh 激活函数。第二个方程表示输出层中发生的变换,在我们的例子中是 sigmoid 激活函数。
RNN 解决什么类型的问题?
多对一
我们刚刚讨论了这种场景,其中多个输入(在我们的例子中是评论中的所有单词)被输入到 RNN 中。然后,RNN 生成一个输出,代表评论的情绪。虽然每一步都可以有一个输出,但我们的主要兴趣在于最终输出,因为它囊括了整个评论的情绪。
另一个例子是文本补全。给定一串单词,我们希望 RNN 预测下一个单词。
一对多
一对多问题的一个经典例子是图像字幕。在这里,单个输入是一张图片,输出是包含多个单词的字幕。
多对多
这种类型的 RNN 用于机器翻译之类的任务,例如将英语句子翻译成印地语。
缺点
现在我们已经了解了 RNN 的工作原理,现在值得讨论一下为什么它们没有得到广泛使用(情节转折!)。尽管 RNN 潜力巨大,但它在训练过程中面临着重大挑战,特别是由于所谓的消失梯度问题。随着我们进一步展开 RNN,这个问题往往会加剧,这反过来又使训练过程复杂化。
在理想情况下,我们希望 RNN 能够平等地考虑当前步骤的输入和先前步骤的输入:
然而,它实际上看起来像这样:
每一步都会稍微忘记前一步,从而导致短期记忆问题,即消失梯度问题。随着 RNN 处理更多步骤,它往往会难以保留前一步的信息。
如果只有三个输入,这个问题就不太明显。但如果有六个输入怎么办?
我们发现前两个步骤的信息在最后一步中几乎不存在,这是一个重大问题。
以下示例使用文本完成任务来说明这一点。给定这个句子进行完成,RNN 可能会成功。
然而,如果中间添加了更多单词,RNN 可能难以准确预测下一个单词。这是因为 RNN 可能会忘记初始单词提供的上下文,因为它们与要预测的单词之间的距离增加了。
这凸显了一个事实,即尽管 RNN 在理论上听起来很棒,但在实践中却常常存在不足。为了解决短期记忆问题,我们使用了一种称为长短期记忆 (LSTM) 网络的特殊 RNN 类型,本系列的第 5 部分将介绍该网络!
奖励:Softmax 激活函数
我们之前谈到了另一种更好的处理情绪预测的方法。让我们回到绘图板上,回到我们决定输出神经元的激活函数的时候。
但这次我们的重点有点不同。让我们把注意力集中在一个基本的神经网络上,抛开循环方面。我们现在的目标是什么?预测单个输入词的情绪,而不是整个电影评论。
之前,我们的预测模型旨在输出输入为正向的概率。我们使用输出神经元中的 S 型激活函数来实现这一点,该函数会产生正向情绪可能性的概率值。例如,如果我们输入单词“terrible”,我们的模型理想情况下会输出一个较低的值,表示正向可能性较低。
然而,仔细想想,这并不是一个好的输出。积极情绪的概率低并不一定意味着消极情绪 — — 它也可能意味着输入是中性的。那么,我们如何改进这一点呢?
考虑一下:如果我们想知道电影评论是正面的、中性的还是负面的,该怎么办?
因此,我们可以使用三个输出神经元,而不是只有一个输出神经元输出输入为正面的概率预测。每个神经元分别预测评论为正面、中性和负面的可能性。
正如我们对单输出神经元网络使用 S 型函数来输出概率一样,我们可以将相同的原理应用于当前网络中的每个神经元,并在所有神经元中使用 S 型函数。
每个神经元将输出各自的概率值:
然而,有一个问题:概率不能正确相加(0.1 + 0.2 + 0.85 != 1),所以这不是一个很好的解决方法。简单地为所有输出神经元使用 S 型函数并不能解决问题。我们需要找到一种方法来在三个输出之间规范化这些概率。
在这里,我们引入了一个强大的激活函数 — — softmax 激活函数。通过使用 softmax 激活函数,我们的神经网络呈现出一种新的形式:
虽然乍一看可能令人望而生畏,但 softmax 函数实际上非常简单。它只是从输出神经元中获取输出值 ( y_hat ) 并对其进行归一化。
然而,至关重要的是,对于这三个输出神经元,我们不会使用任何激活函数;输出(y_hats)将是我们在求和步骤后直接获得的结果。
如果您需要复习一下神经元中的总结步骤和激活步骤的内容, 本 系列文章将详细介绍神经元的内部工作原理!
我们通过使用 softmax 公式对这些y_hat输出进行归一化。此公式提供了积极情绪概率的预测:
类似地,我们还可以得到负面和中性结果的预测概率:
让我们看看实际效果。例如,如果我们的输入是“terrible”,则结果y_hat值如下:
然后,我们可以取这些值并将它们插入 softmax 公式中,以计算“可怕”一词具有积极含义的预测概率。
这意味着,通过使用情绪神经元的组合输出, “可怕”带有积极情绪的概率为 0.05。
如果我们想计算输入为中性的概率,我们将使用类似的公式,只改变分子。因此,“terrible”一词为中性的可能性为:
“可怕”为负面的概率预测是:
瞧!现在概率加起来是 1,使我们的模型更易于解释和合乎逻辑。
因此,当我们问神经网络 — — “‘terrible’ 带有负面情绪的概率是多少?”时,我们得到了一个相当直接的答案。它自信地指出, “terrible”带有负面情绪的概率为 85% 。这就是 softmax 激活函数的美妙之处!
今天就到此为止!我们已经解决了两个大问题 — — 循环神经网络和 Softmax 激活函数。这些是我们稍后深入探讨的许多高级概念的基础。所以,请花点时间,慢慢理解,如果您有任何问题/意见,请随时通过下方找到。
感谢关注雲闪世界。(亚马逊aws和谷歌GCP服务协助解决云计算及产业相关解决方案)
订阅频道(https://t.me/awsgoogvps_Host)
TG交流群(t.me/awsgoogvpsHost)