RNN预测下一句文本简单示例

根据句子前半句的内容推理出后半部分的内容,这样的任务可以使用循环的方式来实现。

RNN(Recurrent Neural Network,循环神经网络)是一种用于处理序列数据的强大神经网络模型。与传统的前馈神经网络不同,RNN能够通过其循环结构捕获序列内部的时间依赖性或顺序信息。

在RNN中,每个时间步(timestep)的隐藏状态不仅取决于当前输入,还与上一时间步的隐藏状态有关。这种递归特性使得网络能记忆过去的信息,并将其与当前输入相结合以做出决策或生成输出。

由于存在“梯度消失”和“梯度爆炸”的问题,在长序列建模时原始RNN可能效果不佳。因此,发展出了更复杂的变体,如LSTM(Long Short-Term Memory)和GRU(Gated Recurrent Units),它们通过门控机制更好地保留长期依赖信息。这些改进后的循环神经网络广泛应用于语音识别、自然语言处理(NLP)、机器翻译、视频分析等多种领域。

training_file = 'wordstest.txt' 在里面随便写入一些文章,当做数据,

具体代码如下,写了注释

import torch
import torch.nn.functional as F
import time
import random
import numpy as np
from collections import Counter# 确保每次结果可复现
RANDOM_SEED = 123
torch.manual_seed(RANDOM_SEED)DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')def elapsed(sec):if sec<60:return str(sec) + " sec"elif sec<(60*60):return str(sec/60) + " min"else:return str(sec/(60*60)) + " hr"#中文多文件
def readalltxt(txt_files):labels = []for txt_file in txt_files:target = get_ch_lable(txt_file)labels.append(target)return labelsdef get_ch_lable(txt_file):"""读取数据:param txt_file::return:"""labels = ""with open(txt_file, 'rb') as f:for label in f:labels += label.decode('utf-8')#labels += label.decode('gb2312')return labelsdef get_ch_lable_v(txt_file, word_num_map, txt_label=None):"""字符转向量:param txt_file::param word_num_map::param txt_label::return:"""words_size = len(word_num_map)to_num = lambda word: word_num_map.get(word, words_size)if txt_file != None:txt_label = get_ch_lable(txt_file)labels_vector = list(map(to_num, txt_label))return labels_vector# 文本预处理,生成词向量
training_file = 'wordstest.txt'
training_data = get_ch_lable(training_file)
print("Loaded training data...")
print('样本长度:', len(training_data))
counter = Counter(training_data)
words = sorted(counter)
words_size= len(words)
word_num_map = dict(zip(words, range(words_size)))  # 给每个字构建索引,通过索引来处理计算预测每一个字
print('字表大小:', words_size)
wordlabel = get_ch_lable_v(training_file, word_num_map)'''
GRU 构建 RNN 模型
1、将输入的文字索引转为词嵌入
2、将词嵌入结果输入用 GRU 所形成的网络层
3、对步骤 2 的输出结果做全连接处理,得到维度为【字表长度】的预测结果,这个结果代表的是每个文字的频率
'''
class GRURNN(torch.nn.Module):def __init__(self, word_size, embed_dim,hidden_dim, output_size, num_layers):super(GRURNN, self).__init__()self.num_layers = num_layersself.hidden_dim = hidden_dimself.embed = torch.nn.Embedding(word_size, embed_dim)self.gru = torch.nn.GRU(input_size=embed_dim,hidden_size=hidden_dim,num_layers=num_layers, bidirectional=True)# bidirectional=True 代表网络是双向的,从前往后,从后往前# hidden_dim*2 代表包含了两个维度的层数# 全连接层(线性层),它将接收前面双向GRU输出的隐藏状态作为输入self.fc = torch.nn.Linear(hidden_dim*2, output_size)def forward(self, features, hidden):embedded = self.embed(features.view(1, -1))output, hidden = self.gru(embedded.view(1, 1, -1), hidden)output = self.fc(output.view(1, -1))return output, hiddendef init_zero_state(self):"""一个初始化隐藏状态的方法,主要用于循环神经网络(RNN)类的实例。这个方法的作用是为RNN创建一组全零初始隐藏状态。self.num_layers * 2: 表示双向RNN时的层数(如果模型是双向的,即参数bidirectional=True),因为每个方向都会有一个隐藏层,所以总共有num_layers * 2个隐藏层。1: 表示批量大小(batch size),在这里初始化的是单个样本的隐藏状态,因此设置为1。若需要处理批量数据,则应根据实际批量大小调整。self.hidden_dim: 表示隐藏层的维度(hidden dimension),也就是每个隐藏单元的特征数量。:return:"""init_hidden = torch.zeros(self.num_layers * 2, 1, self.hidden_dim).to(DEVICE)return init_hiddenEMBEDDING_DIM = 10  # 向量的维度或者说长度
HIDDEN_DIM = 20  # 每一个隐藏层的神经元数量
NUM_LAYERS = 1  # 隐藏层数量model = GRURNN(words_size, EMBEDDING_DIM, HIDDEN_DIM, words_size, NUM_LAYERS)
model = model.to(DEVICE)  # 将模型移动到指定设备上进行计算
# model.parameters():获取模型中所有需要优化的参数。
# Adam:是优化算法的一种,它基于梯度下降法,并结合了动量项(Momentum)和自适应学习率调整策略(RMSProp)。Adam通常在很多深度学习任务中表现良好,因为它能够自动调整学习率并减少对初始化学习率的敏感性。
# lr=0.005:表示设置学习率为0.005,这是Adam算法中的一个重要超参数,决定了每次更新参数时步伐的大小。
optimizer = torch.optim.Adam(model.parameters(), lr=0.005)def evaluate(model, prime_str, predict_len, temperature=0.8):"""评估函数:param model::param prime_str: 一个表示起始序列的整数列表,每个整数代表词汇表中的索引:param predict_len: 指定要预测的字符或单词数量:param temperature: 控制生成文本时随机性的一个超参数,较小的值会让模型更倾向于生成概率最高的结果,较大的值则会增加多样性:return:"""hidden = model.init_zero_state().to(DEVICE)predicted = ''# 处理输入语义# 将生成的字符添加到预测结果字符串 predicted 中for p in range(len(prime_str) - 1):_, hidden = model(prime_str[p], hidden)predicted += words[prime_str[p]]# 用最后一个输入字符开始进行预测inp = prime_str[-1]predicted += words[inp]for p in range(predict_len):output, hidden = model(inp, hidden)#从多项式分布中采样# 将模型输出转换为分布形式,通过除以温度 temperature 并求指数得到softmax分布output_dist = output.data.view(-1).div(temperature).exp()# 根据调整后的分布采样下一个字符的索引inp = torch.multinomial(output_dist, 1)[0]predicted += words[inp]return predicted#定义参数训练模型
training_iters = 5000
display_step = 1000
n_input = 4
step = 0
offset = random.randint(0, n_input+1)  # 每次迭代结束时,将偏移值向后移动 n_input+1 个距离,保证输入样本的相对均匀
end_offset = n_input + 1while step < training_iters:start_time = time.time()# 随机取一个位置偏移if offset > (len(training_data) - end_offset):offset = random.randint(0, n_input+1)# 取出偏移量为 4 的数据长度,因为文本时序列数据inwords = wordlabel[offset:offset + n_input]# [n_input, -1, 1] 表示重塑后的三维形状:# 第一维是序列长度(即每个序列有 n_input 个元素),# 第二维 -1 表示自动计算以适应原始数据大小,# 第三维为通道数(这里设为1,通常用于表示一维特征)inwords = np.reshape(np.array(inwords), [n_input, -1,  1])# 编码out_onehot = wordlabel[offset+1:offset+n_input+1]# 初始化隐藏层hidden = model.init_zero_state()'''模型完成一次前向传播计算并得到损失(loss)后,在反向传播(backpropagation)之前,需要调用这个函数来清零所有可训练参数的梯度。在开始新一轮的前向传播和反向传播之前,使用 optimizer.zero_grad() 来清零所有参数的梯度是至关重要的,确保每次优化步骤只基于当前批次数据计算出的梯度来进行参数更新'''optimizer.zero_grad()'''模型训练'''loss = 0.# 将输入数据 inwords 和目标数据 out_onehot 转换为PyTorch张量inputs, targets = torch.LongTensor(inwords).to(DEVICE), torch.LongTensor(out_onehot).to(DEVICE)for c in range(n_input):# 当前时间步的输入和前一时间步的隐藏状态运行模型,得到输出 (outputs) 和新的隐藏状态 (hidden)。outputs, hidden = model(inputs[c], hidden)# 计算当前时间步的交叉熵损失(Cross Entropy Loss),将模型预测的输出与实际的目标标签比较loss += F.cross_entropy(outputs, targets[c].view(1))# 所有时间步完成后,平均损失值loss /= n_input# 反向传播计算梯度:调用 .backward() 函数来计算关于损失函数关于模型参数的梯度loss.backward()# 使用优化器(在这里是 optimizer)根据计算出的梯度更新模型参数optimizer.step()#输出日志# with torch.set_grad_enabled(False): 这一上下文管理器用于在计算过程中暂时禁用梯度计算。这样,在打印损失、评估模型性能等操作时,# 不会占用额外的内存来存储中间计算的梯度,同时避免不必要的反向传播计算。with torch.set_grad_enabled(False):if (step+1) % display_step == 0:print(f'Time elapsed: {(time.time() - start_time)/60:.4f} min')print(f'step {step+1} | Loss {loss.item():.2f}\n\n')# torch.no_grad() 上下文管理器再次禁用梯度计算,以便于高效地进行模型评估,并且不影响之前或之后的梯度计算状态。with torch.no_grad():print(evaluate(model, inputs, 32), '\n')print(50*'=')step += 1offset += (n_input+1)#中间隔了一个,作为预测print("Finished!")# 使用模型
while True:prompt = "请输入几个字,最好是%s个: " % n_inputsentence = input(prompt)inputword = sentence.strip()try:inputword = get_ch_lable_v(None, word_num_map, inputword)keys = np.reshape(np.array(inputword), [len(inputword), -1, 1])'''调用 model.eval() 方法将模型设置为评估模式。在评估模式下,模型中的批量归一化层(如果有)会使用经过训练时平均的移动统计量,并且不会更新模型参数(梯度计算被禁用)。接下来,通过 with torch.no_grad(): 语句创建了一个临时上下文,在此上下文中执行所有操作时都不会累积梯度。这对于生成任务非常关键,因为在这种情况下我们并不关心反向传播以更新模型权重,而是要利用当前模型状态来生成文本。'''model.eval()with torch.no_grad():sentence = evaluate(model, torch.LongTensor(keys).to(DEVICE), 32)print(sentence)except:print("该字我还没学会")

运行结果类似:

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

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

相关文章

【JVM】运行时数据区域,内存如何分配和对象在内存中的组成

目录 一.运行时数据区域 1.线程独享 2.线程共享 二.内存如何分配 1.指针碰撞法 2.空闲列表法 3.TLAB 三.对象在内存中的组成 ​编辑1.对象头 2.实例数据 3.对齐填充 一.运行时数据区域 1.线程独享 &#xff08;1&#xff09;栈 虚拟机栈&#xff1a;每个 Java 方法在…

熟人免疫算法优化复杂网络(MATLAB)

熟人免疫算法是一种用于优化复杂网络的进化算法。它通过模拟熟人关系和免疫机制的思想来改进网络的性能。该算法首先随机生成一组个体作为初始种群&#xff0c;然后通过计算每个个体的适应度值来评估其优劣。接下来&#xff0c;通过选择、交叉和变异等操作&#xff0c;不断迭代…

关于Spring Boot和MyBatis常见的十道面试题

拦截器和过滤器有什么区别&#xff1f; 拦截器&#xff08;Interceptor&#xff09;和过滤器&#xff08;Filter&#xff09;都是用于在请求道道目标资源的之前或之后进行处理的组件。主要区别有以下几点&#xff1a; 依赖对象不同&#xff1a;过滤器是来时Servlet&#xff0…

c语言常量详解 全

c语言常量详解 全 一 常量的基本概念及分类二 常量的存储方式三 c语言常量和变量的具体区别四 字面常量详解4.1 常见类型的字面常量及其示例&#xff1a;4.2 字面常量的使用情况4.3 字面常量的优点 五 const 关键字常量详解5.1 const关键字在C语言中的使用情况&#xff1a;5.2 …

温酒读Qt:QObject中篇2 ——欲遮还羞的 QObjectPrivate

《妙法莲华经》曰&#xff1a;“佛道长远&#xff0c;久受勤苦&#xff0c;乃可得成。” 世事修炼&#xff0c;莫不如是&#xff0c;日拱一卒无有尽&#xff0c;功不唐捐终入海。 传送门: 《温酒读Qt&#xff1a;QObject 序篇》 《温酒读Qt&#xff1a;QObject中篇1—— Q_OBJ…

设计模式——模板方法模式(Template Method Pattern)

概述 模板方法模式&#xff1a;定义一个操作中算法的框架&#xff0c;而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。模板方法模式是一种基于继承的代码复用技术&#xff0c;它是一种类行为型模式。模板方法模式是结…

Android中下载 HAXM 报错 Intel® HAXM installation failed,如何解决?

最近在搭建 Flutter 环境&#xff0c;但是在 Android Studio 中安装 Virtual Device 时&#xff0c;出现了一个 问题 Intel HAXM installation failed. To install Intel HAXM follow the instructions found at: https://github.com/intel/haxm/wiki/Installation-Instructio…

1.25时间序列分析,FB先知模型、简要傅里叶变化解决周期性变化,实例步骤

目录 FB概念 ​编辑 GEOGEBRA可视化傅里叶​编辑 先知模型步骤 财务数据要考虑到可解释性 FB模型概念 可以用傅里叶级数来描述周期性变化的因素 GEOGEBRA可视化傅里叶 先知模型步骤

安装好IntelliJ IDEA点击无反应,如何解决配置文件不一致导致的启动问题

在我们的开发生涯中&#xff0c;遇到IDE工具出现问题是在所难免的。最令人头疼的莫过于&#xff0c;你的IDEA(IntelliJ IDEA)无法启动&#xff0c;而且没有任何错误提示。这篇文章将详细讲解如何解决IntelliJ IDEA 2023.3.3版本启动失败的问题&#xff0c;这个问题可能也适用于…

如何让wordpress首页只显示某一篇文章全部内容?在您的主页显示选择

大多数WordPress站点首页默认都是显示最新发布的文章列表&#xff0c;不过有些站点比较特殊&#xff0c;只想显示某一篇文章的全部内容&#xff0c;那么应该怎么设置呢&#xff1f; 其实&#xff0c;WordPress后台 >> 设置 >> 阅读 >> 在“您的主页显示”中…

OpenHarmony RK3568 启动流程优化

目前rk3568的开机时间有21s&#xff0c;统计的是关机后从按下 power 按键到显示锁屏的时间&#xff0c;当对openharmony的系统进行了裁剪子系统&#xff0c;系统app&#xff0c;禁用部分服务后发现开机时间仅仅提高到了20.94s 优化微乎其微。在对init进程的log进行分析并解决其…

解决Linux环境下gdal报错:ERROR 4: `/xxx.hdf‘ not recognized as a supported file format.

网上查了一堆资料&#xff0c;五花八门&#xff0c;总结了一下可能的原因&#xff1a; ① gdal不支持该格式 使用命令“gdalinfo --formats” 即可查看当前环境中的gdal所能支持的数据格式。如下图&#xff08;没截完整&#xff0c;下面还有一大串&#xff09;。 这个是很常见…