一键重装系统工具 | U盘启动盘制作工具 | 误删文件恢复软件 | 硬盘数据抢救专家 | 电脑蓝屏修复助手 | C盘空间清理神器 | 电脑驱动离线安装工具 | 微信聊天记录恢复工具 | 照片误格式化恢复 | 电脑密码破解清除工具 | 系统崩溃紧急救援盘 | 电脑加速优化大师 | 电脑开不了机怎么重装系统 | 回收站清空了怎么恢复 | 硬盘分区丢失数据恢复 | 电脑卡顿重装系统有用吗 | U盘插入提示格式化数据恢复 | 电脑中毒文件被隐藏恢复 | 忘记电脑开机密码怎么办 | 新硬盘分区对齐工具 | 旧电脑装Win10流畅工具 | SD卡照片删除恢复免费版 | 移动硬盘打不开提示损坏修复 | 电脑无故重启系统修复工具 | 电脑小白一键重装神器 | 程序员电脑环境配置助手 | 设计师电脑字体/素材恢复工具 | 网吧网管系统维护工具箱 | 财务人员电脑发票备份恢复 | 学生党免费电脑系统安装包 | 电脑维修师傅必备工具盘 | 游戏玩家电脑性能优化助手 | 办公白领误删文档恢复软件 | 自媒体视频素材恢复工具 | 网课录制视频损坏修复工具 | 最好的U盘PE系统排名 | 数据恢复软件哪个最强 | 免费电脑助手与收费版区别 | 国产装机工具哪款无广告 | 离线版驱动助手推荐 | 轻量级电脑优化工具对比 | 支持NVMe驱动的PE工具 | 带网络功能的应急启动盘 | 2026最新版万能装机工具 | 支持Win11 24H2的PE工具 | 最新免激活系统重装工具 | 2026数据恢复软件破解版合集 | 纯净无捆绑装机助手V3.0 | 支持苹果M芯片的电脑助手 | 秋季更新版系统维护工具箱 | 电脑系统崩了怎么用U盘把重要资料拷贝出来 | 重装系统前哪些文件夹必须备份 | 固态硬盘误格式化还能恢复数据吗 | 如何制作一个既带PE又能存数据的双分区U盘 | 电脑总是弹窗广告用什么助手彻底拦截 后台管理
📢 欢迎访问系统之家!所有资源均经过安全检测。

循环神经网络入门

发布时间:2026-08-12 | 浏览:6
📥 下载地址(文章开头)
装机神器,可以安装一切系统。
探索循环神经网络的基础概念,使用 NumPy 从头实现情绪分析模型! 创建日期: 2025-01-18 循环神经网络 (Recurrent Neural Network, RNN) 是一种专门处理序列的神经网络,由于其在文本处理方面非常有效,因此常用于 自然语言处理 (Natural Language Processing, NLP) 任务中。本节我们将探索 RNN 是什么,理解其工作原理,并使用 Python 语言从头开始构建一个真正的 RNN 网络(仅使用 NumPy 库)。 这需要我们有神经网络的基础知识,如果不了解神经网络的概念,可以查看 第 02 章 深度学习原理 和 第 04 章 详解反向传播算法 的内容,让我们开始吧! 序列数据 (Sequence Data) 是指具有顺序性的结构化数据,通常以特定的时间或逻辑顺序排列。它在自然语言处理、时间序列分析、信号处理等领域中广泛使用。以下是序列数据的特点: 1. 顺序性 数据点之间的顺序至关重要,打乱顺序可能会丢失信息或改变数据的意义。比如股票价格: 100, 102, 105, 101 ,顺序决定价格变化的趋势;句子中单词的顺序: “I am happy” 和 “Happy am I” 的意思不同。 数据点之间的顺序至关重要,打乱顺序可能会丢失信息或改变数据的意义。比如股票价格: 100, 102, 105, 101 ,顺序决定价格变化的趋势;句子中单词的顺序: “I am happy” 和 “Happy am I” 的意思不同。 2. 依赖性 前后数据点之间可能存在依赖关系,比如当前数据点只依赖于临近的点,或者当前数据依赖较远的历史数据。文本序列 “The cat is on the …” ,预测最后一个单词,通常只需要考虑最近的几个单词 “is on the” 。 前后数据点之间可能存在依赖关系,比如当前数据点只依赖于临近的点,或者当前数据依赖较远的历史数据。文本序列 “The cat is on the …” ,预测最后一个单词,通常只需要考虑最近的几个单词 “is on the” 。 序列数据具有独特的顺序性和依赖性,能够有效地表示时间、空间或逻辑顺序关系。在实际应用中,了解序列数据的特点并选择合适的分析方法和模型,对于提高预测精度和决策质量具有重要意义。 文件 1_1_sequence_data.py 对序列数据进行绘制(可以使用 yfinance 获取真实股票数据): 基础神经网络(包括 CNN )的一个问题是它们只能处理预定大小的样本:使用固定大小的输入,并产生固定大小的输出。RNN 很有用,因为它们允许我们将可变长度的序列作为输入和输出。下图列举 RNN 的几种样式: 这种处理序列的能力使得 RNN 非常有用,以下是几个例子: 机器翻译(例如谷歌翻译)是通过“多对多” RNN 完成的,原始文本序列输入到 RNN 中,然后 RNN 生成翻译文本作为输出。 机器翻译(例如谷歌翻译)是通过“多对多” RNN 完成的,原始文本序列输入到 RNN 中,然后 RNN 生成翻译文本作为输出。 情绪分析模型通常使用“多对一” 的 RNN 网络。要分析的文本被输入到 RNN 中,然后 RNN 产生单个输出分类(正向或者负向)。 情绪分析模型通常使用“多对一” 的 RNN 网络。要分析的文本被输入到 RNN 中,然后 RNN 产生单个输出分类(正向或者负向)。 接下来,我们将从头构建一个“多对一” RNN 网络,来执行基本的情绪分析,比如 “This is not happy” 属于负向情绪。 让我们考虑“多对多”的 RNN 网络,它的输入为 \( x_0, x_1, \dots, x_{n-1}, x_n \) ,想要产生的输出为 \( y_0, y_1, \dots, y_{n-1}, y_n \) 。 \(x_i\) 和 \(y_i\) 都是向量,可以任意长度。 RNN 通过迭代中间隐藏状态 \(h\) 工作,\(h\) 是一个任意维度的向量。初始时,没有隐藏状态,\(h_0\) 使用随机值进行初始化,通过输入 \(x_0\) 和 \(h_0\) 计算输出 \(y_0\) 。在任意给定步骤 \(t\) : 下一个隐藏状态 \(h_t\) 可以通过之前的隐藏状态 \(h_{t-1}\) 和下一个输入 \(x_t\) 计算出来。 下一个隐藏状态 \(h_t\) 可以通过之前的隐藏状态 \(h_{t-1}\) 和下一个输入 \(x_t\) 计算出来。 下一个输出 \(y_t\) 可以使用 \(h_t\) 计算。 下一个输出 \(y_t\) 可以使用 \(h_t\) 计算。 以上操作让 RNN 具有循环性:它在每个步骤中使用相同的权重。更具体地说,一个典型的基础循环神经网络仅使用 3 组权重来执行计算: \(W_{xh}\) ,用于所有 \(x_t\) -> \(h_t\) 连接; \(W_{xh}\) ,用于所有 \(x_t\) -> \(h_t\) 连接; \(W_{hh}\) ,用于所有 \(h_{t-1}\) -> \(h_t\) 连接; \(W_{hh}\) ,用于所有 \(h_{t-1}\) -> \(h_t\) 连接; \(W_{hy}\) ,用于所有 \(h_t\) -> \(y_t\) 连接。 \(W_{hy}\) ,用于所有 \(h_t\) -> \(y_t\) 连接。 我们的 RNN 网络还有两个偏置: \(b_h\) ,用于计算 \(h_t\) 的相加操作; \(b_h\) ,用于计算 \(h_t\) 的相加操作; \(b_y\) ,用于计算 \(y_t\) 的相加操作。 \(b_y\) ,用于计算 \(y_t\) 的相加操作。 使用矩阵表示权重,使用向量表示偏置,上面 3 组权重和 2 组偏置就能构成一个完整的 RNN 。下面公式将所有的参数放在一起: \(h_t = tanh(W_{xh} \cdot x_t + W_{hh} \cdot h_{t-1} + b_h)\) \(y_t = W_{hy} \cdot h_t + b_y\) 注:不要跳过这些等式,停下来思考一分钟,记住这些权重是矩阵,其它变量是向量。 所有权重都使用矩阵乘法计算,并将偏置添加到乘积结果中。使用 tanh 作为第一个激活函数(也可以使用其它激活函数,如 sigmoid 函数)。如果不知道什么是激活函数, 第 4.2 节 激活函数 详细地介绍了它们。 让我们开始动手吧!将从头开始实现一个 RNN 网络 来执行简单的情感分析任务:确定给定的文本字符串的情绪是正向 (Positive) 的,还是负向 (Negative) 的。 文件 pos_peg.py 存放全部的样本数据,以 Python 字典的形式,包含训练集 train_data 和测试集 test_data : 由于这是一个分类问题,我们将使用“多对一”的 RNN 。这与我们之前讨论的“多对多”的 RNN 类似,但它仅使用最后的隐藏状态产生一个输出 \(y\) : 每个 \(x_i\) 都是个向量,表示文本中的单词。输出 \(y\) 是一个包含两个数字的向量,一个代表正向情绪,另一个代表负向情绪。我们将应用 softmax 函数将这些值转换为概率,并最终在 正向 / 负向 之间做出判断。 让我们开始构建 RNN 模型! 之前提到的数据集包含两个 Python 字典结构: train_data 和 test_data 。我们需要对数据进行预处理,将它转换为可用的形式。对数据集里面存在的单词,构建一个单词表 vocab ,使用单词表中的下标表示单词。 可以运行文件 1_5_pre_process.py 查看具体的情况,因为使用的 Python 语言 set 结构体,内部是无序的,所以每次程序执行,每个单词都能获取到不同的下标值: 注:set 结构体会自动过滤到重复的单词。 vocab 包含训练集中至少出现一次的所有单词,现在可以使用对应的整数表示单词表中的单词,这是必要的,因为 RNN 不能理解文本,我们必须给它输入数字。 上述代码生成了两个 dict 结构体,使用第一个结构体查看单词 good 的下标,使用第二个结构体查看下标 0 是哪个单词: 之前提到过每个输入 \(x_i\) 都是一个向量,这里我们使用 独热 (One-Hot) 向量 进行编码,用于将离散的单词数据编码成向量的形式。每个单词由一个独特的向量表示,其中只有一个位置为1,其他位置为0。 假设有三个类别:“Cat” ,“Dog” ,“Rabbit” ,对应的索引为 0,1,2 。那么 “Cat” 的 one-hot 向量为 [1, 0, 0] ,“Dog” 的 one-hot 向量为 [0, 1, 0] 。 因为在字典里有 18 个不同的单词,所以每个 \(x_i\) 的 one-hot 向量长度为 18 。使用 create_inputs 将文本数据转换为向量输入传递到神经网络中: 比如将 “i am not at all good” 编码成为输入矩阵,得到的形状为 (6, 18, 1) 。 第一个维度大小表示句子中单词的个数,第二个维度表示词汇表中单词的个数,注意第三个维度的大小为 1 ,主要是便于后续计算。 让我们开始实现 RNN 网络。使用标准正态分布,初始化 3 组权重值和 2 组偏置: 接下来实现 RNN 网络的前向传播,记住下面两个公式: \(h_t = tanh(W_{xh} \cdot x_t + W_{hh} \cdot h_{t-1} + b_h)\) \(y_t = W_{hy} \cdot h_t + b_y\) 文件 1_6_rnn_forward.py 将它们用代码实现: 看上去非常简单?注意第一步我们将 \(h\) 初始化为零向量,因为在那之前没有隐藏状态。 当我们的第一个输入单词为 \(x \in \mathbb{R}^{18 \times 1}\) 时,下述公式可以看到网络的维度变化: \(h \in \mathbb{R}^{64 \times 1} = tanh(W_{xh} \in \mathbb{R}^{64 \times 18} \cdot x \in \mathbb{R}^{18 \times 1} + W_{hh} \in \mathbb{R}^{64 \times 64} \cdot h \in \mathbb{R}^{64 \times 1} + b_h \in \mathbb{R}^{64 \times 1})\) \(y \in \mathbb{R}^{2 \times 1} = W_{hy} \in \mathbb{R}^{2 \times 64} \cdot h \in \mathbb{R}^{64 \times 1} + b_y \in \mathbb{R}^{2 \times 1}\) 以此类推,直到最后一个单词,经过 softmax 函数转换为概率值,完成网络的前向传播过程: 传递 “i am very good” 看看网络的输出情况: 此时网络起作用了,输出两个相近的概率值,但是并没有什么用,接下来使用反向传播进行训练! 以下部分假设你具有微积分的基本知识,如果不想看,可以跳过它,但是我建议你不要跳过。如果你没有这部分背景,可以阅读 第 4.1 节 导数 的内容。即使只是大概地浏览计算过程,对于理解循环神经网络也是有帮助的。 为了训练我们的 RNN ,需要有损失函数,这里选择交叉熵损失函数,它经常和 softmax 函数一起使用,具体介绍查看 第 4.3.3 小节 交叉熵损失 的内容 ,计算规则如下: \(loss = - \sum_{i=1}^n y_i \ln(p_i)\) \(y_i\) 是目标分布的真实标签,如果属于类别 \(i\) ,则 \(y_i = 1\) ,否则 \(y_i = 0\) ; \(y_i\) 是目标分布的真实标签,如果属于类别 \(i\) ,则 \(y_i = 1\) ,否则 \(y_i = 0\) ; \(p_i\) 是模型预测属于类别 \(i\) 的概率(通过 softmax 得到的概率值)。 \(p_i\) 是模型预测属于类别 \(i\) 的概率(通过 softmax 得到的概率值)。 在本例中,目标分布有 [0, 1] 和 [1, 0] 两种情况,[0, 1] 表示目标为正向情绪的类别,[1, 0] 表示目标为负向情绪的类别。对于单个样本,如果真实类别为 \(c\) ,只有对应的 \(y_c = 1\) ,其它为 0。因此可以将上面公式进行简化: \(l = - \ln(p_c)\) 其中 \(p_c\) 表示模型对正确类别(正向情绪或负向情绪)的预测概率。 比如文本预测出来的结果为 [0.1, 0.9] ,真实标签是正向的情绪,那么它的损失为: \(l = -\ln(0.9) = 0.105\) 如果真实标签为负向情绪,那么它的损失为: \(l = -\ln(0.1) = 2.302585\) 如果目标预测错误,那么它的损失较大。如果目标预测正确,那么它的损失接近于 0 。 有了损失函数后,就可以用梯度下降最小化损失,这意味着需要对一些变量进行求导。 \(y\) 表示 RNN 神经网络的输出; \(y\) 表示 RNN 神经网络的输出; \(p\) 表示最后的概率:\(p = softmax(y)\) ; \(p\) 表示最后的概率:\(p = softmax(y)\) ; \(c\) 表示文本的正确标签;
📥 下载地址(文章中间)
装机神器,可以安装一切系统。
\(c\) 表示文本的正确标签; \(l\) 表示交叉熵损失:\(l = -\ln(p_c)\) ,\(p_c\) 是预测正确类别的概率; \(l\) 表示交叉熵损失:\(l = -\ln(p_c)\) ,\(p_c\) 是预测正确类别的概率; \(W_{xh}\) ,\(W_{hh}\) 和 \(W_{hy}\) 表示 RNN 的 3 个权重矩阵; \(W_{xh}\) ,\(W_{hh}\) 和 \(W_{hy}\) 表示 RNN 的 3 个权重矩阵; \(b_h\) 和 \(b_y\) 表示 RNN 的 2 个偏置向量。 \(b_h\) 和 \(b_y\) 表示 RNN 的 2 个偏置向量。 另外我们需要在前向传播的过程中,存储一些数值,主要是每个单词的隐藏状态,用于反向传播的计算。构建反向传播的框架: 接下来是数学时间!梯度分为三个阶段进行计算: 第一个阶段计算损失 \(l\) 相对于输出 \(y\) 的梯度; 第一个阶段计算损失 \(l\) 相对于输出 \(y\) 的梯度; 第二个阶段计算输出 \(y\) 相对于最后一个节点的隐藏状态 \(h_n\) 的梯度 ,同时更新参数 \(W_{hy}\) 和 \(b_y\) ; 第二个阶段计算输出 \(y\) 相对于最后一个节点的隐藏状态 \(h_n\) 的梯度 ,同时更新参数 \(W_{hy}\) 和 \(b_y\) ; 第三个阶段是计算最后一个隐藏状态 \(h_n\) 相对于输入 \(x\) 的梯度,同时更新参数 \(W_{xh}\) 、\(W_{hh}\) 和 \(b_h\) 。 第三个阶段是计算最后一个隐藏状态 \(h_n\) 相对于输入 \(x\) 的梯度,同时更新参数 \(W_{xh}\) 、\(W_{hh}\) 和 \(b_h\) 。 第一阶段计算 \(\frac{\partial l}{\partial y}\) ,根据公式: \(l = -\ln(p_c) = -\ln(softmax(y_c))\) \(l\) 关于 \(y_c\) 的偏导数,分两种情况讨论:当 \(i = c\) 和 \(i \ne c\) : 1. 当 \(i = c\) (目标类别) \(\frac{\partial l}{\partial y_c} = \frac{\partial (-ln(p_c))}{\partial y_c}\) ,利用链式法则:\(\frac{\partial l}{\partial y_c} = \frac{\partial l}{\partial p_c} \cdot \frac{\partial p_c}{\partial y_c}\) 交叉熵损失函数的导数公式为:\(\frac{\partial l}{\partial p_c} = - \frac{1}{p_c}\) softmax 的导数公式为:\(\frac{\partial p_c}{\partial y_c} = p_c(1 - p_c)\) 代入得到 \(\frac{\partial l}{\partial y_c} = -\frac{1}{p_c} \cdot p_c \cdot (1 - p_c) = p_c - 1\) 1. 当 \(i = c\) (目标类别) \(\frac{\partial l}{\partial y_c} = \frac{\partial (-ln(p_c))}{\partial y_c}\) ,利用链式法则:\(\frac{\partial l}{\partial y_c} = \frac{\partial l}{\partial p_c} \cdot \frac{\partial p_c}{\partial y_c}\) 交叉熵损失函数的导数公式为:\(\frac{\partial l}{\partial p_c} = - \frac{1}{p_c}\) softmax 的导数公式为:\(\frac{\partial p_c}{\partial y_c} = p_c(1 - p_c)\) 代入得到 \(\frac{\partial l}{\partial y_c} = -\frac{1}{p_c} \cdot p_c \cdot (1 - p_c) = p_c - 1\) 2. 当 \(i \ne c\) (非目标类别) \(\frac{\partial l}{\partial y_c} = \frac{\partial (-ln(p_c))}{\partial y_c}\) ,同样利用链式法则:\(\frac{\partial l}{\partial y_c} = \frac{\partial l}{\partial p_c} \cdot \frac{\partial p_c}{\partial y_c}\) softmax 的导数公式为:\(\frac{\partial p_c}{\partial y_i} = -p_c \cdot p_i\) 代入得到 \(\frac{\partial l}{\partial y_i} = -\frac{1}{p_c} \cdot (-p_c \cdot p_i) = p_i\) 2. 当 \(i \ne c\) (非目标类别) \(\frac{\partial l}{\partial y_c} = \frac{\partial (-ln(p_c))}{\partial y_c}\) ,同样利用链式法则:\(\frac{\partial l}{\partial y_c} = \frac{\partial l}{\partial p_c} \cdot \frac{\partial p_c}{\partial y_c}\) softmax 的导数公式为:\(\frac{\partial p_c}{\partial y_i} = -p_c \cdot p_i\) 代入得到 \(\frac{\partial l}{\partial y_i} = -\frac{1}{p_c} \cdot (-p_c \cdot p_i) = p_i\) 经过计算我们得到损失 \(l\) 相对于输出 \(y\) 的梯度: \( \frac{\partial l}{\partial y_i} = \left\{ \begin{array}{ll} p_i - 1 & \text{if } i = j \\ p_i & \text{if } i \neq j \end{array} \right. \) 比如我们有一个概率 \(p = [0.2, 0.2, 0.6]\) ,正确得分类为 \(c = 0\) ,那么可以得到 \(\frac{\partial l}{\partial y} = [-0.8, 0.2, 0.6]\) 。这很容易转化为代码: 第二阶段需要计算 \(W_{hy}\) 和 \(b_y\) 的梯度,它们是唯一将隐藏状态转换为输出的节点: \(\frac{\partial l}{\partial W_{hy}} = \frac{\partial l}{\partial y} \cdot \frac{\partial y}{\partial W_{hy}}\) 根据公式 \(y = W_{hy} \cdot h_n + b_y\) \(\frac{\partial y}{\partial W_{hy}} = h_n\),其中 \(h_n\) 是最后的隐藏状态,因此可以得到: \(\frac{\partial l}{\partial W_{hy}} = \frac{\partial l}{\partial y} \cdot h_n\) 同样 \(\frac{\partial y}{\partial b_y} = 1\) ,得到: \(\frac{\partial l}{\partial b_y} = \frac{\partial l}{\partial y}\) 第三阶段需要计算每一步的 \(W_{hh}\) ,\(W_{xh}\) 和 \(b_h\) 的梯度,我们有下面公式: \(\frac{\partial l}{\partial W_{xh}} = \frac{\partial l}{\partial y} \sum_{t=0}^{n} (\frac{\partial y}{\partial h_t} \cdot \frac{\partial h_t}{\partial W_{xh}}) \) 因为改变 \(W_{xh}\) 会影响每个 \(h_t\) ,通过影响 \(y\) 值,最终影响损失 \(l\) 。为了计算 \(W_{xh}\) 的梯度,我们需要对所有的 \(t\) 进行反向传播,这就是著名的 时间上反向传播 (Backpropagation Through Time, BPTT) 。 上述公式需要分别计算 \(\frac{\partial y}{\partial h_t}\) 和 \(\frac{\partial h_t}{\partial W_{xh}}\) 的梯度。 \(W_{xh}\) 在所有的 \(x_t\) -> \(h_t\) 连接中都用到,所以要对所有的此类连接进行反向传播。对于给定步骤 \(t\) ,我们需要计算 \(\frac{\partial h_t}{\partial W_{xh}}\) : \(h_t = tanh(W_{xh} \cdot x_t + W_{hh} \cdot h_{t-1} + b_h)\) 其中,我们知道 \(\frac{d \tanh(x)}{dx} = 1 - \tanh^2(x)\) ,因此 \(\frac{\partial h_t}{\partial W_{xh}} = (1 - h_t^2)x_t\) 同样根据上述公式对其它两个参数进行求导得到: \(\frac{\partial h_t}{\partial W_{hh}} = (1 - h_t^2)h_{t-1}\) \(\frac{\partial h_t}{\partial b_h} = (1 - h_t^2)\) 最后需要 \(\frac{\partial y}{\partial h_t}\) ,我们可以使用循环计算: \(\frac{\partial y}{\partial h_t} = \frac{\partial y}{\partial h_{t+1}} \cdot \frac{\partial h_{t+1}}{\partial h_t} = \frac{\partial y}{\partial h_{t+1}} \cdot (1 - h_t^2) \cdot W_{hh}\) BPTT 的实现从最后一个隐藏状态开始,然后反向传递。因此当我们想要计算 \(\frac{\partial y}{\partial h_t}\) 时,已经计算出 \(\frac{\partial y}{\partial h_{t+1}}\) 的值,除了最后一个状态 \(h_n\) : \(\frac{\partial y}{\partial h_n} = W_{hy}\) 现在我们已经有了实施 BPTT 需要的一切参数,文件 1_7_rnn_backward.py 用代码实现 RNN 的反向传播: 为了方便,使用 \(\frac{\partial l}{\partial h}\) 直接代替 \(\frac{\partial l}{\partial y} \cdot \frac{\partial y}{\partial h}\) 。 为了方便,使用 \(\frac{\partial l}{\partial h}\) 直接代替 \(\frac{\partial l}{\partial y} \cdot \frac{\partial y}{\partial h}\) 。 为了计算 \(\frac{\partial l}{\partial h_t}\) ,不停地更新 dh 的值,它存储最新计算出来的 \(\frac{\partial l}{\partial h_{t+1}}\) 的值。 为了计算 \(\frac{\partial l}{\partial h_t}\) ,不停地更新 dh 的值,它存储最新计算出来的 \(\frac{\partial l}{\partial h_{t+1}}\) 的值。 结束 BPTT 后,使用 numpy.clip() 去掉梯度在 -1 以下,或者 +1 以上的值。这有助于缓解梯度爆炸问题,即由于存在大量乘项导致梯度变得非常大。梯度爆炸或消失对于普通 RNN 来说是个问题 - 更复杂的 RNN (如 LSTM)通常更有能力处理它们。 结束 BPTT 后,使用 numpy.clip() 去掉梯度在 -1 以下,或者 +1 以上的值。这有助于缓解梯度爆炸问题,即由于存在大量乘项导致梯度变得非常大。梯度爆炸或消失对于普通 RNN 来说是个问题 - 更复杂的 RNN (如 LSTM)通常更有能力处理它们。 一旦计算出所有梯度,就使用梯度下降来更新权重和偏差。 一旦计算出所有梯度,就使用梯度下降来更新权重和偏差。 我们已经成功完成 RNN 的反向传播! 终于到了激动人心的时刻,接下来就需要对 RNN 网络进行测试,编写一个辅助函数: 跑程序文件 1_7_rnn_backward.py 会得到一些输出,像下面这样: 绘制训练过程的损失和精确度变化: 可以看到训练损失逐渐降低,训练精度逐渐提高,最终达到平衡,训练结束。 训练完成后,使用新的用例进行预测: 这就是全部!在这节中,我们经历了循环神经网络的整个过程,包括它们是什么、如何工作、它们为什么有用、如何训练它们以及如何实现。我们还可以做得更多: 了解长短期记忆网络(LSTM ,一种更强大、更流行的 RNN 架构)或门控循环单元 (GRU,LSTM 的著名变体)。 了解长短期记忆网络(LSTM ,一种更强大、更流行的 RNN 架构)或门控循环单元 (GRU,LSTM 的著名变体)。 使用机器学习库,(如 TensorFlow 、PyTorch 、JAX )实验更大/更好的数据。 使用机器学习库,(如 TensorFlow 、PyTorch 、JAX )实验更大/更好的数据。 阅读有关 双向 RNNs 的信息,它可以处理正向的和反向序列,以便为输出层提供更多的信息。 阅读有关 双向 RNNs 的信息,它可以处理正向的和反向序列,以便为输出层提供更多的信息。 尝试使用 词嵌入 (Word Embedding) ,比如 GloVe 或 Word2Vec ,它可以将语句转换为更有用的向量表示。 尝试使用 词嵌入 (Word Embedding) ,比如 GloVe 或 Word2Vec ,它可以将语句转换为更有用的向量表示。 8.1.9 PyTorch 实现 文件 1_9_rnn_torch.py 使用 PyTorch 实现 RNN 架构,对文本进行正向和负向分类的完整示例,其中核心代码为: 数据预处理:文本被编码为词索引,并填充到固定长度 (max_len) 。 数据预处理:文本被编码为词索引,并填充到固定长度 (max_len) 。 RNN 模型使用嵌入层 (nn.Embedding) 将词索引映射为向量,使用 (nn.RNN) 构建循环神经网络。用全连接层 (nn.Linear) 将隐藏状态映射为分类结果。 RNN 模型使用嵌入层 (nn.Embedding) 将词索引映射为向量,使用 (nn.RNN) 构建循环神经网络。用全连接层 (nn.Linear) 将隐藏状态映射为分类结果。 训练与测试:通过 DataLoader 迭代数据,使用交叉熵损失函数优化模型。 训练与测试:通过 DataLoader 迭代数据,使用交叉熵损失函数优化模型。 和手写 RNN 的逻辑基本一致。 损失逐渐降低,最终接近 0 ,非常好的结果。下图是绘制的损失变化图像:
📥 下载地址(文章结尾)
装机神器,可以安装一切系统。