动手学深度学习(Pytorch版)代码实践 -循环神经网络-54~55循环神经网络的从零开始实现和简洁实现

54循环神经网络的从零开始实现

在这里插入图片描述

import math
import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l
import matplotlib.pyplot as plt
import liliPytorch as lp# 读取H.G.Wells的时光机器数据集
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)# 查看数据集
# for X, Y in train_iter:
#     print('X:', X.shape)
#     print('Y:', Y.shape)
# print(vocab.token_freqs)
# print(vocab.idx_to_token)
# print(vocab.token_to_idx)# 独热编码
# 将每个索引映射为相互不同的单位向量: 假设词表中不同词元的数目为N(即len(vocab)), 词元索引的范围为0
# 到N-1。 如果词元的索引是整数i, 那么我们将创建一个长度为N的全0向量, 并将第i处的元素设置为1。 
# 此向量是原始词元的一个独热向量。
# print(F.one_hot(torch.tensor([0,3,6]), len(vocab)))
"""
tensor([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0],[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,        0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,        0, 0, 0, 0]])
"""# 每次采样的小批量数据形状是二维张量: (批量大小,时间步数)。 
# one_hot函数将这样一个小批量数据转换成三维张量, 张量的最后一个维度等于词表大小(len(vocab))。
# 我们经常转换输入的维度,以便获得形状为 (时间步数,批量大小,词表大小)的输出。 
# 这将使我们能够更方便地通过最外层的维度, 一步一步地更新小批量数据的隐状态。# X = torch.arange(10).reshape((2, 5))
# print(X)
# tensor([[0, 1, 2, 3, 4],
#         [5, 6, 7, 8, 9]])
# print(X.T)
# tensor([[0, 5],
#         [1, 6],
#         [2, 7],
#         [3, 8],
#         [4, 9]])
# print(F.one_hot(X.T, 28).shape) # torch.Size([5, 2, 28])
# print(F.one_hot(X.T, 28))
"""
tensor([[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0]],[[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0]],[[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0]],[[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0]],[[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0]]])
"""# 初始化模型参数
def get_params(vocab_size, num_hiddens, device):# 设置输入和输出的数量为词汇表的大小num_inputs = num_outputs = vocab_size# 定义一个函数,用于以正态分布初始化权重def normal(shape):return torch.randn(size=shape, device=device) * 0.01# 初始化隐藏层参数W_xh = normal((num_inputs, num_hiddens))  # 输入到隐藏层的权重W_hh = normal((num_hiddens, num_hiddens))  # 隐藏层到隐藏层的权重(循环权重)b_h = torch.zeros(num_hiddens, device=device)  # 隐藏层的偏置# 初始化输出层参数W_hq = normal((num_hiddens, num_outputs))  # 隐藏层到输出层的权重b_q = torch.zeros(num_outputs, device=device)  # 输出层的偏置# 将所有参数收集到一个列表中params = [W_xh, W_hh, b_h, W_hq, b_q]# 设置每个参数的requires_grad属性为True,以便在反向传播期间计算梯度for param in params:param.requires_grad_(True)return params  # 返回参数列表# 循环神经网络模型
# 初始化时返回隐状态
def init_rnn_state(batch_size, num_hiddens, device):# batch_size:批量的大小,即每次输入到RNN的序列数量。# num_hiddens:隐藏层单元的数量,即隐藏状态的维度。return (torch.zeros((batch_size, num_hiddens), device=device), ) # 返回一个包含一个张量的元组def rnn(inputs, state, params):# inputs的形状:(时间步数量,批量大小,词表大小)# state:初始隐藏状态,通常是一个元组,包含隐藏层的状态。# params:RNN的参数,包含权重和偏置。W_xh, W_hh, b_h, W_hq, b_q = paramsH, = state # 当前的隐藏状态。outputs = []# X的形状:(批量大小,词表大小)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_qoutputs.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_hiddensself.params = get_params(vocab_size, num_hiddens, device)self.init_state, self.forward_fn = init_state, forward_fndef __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)# X = torch.arange(10).reshape((2, 5))
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()) # 初始化隐藏状态
# 调用模型实例的 __call__ 方法执行前向传播。
# Y, new_state = net(X.to(d2l.try_gpu()), state)
# Y:模型输出。
# new_state:更新后的隐藏状态。# print(Y.shape, len(new_state), new_state[0].shape)
# torch.Size([10, 28]) 1 torch.Size([2, 512])
# 输出形状是(时间步数 X 批量大小,词表大小), 而隐状态形状保持不变,即(批量大小,隐藏单元数)def predict_ch8(prefix, num_preds, net, vocab, device):  #@save"""在prefix后面生成新字符prefix:生成文本的前缀,即初始输入字符序列。num_preds:要预测的字符数。net:训练好的循环神经网络模型。vocab:词汇表,包含字符到索引和索引到字符的映射。"""state = net.begin_state(batch_size=1, device=device)outputs = [vocab[prefix[0]]] # outputs:用于存储生成字符的索引列表。get_input = lambda: torch.tensor([outputs[-1]], device=device).reshape((1, 1))for y in prefix[1:]:  # 预热期,遍历前缀中的剩余字符(从第二个字符开始)。_, state = net(get_input(), state) # 调用 net 进行前向传播,更新隐藏状态 state。outputs.append(vocab[y]) # 将当前字符的索引添加到 outputs 中。for _ in range(num_preds):  # 预测num_preds步# 调用 net 进行前向传播,获取预测结果 y 和更新后的隐藏状态 state。y, state = net(get_input(), state)# 使用 y.argmax(dim=1) 获取预测的字符索引,并将其添加到 outputs 中。outputs.append(int(y.argmax(dim=1).reshape(1)))return ''.join([vocab.idx_to_token[i] for i in outputs])# print(predict_ch8('time traveller ', 10, net, vocab, d2l.try_gpu()))
# time traveller cfjwsthaqc# 梯度裁剪
"""
在训练深层神经网络(特别是循环神经网络)时,梯度爆炸(gradients exploding)问题会导致梯度值变得非常大,
从而导致模型不稳定甚至训练失败。为了防止梯度爆炸,可以对梯度进行裁剪,使得梯度的范数不超过某个预设的阈值。
"""
def grad_clipping(net, theta):  #@save"""裁剪梯度net:神经网络模型。theta:梯度裁剪的阈值。"""if isinstance(net, nn.Module):params = [p for p in net.parameters() if p.requires_grad]else:params = net.params# 计算梯度范数, L2 范数norm = torch.sqrt(sum(torch.sum((p.grad ** 2)) for p in params))if norm > theta:for param in params:param.grad[:] *= theta / norm# 将每个参数的梯度按比例缩放,使得新的梯度范数等于 theta。# 训练
def train_epoch_ch8(net, train_iter, loss, updater, device, use_random_iter):"""训练网络一个迭代周期(定义见第8章)"""state, timer = None, d2l.Timer()metric = lp.Accumulator(2)  # 训练损失之和,词元数量for X, Y in train_iter:if state is None or use_random_iter:# 在第一次迭代或使用随机抽样时初始化statestate = 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()#@save
def train_ch8(net, train_iter, vocab, lr, num_epochs, device,use_random_iter=False):"""训练模型(定义见第8章)"""loss = nn.CrossEntropyLoss()animator = lp.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())
# plt.show()
"""
困惑度 1.0, 95138.3 词元/秒 cuda:0
time traveller you can show black is white by argument said filby
traveller you can show black is white by argument said filby
"""# 随机抽样方法
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)
plt.show()
"""
困惑度 1.3, 109268.9 词元/秒 cuda:0
time traveller held in his hand was a glitteringmetallic framewor
traveller held in his hand was a glitteringmetallic framewor
"""

顺序抽样:
在这里插入图片描述

随机抽样:
在这里插入图片描述

55循环神经网络的简洁实现

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l
import matplotlib.pyplot as plt# 加载时光机器数据集并设置批量大小和序列长度
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)# 定义RNN模型
num_hiddens = 256
rnn_layer = nn.RNN(len(vocab), num_hiddens)# 用零张量初始化隐藏状态
state = torch.zeros((1, batch_size, num_hiddens))
# print(state.shape) # torch.Size([1, 32, 256])# X = torch.rand(size=(num_steps, batch_size, len(vocab)))
# Y, state_new = rnn_layer(X, state)
# print(Y.shape, state_new.shape, X.shape)
# torch.Size([35, 32, 256]) torch.Size([1, 32, 256]) torch.Size([35, 32, 28])# 完整的循环神经网络模型定义了一个RNNModel类
#@save
class RNNModel(nn.Module):"""循环神经网络模型"""def __init__(self, rnn_layer, vocab_size, **kwargs):super(RNNModel, self).__init__(**kwargs)self.rnn = rnn_layerself.vocab_size = vocab_sizeself.num_hiddens = self.rnn.hidden_size# 如果RNN是双向的,num_directions应该是2,否则应该是1if not self.rnn.bidirectional:self.num_directions = 1self.linear = nn.Linear(self.num_hiddens, self.vocab_size)else:self.num_directions = 2self.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, statedef 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)
num_epochs, lr = 500, 1
d2l.train_ch8(net, train_iter, vocab, lr, num_epochs, device)
"""
perplexity 1.3, 236379.1 tokens/sec on cuda:0
time traveller held in his hand was a glitteringmetallic framewo
traveller fith a slan but move anotle bothe thon st stagee 
"""
plt.show()
print(d2l.predict_ch8('time traveller', 10, net, vocab, device))
# time traveller held in h

在这里插入图片描述

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

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

相关文章

多特征线性回归

目录 一、多特征符号意义说明:二、多特征模型表示:三、Numpy向量表示、内积计算:1.向量表示:2.内积计算: 四、多元线性回归梯度下降算法: 一、多特征符号意义说明: x下标j:表示第j个…

怎么做外贸推广:10个详细教程和工具

1. 介绍 1.1 什么是外贸推广 外贸推广指的是将产品或服务推广到国际市场的过程。它的主要目的是吸引海外客户,增加销售额,并扩大企业的全球影响力。外贸推广不仅仅是销售产品,它还包括品牌建设、市场研究和客户关系管理。 谷歌外贸推广案例…

机器学习---线性回归

1、线性回归 例如:对于一个房子的价格,其影响因素有很多,例如房子的面积、房子的卧室数量、房子的卫生间数量等等都会影响房子的价格。这些影响因子不妨用 x i x_{i} xi​表示,那么房价 y y y可以用如下公式表示: y …

吴恩达机器学习 第三课 week3 强化学习(月球着陆器自动着陆)

目录 01 学习目标 02 概念 2.1 强化学习 2.2 深度Q学习(Deep Q-Learning ) 03 问题描述 04 算法中的概念及原理 05 月球着陆器自动着陆的算法实现 06 拓展:基于pytorch实现月球着陆器着陆 07 总结 写在最前:关于强化学习…

python conda查看源,修改源

查看源 conda config --show-sources 修改源 可以直接vim .condarc修改源,

Shell学习——Shell变量

文章目录 Shell变量使用变量只读变量删除变量变量类型字符串变量: 在 Shell中,变量通常被视为字符串。整数变量: 在一些Shell中,你可以使用 declare 或 typeset 命令来声明整数变量。数组变量: Shell 也支持数组&#…

平价猫粮新选择!福派斯鲜肉猫粮,让猫咪享受美味大餐!

福派斯鲜肉猫粮,作为一款备受铲屎官们青睐的猫粮品牌,凭借其卓越的品质和高性价比,为众多猫主带来了健康与美味的双重享受。接下来,我们将从多个维度对这款猫粮进行解析,让各位铲屎官更加全面地了解它的魅力所在。 1️…

【三】ubuntu24虚拟机集群配置免密登陆

文章目录 环境背景1. 配置域名映射2. 配置免密登录2.1 在每台机器上生成SSH密钥对:2.2 将公钥分发到其他机器:2.2.1 报错问题2.2.2 修复方法 3. 验证免密登录在 ubuntu1 上:在 ubuntu2 上:在 ubuntu3 上: 测试连接 环境…

三级_02_网络系统结构与设计的基本原则

1.下列关于接入技术特征的描述中,错误的是()。 无线统一网络中AC如果发现某个AP出现故障,将自动调高周围AP的发射功率以覆盖出现的空洞 ADSL技术具有非对称带宽特性 APON是一种无线接入技术 Cable Modem利用频分复用的方法将信道分为上行信道和下行信…

Linux系统的服务——以Centos7为例

一、Linux系统的服务简介 服务是向外部提供对应功能的进程,其运行在系统后台,能够7*24小时持续不断的提供外界随时发来的服务请求,且服务进程常驻在内存中,具有固定的端口号,通过端口号就能找到服务内容。 提供服务的一…

【PB案例学习笔记】-27制作一个控制任务栏显示与隐藏的小程序

写在前面 这是PB案例学习笔记系列文章的第27篇,该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习,提高编程技巧,以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码,小凡都上传到了gite…

柯西施瓦茨不等式证明过程

柯西-施瓦茨不等式(Cauchy-Schwarz Inequality)是数学分析中的一个重要不等式,它在向量空间、内积空间等多个领域都有广泛应用。对于实数或复数域上的内积空间,柯西-施瓦茨不等式可以表述为: 对于任意向量 u \mathbf…

Android Gradle 开发与应用 (七): Gradle 插件开发与发布

目录 一、概述 二、Gradle插件的基础知识 2.1 Gradle插件的定义 2.2 Gradle插件的种类 2.3 Gradle插件的生命周期 三、开发一个Gradle插件 3.1 创建Gradle插件项目 3.2 编写插件实现 3.3 配置插件元数据 3.4 构建和测试插件 3.5 在项目中应用插件 四、发布Gradle插…

计算机未来大方向的选择

选专业要了解自己的兴趣所在。 即想要学习什么样的专业,如果有明确的专业意向,就可以有针对性地选择那些专业实力较强的院校。 2.如果没有明确的专业意向,可以优先考虑一下院校。 确定一下自己想要选择综合性院校还是理工类院校或是像财经或者…

C语言结构体的相关知识

前言 从0开始记录我的学习历程,我会尽我所能,写出最最大白话的文章,希望能够帮到你,谢谢。 1.结构体类型的概念及定义 1.1、概念: 结构体是一种构造类型的数据结构, 是一种或多种基本类型或构造类型的数…

springboot集成gzip和zip数据压缩传输-满足2k数据自动压缩(适用大数据信息传输)

文章目录 1)、springboot的gzip压缩-满足2k数据自动压缩1.1后端压缩1.2前端解压1.3 满足最小响应大小(2KB)和指定MIME类型的响应进行GZIP压缩yml配置自定义配置或者使用Java配置 2)、gzip压缩1.1接口使用-数据压缩发送前端1.2 接口…

Java面试题系列 - 第3天

题目:Java集合框架详解与高效使用策略 背景说明:Java集合框架是Java标准库的重要组成部分,提供了一系列容器类,如List、Set、Map等,用于存储和操作集合数据。熟练掌握集合框架的使用,对于编写高效、健壮的…

机器学习之神经网络

简介 神经网络(Neural Network)是一种模仿人类大脑的机器学习算法,由一系列相互连接的神经元组成。它能够自动学习数据的特征和规律,并对新的输入数据进行预测和分类。 神经网络作为一种模仿生物大脑机制的机器学习算法,其产生和发展主要源于以下几个方面的背景: 对人脑认知…

第11章 规划过程组(二)(11.8排列活动顺序)

第11章 规划过程组(二)11.8排列活动顺序,在第三版教材第390~391页; 文字图片音频方式 第一个知识点:主要工具与技术(重要知识点) 1、箭线图法(ADM) (双代号网络图或活动箭线图&am…

template配置项详情——03

<body> // vue.config是vue全局配置对象 // productionTip 属性可能设置是否生产提示信息 //默认值是&#xff1a;true,如果是false 则表示组织生产提示信息 vue.congfig.productionTip false //指定挂载位置 //注意&#xff1a;以下代码只有vue框架能够看懂的代码。…