日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

BiLSTM-CRF学习笔记(原理和理解) 维特比

發(fā)布時(shí)間:2023/11/28 生活经验 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BiLSTM-CRF学习笔记(原理和理解) 维特比 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

https://www.zhihu.com/question/20136144

維特比詳解

BiLSTM-CRF 被提出用于NER或者詞性標(biāo)注,效果比單純的CRF或者lstm或者bilstm效果都要好。

根據(jù)pytorch官方指南(https://pytorch.org/tutorials/beginner/nlp/advanced_tutorial.html#bi-lstm-conditional-random-field-discussion),實(shí)現(xiàn)了BiLSTM-CRF一個(gè)toy級(jí)別的源碼。下面是我個(gè)人的學(xué)習(xí)理解過(guò)程。

1. LSTM

LSTM的原理前人已經(jīng)解釋的非常清楚了:https://zhuanlan.zhihu.com/p/32085405
BiLSTM-CRF中,BiLSTM部分主要用于,根據(jù)一個(gè)單詞的上下文,給出當(dāng)前單詞對(duì)應(yīng)標(biāo)簽的概率分布,可以把BiLSTM看成一個(gè)編碼層。
比如,對(duì)于標(biāo)簽集{N, V, O}和單詞China,BiLSTM可能輸出形如(0.88,-1.23,0.03)的非歸一化概率分布。
這個(gè)分布我們看作是crf的特征分布輸入,那么在CRF中我們需要學(xué)習(xí)的就是特征轉(zhuǎn)移概率。

2. CRF

主要講一下代碼中要用到的CRF的預(yù)測(cè)(維特比解碼)
維特比算法流程:
1.求出位置1的各個(gè)標(biāo)記的非規(guī)范化概率δ1(j)δ1(j)

δ1(j)=w?F1(y0=START,yi=j,x),j=1,2,…,mδ1(j)=w?F1(y0=START,yi=j,x),j=1,2,…,m

?

2.由遞推公式(前后向概率計(jì)算)

δi(l)=max(1≤j≤m){δi?1(j)+w?Fi(yi?1=j,yi=l,x)},l=1,2,…,lδi(l)=max(1≤j≤m){δi?1(j)+w?Fi(yi?1=j,yi=l,x)},l=1,2,…,l


每一步都保留當(dāng)前所有可能的狀態(tài)ll?對(duì)應(yīng)的最大的非規(guī)范化概率,
并將最大非規(guī)范化概率狀態(tài)對(duì)應(yīng)的路徑(當(dāng)前狀態(tài)得到最大概率時(shí)上一步的狀態(tài)yiyi)記錄
Ψi(l)=argmax(1≤j≤m){δi?1(j)+w?Fi(yi?1=j,yi=l,x)}=argmaxδi(l),l=1,2,…,mΨi(l)=arg?max(1≤j≤m){δi?1(j)+w?Fi(yi?1=j,yi=l,x)}=argmax?δi(l),l=1,2,…,m
就是PijPij的取值有m*m個(gè),對(duì)每一個(gè)yjyj,都確定一個(gè)(而不是可能的m個(gè))能最大化概率的yiyi狀態(tài)

?

3.遞推到i=ni=n時(shí)終止
這時(shí)候求得非規(guī)范化概率的最大值為

maxy{w?F(y,x)}=max(1≤j≤m)δn(j)=max(1≤j≤m){δn?1(j)+w?Fn(yn?1=Ψn?1(k),yi=l,x)},l=1,2,…,mmaxy?{w?F(y,x)}=max(1≤j≤m)δn(j)=max(1≤j≤m){?δn?1(j)+w?Fn(yn?1=Ψn?1(k),yi=l,x)},l=1,2,…,m


最優(yōu)路徑終點(diǎn)

y?n=argmax(1≤j≤m)δn(j)yn?=arg?max(1≤j≤m)?δn(j)

?

4.遞歸路徑
由最優(yōu)路徑終點(diǎn)遞歸得到的最優(yōu)路徑(由當(dāng)前最大概率狀態(tài)狀態(tài)對(duì)應(yīng)的上一步狀態(tài),然后遞歸)

y?i=Ψi+1(y?i+1),i=n?1,n?2,…,1yi?=Ψi+1(yi+1?),i=n?1,n?2,…,1


求得最優(yōu)路徑:

y?=(y?1,y?2,…,y?n)Ty?=(y1?,y2?,…,yn?)T

?

3. 損失函數(shù)

最后由CRF輸出,損失函數(shù)的形式主要由CRF給出
在BiLSTM-CRF中,給定輸入序列X,網(wǎng)絡(luò)輸出對(duì)應(yīng)的標(biāo)注序列y,得分為

S(X,y)=∑ni=0Ayi,yi+1+∑ni=1Pi,yiS(X,y)=∑i=0nAyi,yi+1+∑i=1nPi,yi


(轉(zhuǎn)移概率和狀態(tài)概率之和)
利用softmax函數(shù),我們?yōu)槊恳粋€(gè)正確的tag序列y定義一個(gè)概率值

p(y│X)=eS(X,y)∑y'∈YXeS(X,y')p(y│X)=eS(X,y)∑y′∈YXeS(X,y′)

?

在訓(xùn)練中,我們的目標(biāo)就是最大化概率p(y│X) ,怎么最大化呢,用對(duì)數(shù)似然(因?yàn)閜(y│X)中存在指數(shù)和除法,對(duì)數(shù)似然可以化簡(jiǎn)這些運(yùn)算)
對(duì)數(shù)似然形式如下:

log(p(y│X)=loges(X,y)∑y∈YXes(X,y′)=S(X,y)?log(∑y′∈YXes(X,y′))log?(p(y│X)=log?es(X,y)∑y∈YXes(X,y′)=S(X,y)?log?(∑y′∈YXes(X,y′))


最大化這個(gè)對(duì)數(shù)似然,就是最小化他的相反數(shù):
¥?log(p(y│X))=log(∑y′∈YXes(X,y′))?S(X,y)?log?(p(y│X))=log?(∑y′∈YXes(X,y′))?S(X,y)$
(loss function/object function)
最小化可以借助梯度下降實(shí)現(xiàn)

?

在對(duì)損失函數(shù)進(jìn)行計(jì)算的時(shí)候,前一項(xiàng)S(X,y)S(X,y)很容易計(jì)算,
后一項(xiàng)log(∑y′∈YXes(X,y′))log?(∑y′∈YXes(X,y′))比較復(fù)雜,計(jì)算過(guò)程中由于指數(shù)較大常常會(huì)出現(xiàn)上溢或者下溢,
由公式?log∑e(xi)=a+log∑e(xi?a)log∑e(xi)=a+log?∑e(xi?a),可以借助a對(duì)指數(shù)進(jìn)行放縮,通常a取xixi的最大值(即a=max[Xi]a=max?[Xi]),這可以保證指數(shù)最大不會(huì)超過(guò)0,于是你就不會(huì)上溢出。即便剩余的部分下溢出了,你也能得到一個(gè)合理的值。

又因?yàn)閘og(∑yelog(∑xex)+y)log?(∑yelog(∑xex)+y),在loglog取ee作為底數(shù)的情況下,可以化簡(jiǎn)為
log(∑yey?elog(∑xex))=log(∑yey?∑xex)=log(∑y∑xex+y)log?(∑yey?elog?(∑xex))=log?(∑yey?∑xex)=log?(∑y∑xex+y)。
log_sum_exp因?yàn)樾枰?jì)算所有路徑,那么在計(jì)算過(guò)程中,計(jì)算每一步路徑得分之和和直接計(jì)算全局得分是等價(jià)的,就可以大大減少計(jì)算時(shí)間。
當(dāng)前的分?jǐn)?shù)可以由上一步的總得分+轉(zhuǎn)移得分+狀態(tài)得分得到,這也是pytorch范例中
next_tag_var = forward_var + trans_score + emit_score?
的由來(lái)

注意,由于程序中比較好選一整行而不是一整列,所以調(diào)換i,j的含義,t[i][j]表示從j狀態(tài)轉(zhuǎn)移到i狀態(tài)的轉(zhuǎn)移概率

直接分析源碼的前向傳播部分,其中_get_lstm_features函數(shù)調(diào)用了pytorch的BiLSTM

def forward(self, sentence):"""重寫前向傳播:param sentence: 輸入的句子序列:return:返回分?jǐn)?shù)和標(biāo)記序列"""lstm_feats = self._get_lstm_features(sentence)score, tag_seq = self._viterbi_decode(lstm_feats)return score, tag_seq

源碼的維特比算法實(shí)現(xiàn),在訓(xùn)練結(jié)束,還要使用該算法進(jìn)行預(yù)測(cè)

def _viterbi_decode(self, feats):"""使用維特比算法預(yù)測(cè):param feats:lstm的所有輸出:return:返回最大概率和最優(yōu)路徑""" backpointers = []# step1. 初始化init_vvars = torch.full((1, self.tagset_size), -1000.)# 初始化第一步的轉(zhuǎn)移概率init_vvars[0][self.tag_to_idx[START_TAG]] = 0# 初始化每一步的非規(guī)范化概率forward_var = init_vvars # step2. 遞推# 遍歷每一個(gè)單詞通過(guò)bilstm輸出的概率分布for feat in feats:# 每次循環(huán)重新統(tǒng)計(jì)bptrs_t = []viterbivars_t = []for next_tag in range(self.tagset_size):# 根據(jù)維特比算法# 下一個(gè)tag_i+1的非歸一化概率是上一步概率加轉(zhuǎn)移概率(勢(shì)函數(shù)和勢(shì)函數(shù)的權(quán)重都統(tǒng)一看成轉(zhuǎn)移概率的一部分)next_tag_var = forward_var + self.transitions[next_tag]# next_tag_var = tensor([[-3.8879e-01,  1.5657e+00,  1.7734e+00, -9.9964e+03, -9.9990e+03]])# 計(jì)算所有前向概率(?)# CRF是單步線性鏈馬爾可夫,所以每個(gè)狀態(tài)只和他上1個(gè)狀態(tài)有關(guān),可以用二維的概率轉(zhuǎn)移矩陣表示# 保存當(dāng)前最大狀態(tài)best_tag_id = argmax(next_tag_var)# best_tag_id = torch.argmax(next_tag_var).item()bptrs_t.append(best_tag_id)# 從一個(gè)1*N向量中取出一個(gè)值(標(biāo)量),將這個(gè)標(biāo)量再轉(zhuǎn)換成一維向量viterbivars_t.append(next_tag_var[0][best_tag_id].view(1))  # viterbivars 長(zhǎng)度為self.tagset_size,對(duì)應(yīng)feat的維度f(wàn)orward_var = (torch.cat(viterbivars_t) + feat).view(1, -1)# 記錄每一個(gè)時(shí)間i,每個(gè)狀態(tài)取值l取最大非規(guī)范化概率對(duì)應(yīng)的上一步狀態(tài)backpointers.append(bptrs_t)# step3. 終止terminal_var = forward_var + self.transitions[self.tag_to_idx[STOP_TAG]]best_tag_id = argmax(terminal_var)path_score = terminal_var[0][best_tag_id]# step4. 返回路徑best_path = [best_tag_id]for bptrs_t in reversed(backpointers):best_tag_id = bptrs_t[best_tag_id]best_path.append(best_tag_id)# Pop off the start tag (we dont want to return that to the caller)start = best_path.pop()assert start == self.tag_to_idx[START_TAG]  # Sanity checkbest_path.reverse()return path_score, best_path

源碼的損失函數(shù)計(jì)算

def neg_log_likelihood(self, sentence, tags):"""實(shí)現(xiàn)負(fù)對(duì)數(shù)似然函數(shù):param sentence::param tags::return:"""# 返回句子中每個(gè)單詞對(duì)應(yīng)的標(biāo)簽概率分布feats = self._get_lstm_features(sentence)forward_score = self._forward_alg(feats)gold_score = self._score_sentence(feats, tags) # 輸出路徑的得分(S(X,y))# 返回負(fù)對(duì)數(shù)似然函數(shù)的結(jié)果return forward_score - gold_scoredef _forward_alg(self, feats):"""使用前向算法計(jì)算損失函數(shù)的第一項(xiàng)log(\sum(exp(S(X,y’)))):param feats: 從BiLSTM輸出的特征:return: 返回"""init_alphas = torch.full((1, self.tagset_size), -10000.)init_alphas[0][self.tag_to_idx[START_TAG]] = 0.forward_var = init_alphasfor feat in feats:# 存放t時(shí)刻的 概率狀態(tài)alphas_t = [] for current_tag in range(self.tagset_size):# lstm輸出的是非歸一化分布概率emit_score = feat[current_tag].view(1, -1).expand(1, self.tagset_size)# self.transitions[current_tag] 就是從上一時(shí)刻所有狀態(tài)轉(zhuǎn)移到當(dāng)前某狀態(tài)的非歸一化轉(zhuǎn)移概率# 取出的轉(zhuǎn)移矩陣的行是一維的,這里調(diào)用view函數(shù)轉(zhuǎn)換成二維矩陣trans_score = self.transitions[current_tag].view(1, -1)# trans_score + emit_score 等于所有特征函數(shù)之和# forward 是截至上一步的得分current_tag_var = forward_var + trans_score + emit_scorealphas_t.append(log_sum_exp(current_tag_var).view(1))forward_var = torch.cat(alphas_t).view(1, -1) # 調(diào)用view函數(shù)轉(zhuǎn)換成1*N向量terminal_var = forward_var + self.transitions[self.tag_to_idx[STOP_TAG]]alpha = log_sum_exp(terminal_var)return alphadef _score_sentence(self, feats, tags):"""返回S(X,y):param feats: 從BiLSTM輸出的特征:param tags: CRF輸出的標(biāo)記路徑:return:"""score = torch.zeros(1)tags = torch.cat([torch.tensor([self.tag_to_idx[START_TAG]], dtype=torch.long),tags])for i, feat in enumerate(feats):score = score + self.transitions[tags[i + 1], tags[i]] + feat[tags[i + 1]]score = score + self.transitions[self.tag_to_idx[STOP_TAG],tags[-1]]return score

總結(jié)

以上是生活随笔為你收集整理的BiLSTM-CRF学习笔记(原理和理解) 维特比的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。