24/10/14 算法笔记 循环神经网络RNN

news2025/1/19 10:39:51

RNN:

        一种专门用于处理序列数据的神经网络,它能够捕捉时间序列中的动态特征。RNN的核心特点是其循环连接,这允许网络在不同时间步之间传递信息,从而实现对序列数据的记忆和处理能力。

应用的场景:

自然语言处理(NLP)语音识别,时间序列预测(天气预报,股票),机器人控制(预测动作),图像处理

在前向传播过程中,RNN利用前一时间步的隐藏状态和当前时间步的输入来计算当前时间步的隐藏状态和输出,这种循环连接允许RNN在处理序列数据时考虑时间依赖性,从而在多种应用中表现出色。

然而,RNN在训练过程中可能会遇到梯度消失和梯度爆炸的问题,尤其是在处理长序列时。为了解决这些问题,研究者们开发了LSTM(长短期记忆网络)和GRU(门控循环单元)等变体,它们通过引入门控机制来控制信息的流动,从而有效地解决了梯度问题,并提高了RNN在长序列数据上的性能。

隐状态:

它代表了网络在处理序列数据时的内部记忆或信息状态。隐状态是网络在每个时间步的内部表示,它携带了序列中之前信息的累积效应,并用于预测当前时间步的输出。

  1. 信息的累积: 隐状态捕捉了序列中之前所有时间步的信息。在处理序列数据时,如文本、语音或时间序列数据,隐状态帮助网络记住重要的上下文信息。

  2. 序列依赖性: 由于隐状态的存在,RNN能够处理输入数据之间的序列依赖性。这意味着网络的输出不仅依赖于当前的输入,还依赖于之前的输入。

困惑度:困惑度(Perplexity)是一个衡量语言模型性能的指标,尤其在自然语言处理(NLP)领域中。它主要用于评估语言模型对文本序列的预测能力。困惑度越低,表示模型对数据的预测越准确。

困惑度可以被解释为模型在预测下一个词时的平均分支数。例如,如果困惑度为 100,这意味着对于每个词,模型平均需要从 100 个可能的词中选择下一个词。因此,困惑度越低,表示模型的预测越准确。困惑度常用于比较不同的语言模型或评估模型在不同数据集上的性能。它也用于监控模型训练过程中的性能变化,帮助确定何时停止训练以避免过拟合。

循环神经网络的实现

初始化返回隐状态的函数

def __init_rnn_state(batch_size,num_hiddens,device):
    return(torch.zeros((batch_size,num_hiddens),device = device),)

在一个时间步内计算隐状态和输出

RNN的前向传播

def rnn(inputs,state,params):
    W_xh,W_hh,b_h,W_hq,b_q = params
    H, = state #这里的逗号 , 是必需的,它告诉 Python 解释器 H 是一个单独的元素,而不是一个元组。如果没有逗号,H = state 将会尝试将整个 state 赋值给变量 H
    outputs = []
    for X in inputs:
        H = torch.tanh(torch.mm(X,W_xh)+torch.mm(H,W_hh)+b_h)
        Y = torch.mm(H, W_hq) + b_q   #torch.mm矩阵乘法
        outputs.append(Y)
    return torch.cat(outputs, dim=0), (H,)

包装

class RNNModelScratch: #@save
    """从零开始实现的循环神经网络模型"""
    def __init__(self, vocab_size, num_hiddens, device,
                 get_params, init_state, forward_fn):
        self.vocab_size, self.num_hiddens = vocab_size, num_hiddens
        self.params = get_params(vocab_size, num_hiddens, device)
        self.init_state, self.forward_fn = init_state, forward_fn

    def __call__(self, X, state):
        X = F.one_hot(X.T, self.vocab_size).type(torch.float32)
        return self.forward_fn(X, state, self.params)

    def begin_state(self, batch_size, device):
        return self.init_state(batch_size, self.num_hiddens, device)

检查输出是否具有正确的形状

num_hiddens = 512
net = RNNModelScratch(len(vocab), num_hiddens, d2l.try_gpu(), get_params,
                      init_rnn_state, rnn)
state = net.begin_state(X.shape[0], d2l.try_gpu())
Y, new_state = net(X.to(d2l.try_gpu()), state)
Y.shape, len(new_state), new_state[0].shape

 预测

其中的prefix是一个用户提供的包含多个字符的字符串。 在循环遍历prefix中的开始字符时, 我们不断地将隐状态传递到下一个时间步,但是不生成任何输出。 这被称为预热(warm-up)期, 因为在此期间模型会自我更新(例如,更新隐状态), 但不会进行预测。 预热期结束后,隐状态的值通常比刚开始的初始值更适合预测, 从而预测字符并输出它们。
def predict_ch8(prefix, num_preds, net, vocab, device):  #@save
    """在prefix后面生成新字符"""
    state = net.begin_state(batch_size=1, device=device)
    outputs = [vocab[prefix[0]]]
    get_input = lambda: torch.tensor([outputs[-1]], device=device).reshape((1, 1))
    for y in prefix[1:]:  # 预热期
        _, state = net(get_input(), state)
        outputs.append(vocab[y])
    for _ in range(num_preds):  # 预测num_preds步
        y, state = net(get_input(), state)
        outputs.append(int(y.argmax(dim=1).reshape(1)))
    return ''.join([vocab.idx_to_token[i] for i in outputs])

梯度裁剪

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

训练

def train_epoch_ch8(net, train_iter, loss, updater, device, use_random_iter):
    """训练网络一个迭代周期(定义见第8章)"""
    state, timer = None, d2l.Timer()
    metric = d2l.Accumulator(2)  # 训练损失之和,词元数量
    for X, Y in train_iter:
        if state is None or use_random_iter:
            # 在第一次迭代或使用随机抽样时初始化state
            state = net.begin_state(batch_size=X.shape[0], device=device)
        else:
            if isinstance(net, nn.Module) and not isinstance(state, tuple):
                # state对于nn.GRU是个张量
                state.detach_()
            else:
                # state对于nn.LSTM或对于我们从零开始实现的模型是个张量
                for s in state:
                    s.detach_()
        y = Y.T.reshape(-1)
        X, y = X.to(device), y.to(device)
        y_hat, state = net(X, state)
        l = loss(y_hat, y.long()).mean()
        if isinstance(updater, torch.optim.Optimizer):
            updater.zero_grad()
            l.backward()
            grad_clipping(net, 1)
            updater.step()
        else:
            l.backward()
            grad_clipping(net, 1)
            # 因为已经调用了mean函数
            updater(batch_size=1)
        metric.add(l * y.numel(), y.numel())
    return math.exp(metric[0] / metric[1]), metric[1] / timer.stop()

用高级API实现

def train_ch8(net, train_iter, vocab, lr, num_epochs, device,
              use_random_iter=False):
    """训练模型(定义见第8章)"""
    loss = nn.CrossEntropyLoss()
    animator = d2l.Animator(xlabel='epoch', ylabel='perplexity',
                            legend=['train'], xlim=[10, num_epochs])
    # 初始化
    if isinstance(net, nn.Module):
        updater = torch.optim.SGD(net.parameters(), lr)
    else:
        updater = lambda batch_size: d2l.sgd(net.params, lr, batch_size)
    predict = lambda prefix: predict_ch8(prefix, 50, net, vocab, device)
    # 训练和预测
    for epoch in range(num_epochs):
        ppl, speed = train_epoch_ch8(
            net, train_iter, loss, updater, device, use_random_iter)
        if (epoch + 1) % 10 == 0:
            print(predict('time traveller'))
            animator.add(epoch + 1, [ppl])
    print(f'困惑度 {ppl:.1f}, {speed:.1f} 词元/秒 {str(device)}')
    print(predict('time traveller'))
    print(predict('traveller'))
num_epochs, lr = 500, 1
train_ch8(net, train_iter, vocab, lr, num_epochs, d2l.try_gpu())

检查一下使用随机抽样方法的结果

net = RNNModelScratch(len(vocab), num_hiddens, d2l.try_gpu(), get_params,
                      init_rnn_state, rnn)
train_ch8(net, train_iter, vocab, lr, num_epochs, d2l.try_gpu(),
          use_random_iter=True)

循环神经网络的简洁实现

定义模型

num_hiddens = 256
rnn_layer = nn.RNN(len(vocab), num_hiddens)

使用张量来初始化隐状态

state = torch.zeros((1, batch_size, num_hiddens))

通过一个隐状态和一个输入,我们就可以用更新后的隐状态计算输出。

X = torch.rand(size=(num_steps, batch_size, len(vocab)))
Y, state_new = rnn_layer(X, state)
Y.shape, state_new.shape

为一个完整的循环神经网络模型定义一个RNNModel

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))

训练与预测

device = d2l.try_gpu()
net = RNNModel(rnn_layer, vocab_size=len(vocab))
net = net.to(device)
d2l.predict_ch8('time traveller', 10, net, vocab, device)

由于深度学习框架的高级API对代码进行了更多的优化, 该模型在较短的时间内达到了较低的困惑度。

  • 相比从零开始实现的循环神经网络,使用高级API实现可以加速训练。

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

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

相关文章

这款懂人情世故的大模型强得可怕!

这款孵化于首期书生大模型实战营,基于 InternLM2 开发的项目——天机,更懂人情世故的大模型,这 2 天在社区可谓有点火!相关内容在小红书上至少收获了六千多点赞与收藏 ! 你是否还在苦苦挣扎于各种应酬,四处寻找“高情商…

MySQL-04.DDL-数据库操作

一.数据库的操作 DDL(data definition language):数据定义语言,用来定义数据库对象(数据库、表) DDL分为两类:1.数据库的DDL语句,主要是针对数据库的定义,增加,删除,使用 2.表结构的DDL语句&…

大数据-160 Apache Kylin 构建Cube 按照日期构建Cube 详细记录

点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…

TuyaOS开发学习笔记(4)——BLE开发搭建环境、编译烧写(NRF52832)

一、搭建环境 1.1 官方资料 TuyaOS 1.2 安装Visual Studio Code 官网下载:https://code.visualstudio.com 百度网盘:https://pan.baidu.com/s/1R62HT0PVmVzMwOXtCmIQwA 提取码:g9fb 1.3 安装Tuya Wind IDE 启动 Visual Studio Code 后&am…

windows10 输入法突然变成繁体字。

1.在任务栏的输入法上切换到设置页面 2. 进入语言选项 3.浮动在桌面上? 4. 点击繁体或简体切换。

IWO-Kmeans聚类 | MATLAB实现IWO-Kmeans侵入性杂草优化K均值聚类算法

智能优化 | MATLAB实现IWO-Kmeans侵入性杂草优化K均值聚类算法 目录 智能优化 | MATLAB实现IWO-Kmeans侵入性杂草优化K均值聚类算法效果一览基本介绍模型描述程序设计参考资料效果一览 基本介绍 侵入性杂草优化 (IWO) 聚类, 与 K-means 和 GMM 高斯混合模型的比较。 入侵杂草优…

jupyter notebook显示左侧内容方法(版本7也可以用)

1 安装 Nbextensions pip install jupyter_contrib_nbextensions如果安装不成功, jupyter安装Nbextensions后不出现Nbextensions选项 就使用以下语句 conda install -c conda-forge jupyter_contrib_nbextensions然后设置下 jupyter contrib nbextension insta…

kali在git外网的代理

如果发现用git无法直接连接到某些外网项目。可以配置一下代理。 vi /etc/proxychains4.conf 主机可以开一下机场代理&#xff0c;查一下主机的地址和代理所开的端口&#xff0c;我这里是7890 写上代码&#xff1a; socks5 <your ip> <your port> 写上之后wq保…

java内存管理

Java内存管理主要涉及Java虚拟机&#xff08;JVM&#xff09;对内存的分配与回收过程。这一过程确保了Java程序在运行时能够有效地使用内存资源&#xff0c;同时避免了手动管理内存所带来的复杂性和潜在错误。 内存分配&#xff1a; 堆&#xff08;Heap&#xff09;&#xff1a…

【C++】拆分详解 - list

文章目录 一、list的介绍二、list的使用1. 构造2. 迭代器3. 增 删 查 改4. list 迭代器失效问题5. list 排序问题 三、list的模拟实现0. 整体框架1. 迭代器类1.1 operator->1.2 临时对象1.3 const_iterator 2. list类2.1 begin / end2.2 构造 / 析构 / 拷贝构造 / 赋值重载2…

谷歌浏览器如何防范恶意网站和广告

在日常使用互联网时&#xff0c;我们经常会遇到一些恶意网站或广告&#xff0c;这些不仅会影响我们的浏览体验&#xff0c;还可能对我们的设备安全造成威胁。为了帮助大家更好地防范这些问题&#xff0c;本文将详细介绍如何在谷歌浏览器中采取有效的措施来防范恶意网站和广告。…

Grafana+ Node+ Prometheus对服务器进行性能监控

目录 一、Grafana 1.把Grafana压缩文件上传到Linux服务器 2.安装服务 3.启动服务 4.访问 二、Node 1.上传node_exporter-1.5.0.linux-amd64.tar到服务器 2.解压 3.启动服务 三、Prometheus 1.上传prometheus-2.43.0.linux-amd64.tar到服务器 2.解压 3.进入prometh…

【Linux】ComfyUI和SD WebUI之PYTHON环境共享,模型共享,LORA等公共资源共享。最大限度节约空间

需求 一般玩AI绘图都会装ComfyUI和SD WebUI。而且这俩的模型、lora等都是一致的。为了避免空间的浪费&#xff0c;一般会采用共享数据的方式。而且共享的数据可以任意指定分区&#xff0c;这让挂载NAS共享空间成为可能&#xff0c;实现多绘画机ComfyUI和SD WebUI共享资源。 实…

SpringCloud学习记录|day4

学习材料 2024最新SpringCloud微服务开发与实战&#xff0c;java黑马商城项目微服务实战开发&#xff08;涵盖MybatisPlus、Docker、MQ、ES、Redis高级等&#xff09; 网关 微服务下&#xff0c;好多不同地址和端口&#xff0c;而前端只知道8080&#xff0c;这怎么解决&…

不起眼的错误参数导致remote-debugging-port不生效

引言 背景 由于有一些小需求需要控制浏览器批量执行请求&#xff0c;最简单的方案是使用 DrissionPage 来实现&#xff0c;遂有了下面的问题。 问题 通过命令行传入 remote-debugging-port9111 参数&#xff0c;但是调试了一天&#xff0c;一直不生效&#xff0c;各种方法都…

【数据结构与算法】线性表链式存储结构

线性表链式存储结构 文章目录 链式存储结构*头结点和头指针一.线性链表&#xff08;单链表&#xff09;1.1定义1.2初始化1.2.1带头结点的初始化1.2.2不带头结点的初始化 1.3插入1.3.1按位序插入1.3.2指定结点的后插入操作1.3.3指定结点的前插入操作 1.4删除1.4.1按位序删除1.4.…

小猿口算安卓端安装包PK一题秒过关。。。

大家好&#xff0c;我是小黄。 近段时间&#xff0c;越来越多的同学都想去小猿口算里面虐小学生&#xff0c;但是发现越来越多的计算机学生带着科技与他们进行对抗&#xff0c;这样非计算机专业的大学生们​苦不堪言。 现在&#xff0c;非计算机大学生们翻身的机会来了&#…

二叉平衡树(AVL树)Java语言实现

一、二叉平衡树 上一章所示的同一组元素按照不同顺序插入到二叉排序树中可能会产生两种形状不同的二叉排序树。 当出现右边的情况时&#xff0c;树的高度过高&#xff0c;如果要查找值为“70”的节点需要查找7次&#xff0c;其查找次数已经接近于链表了&#xff0c;这样会导致…

短短几日连发数案,艺术家Jennifer Le Feuvre插画版权维权

案件基本情况起诉时间&#xff1a;2024-10-7、2024-10-8、2024-10-9案件号&#xff1a;24-cv-09629、24-cv-09636、24-cv-09640、24-cv-09688、24-cv-09697、24-cv-09709、24-cv-09712、24-cv-09757、24-cv-09775、24-cv-09794原告&#xff1a;Jennifer Le Feuvre原告律所&…

【安装教程】Windows10环境下Pytorch(GPU版)的安装与配置

目录 Pytorch的概念安装前要求一、NVIDIA驱动查看二、Anaconda的安装2.1 Anaconda的安装2.2 创建虚拟环境2.3 激活虚拟环境 三、CUDA ToolKit的安装&#xff08;选做&#xff0c;CPU版本可跳过&#xff09;3.1 CUDA安装包的下载&#xff08;以CUDA11.6.0为例&#xff09;3.2 CU…