RNN(Recurrent?Neural?Network),中文稱作循環(huán)神經(jīng)網(wǎng)絡(luò),它一般以序列數(shù)據(jù)為輸入,通過網(wǎng)絡(luò)內(nèi)部的結(jié)構(gòu)設(shè)計(jì)有效捕捉序列之間的關(guān)系特征,一般也是以序列形式進(jìn)行輸出。
因?yàn)镽NN結(jié)構(gòu)能夠很好利用序列之間的關(guān)系,因此針對(duì)自然界具有連續(xù)性的輸入序列,如人類的語言,語音等進(jìn)行很好的處理,廣泛應(yīng)用于NLP領(lǐng)域的各項(xiàng)任務(wù),如文本分類,情感分析,意圖識(shí)別,機(jī)器翻譯等.
RNN模型的分類:
這里我們將從兩個(gè)角度對(duì)RNN模型進(jìn)行分類.第一個(gè)角度是輸入和輸出的結(jié)構(gòu),第二個(gè)角度是RNN的內(nèi)部構(gòu)造.
按照輸入和輸出的結(jié)構(gòu)進(jìn)行分類:
N vs N-RNN
它是RNN最基礎(chǔ)的結(jié)構(gòu)形式,最大的特點(diǎn)就是:輸入和輸出序列是等長(zhǎng)的.由于這個(gè)限制的存在,使其適用范圍比較小,可用于生成等長(zhǎng)度的合轍詩句.
N vs 1-RNN
有時(shí)候我們要處理的問題輸入是一個(gè)序列,而要求輸出是一個(gè)單獨(dú)的值而不是序列,要在最后一個(gè)隱層輸出h上進(jìn)行線性變換。
大部分情況下,為了更好的明確結(jié)果,還要使用sigmoid或者softmax進(jìn)行處理.這種結(jié)構(gòu)經(jīng)常被應(yīng)用在文本分類問題上.
1?vs?N-RNN
我們最常采用的一種方式就是使該輸入作用于每次的輸出之上.這種結(jié)構(gòu)可用于將圖片生成文字任務(wù)等.
N vs?M-RNN
這是一種不限輸入輸出長(zhǎng)度的RNN結(jié)構(gòu),它由編碼器和解碼器兩部分組成,兩者的內(nèi)部結(jié)構(gòu)都是某類RNN,它也被稱為seq2seq架構(gòu)。
輸入數(shù)據(jù)首先通過編碼器,最終輸出一個(gè)隱含變量c,之后最常用的做法是使用這個(gè)隱含變量c作用在解碼器進(jìn)行解碼的每一步上,以保證輸入信息被有效利用。
按照RNN的內(nèi)部構(gòu)造進(jìn)行分類:
傳統(tǒng)RNN
內(nèi)部計(jì)算函數(shù)
tanh的作用:?用于幫助調(diào)節(jié)流經(jīng)網(wǎng)絡(luò)的值,tanh函數(shù)將值壓縮在﹣1和1之間。
傳統(tǒng)RNN的優(yōu)勢(shì):
由于內(nèi)部結(jié)構(gòu)簡(jiǎn)單,對(duì)計(jì)算資源要求低,相比之后我們要學(xué)習(xí)的RNN變體:LSTM和GRU模型參數(shù)總量少了很多,在短序列任務(wù)上性能和效果都表現(xiàn)優(yōu)異。
傳統(tǒng)rnn的缺點(diǎn):
傳統(tǒng)RNN在解決長(zhǎng)序列之間的關(guān)聯(lián)時(shí),通過實(shí)踐,證明經(jīng)典RNN表現(xiàn)很差,原因是在進(jìn)行反向傳播的時(shí)候,過長(zhǎng)的序列導(dǎo)致梯度的計(jì)算異常,發(fā)生梯度消失或爆炸。
LSTM
LSTM?(Long?Short-Term?Memory)也稱長(zhǎng)短時(shí)記憶結(jié)構(gòu),它是傳統(tǒng)RNN的變體,與經(jīng)典RNN相比能夠有效捕捉長(zhǎng)序列之間的語義關(guān)聯(lián),緩解梯度消失或爆炸現(xiàn)象,同時(shí)LSTM的結(jié)構(gòu)更復(fù)雜。
LSTM缺點(diǎn):由于內(nèi)部結(jié)構(gòu)相對(duì)較復(fù)雜,因此訓(xùn)練效率在同等算力下較傳統(tǒng)RNN低很多.
LSTM優(yōu)勢(shì):LSTM的門結(jié)構(gòu)能夠有效減緩長(zhǎng)序列問題中可能出現(xiàn)的梯度消失或爆炸,雖然并不能杜絕這種現(xiàn)象,但在更長(zhǎng)的序列問題上表現(xiàn)優(yōu)于傳統(tǒng)RNN.
?
它的核心結(jié)構(gòu)可以分為四個(gè)部分去解析:
遺忘門
與傳統(tǒng)RNN的內(nèi)部結(jié)構(gòu)計(jì)算非常相似,首先將當(dāng)前時(shí)間步輸入x(t)與上一個(gè)時(shí)間步隱含狀態(tài)h(t-1)拼接,?得到[x(t),?h(t-1)],然后通過一個(gè)全連接層做變換,最后通過sigmoid函數(shù)(變化到【0,1】)進(jìn)行激活得到f(t),我們可以將f(t)看作是門值,好比一扇門開合的大小程度,門值都將作用在通過該扇門的張量,遺忘門門值將作用的上一層的細(xì)胞狀態(tài)上,代表遺忘過去的多少信息,又因?yàn)檫z忘門門值是由x(t),?h(t-1)計(jì)算得來的,因此整個(gè)公式意味著根據(jù)當(dāng)前時(shí)間步輸入和上一個(gè)時(shí)間步隱含狀態(tài)h(t-1)來決定遺忘多少上一層的細(xì)胞狀態(tài)所攜帶的過往信息.
輸入門
輸入門的計(jì)算公式有兩個(gè),第一個(gè)就是產(chǎn)生輸入門門值的公式,它和遺忘門公式幾乎相同,區(qū)別只是在于它們之后要作用的目標(biāo)上,這個(gè)公式意味著輸入信息有多少需要進(jìn)行過濾.輸入門的第二個(gè)公式是與傳統(tǒng)RNN的內(nèi)部結(jié)構(gòu)計(jì)算相同.對(duì)于LSTM來講,它得到的是當(dāng)前的細(xì)胞狀態(tài),而不是像經(jīng)典RNN一樣得到的是隱含狀態(tài).
細(xì)胞狀態(tài)
我們看到輸入門的計(jì)算公式有兩個(gè),第一個(gè)就是產(chǎn)生輸入門門值的公式,它和遺忘門公式幾乎相同,區(qū)別只是在于它們之后要作用的目標(biāo)上.這個(gè)公式意味著輸入信息有多少需要進(jìn)行過濾.輸入門的第二個(gè)公式是與傳統(tǒng)RNN的內(nèi)部結(jié)構(gòu)計(jì)算相同.對(duì)于LSTM來講,它得到的是當(dāng)前的細(xì)胞狀態(tài),而不是像經(jīng)典RNN一樣得到的是隱含狀態(tài)。
輸出門
輸出門部分的公式也是兩個(gè),第一個(gè)即是計(jì)算輸出門的門值,它和遺忘門,輸入門計(jì)算方式相同.第二個(gè)即是使用這個(gè)門值產(chǎn)生隱含狀態(tài)h(t),他將作用在更新后的細(xì)胞狀態(tài)C(t)上,并做tanh激活,最終得到h(t)作為下一時(shí)間步輸入的一部分.整個(gè)輸出門的程,就是為了產(chǎn)生隱含狀態(tài)h(t)。
Bi-LSTM
Bi-LSTM即雙向LSTM,它沒有改變LSTM本身任何的內(nèi)部結(jié)構(gòu),只是將LSTM應(yīng)用兩次且方向不同,再將兩次得到的LSTM結(jié)果進(jìn)行拼接作為最終輸出
GRU
GRU(Gated?Recurrent?Unit)也稱門控循環(huán)單元結(jié)構(gòu),它也是傳統(tǒng)RNN的變體,同LSTM一樣能夠有效捕捉長(zhǎng)序列之間的語義關(guān)聯(lián),緩解梯度消失或爆炸現(xiàn)象.同時(shí)它的結(jié)構(gòu)和計(jì)算要比LSTM?更簡(jiǎn)單。
GRU的優(yōu)勢(shì):GRU和LSTM作用相同,在捕捉長(zhǎng)序列語義關(guān)聯(lián)時(shí),能有效抑制梯度消失或爆炸,效果都優(yōu)于傳統(tǒng)rnn且計(jì)算復(fù)雜度相比lstm要小.
GRU的缺點(diǎn):GRU仍然不能完全解決梯度消失問題,同時(shí)其作用RNN的變體,有著RNN結(jié)構(gòu)本身的一大弊端,即不可并行計(jì)算,這在數(shù)據(jù)量和模型體量逐步增大的未來,是RNN發(fā)展的關(guān)鍵瓶頸
它的核心結(jié)構(gòu)可以分為兩個(gè)部分去解析:
更新門?
重置門
Bi-GRU
Bi-GRU與Bi-LSTM的邏輯相同,都是不改變其內(nèi)部結(jié)構(gòu),而是將模型應(yīng)用兩次且方向不同,再將兩次得到的LSTM結(jié)果進(jìn)行拼接作為最終輸出.具體參見上小節(jié)中的Bi-LSTM。
注意力機(jī)制
注意力機(jī)制是注意力計(jì)算規(guī)則能夠應(yīng)用的深度學(xué)習(xí)網(wǎng)絡(luò)的載體,同時(shí)包括一些必要的全連接層以及相關(guān)張量處理,使其與應(yīng)用網(wǎng)絡(luò)融為一體.使自注意力計(jì)算規(guī)則的注意力機(jī)制稱為自注意力機(jī)制.
注意力計(jì)算規(guī)則
它需要三個(gè)指定的輸入Q(query),?K(key),?V(value),?然后通過計(jì)算公式得到注意力的結(jié)果,這個(gè)結(jié)果代表query在key和value作用下的注意力表示.當(dāng)輸入的Q=K=V時(shí),稱作自注意力計(jì)算規(guī)則.
注意力機(jī)制的作用
在解碼器端的注意力機(jī)制:?能夠根據(jù)模型目標(biāo)有效的聚焦編碼器的輸出結(jié)果,當(dāng)其作為解碼器的輸入時(shí)提升效果,改善以往編碼器輸出是單一定長(zhǎng)張量,無法存儲(chǔ)過多信息的情況.
在編碼器端的注意力機(jī)制:主要解決表征問題,相當(dāng)于特征提取過程,得到輸入的注意力表示.一般使用自注意力(self-attention).
注意力機(jī)制實(shí)現(xiàn)步驟
第一步:根據(jù)注意力計(jì)算規(guī)則,對(duì)Q,K,V進(jìn)行相應(yīng)的計(jì)算.
第二步:根據(jù)第一步采用的計(jì)算方法,如果是拼接方法,則需要將Q與第二步的計(jì)算結(jié)果再進(jìn)行拼接,如果是轉(zhuǎn)置點(diǎn)積,一般是自注意力,Q與V相同,則不需要進(jìn)行與Q的拼接.
第三步:最后為了使整個(gè)attention機(jī)制按照指定尺寸輸出,使用線性層作用在第二步的結(jié)果上做一個(gè)線性變換,得到最終對(duì)Q的注意力表示.
代碼實(shí)現(xiàn)
傳統(tǒng)模型
import torch
import torch.nn as nn
"""
nn.RNN類初始化主要參數(shù)解釋
input_size:輸入張量x中特征維度的大小
hidden_size:隱層張量h中特征維度的大小
num_layers: 隱含層的數(shù)量.
nonlinearity: 激活函數(shù)的選擇,默認(rèn)是tanh.
"""
rnn=nn.RNN(input_size=5,hidden_size=6,num_layers=1)
"""
設(shè)定輸入的張量x
第一個(gè)參數(shù):sequence_length(輸入序列的長(zhǎng)度)
第二個(gè)參數(shù):batch_size(批次的樣本數(shù))
第三個(gè)參數(shù):input_size(輸入張量x的維度)
"""
input=torch.randn(1,3,5)
"""
設(shè)定初始化的h0
第一個(gè)參數(shù):num_layers *num_directions(層數(shù)*網(wǎng)絡(luò)方向數(shù))
第二個(gè)參數(shù):batch_size(批次的樣本數(shù))
第三個(gè)參數(shù):hiddeh_size(隱藏層的維度)
"""
h0=torch.randn(1,3,6)
"""
nn.RNN類實(shí)例化對(duì)象主要參數(shù)解釋
input: 輸入張量x
h0:初始化的隱層張量h
"""
output,hn=rnn(input,h0)
# 傳統(tǒng)RNN
class RNN(nn.Module):
def __init__(self,input_size,hidden_size,output_size,num_layers=1):
"""
input_size:代表輸入張量x中最后一個(gè)維度
hidden_size: 代表隱藏層張量的最后一個(gè)維度
output_size: 代表線性層最后的輸出維度
num_layers:代表RNN網(wǎng)絡(luò)的層數(shù)
"""
super(RNN,self).__init__()
self.input_size=input_size
self.hidden_size=hidden_size
self.output_size=output_size
self.num_layers=num_layers
self.rnn=nn.RNN(input_size,hidden_size,num_layers)
# 全連接線性層
self.linear=nn.linear(hidden_size,output_size)
# 預(yù)定義的softmax層
self.softmax=nn.LogSoftmax(dim=-1)
def forward(self,input1,hidden):
input1=input1.unsqueeze(0)
rr,hn=self.rnn(input1,hidden)
return self.softmax(self.linear(rr)),hn
def init_hidden(self):
"""初始化全零的隱藏層張量"""
return torch.zeros(self.num_layers,1,self.hidden_size)
?
LSTM模型
import torch
import torch.nn as nn
"""
nn.LSTM類初始化主要參數(shù)解釋:
input_size: 輸入張量x中特征維度的大?。?hidden_size: 隱層張量h中特征維度的大?。?num_layers: 隱含層的數(shù)量.
bidirectional: 是否選擇使用雙向LSTM,如果為True,則使用;默認(rèn)不使用.
"""
rnn=nn.LSTM(input_size=5,hidden_size=6,num_layers=2)
"""
設(shè)定輸入的張量x
第一個(gè)參數(shù):sequence_length(輸入序列的長(zhǎng)度)
第二個(gè)參數(shù):batch_size(批次的樣本數(shù))
第三個(gè)參數(shù):input_size(輸入張量x的維度)
"""
input=torch.randn(1,3,5)
"""
設(shè)定初始化的h0,c0
第一個(gè)參數(shù):num_layers *num_directions(層數(shù)*網(wǎng)絡(luò)方向數(shù))
第二個(gè)參數(shù):batch_size(批次的樣本數(shù))
第三個(gè)參數(shù):hiddeh_size(隱藏層的維度)
"""
h0=torch.randn(2,3,6)
c0=torch.randn(2,3,6)
"""
nn.LSTM類實(shí)例化對(duì)象主要參數(shù)解釋
input: 輸入張量x
h0:初始化的隱層張量h.
cO:初始化的細(xì)胞狀態(tài)張量c.
"""
output,(hn,cn)=rnn(input,(h0,c0))
# LSTM型RNN
class LSTM(nn.Module):
def __init__(self,input_size,hidden_size,output_size,num_layers=1):
"""
input_size:代表輸入張量x中最后一個(gè)維度
hidden_size: 代表隱藏層張量的最后一個(gè)維度
output_size: 代表線性層最后的輸出維度
num_layers:代表RNN網(wǎng)絡(luò)的層數(shù)
"""
super(LSTM,self).__init__()
self.input_size=input_size
self.hidden_size=hidden_size
self.output_size=output_size
self.num_layers=num_layers
self.lstm=nn.LSTM(input_size,hidden_size,num_layers)
# 全連接線性層
self.linear=nn.linear(hidden_size,output_size)
# 預(yù)定義的softmax層
self.softmax=nn.LogSoftmax(dim=-1)
def forward(self,input1,hidden,c):
input1=input1.unsqueeze(0)
rr,(hn,cn)=self.lstm(input1,(hidden,c))
return self.softmax(self.linear(hn)),hn,cn
def init_hidden_and_c(self):
c=hidden=torch=torch.zeros(self.num_layers,1,self.hidden_size)
return hidden,c
?文章來源:http://www.zghlxwxcb.cn/news/detail-802324.html
GRU模型
import torch
import torch.nn as nn
"""
nn.GRU類初始化主要參數(shù)解釋
Input_size: 輸入張量x中特征維度的大小
hidden_size:隱層張量h中特征維度的大小
num_layers:隱含層的數(shù)量
bidirectional: 是否選擇使用雙向LSTM,如果為True,則使用;默認(rèn)不使用
"""
rnn=nn.GRU(input_size=5,hidden_size=6,num_layers=2)
"""
設(shè)定輸入的張量x
第一個(gè)參數(shù):sequence_length(輸入序列的長(zhǎng)度)
第二個(gè)參數(shù):batch_size(批次的樣本數(shù))
第三個(gè)參數(shù):input_size(輸入張量x的維度)
"""
input=torch.randn(1,3,5)
"""
設(shè)定初始化的h0
第一個(gè)參數(shù):num_layers *num_directions(層數(shù)*網(wǎng)絡(luò)方向數(shù))
第二個(gè)參數(shù):batch_size(批次的樣本數(shù))
第三個(gè)參數(shù):hiddeh_size(隱藏層的維度)
"""
h0=torch.randn(2,3,6)
"""
nn.GRU類實(shí)例化對(duì)象主要參數(shù)解釋
input: 輸入張量x.
h0:初始化的隱層張量h.
"""
output,hn=rnn(input,h0)
# GRU模型
class GRU(nn.Module):
def __init__(self,input_size,hidden_size,output_size,num_layers=1):
"""
input_size:代表輸入張量x中最后一個(gè)維度
hidden_size: 代表隱藏層張量的最后一個(gè)維度
output_size: 代表線性層最后的輸出維度
num_layers:代表RNN網(wǎng)絡(luò)的層數(shù)
"""
super(GRU,self).__init__()
self.input_size=input_size
self.hidden_size=hidden_size
self.output_size=output_size
self.num_layers=num_layers
self.gru=nn.GRU(input_size,hidden_size,num_layers)
self.linear=nn.linear(hidden_size,output_size)
self.softmax=nn.LogSoftmax(dim=-1)
def forward(self,input1,hidden):
input1=input1.unsqueeze(0)
output,hn=self.gru(input1,hidden)
return self.softmax(self.linear(hidden)),hn
def init_hidden(self):
return torch.zeros(self.num_layers,1,self.hidden_size)
?文章來源地址http://www.zghlxwxcb.cn/news/detail-802324.html
注意力模型
import torch
import torch.nn as nn
import torch.nn.functional as F
#建立attn類
class Attn(nn.Module):
def __init__(self, query_size,key_size,value_size1,value_size2,output_size):
"""_summary_
Args:
query_size (_type_): 代表的是Q的最后一個(gè)維度
key_size (_type_): 代表的K的最后一個(gè)維度
value_size1 (_type_): 代表value的導(dǎo)數(shù)第二維大小
value_size2 (_type_): 代表value的倒數(shù)第一維大小
output_size (_type_): 代表輸出的最后一個(gè)維度的大小
"""
super(Attn, self).__init__()
self.query_size = query_size
self.key_size = key_size
self.value_size1 = value_size1
self.value_size2 = value_size2
self.output_size = output_size
# 初始化注意力機(jī)制
self.attn=nn.Linear(self.query_size+self.key_size,self.value_size1)
self.attn_combine=nn.Linear(self.query_size+self.value_size2,self.output_size)
def forward(self,query,key,value):
"""_summary_
Args:
query (_type_): 代表Q
key (_type_): 代表K
value (_type_): 代表V
Returns:
_type_: 返回注意力機(jī)制的輸出
"""
# 計(jì)算注意力權(quán)重
attn_weights=F.softmax(self.attn(torch.cat((query[0],key[0]),1)),dim=1)
attn_applied=torch.bmm(attn_weights.unsqueeze(0),value)
# 計(jì)算注意力機(jī)制的輸出
output=torch.cat((query[0],attn_applied[0]),1)
output=self.attn_combine(output).unsqueeze(0)
return output,attn_weights
query_size=32
key_size=32
value_size1=32
value_size2=64
output_size=64
#初始化attn
attn=Attn(query_size,key_size,value_size1,value_size2,output_size)
#使用attn實(shí)例
Q=torch.randn(1,1,32)
K=torch.randn(1,1,32)
V=torch.randn(1,32,64)
output=attn(Q,K,V)
到了這里,關(guān)于【python,機(jī)器學(xué)習(xí),nlp】RNN循環(huán)神經(jīng)網(wǎng)絡(luò)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!