news 2026/9/2 23:48:16

循环神经网络与文本处理:深度循环神经网络的实现与应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
循环神经网络与文本处理:深度循环神经网络的实现与应用

深度循环神经网络

学习目标

通过学习本课程,学员将了解深度循环神经网络的函数依赖关系,简洁实现,训练与预测。

相关知识点

  • 深度循环神经网络

学习内容

讨论一个具有单向隐藏层的循环神经网络。其中,隐变量和观测值与具体的函数形式的交互方式是相当随意的。只要交互类型建模具有足够的灵活性,这就不是一个大问题。然而,对一个单层来说,这可能具有相当的挑战性。而在循环神经网络中,我们首先需要确定如何添加更多的层,以及在哪里添加额外的非线性。

事实上,我们可以将多层循环神经网络堆叠在一起,通过对几个简单层的组合,产生了一个灵活的机制。特别是,数据可能与不同层的堆叠有关。

下图描述了一个具有LLL个隐藏层的深度循环神经网络,每个隐状态都连续地传递到当前层的下一个时间步和下一层的当前时间步。

图1 深度循环神经网络结构

1 深度循环神经网络

1.1 函数依赖关系

我们可以将深度架构中的函数依赖关系形式化,这个架构是由 图1 中描述了LLL个隐藏层构成。

假设在时间步ttt有一个小批量的输入数据Xt∈Rn×d\mathbf{X}_t \in \mathbb{R}^{n \times d}XtRn×d
(样本数:nnn,每个样本中的输入数:ddd)。同时,将lthl^\mathrm{th}lth隐藏层(l=1,…,Ll=1,\ldots,Ll=1,,L)的隐状态设为Ht(l)∈Rn×h\mathbf{H}_t^{(l)} \in \mathbb{R}^{n \times h}Ht(l)Rn×h
(隐藏单元数:hhh),输出层变量设为Ot∈Rn×q\mathbf{O}_t \in \mathbb{R}^{n \times q}OtRn×q
(输出数:qqq)。设置Ht(0)=Xt\mathbf{H}_t^{(0)} = \mathbf{X}_tHt(0)=Xt,第lll个隐藏层的隐状态使用激活函数ϕl\phi_lϕl,则为公式(1):

Ht(l)=ϕl(Ht(l−1)Wxh(l)+Ht−1(l)Whh(l)+bh(l)),(1)\mathbf{H}_t^{(l)} = \phi_l(\mathbf{H}_t^{(l-1)} \mathbf{W}_{xh}^{(l)} + \mathbf{H}_{t-1}^{(l)} \mathbf{W}_{hh}^{(l)} + \mathbf{b}_h^{(l)})\tag{1},Ht(l)=ϕl(Ht(l1)Wxh(l)+Ht1(l)Whh(l)+bh(l)),(1)
eq_deep_rnn_H

其中,权重Wxh(l)∈Rh×h\mathbf{W}_{xh}^{(l)} \in \mathbb{R}^{h \times h}Wxh(l)Rh×hWhh(l)∈Rh×h\mathbf{W}_{hh}^{(l)} \in \mathbb{R}^{h \times h}Whh(l)Rh×h和偏置bh(l)∈R1×h\mathbf{b}_h^{(l)} \in \mathbb{R}^{1 \times h}bh(l)R1×h
都是第lll个隐藏层的模型参数。
最后,输出层的计算仅基于第lll个隐藏层最终的隐状态,如公式(2)所示:

Ot=Ht(L)Whq+bq,(2)\mathbf{O}_t = \mathbf{H}_t^{(L)} \mathbf{W}_{hq} + \mathbf{b}_q\tag{2},Ot=Ht(L)Whq+bq,(2)

其中,权重Whq∈Rh×q\mathbf{W}_{hq} \in \mathbb{R}^{h \times q}WhqRh×q和偏置bq∈R1×q\mathbf{b}_q \in \mathbb{R}^{1 \times q}bqR1×q都是输出层的模型参数。

与多层感知机一样,隐藏层数目LLL和隐藏单元数目hhh都是超参数。它们可以进行调整。另外,用门控循环单元或长短期记忆网络的隐状态来代替eq_deep_rnn_H中的隐状态进行计算,可以很容易地得到深度门控循环神经网络或深度长短期记忆神经网络。

1.2 深度循环神经网络的简洁实现

实现多层循环神经网络所需的许多逻辑细节在高级API中都是现成的。简单起见,我们仅示范使用此类内置函数的实现方式。以长短期记忆网络模型为例,我们指定了层的数量,而不是使用单一层这个默认值。我们从加载时间机器数据集开始。

1.2.1 安装环境依赖与加载数据集
%pip install d2l==0.17.6--no-deps%pip install matplotlib-inline
%matplotlib inlineimportmathimporttorchimportrandomimportrefromtorchimportnnfromtorch.nnimportfunctionalasFfromd2limporttorchasd2limportcollections
#获取数据集!wget https://model-community-picture.obs.cn-north-4.myhuaweicloud.com/ascend-zone/notebook_datasets/0f19d2300e0711f09b46fa163edcddae/timemachine.txt

本课程采用本地加载数据集的方式加载数据集,需要定义以下函数:

defread_time_machine_local(file_path):"""从本地文件加载时间机器数据集"""withopen(file_path,'r',encoding='utf-8')asf:lines=f.readlines()return[re.sub('[^A-Za-z]+',' ',line).strip().lower()forlineinlines]deftokenize(lines,token='word'):"""分词器:将文本行拆分为单词或字符标记"""iftoken=='word':return[line.split()forlineinlines]eliftoken=='char':return[list(line)forlineinlines]else:print('ERROR: unknown token type: '+token)

定义Vocab类:

classVocab:def__init__(self,tokens=None,min_freq=0,reserved_tokens=None):iftokensisNone:tokens=[]ifreserved_tokensisNone:reserved_tokens=[]counter=count_corpus(tokens)self._token_freqs=sorted(counter.items(),key=lambdax:x[1],reverse=True)self.idx_to_token=['<unk>']+reserved_tokens self.token_to_idx={token:idxforidx,tokeninenumerate(self.idx_to_token)}fortoken,freqinself._token_freqs:iffreq<min_freq:breakiftokennotinself.token_to_idx:self.idx_to_token.append(token)self.token_to_idx[token]=len(self.idx_to_token)-1def__len__(self):returnlen(self.idx_to_token)def__getitem__(self,tokens):ifnotisinstance(tokens,(list,tuple)):returnself.token_to_idx.get(tokens,self.unk)return[self.__getitem__(token)fortokenintokens]defto_tokens(self,indices):ifnotisinstance(indices,(list,tuple)):returnself.idx_to_token[indices]return[self.idx_to_token[index]forindexinindices]@propertydefunk(self):return0@propertydeftoken_freqs(self):returnself._token_freqs

定义计算token频率、本地文件加载语料库和词汇表、随机采样生成小批量数据等用于本地数据加载的函数:

defcount_corpus(tokens):"""计算token频率"""iflen(tokens)==0orisinstance(tokens[0],list):tokens=[tokenforlineintokensfortokeninline]returncollections.Counter(tokens)defload_corpus_time_machine_local(file_path,max_tokens=-1):"""从本地文件加载语料库和词汇表"""lines=read_time_machine_local(file_path)tokens=tokenize(lines,'char')vocab=Vocab(tokens)corpus=[vocab[token]forlineintokensfortokeninline]ifmax_tokens>0:corpus=corpus[:max_tokens]returncorpus,vocabdefseq_data_iter_random(corpus,batch_size,num_steps):"""随机采样生成小批量数据"""corpus=corpus[random.randint(0,num_steps-1):]num_subseqs=(len(corpus)-1)//num_steps initial_indices=list(range(0,num_subseqs*num_steps,num_steps))random.shuffle(initial_indices)defdata(pos):returncorpus[pos:pos+num_steps]num_batches=num_subseqs//batch_sizeforiinrange(0,batch_size*num_batches,batch_size):initial_indices_per_batch=initial_indices[i:i+batch_size]X=[data(j)forjininitial_indices_per_batch]Y=[data(j+1)forjininitial_indices_per_batch]yieldtorch.tensor(X),torch.tensor(Y)defseq_data_iter_sequential(corpus,batch_size,num_steps):"""顺序分区生成小批量数据"""offset=random.randint(0,num_steps)num_tokens=((len(corpus)-offset-1)//batch_size)*batch_size Xs=torch.tensor(corpus[offset:offset+num_tokens])Ys=torch.tensor(corpus[offset+1:offset+1+num_tokens])Xs,Ys=Xs.reshape(batch_size,-1),Ys.reshape(batch_size,-1)num_batches=Xs.shape[1]//num_stepsforiinrange(0,num_steps*num_batches,num_steps):X=Xs[:,i:i+num_steps]Y=Ys[:,i:i+num_steps]yieldX,YclassSeqDataLoader:"""序列数据加载器"""def__init__(self,file_path,batch_size,num_steps,use_random_iter,max_tokens):self.data_iter_fn=seq_data_iter_randomifuse_random_iterelseseq_data_iter_sequential self.corpus,self.vocab=load_corpus_time_machine_local(file_path,max_tokens)self.batch_size,self.num_steps=batch_size,num_stepsdef__iter__(self):returnself.data_iter_fn(self.corpus,self.batch_size,self.num_steps)defload_data_time_machine_local(file_path,batch_size,num_steps,use_random_iter=False,max_tokens=10000):"""从本地加载时间机器数据集的主函数"""data_iter=SeqDataLoader(file_path,batch_size,num_steps,use_random_iter,max_tokens)returndata_iter,data_iter.vocab
# 从本地加载数据集file_path="./timemachine.txt"batch_size,num_steps=32,35train_iter,vocab=load_data_time_machine_local(file_path,batch_size,num_steps)

我们有不同的词元,所以输入和输出都选择相同数量,即vocab_size。隐藏单元的数量仍然是256256256。唯一的区别是,我们现在通过num_layers的值来设定隐藏层数

importtorch_npu vocab_size,num_hiddens,num_layers=len(vocab),256,2num_inputs=vocab_size device=torch.device('npu:0')lstm_layer=nn.LSTM(num_inputs,num_hiddens,num_layers)model=d2l.RNNModel(lstm_layer,len(vocab))model=model.to(device)
1.2.2 深度循环神经的训练预测

由于使用了长短期记忆网络模型来实例化两个层,因此训练速度被大大降低了。

num_epochs,lr=100,2d2l.train_ch8(model,train_iter,vocab,lr*1.0,num_epochs,device)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/30 8:23:24

算法备案自评估不返工!高频驳回原因与核心要点解析

一、自评估报告常见驳回原因在算法备案的实操过程中&#xff0c;我们发现很多企业被驳回的报告往往栽在几个非常具体的细节上&#xff0c;这些细节甚至与算法的代码无关&#xff0c;纯粹是“证据链”的缺失&#xff1a;1.使用第三方模型但报告中没有有效的第三方购买记录最典型…

作者头像 李华
网站建设 2026/9/2 23:15:43

用 ClickHouse 实现大数据实时监控

用 ClickHouse 实现大数据实时监控:从0到1搭建高可用系统 引言:为什么传统监控系统解决不了大数据实时问题? 1. 你可能遇到的痛点 做过大数据监控的同学,大概率踩过这些坑: 实时性差:用 Elasticsearch 做实时聚合,当数据量超过10亿条时,date_histogram 查1分钟窗口的…

作者头像 李华
网站建设 2026/9/1 18:06:03

JVM 内存分区

目录一、JVM内存分区1.程序计数器2.栈3.堆4.方法区&#xff08;元空间&#xff09;5.字符串常量池二、对象创建过程1.类加载检查2.分配内存3.初始化0值4.设置对象头5.执行init()方法&#xff08;构造方法&#xff09;一、JVM内存分区 Java虚拟机&#xff08;Java Virtual Mach…

作者头像 李华
网站建设 2026/9/2 21:07:45

釉匠水性釉面涂料防水性能深度解析:科技釉面打造长效屏障

在现代家居装修和建筑工程中&#xff0c;墙面涂料的防水防潮性能直接关系到居住质量与建筑寿命。针对消费者关注的“釉匠水性釉面涂料防水性能好吗”这一核心疑问&#xff0c;本文将结合武汉釉匠环保科技有限公司的官方技术资料及行业标准&#xff0c;从技术原理、功能特性、资…

作者头像 李华
网站建设 2026/9/2 23:14:28

救命神器8个AI论文平台,本科生毕业论文救星!

救命神器8个AI论文平台&#xff0c;本科生毕业论文救星&#xff01; 论文写作的“隐形助手”&#xff1a;AI 工具如何改变你的毕业之路 在当今信息爆炸的时代&#xff0c;高校学生尤其是本科生&#xff0c;面对毕业论文的压力日益增大。从选题、开题到撰写、查重&#xff0c;每…

作者头像 李华