李沐机器学习系列5---循环神经网络

news2024/11/20 20:40:56

1 Introduction

对于样本的分析,通过全连接层处理表格数据,通过卷积神经网络处理图像数据;第一种假设,所有数据都是独立同分布的RNN 处理序列信号
序列数据的更多场景
1)用户使用习惯具有时间的先后性
2)外推法和内插法

1.1 自回归模型

1)自回归模型,对自己执行回归
在这里插入图片描述
2)隐变量的自回归模型
在这里插入图片描述
生成训练数据,

在这里插入图片描述

1.2 马尔科夫模型

一个模型被称为马尔可夫模型,主要是因为它满足马尔可夫性质,也就是说,该模型中的未来状态仅依赖于当前状态,而不依赖于过去的历史状态。在数学上,这被表达为条件概率的形式: ( p ( x k ∣ x k − 1 , x k − 2 , … ) = p ( x k ∣ x k − 1 ) ( p(x_k|x_{k-1}, x_{k-2}, \ldots) = p(x_k|x_{k-1}) (p(xkxk1,xk2,)=p(xkxk1)。这意味着下一个状态( x_k )的概率分布只取决于紧邻的前一个状态( x_{k-1} ),而与之前的所有其他状态无关。

在这里插入图片描述

2 文本序列处理

将文本拆分成次元,将词源字符串映射成数字索引,并将文本数据转换成词元索引以供模型操作。

将文本作为字符串加载到内存中。
将字符串拆分为词元(如单词和字符)。
建立一个词表,将拆分的词元映射到数字索引。
将文本转换为数字索引序列,方便模型操作。

3 语言模型和数据集

语言模型的目标是估计序列的联合概率
P ( x 1 , x 2 , . . . , x T ) P(x_1, x_2, ..., x_T) P(x1,x2,...,xT)
在这里插入图片描述
用贝叶斯条件概率估计,这种贝叶斯估计,会因为样本的稀疏,并不好建立足够的联系。
在这里插入图片描述
在这里插入图片描述
可以用马尔科夫模型来近似,因为当前状态基本上只依赖于前几个词元。
在这里插入图片描述

单词出现的频率以非常快的速度进行衰减,齐普夫定律(Zipf’s law), 即第个最常用单词的频率为:
在这里插入图片描述
多元语法的频率
在这里插入图片描述

  • 除了一元语法词,单词序列似乎也遵循齐普夫定律, 尽管公式 (8.3.7)中的指数
    更小 (指数的大小受序列长度的影响);
  • 词表中元组的数量并没有那么大,这说明语言中存在相当多的结构, 这些结构给了我们应用模型的希望;
  • 很多元组很少出现,这使得拉普拉斯平滑非常不适合语言建模。 作为代替,我们将使用基于深度学习的模型

读取长序列数据,如果采用固定长度,效果不太好,采用随机偏移量划分序列,以获得覆盖性和随机性。
在这里插入图片描述

2.1 随机采样

def seq_data_iter_random(corpus, batch_size, num_steps):  #@save
    """使用随机抽样生成一个小批量子序列"""
    # 从随机偏移量开始对序列进行分区,随机范围包括num_steps-1
    corpus = corpus[random.randint(0, num_steps - 1):]
    # 减去1,是因为我们需要考虑标签
    num_subseqs = (len(corpus) - 1) // num_steps
    # 长度为num_steps的子序列的起始索引
    initial_indices = list(range(0, num_subseqs * num_steps, num_steps))
    # 在随机抽样的迭代过程中,
    # 来自两个相邻的、随机的、小批量中的子序列不一定在原始序列上相邻
    random.shuffle(initial_indices)

    def data(pos):
        # 返回从pos位置开始的长度为num_steps的序列
        return corpus[pos: pos + num_steps]

    num_batches = num_subseqs // batch_size
    for i in range(0, batch_size * num_batches, batch_size):
        # 在这里,initial_indices包含子序列的随机起始索引
        initial_indices_per_batch = initial_indices[i: i + batch_size]
        X = [data(j) for j in initial_indices_per_batch]
        Y = [data(j + 1) for j in initial_indices_per_batch]
        yield torch.tensor(X), torch.tensor(Y)

2.2 顺序分区

完全按照顺序进行分区,没有洗牌的操作。

def seq_data_iter_sequential(corpus, batch_size, num_steps):  #@save
    """使用顺序分区生成一个小批量子序列"""
    # 从随机偏移量开始划分序列
    offset = random.randint(0, num_steps)
    num_tokens = ((len(corpus) - offset - 1) // batch_size) * batch_size
    Xs = torch.tensor(corpus[offset: offset + num_tokens])
    Ys = torch.tensor(corpus[offset + 1: offset + 1 + num_tokens])
    Xs, Ys = Xs.reshape(batch_size, -1), Ys.reshape(batch_size, -1)
    num_batches = Xs.shape[1] // num_steps
    for i in range(0, num_steps * num_batches, num_steps):
        X = Xs[:, i: i + num_steps]
        Y = Ys[:, i: i + num_steps]
        yield X, Y

4 循环神经网络

循环圣经网络的核心思想
在这里插入图片描述

4.1 无隐状态的神经网络

在这里插入图片描述

4.2 有隐状态的神经网络

H t − 1 H_{t-1} Ht1捕获并保留序列知道当前时间步的历史信息
在这里插入图片描述
对于第一个输入,往往也会初始化一个隐变量
在这里插入图片描述
输出层,采用softmax的分类器;因为有很多个head,中间的输出层的结果如下图,会推断到下一个
在这里插入图片描述

4.3 困惑度

质量上,从人的评价来说,满足基本的结构,满足填充的内容正确,
在这里插入图片描述

似然概率来度量模型的质量,但是因序列的长度有差异,需要借用信息论中信息熵的概念来分析
类似调和平均数来判断,困惑度
在这里插入图片描述
在这里插入图片描述

5 RNN的从零实现

5.1 独热编码

在这里插入图片描述

独热编码(One-Hot Encoding)的好处主要包括:

  1. 清晰表示:独热编码通过将每个类别表示为一个唯一的二进制向量,为类别提供了明确的表示,这在处理类别数据时非常有用。

  2. 无序性:在独热编码中,不同类别之间没有数值上的关联,这避免了模型错误地解释类别间的数值关系,特别是在类别没有内在顺序的情况下。

  3. 适合距离计算:由于每个类别都被转换成相互正交的向量,它们在空间中的距离是相等的。这对于基于距离的算法(如K-近邻算法)非常有用。

在处理不同长度的序列样本时,RNN网络通常采用以下策略之一:

  1. 填充(Padding):将所有序列填充到相同的长度。较短的序列在末尾添加特殊的填充符号,以便所有序列具有相同的长度。这允许网络具有固定的结构。

  2. 动态计算图:某些深度学习框架支持动态计算图,它们可以处理可变长度的输入。在这种情况下,RNN可以在每个批次中处理不同长度的序列,而无需填充。

  3. 分批处理不同长度:将序列分组到不同长度的批次中。这种方法避免了过多的填充,但可能需要更复杂的批次管理。

5.2 梯度裁剪

梯度裁剪和Wolfe原则有一定的相似性,但也存在重要的区别:

  1. 梯度裁剪:主要关注梯度的大小。当梯度的范数超过一个预定的阈值时,会按比例缩减梯度,以防止梯度过大导致的训练不稳定问题。

  2. Wolfe原则:是一种在线搜索(Line Search)策略,用于选择步长。它包含两个条件:充分下降条件和曲率条件,旨在确保每一步优化都朝着目标函数下降的方向,并且步长既不太大也不太小。

共同之处在于它们都旨在通过控制优化步骤的大小来提高优化过程的稳定性。不同之处在于梯度裁剪是一种更直接的方法,用于控制梯度的大小,而Wolfe原则是一种更复杂的策略,用于在优化过程中选择合适的步长。
在这里插入图片描述
在这里插入图片描述

def grad_clipping(net, theta):  #@save
    """裁剪梯度"""
    if isinstance(net, nn.Module):
        params = [p for p in net.parameters() if p.requires_grad]
    else:
        params = net.params
    norm = torch.sqrt(sum(torch.sum((p.grad ** 2)) for p in params))
    if norm > theta:
        for param in params:
            param.grad[:] *= theta / norm

6 简洁实现

#@save
class RNNModel(nn.Module):
    """循环神经网络模型"""
    def __init__(self, rnn_layer, vocab_size, **kwargs):
        super(RNNModel, self).__init__(**kwargs)
        self.rnn = rnn_layer
        self.vocab_size = vocab_size
        self.num_hiddens = self.rnn.hidden_size
        # 如果RNN是双向的(之后将介绍),num_directions应该是2,否则应该是1
        if not self.rnn.bidirectional:
            self.num_directions = 1
            self.linear = nn.Linear(self.num_hiddens, self.vocab_size)
        else:
            self.num_directions = 2
            self.linear = nn.Linear(self.num_hiddens * 2, self.vocab_size)

    def forward(self, inputs, state):
        X = F.one_hot(inputs.T.long(), self.vocab_size)
        X = X.to(torch.float32)
        Y, state = self.rnn(X, state)
        # 全连接层首先将Y的形状改为(时间步数*批量大小,隐藏单元数)
        # 它的输出形状是(时间步数*批量大小,词表大小)。
        output = self.linear(Y.reshape((-1, Y.shape[-1])))
        return output, state

    def begin_state(self, device, batch_size=1):
        if not isinstance(self.rnn, nn.LSTM):
            # nn.GRU以张量作为隐状态
            return  torch.zeros((self.num_directions * self.rnn.num_layers,
                                 batch_size, self.num_hiddens),
                                device=device)
        else:
            # nn.LSTM以元组作为隐状态
            return (torch.zeros((
                self.num_directions * self.rnn.num_layers,
                batch_size, self.num_hiddens), device=device),
                    torch.zeros((
                        self.num_directions * self.rnn.num_layers,
                        batch_size, self.num_hiddens), device=device))

7 通过时间反向传播

7.1 梯度分析

通过链式法则回顾循环神经网络的梯度爆炸问题;类似控制中的乘积累加的问题,第一个词元对最后位置的词元产生重大的影响。
每个时间步的隐状态和输出,完整的RNN表示如下:
在这里插入图片描述

在这里插入图片描述
统计T个时间步内的总体的loss,
在这里插入图片描述
计算目标函数L关于参数 w h w_h wh的梯度时,
在这里插入图片描述
这里的因为链式法则比较复杂,
在这里插入图片描述
有以下几种策略:

  • 完全计算
    因为有循环结算,容易梯度爆炸
    在这里插入图片描述

  • 截断时间步
    截断到 ∂ h t − τ ∂ w h \frac{\partial h_{t-\tau}}{\partial w_h} whhtτ

  • 随机截断

  • 比较策略
    实践中,随机截断的效果不比常规截断更好,
    在这里插入图片描述

7.2 通过时间反向传播的细节

在这里插入图片描述
一套链式法则以后,类似于控制中的状态变量,初始的隐变量对应的参数的梯度是指数型的,导致数值上的不稳定;
在这里插入图片描述
解决方法:
1)截断时间不长,取近似的梯度;
2)LSTM

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1358271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vm】兆懿,安卓虚拟机

以前用了Win11安卓子系统,体验不好 这次试试兆懿。弄了几个小时,终于安装成功 实际体验极差:虚拟机占用内存多机箱一直呜呜叫个不停;打开软件发现卡到爆炸还时不时闪退 为了不让他占空间,第二天卸载。 虚拟机就是折腾着…

java实现list去重(四种方法)

📑前言 本文主要是【Java】——java实现list去重(四种方法)的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页…

工厂如何确定设备故障的原因?

设备故障是制造业中常见的问题,对生产效率和运营成本产生重大影响。为了解决设备故障并提高生产效率,确定设备故障的准确原因至关重要。本文将介绍一些关键步骤和方法,帮助工厂确定设备故障的原因。 1. 收集和分析数据 要确定设备故障的原因…

互联网加竞赛 基于CNN实现谣言检测 - python 深度学习 机器学习

文章目录 1 前言1.1 背景 2 数据集3 实现过程4 CNN网络实现5 模型训练部分6 模型评估7 预测结果8 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 基于CNN实现谣言检测 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐&am…

局域网共享打印机设置

一 配置共享打印机环境 方法1(打印机连接的电有设置密码的设置): 1 需要在非直接连接打印机的pc上设置,登录账号,在控制面板中进入凭证管理,添加连接打印机主机的登录凭证 方法2(免账号密码…

【InnoDB数据存储结构】第3章节:区、段、碎片区和表空间

文章目录结构 区、段、碎片区和表空间 什么是区?什么是段?什么是碎片区?什么是表空间? 在上文 InooDB 存储行格式一文中已经大致讲述过,再来回顾一下,直接上图: 名词解释如下: 行…

使用 Parallels Desktop 彻底改变您的开发和测试工作流程

Parallels Desktop 等虚拟机平台已经改变了应用程序开发和测试。 在当今快节奏的技术环境中,开发人员和测试人员现在能够在虚拟沙箱中进行操作,能够使用容器、虚拟机或 Kubernetes 集群快速创建和拆除类似虚拟生产的环境。 无论您是为 Windows 或 Mac …

(03)光刻——半导体电路的绘制

01、绘制精细电路的第一步 金属-氧化物半导体场效应晶体管(MOSFET)的革命,让我们可以在相同面积的晶圆上同时制造出更多晶体管。MOSFET体积越小,单个 MOSFET的耗电量就越少,还可以制造出更多的晶体管,让其发挥作用,可谓是一举多得。可见,制造更小的MOSFET成了关键因素…

第五周:深度学习知识点回顾

前言: 讲真,复习这块我是比较头大的,之前的线代、高数、概率论、西瓜书、樱花书、NG的系列课程、李宏毅李沐等等等等…那可是花了三年学习佳实践下来的,现在一想脑子里就剩下几个名词就觉得废柴一个了,朋友们有没有同感…

SDRAM小项目——SDRAM初始化配置

主要写了SDRAM的初始化模块,注重文档信息的查找,时序图的设计,SDRAM仿真插件的使用。 文档信息: 根据文档说明,SDRAM在使用之前必须先进行初始化 初始化之前要进行100us的延迟,在100us内除了INHIBIT和NOP命…

【数据分析实战】冰雪大世界携程景区评价信息情感分析采集词云

文章目录 引言数据采集数据集展示数据预处理 数据分析评价总体情况分析本人浅薄分析 各游客人群占比分析本人浅薄分析 各评分雷达图本人浅薄分析 差评词云-可视化本人浅薄分析 好评词云-可视化本人浅薄分析 综合分析写在最后 今年冬天,哈尔滨冰雪旅游"杀疯了&q…

炫酷的倒计时引导页

文章目录 文件分布介绍效果预览代码css样式Locationplayer.css js样式player.js 文件分布介绍 效果预览 代码 css样式 Location html {height: 100%;}body {font-family: "Helvetica Neue", "Luxi Sans", "DejaVu Sans", Tahoma, "Hirag…

SwiftUI 打造一款收缩自如的 HStack(三):“魔镜魔镜,我爱你”

概览 在前两篇博文中,我们分别讨论了用 HStack 和 对齐+ZStack 来实现收缩自如“HStack”的方法。 虽然看起来“各有千秋”,但实际上它们都拖着一坨厚重的 datas,这不禁为其“减分不少”。 而从上图演示中可以看到:我们完全摆脱了 datas 数据的桎梏,现在我们可以按照轻松…

【Java EE初阶九】多线程案例(线程池)

一、线程池的引入 引入池---->主要是为了提高效率; 最开始,进程可以解决并发编程的问题,但是代价有点大了,于是引入了 “轻量级进程” ---->线程 线程也能解决并发编程的问题,而且线程的开销比进程要小的多&…

JS新手入门笔记整理:条件判断

判断语句:IF 单向判断:if... 语法 if(条件) {…… } 如果“条件”返回结果为true,则会执行大括号{}内部的程序;如果“条件”返回结果为false,则会直接跳过大括号{}内部的程序,然后…

Python中User-Agent的重要作用及实际应用

摘要: User-Agent是HTTP协议中的一个重要字段,用于标识发送请求的客户端信息。在Python中,User-Agent的作用至关重要,它可以影响网络请求的结果和服务器端的响应。将介绍User-Agent在Python中的重要作用,并结合实际案…

编码器原理详解

编码器 什么是编码器 编码器可以用来将信息编码成为二进制代码,有点类似于取代号,人为的将二进制代码与对应的信息联系起来。 如下图所示: 假设有这三种情况会发生,且每次只发生一种情况 为了给这三种情况做一个区分&#xff…

FPGA - 240102 - FPGA期末速成

TAG - F P G A 、期末、速成 FPGA、期末、速成 FPGA、期末、速成 // – 习题1 – //CPLD(Complex Programmable Logic Device)是 Complex PLD 的简称,一种较 PLD 为复杂的逻辑元件。CPLD 逻辑资源多寄存器少,FPGA 逻辑弱而寄存器…

TemporalKit的纯手动安装

最近在用本地SD安装temporalkit插件 本地安装插件最常见的问题就是,GitCommandError:… 原因就是,没有科学上网,而且即使搭了ladder,在SD的“从网址上安装”或是“插件安装”都不行,都不行!!&am…

PMP考试的通过标准是什么?

PMP 新考纲一共是 180道题,答对 108道就通过了,具体怎么看? 登录网站查询: 第一步:登录PMI网站:www.pmi.org 第二步:进入Dashboard: 第三步:点击菜单Certifications - …