[PyTorch][chapter 45][RNN_2]

news2024/9/27 15:51:43

目录:

  1.     RNN 问题
  2.     RNN 时序链问题
  3.     RNN 词组预测的例子
  4.      RNN简洁实现

 


一  RNN 问题

     RNN 主要有两个问题,梯度弥散和梯度爆炸

    1.1  损失函数

               E=\sum_{t=1}^TE_t

               h_t= tanh(W_{xh}x_t+W_{hh}h_t)

               y_t=W_{ho}h_t

           梯度

              \frac{\partial E_t}{\partial W_{hh}}=\sum_{i=1}^{t}\frac{\partial E_t}{\partial y_{t}}\frac{\partial y_t}{\partial h_{t}}\frac{\partial h_t}{\partial h_{i}}\frac{\partial h_i}{\partial W_{hh}}

              其中:

              \frac{\partial h_t}{\partial h_i}=\prod_{k=i}^{t-1} \frac{\partial h_{k+1}}{\partial h_k}

              \frac{\partial h_{k+1}}{\partial h_{k}}=diag(1-h_k^2)W_{hh}

             则

                \frac{\partial h_k}{\partial h_1}=\prod_{i}^{k} diag(1-h_i^2)W_{hh}

     1.1  梯度爆炸(Gradient Exploding)

                  上面矩阵进行连乘后k,可能会出现里面参数会变得极大

               

                解决方案:

                  梯度剪裁:对W.grad进行约束

              

           

def print_current_grad(model):
    for  w in model.parameters():
        print(w.grad.norm())
    
loss.criterion(output, y)
model.zero_grad()
loss.backward()
print_current_grad(model)
torch.nn.utils.clip_grad_norm_(p,10)
print_current_grad(model)
optimizer.step()

             

     1.2  梯度弥散(Gradient vanishing)

    是由于时序链过程,导致梯度为0,前面的层参数无法更新。

  解决方案 :

          LSTM.


二  RNN 时序链问题

    

# -*- coding: utf-8 -*-
"""
Created on Mon Jul 24 15:12:49 2023

@author: chengxf2
"""

import torch
import torch.nn as  nn
import numpy as np
import torch.optim as optim
import matplotlib.pyplot as plt  # 导入作图相关的包



'''
    生成训练的数据集
return 
   x: 当前时刻的输入值[batch_size=1, time_step=num_time_steps-1, feature=1]
   y: 当前时刻的标签值[batch_size=1, time_step=num_time_steps-1, feature=1]
'''
def sampleData():
    
    #生成一个[0-3]之间的数据
    start = np.random.randint(3,size=1)[0]
    num_time_steps =20
   
    #时序链长度为num_time_steps
    time_steps= np.linspace(start, start+10,num_time_steps)
    data = np.sin(time_steps)
    data = data.reshape(num_time_steps,1)
    
    #[batch, seq, dimension]
    x= torch.tensor(data[:-1]).float().view(1,num_time_steps-1,1)
    y= torch.tensor(data[1:]).float().view(1, num_time_steps-1,1)
 
    return x,y,time_steps

'''
    网络模型

args:
    input_size – 输入x的特征数量。
    hidden_size – 隐藏层的特征数量。
    num_layers – RNN的层数。
    nonlinearity – 指定非线性函数使用tanh还是relu。默认是tanh。
    bias – 默认是True
    batch_first – 如果True的话,那么输入Tensor的shape应该是[batch_size, time_step, feature],
           输出也是这样。默认是False
           dropout – 如果值非零,那么除了最后一层外,其它层的输出都会套上一个dropout层。

    bidirectional – 如果True,将会变成一个双向RNN,默认为False。
'''
class Net(nn.Module):
    
    def __init__(self,input_dim = 1, hidden_dim =10,  out_dim = 1):
        
        super(Net, self).__init__()
        self.rnn= nn.RNN(input_size = input_dim, 
                        hidden_size = hidden_dim,
                        num_layers = 1,
                        batch_first = True)
        
        self.linear= nn.Linear(in_features= hidden_dim, out_features=out_dim)
      
    #前向传播函数
    def forward(self,x,hidden_prev):
        # 给定一个h_state初始状态,(batch_size=1,layer=1,hidden_dim=10)
        # 给定一个序列x.shape:[batch_size, time_step, feature]
        hidden_dim =10
        
        #print("\n x.shape",x.shape)
        out,hidden_prev= self.rnn(x,hidden_prev)
        out = out.view(-1,hidden_dim) #[1,seq,h]=>[1*seq,h]
        out = self.linear(out)#[seq,h]=>[seq,1]
        
        out = out.unsqueeze(dim=0) #[seq,1] 指定的维度上面添加一个维度[batch=1,seq,1]
        
        return out, hidden_prev
    
    


def main():
    
    
    model = Net()
    criterion = nn.MSELoss()
    optimizer = optim.Adam(model.parameters(),lr=1e-3)
    
    
    hidden_dim =10
    #初始值
    hidden_prv = torch.zeros(1,1,hidden_dim)
    
    for iter in range(5000):
        
        x,y,time_steps =sampleData() #[batch=1,seq=99,dim=1]
        
        output, hidden_prev =model(x,hidden_prv)
        
        hidden_prev = hidden_prev.detach()
        
        
        loss = criterion(output, y)
        
        model.zero_grad()
        loss.backward()
        optimizer.step()
        
        
        if iter %100 ==0:
            
            print("Iter:{} loss{}".format(iter, loss.item()))
            # 对最后一次的结果作图查看网络的预测效果
            
    
    plt.plot(time_steps[0:-1], y.flatten(), 'r-')
    plt.plot(time_steps[0:-1], output.data.numpy().flatten(), 'b-')
main()

三  RNN 词组预测的例子

     这是参考李沐写得一个实现nn.RNN功能的例子

,一般很少用,都是直接用nn.RNN.

# -*- coding: utf-8 -*-
"""
Created on Wed Jul 26 14:17:49 2023

@author: chengxf2
"""

import math
import torch
from torch import nn
from torch.nn import functional as F
import numpy
import d2lzh_pytorch as d2l





#生成随机变量
def normal(shape,device):
    
    return torch.randn(size=shape, device=device)*0.01

#模型需要更新的权重系数
def get_params(vocab_size=27, num_hiddens=10, device='cuda:0'):
    
     num_inputs = num_outputs = vocab_size
     
     W_xh = normal((num_inputs,num_hiddens),device)
     W_hh = normal((num_hiddens,num_hiddens),device)
     b_xh = torch.zeros(num_hiddens,device=device)
     b_hh = torch.zeros(num_hiddens,device=device)
     
     W_hq = normal((num_hiddens,num_outputs),device)
     b_q = torch.zeros(num_outputs, device= device)

     params = [W_xh,W_hh, b_xh,b_hh, W_hq,b_q]
     
     for param in params:
         
         param.requires_grad_(True)
     
     return params
          
#初始的隐藏值 hidden ,tuple
def init_rnn_state(batch_size, hidden_size, device):
    
    h_init= torch.zeros((batch_size,hidden_size),device=device)
    return  (h_init,)


#RNN 函数定义了如何在时间序列上更新隐藏状态和输出
def rnn(X, h_init, params):
    
    W_xh,W_hh, b_xh,b_hh, W_hq,b_q = params
    
    hidden, = h_init
    
    outputs =[]
    for x_t in X:
        
        z_t = torch.mm(x_t, W_xh)+b_xh+ torch.mm(x_t,W_hh)+b_hh
        hidden =torch.tanh(z_t)
        
        out = torch.mm(hidden,W_hq)+b_q
        outputs.append(out)
        
    #[batch_size*T, dimension]
    return torch.cat(outputs, dim=0),(hidden,)

#根据给定的词,预测后面num_preds 个词
def predict_ch8(prefix, num_preds, net, vocab, device):

     #生成初始状态
     state = net.begin_state(batch_size=1, device=device)
     
     #把第一个词拿出来
     outputs = [vocab[prefix[0]]]
     
     
     get_input = lambda: torch.tensor([outputs[-1]],device=device,(1,1))
     
     for y in prefix[1:]:
         
         _,state = net(get_input(), state)
         outputs.append(vocab[y])
         
    for _ in range(num_preds):
        
        y, state = net(get_input(), state)
        
        outputs, (int(y.argmax(dim=1).reshape(1)))
    
    return ''.join([vocab.idex_to_toke[i] for i in output])


#梯度剪裁

def grad_clipping(net, theta):
    
    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
        
        
     
class RNNModel:
    
      #从零开始实现RNN 网络模型#
      
      def __init__(self, vocab_size, hidden_size, device, get_params, init_rnn_state,forward_fn):
          forward_fn
          self.vocab_size = vocab_size, self.num_hiddens = hidden_size
          self.params = get_params(vocab_size, hidden_size, device)
          self.init_state = init_rnn_state(batch_size, hidden_size, device)
          self.forwad_fn = forward_fn
          
      #X.shape [batch_size,num_steps] 
      def __call__(self, X, state):
          
          X = F.one_hot(X.T, self.vocab_size).type(torch.float32)
          
          #[num_steps, batch_size]
          return self.forwad_fn(X, state, self.params)
      
      
      def begin_state(self, batch_size, device):
          
          return self.init_state(batch_size, self.num_hiddens, device)
        
        
# 训练模型

def train_epoch_ch8(net, train_iter, loss, updater, device,)

    state, timer = None, d21.Timer()

    metric = d21.Accumulator(2)

    for X,Y in train_iter:
        
         if state is None or use_random_iter:
             state = net.beign_state(bacth_size=X.shape[0])
        
         else
              if isinstance(net, nn.Module) and not isinstance(o, t)
                  state.detach_()
              else
                  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)
            updater(batch_size=1)
        
        metric.add(1&y.numel(),y.numel())
    return math.exp(metric[0]/metric[1]))
        

def train(net, train_iter,vocab, lr,num_epochs, device, use_random_iter=False):
    
    
    loss = nn.CrossEntropyLoss()
    
    animator = d21.animator(xlabel='epoch',ylabel='preplexity',
                            legend=['train'],xlim=[10,num_epochs])
    
    
    if isinstance(net, nn.Module):
        
        updater = torch.optim.SGD(net.parameters(),lr)
    else:
        
        updater = lambda batch_size: d21.sgd(net.parameters,batch_size,lr)
        
    predict = lambda prefix: predict_ch8(prefix, num_preds=50, net, vocab, device)
    
    for epoch in range(num_epochs):
        
        ppl, spped = train_epoch_ch8(net, train_iter, updater(),use_random_iter())
        
        if (epoch+1)%10 ==0:
            
            print(predict('time traverller'))
            animator.add(epoch+1, [ppl])
            
    print(f'困惑度{ppl:lf},{speed:1f} 标记/秒')
    print(predict('time traveller'))
    print(predict('traveller'))
        
                  
               
        
      
        
def main():

   num_hiddens =512
   num_epochs, ,lr = 500,1
   
   vocab_size = len(vocab)
   #[批量大小,时间步数]
   batch_size, num_steps = 32, 10
   train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
   F.one_hot(torch.tensor([0,2]), len(vocab))
   X= torch.arange(10).reshape((2,5))
   Y = F.one_hot(X.T,28).shape #[step, batch_num]

   model = RNNModel(vocab_size, num_hiddens, dl2.try_gpu(), get_params, init_rnn_state, rnn)            
 
   
   train_ch8(model, train_iter, vocab,lr,num_epochs,dl2.try_gpu())
   
   
   
    
if __name__ == "__main__":
    
    main()

四  RNN简洁实现

     

# -*- coding: utf-8 -*-
"""
Created on Fri Jul 28 10:11:33 2023

@author: chengxf2
"""

import torch
from torch import nn
from torch.nn import functional as F




class SimpleRNN(nn.Module):
    
      def __init__(self,batch_size, input_size, hidden_size,out_size):
          
          super(SimpleRNN,self).__init__()
          
          self.batch_size,self.num_hiddens = batch_size,hidden_size
          self.rnn_layer = nn.RNN(input_size,hidden_size)
          self.linear = nn.Linear(hidden_size, out_size)
          
      
      def  forward(self, X,state):
          '''

          Parameters
          ----------
           X : [seq,batch, feature]
          state : [layer, batch, feature]
          -------
          #output:(layer, batch_size, hidden_size)
          state_new : []
          '''
          
          hidden, hidden_new = self.rnn_layer(X, state)
          
          hidden = hidden.view(-1, hidden.shape[-1])
          output = self.linear(hidden)
          
          
          
          return output ,hidden
    
      def init_hidden_state(self):
           '''
           初始化隐藏状态
          '''
           state = torch.zeros((1,self.batch_size, self.num_hiddens))
           return state
       
        
def main():
    seq_len = 3 #时序链长度
    batch_size =5 #批量大小
    input_size = 27
    hidden_size = 10
    out_size = 9
    
    X = torch.rand(size=(seq_len,batch_size,input_size))
    model = SimpleRNN(batch_size,input_size, hidden_size,out_size)
    
    init_state = model.init_hidden_state()
    output, hidden = model.forward(X, init_state)
    
    print("\n 输出值:",output.shape)
    print("\n 时刻的隐藏状态")
    print(hidden.shape)
    
if __name__ == "__main__":
    
    main()
       
        

pytorch入门10--循环神经网络(RNN)_rnn代码pytorch_微扬嘴角的博客-CSDN博客

【PyTorch】深度学习实践之 RNN基础篇——实现RNN_pytorch实现rnn_zoetu的博客-CSDN博客

RNN 的基本原理+pytorch代码_rnn代码_黄某某很聪明的博客-CSDN博客

55 循环神经网络 RNN 的实现【动手学深度学习v2】_哔哩哔哩_bilibili

《动手学深度学习》环境搭建全程详细教程 window用户_https://zh.d21.ai/d21-zh-1.1.zip_溶~月的博客-CSDN博客

ModuleNotFoundError: No module named ‘d2l’_卡拉比丘流形的博客-CSDN博客

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

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

相关文章

【C++】开源:Boost库常用组件配置使用

😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍Boost库常用组件配置使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下&#xff0c…

Vue触发兄弟级组件中的某个方法

要求:页面上有两个兄弟级组件,假如我点击组件 1 中的按钮,需要触发组件 2 中的某个方法; 在这里,以购物车页面为例:我选择商品列表中的某个商品选中状态,在结算组件中根据列表中是否有未选中状态…

《向量数据库指南》——Milvus Cloud2.2.12 易用性,可视化,自动化大幅提升

Milvus Cloud又迎版本升级,三大新特性全力加持,易用性再上新台阶! 近期,Milvus Cloud上线了 2.2.12 版本,此次更新不仅一次性增加了支持 Restful API、召回原始向量、json_contains 函数这三大特性,还优化了 standalone 模式下的 CPU 使用、查询链路等性能,用一句话总…

三言两语说透process.stdout.write和console.log的区别

Node.js中的process.stdout.write和console.log都是用于向标准输出流(stdout)打印输出的方法,但二者在使用场景和实现方式上有些区别。本文将详细介绍process.stdout.write和console.log的区别。 process.stdout.write介绍 process.stdout.write是Node.js中的一个…

undefined reference to `__android_log_print‘

报错描述 在 Android NDK 相关的工程构建中,出现报错: undefined reference to __android_log_print’ 翻译成 QM 能理解的话: 在链接阶段, 遇到一个需要被链接的符号 __android_log_print, 但是没有在给出的依赖库里面找到 __an…

关于会议OA需求分析与开发功能设计

前言:现如今,企业在会议管理方面对OA系统的需求越来越高。因为会议是企业内部沟通和协作的重要环节,一个高效的会议管理系统可以帮助企业提升会议效率、降低成本,并且提高内部信息共享的效果。 目录 一,以下是OA系统在…

C语言实现通讯录--动态版

一、题目要求 实现一个通讯录,联系人的数量可多可少 二、解题思路 1.在静态版本的基础上改用动态的方法: (1)默认能够存放三个人的信息 (2)不够的话,每次增加两个人的信息 2.其他功能不变 三…

学习自动化测试该怎么学?6个步骤轻松拿捏

自动化测试作为脱离手工测试的基本核心内容,其重要性不言而喻了,而且我们来看近期大厂的一些招聘信息显示,基本上自动化测试是必备前提,没有这个基本就不用谈后面的问题了,下面我们通过联想集团的一个软件测试工程师的…

【C#】async和await 续

前言 在文章《async和await》中,我们观察到了一下客观的规律,但是没有讲到本质,而且还遗留了一个问题: 这篇文章中,我们继续看看这个问题如何解决! 我们再看看之前写的代码: static public void TestWait2() {var t…

VR党建主题数字互动虚拟展馆软件开启党建铸魂育人新篇章

当今时代新媒体技术的发展对大学生的学习、生活等产生着深远的影响。高校作为党建育人的重要场所,充分借助VR技术的强大优势,合理运用到育人工作中,能够不断丰富教育内容。VR智慧党建展厅展馆结合VR技术营造的虚拟现实空间,将党的…

layui手机端上传文件时返回404 Not Found的解决方案(client_body_temp权限设置)

关于 1.client_body_temp的作用 client_body_temp是一个指令指定保存客户端请求体临时文件的目录路径,以及是否进行缓存的配置指令。 在Web服务器中,当客户端向服务器发送请求时,请求体中包含了请求的主体部分,比如表单数据、上…

基于flask徐州市天气信息可视化分析系统【纯干货分享,附源码04600】

摘 要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对天气信息等问题,对天气信息进行…

【网络通信】一文读懂TCP/IP基础,IP、端口、网关、web、超媒体

TCP/IP贯穿在我们学习计算机的生涯中,但TCP/IP终究是个什么玩意儿?在了解他之前我们先看一段历史: 在网络发展初期,许多研究机构、计算机厂商和公司都开始大力发展计算机网络。自ARPANET出现之后,许多商品化的网络系统…

实现二叉排序树

一:二叉树和二叉搜索树 二叉树中的节点最多只能有两个子节点:一个是左侧子节点,另一个是右侧子节点。这个定义有助于我们写出更高效地在树中插入、查找和删除节点的算法,二叉树在计算机科学中的应用非常广泛。 **二叉搜索树&…

Consul的容器服务更新与发现

Consul的容器服务更新与发现 一:Docker consul的容器服务更新与发现(1)什么是服务注册与发现(2)什么是consulconsul提供的一些关键特性: 二:consul 部署consul服务器1. 建立 Consul 服务2. 查看…

一文带你全面理解向量数据库

近些年来,向量数据库引起业界的广泛关注,一个相关事实是许多向量数据库初创公司在短期内就筹集到数百万美元的资金。 你很可能已经听说过向量数据库,但也许直到现在才真正关心向量数据库——至少,我想这就是你现在阅读本文的原因…

美国过境签证的办理流程和注意事项

美国过境签证是一种临时签证,允许你在前往其他国家的途中经过美国。这对于很多旅行者来说是一个便捷的选择,但在申请和办理过程中也需要注意一些要点。 首先,申请美国过境签证需要前往美国驻中国大使馆或领事馆递交申请。以下是办理美国过境签…

四磺酸酞菁锌,61586-86-5,Zn(II) Phthalocyanine tetrasulfonic acid,广泛用于染色

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ 四磺酸酞菁锌试剂 | 基础知识概述(部分): 中文名称:四磺酸酞菁锌 英文名称:Zn(II) Phthalocyanine tetrasulfonic acid CAS号:61586-86-5 分子式:C32H…

图数据库实践 - 如何将图数据库应用于网络安全

网络化办公为企业创造便捷的同时,也带来了数据泄露的威胁。根据IBM Security最新发布的年度《数据泄露成本报告》显示,2023全球数据泄露的平均成本达到445万美元,创该报告有史以来以来最高记录,也较过去3年均值增长了15%。同一时期…

2.3 HLSL常用函数

一、函数介绍 函数图像参考网站:Graphtoy 1.基本数学运算 函数 含义 示例图 min(a,b) 返回a、b中较小的数值 mul(a,b) 两数相乘用于矩阵计算 max(a,b) 返回a、b中较大的数值 abs(a) 返回a的绝对值 round(x) 返回与x最近的整数 sqrt(x) 返回x的…