深度学习--RNN循环神经网络和LSTM

news2024/11/19 6:32:11

RNN

RNN简介

我们来看一看百度百科给的解释

下面是循环神经网络的一部分

黑色直线代表权重,a1,a2代表存储单元,黄色框框代表输入,曲线是激活函数

RNN常用领域

  1. 语言建模(Language Modeling):RNN可以根据前文预测下一个单词或字符,用于自动文本生成、拼写纠错等任务。
  2. 机器翻译(Machine Translation):RNN可以将输入语言的序列转换为输出语言的序列,实现自动翻译。
  3. 文本分类(Text Classification):RNN可以对文本进行情感分析、垃圾邮件过滤等分类任务。
  4. 命名实体识别(Named Entity Recognition):RNN可以识别文本中的人名、地名、组织名等实体。

RNN结构 

这是一个序列模型的例子。

我们可以看出, 这个是模型是由很多个相同的网络结构结成的,因此也称它为循环神经网络。

我们将这个网络的结构进行抽象,然后展开,就得到了以下内容:

RNN的工作原理

循环神经网络的工程原理其实就是它的训练算法,一种基于时间的反向传播算法BPTT.

BPTT算法是针对循环层设计的训练算法,它的工作原理和反向传播BP的工作原理是相同的,也包含同样的三个步骤:

1.前向计算每个神经元的输出值

2.反向计算每个神经元的误差项值,它是误差函数对神经元的加权输入的偏导数。

3.计算每个权重的梯度,用随机梯度下降法更新权重。

以下是加权输入的含义: 

现在,我们就对RNN有了大致的了解,下面就让我们来具体学习它的各个部分的内容。

RNN的前向传播 

我们主要观察中间那层,b我们设为0,可以忽略不计

中间结果z=前一层即隐藏层的值*隐藏层权重U+这一层的输入值*权重W

我们对z加上激活函数得到h,我们这在这里用到的是Tanh激活函数

这是隐藏层中间结果的表示方法。

 

输出层y的表示方法。

V在这里表示的也是权重。

g()是使用Softmax激活函数。

这是我们的输出值的最终函数,也就是一个嵌套的循环函数。

接下来,我们对应公式来书写代码

代码

import numpy as np
def forward_propagation(self,x):
    T=len(x)    # T为输入序列的长度

    # 初始化
    h=np.zeros((T+1,self.hidden_dim))
    h[-1]=np.zeros(self.hidden_dim)
    y_pre=np.zeros((T,self.in_shape))
    
    for t in np.arange(T):
        x_t=np.array(x[t]).reshape(-1,1)
        z=(self.U.dot(x_t)+self.W.dot(h[t-1].reshape(-1,1))).reshape(-1)
        h[t]=self.tanh(z)
        o_t=self.V.dot(h[t])
        y_pre[t]=self.softmax(o_t)
        
    return y_pre,h

RNN的后向传播 

这是我们的公式。

最后的L_t是对预测值求交叉熵损失函数,是一个标量。

c为偏置,不存在的话可以不写。

我们先要了解两部分知识:

必备知识

标量对多个矩阵的链式求导法则

要注意的是,这里要进行转置。

标量对多个向量的链式求导法则

 

 z为标量,x为向量

对权重的求导 

对V求导

对W求导

我们可以对照公式进行理解。

第一部分

这一部分如下

因为

所以就有了

 第二部分

然后是下一个部分

 它是怎么求的呢?

因为h1只和z1有关,h2只和z2有关,所以上面变为了对角矩阵:

 第三部分

这一部分:

我们先要知道tanh的求导公式:

然后我们就得到了以下结果

 对U求导

与对W求导是一样的

RNN的梯度更新

通过后向传播,我们可以得到以下公式:

 既然我们得到了公式,我们就可以写出相对应的代码了:

这里是用纯python写的 

import torch
import numpy as np

class RNN(torch.nn.Module):
    def __init__(self,input_size,output_size,hidden_dim,n_layers):
        super(RNN,self).__init__()
        self.hidden_dim = hidden_dim
        self.n_layers = n_layers
        self.rnn = torch.nn.RNN(input_size,hidden_dim,n_layers,batch_first=True)
        self.linear=torch.nn.Linear(hidden_dim,output_size)
    def forward(self,x):
        batch_size = x.size(0)
        hidden= torch.zeros(self.n_layers,batch_size,self.hidden_dim)
        out,hidden=self.rnn(x,hidden)
        out = self.linear(out)
        return out,hidden

我们在这里简单了解一下就好了,。

RNN的pythorch框架代码实现

在这里,我们需要先了解一些函数

 torch.nn.RNN

参数说明 

input_size:即 d ;
hidden_size:即 h ;
num_layers:即RNN的层数。默认是 1  层。该参数大于 1  时,会形成 Stacked RNN,又称多层RNN或深度RNN;
nonlinearity:即非线性激活函数。可以选择 tanh 或 relu,默认是 tanh;
bias:即偏置。默认启用,可以选择关闭;
batch_first:即是否选择让 batch_size 作为输入的形状中的第一个参数。当 batch_first=True 时,输入应具有 N × L × d这样的形状,否则应具有 L × N × d 这样的形状。默认是 False;
dropout:即是否启用 dropout。如要启用,则应设置 dropout 的概率,此时除最后一层外,RNN的每一层后面都会加上一个dropout层。默认是 0 ,即不启用;
bidirectional:即是否启用双向RNN,默认关闭。

torch.nn.Linear

torch.nn.Linear(in_features, # 输入的神经元个数
           out_features,             # 输出神经元个数
           bias=True                   # 是否包含偏置
           )

 实际上,他进行的是y_pre=w*x+b的线性变换,从而得到预测值y_pre。 

torch.zeros

torch.zeros(

*sizes, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False

)

参数说明

*sizes:一个或多个整数,用于指定张量的形状(shape)。可以传递多个参数来创建一个多维张量。
out:可选参数,用于指定输出张量的位置。
dtype:可选参数,用于指定输出张量的数据类型。默认为 None,表示使用默认数据类型。
layout:可选参数,用于指定张量的布局。默认为 torch.strided。
device:可选参数,用于指定张量的设备(CPU 或 GPU)。
requires_grad:可选参数,指示是否为张量启用梯度计算。默认为 False。

代码

在这里,我们仍需对照图像进行理解

import torch
import numpy as np

class RNN(torch.nn.Module):
    def __init__(self,input_size,output_size,hidden_dim,n_layers):
        super(RNN,self).__init__()
        self.hidden_dim = hidden_dim
        self.n_layers = n_layers
        self.rnn = torch.nn.RNN(input_size,hidden_dim,n_layers,batch_first=True)
        self.linear=torch.nn.Linear(hidden_dim,output_size)
    def forward(self,x):
        batch_size = x.size(0)
        hidden= torch.zeros(self.n_layers,batch_size,self.hidden_dim)
        out,hidden=self.rnn(x,hidden)
        out = self.linear(out)
        return out,hidden

在前向传播中,

batch_size=x.size(0) 这行代码获取输入张量x的第一个维度的大小;

在这里,hidden是形状为(

self.n_layers,batch_size,self.hidden_dim

)的全零张量

RNN的缺点:梯度爆炸和梯度消失

L3是第三个时间点的交叉熵损失函数 

在这里我们是L3对V求偏导,通过图像我们可以得到上面的结果,然后再通过结果可以看出,对V求偏导并没有长期依赖。

我们再来看下面的对U和W求偏导

推导过程上面已经提到了,这里就不多说了。

我们可以看出,对U和W求偏导的式子都特别长,对它们求偏导会随着时间序列产生长期依赖

我们可以把上面的式子写成下面的形式:

然后再加上激活函数

 最终得到

 下面是f(x)=tanh部分的图像

通过上面这张图片,我们可以得到 f(x)的导数的值域是在0到1之间的。

训练过程中,大部分情况tanh的导数都是小于1的,那么如果U也是一个大于0小于1的值,当t很大即时间序列很大时,梯度值就会趋近于0,造成        

同理,当U很大时,梯度时就会趋近于无穷,造成梯度爆炸

那么RNN怎么解决梯度爆炸和梯度消失呢,就是用到了LSTM

LSTM

前向传播

这里的 指的是进行了Sigmoid激活函数

我们可以把图和公式对应起来,进行理解

反向传播

 在这里,f1是指遗忘门的内容,f2是指输入门,ct表示新的记录,而ct-1就表示上一条记录。

f1,遗忘门,我们这里可以理解为橡皮,对f1进行sigmoid,相当于把不重要的信息删除掉,保留重要的信息。

f2,输入门,我们可以理解为铅笔,同样进行sigmoid后,再*tanh,相当于对所有信息进行一个梳理

pytorch代码

import torch
import numpy as np
class LSTM(torch.nn.Module):
    def __init__(self, input_size, hidden_dim, output_size,n_layers):
        super(LSTM, self).__init__()
        self.input_size = input_size
        self.hidden_size = hidden_dim
        self.output_size = output_size
        self.n_layers = n_layers
        self.lstm = torch.nn.LSTM(input_size, hidden_dim, n_layers, batch_first=True)
        self.fc = torch.nn.Linear(hidden_dim, output_size)
    def forward(self,x):
        h0=torch.zeros(self.x.size(0), self.n_layers,self.hidden_size).to(x.device)
        c0 = torch.zeros(self.x.size(0), self.n_layers, self.hidden_size).to(x.device)
        out,hidden=self.lstm(x,(h0,c0))
        out = self.fc(out[:,-1,:])
        return out,hidden

在LSTM模型中,最核心的部分也就是前向传播的部分了。

核心代码解析

h0=torch.zeros(self.x.size(0), self.n_layers,self.hidden_size).to(x.device)
c0 = torch.zeros(self.x.size(0), self.n_layers, self.hidden_size).to(x.device)

需要注意的是,在上面的__init__中,由于我们将batch_first设为Ture,输入和输出的张量的形状就是(batch, seq_len, input_size)

其中batch是批处理大小,seq_len是序列长度,我们在这里用的是n_layers,input_size是特征维度。

如果batch_first=False(默认值),则输入张量的形状为(seq_len, batch, input_size)

所以,在zeros中,传入的参数依次为 self.x.size(1), self.n_layers,self.hidden_size 

由于 batch_first=True,batch 的大小就是张量的第一个维度 ,也就是 x.size(0)

最后面的 to(x.device)用来确保这些张量位于与输入张量x相同的设备上(例如,CPU或GPU)


 out = self.fc(out[:,-1,:])

在这里我们用到了一个截取的操作

python矩阵的切片(或截取)-CSDN博客

我们可以通过这个文章来复习一下。

这是指在最后的结果中,我们截取每个样本(第一个维度)中的最后一个时间步(-1)的所有特征(第三个维度)。

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

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

相关文章

视频抽帧转图片,opencv和ffmpeg效果测评

最近在做一个项目,需要从视频中抽帧转图片,于是对opencv和ffmpeg效果进行了测评。 文章目录 1. open cv2. ffmpeg3.抽帧效果对比 1. open cv open cv 视频抽图片的教程,推荐以下链接,抽的帧数可以自行调节! 用pythono…

重磅!!!监控分布式NVIDIA-GPU状态

简介:Uptime Kuma是一个易于使用的自托管监控工具,它的界面干净简洁,部署和使用都非常方便,用来监控GPU是否在占用,非常美观。 历史攻略: docker应用:搭建uptime-kuma监控站点 win下持续观察…

windows11编译3dslicer_问题总结

编译前准备 CMake:版本>3.16.3(避免使用3.21.0,3.25.0-3.25.2,这些版本,可能会出现build错误)。Git:版本>1.7.10,安装完git,一定要在cmd里面试一试,是…

DRF学习之三大认证

一、认证 1、自定义认证 在前面说的 APIView 中封装了三大认证,分别为认证、权限、频率。认证即登录认证,权限表示该用户是否有权限访问接口,频率表示用户指定时间内能访问接口的次数。整个请求最开始的也是认证。 (1&#xff…

pytest测试基础

assert 验证关键字 需要pahton版本大于3.6,因为有个工具pip3;因为做了映射,所以下面命令pip3即pip pip install -U pytest -U参数可选,是如果已安装可更新。 如果上述demo变化 通过验证代码,测试环境没问题。…

Aigtek:介电弹性体高压放大器在软体机器人研究中的应用

近年来软体机器人的研究成为目前机器人研究领域的热点,由于软体材料的自由度可以根据需求自由变化,因此软体机器人有着极高的灵活性,而且软体机器人因其材料的柔软性有着很好的人机交互性能和安全性。它的出现成功解决了传统的刚性机器人人机…

嵌入式学习62-C++

知识零碎: 构造函数 在执行过程中的三个过程 ←(背) 1.传参:实参向形参传…

Hikyuu-tips-如何使用自定义的 host

Hikyuu 下载数据依赖于 pytdx,如何修改确定的通达信行情服务器的地址,可以参考:如何修改 pytdx 中对应的通达信 IP 地址_通达信行情主站地址-CSDN博客 上面需要去修改 pytdx 中的 hosts.py,但 pytdx 实际是一个 python 的软件包&…

51单片机中断和定时的结合应用

#include <reg52.h>unsigned int cnt 0;sbit led P1^1;// 初始化定时器 void TimerSetup(){TMOD 0x01; // 定时器的第1个模式TH0 0xB8; // 定时器的初始值-高位TL0 0x00; // 定时器的初始值-低位TR0 1; //启动定时器cnt 0;EA 1; // 开启总中断ET0 1; // 时间中断…

【JavaEE网络】TCP/IP协议:细节与应用

目录 TCP/IP协议协议格式传输层重点协议UDP协议UDP协议端格式 UDP的特点TCP协议TCP协议端格式 TCP的特点 TCP/IP协议 协议格式 应用层&#xff08;后端开发必知必会&#xff09;&#xff1a;这一层也有很多现成的协议&#xff08;后面还会重点介绍HTTP协议&#xff0c;这是做…

物联网:从电信物联开发平台AIoT获取物联设备上报数据示例

设备接入到电信AIoT物联平台后&#xff0c;可以在平台上查询到设备上报的数据。 下面就以接入的NBIOT物联远传水表为例。 在产品中选择指定设备&#xff0c;在数据查看中可以看到此设备上报的数据。 示例中这组数据是base64位加密的&#xff0c;获取后还需要转换解密。 而我…

[iOS]CocoaPods安装和使用

1.了解brew、rvm、ruby、gem、cocaspods之间的关系 在 macOS 环境中&#xff0c;Brew、RVM、Ruby、Gem 和 CocoaPods 之间存在以下关系&#xff1a; Homebrew (Brew)&#xff1a;Homebrew 是 macOS 上的包管理器&#xff0c;用于安装和管理各种开源软件包。它使您能够轻松地从…

ARK Invest:比特币,一种被低估且独特的避险资产

由于 2008 年全球金融危机&#xff0c;人们对政府和金融机构的信任度下降。此后&#xff0c;欧洲主权债务危机、美联储对 COVID19 的应对措施以及美国主要地区性银行的倒闭等事件暴露了依赖中心化机构的弊端。 随着技术创新的加速影响&#xff0c;信任度的下降使人们开始质疑传…

【C++】双指针算法:和为s的两个数字

1.题目 虽然在牛客上是个中等题&#xff0c;但我感觉是比较简单的。大家在看完这篇文章后可以看看我的上一篇文章&#xff1a;有效三角形的个数。本文章的题目的解法只是有效三角形的个数这道题目的一个环节。看懂这篇文章后可以更好的解决有效三角形个数那道题目&#xff01; …

AI 重写人类DNA,开源基因编辑器问世;安卓版Gemini新增多项功能

&#x1f989; AI新闻 &#x1f680; AI 重写人类DNA&#xff0c;开源基因编辑器问世 摘要&#xff1a;初创公司 Profluent 最新宣布&#xff0c;开发出世界首个完全由 AI 设计的基因编辑器&#xff0c;并成功应用于人类细胞 DNA&#xff0c;这一技术可谓是分子生物学的一大突…

Oracle之RMAN联机和脱机备份(二)

rman脱机备份,首先使用rman登入数据库服务器,然后关闭数据库后,启动数据库到mount状态,在执行backup database指定备份整个数据库。 1、启动mount归档模式 sys@ORCL>archive log list; Database log mode Archive Mode Automatic archival Enabl…

文本向量化模型新突破——acge_text_embedding勇夺C-MTEB榜首

在人工智能的浪潮中&#xff0c;以GPT4、Claude3、Llama 3等大型语言模型&#xff08;LLM&#xff09;无疑是最引人注目的潮头。这些模型通过在海量数据上的预训练&#xff0c;学习到了丰富的语言知识和模式&#xff0c;展现了出惊人的能力。在支撑这些大型语言模型应用落地方面…

网络爬虫之爬虫原理

** 爬虫概述 Python网络爬虫是利用Python编程语言编写的程序&#xff0c;通过互联网爬取特定网站的信息&#xff0c;并将其保存到本地计算机或数据库中。 """ 批量爬取各城市房价走势涨幅top10和跌幅top10 """ ​ from lxml import etree impor…

Oceanbase体验之(一)运维管理工具OCP部署(社区版4.2.2)

资源规划建议 ocp主机1台 内存:64G CPU1:2C及以上 硬盘大于500G observer服务器3台 内存32G CPU&#xff1a;4C以上 硬盘大于1T 建议存储硬盘与操作系统硬盘隔开实现IO隔离 一、OBD、OCP安装包准备 [rootobserver /]# chown -R admin:admin /software/ [rootobserver /]# …

云LIS系统概述JavaScript+前端框架JQuery+EasyUI+Bootstrap医院云HIS系统源码 开箱即用

云LIS系统概述JavaScript前端框架JQueryEasyUIBootstrap医院云HIS系统源码 开箱即用 云LIS&#xff08;云实验室信息管理系统&#xff09;是一种结合了计算机网络化信息系统的技术&#xff0c;它无缝嵌入到云HIS&#xff08;医院信息系统&#xff09;中&#xff0c;用于连…