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

歡迎訪問 生活随笔!

生活随笔

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

生活经验

ELMo解读(论文 + PyTorch源码)

發(fā)布時間:2023/11/28 生活经验 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ELMo解读(论文 + PyTorch源码) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

ELMo的概念也是很早就出了,應(yīng)該是18年初的事情了。但我仍然是后知后覺,居然還是等BERT出來很久之后,才知道有這么個東西。這兩天才仔細(xì)看了下論文和源碼,在這里做一些記錄,如果有不詳實的地方,歡迎指出~

文章目錄
前言
一. ELMo原理
1. ELMo整體模型結(jié)構(gòu)
2. 字符編碼層
3. biLMs原理
4. 生成ELMo詞向量
5. 結(jié)合下游NLP任務(wù)
二. PyTorch實現(xiàn)
1. 字符編碼層
2. biLMs層
3. 生成ELMo詞向量
三. 實驗
四. 一些分析
1. 使用哪些層的輸出?
2. 在哪里加入ELMo?
3. 每層輸出的側(cè)重點是什么?
4. 效率分析
五. 總結(jié)
傳送門
前言

前言
ELMo出自Allen研究所在NAACL2018會議上發(fā)表的一篇論文《Deep contextualized word representations》,從論文名稱看,應(yīng)該是提出了一個新的詞表征的方法。據(jù)他們自己的介紹:ELMo是一個深度帶上下文的詞表征模型,能同時建模(1)單詞使用的復(fù)雜特征(例如,語法和語義);(2)這些特征在上下文中會有何變化(如歧義等)。這些詞向量從深度雙向語言模型(biLM)的隱層狀態(tài)中衍生出來,biLM是在大規(guī)模的語料上面Pretrain的。它們可以靈活輕松地加入到現(xiàn)有的模型中,并且能在很多NLP任務(wù)中顯著提升現(xiàn)有的表現(xiàn),比如問答、文本蘊含和情感分析等。聽起來非常的exciting,它的原理也十分reasonable!下面就將針對論文及其PyTorch源碼進行剖析,具體的資料參見文末的傳送門。

這里先聲明一點:筆者認(rèn)為“ELMo”這個名稱既可以代表得到詞向量的模型,也可以是得出的詞向量本身,就像Word2Vec、GloVe這些名稱一樣,都是可以代表兩個含義的。下面提到ELMo時,一般帶有“模型”相關(guān)字眼的就是指的訓(xùn)練出詞向量的模型,而帶有“詞向量”相關(guān)字眼的就是指的得出的詞向量。

一. ELMo原理
之前我們一般比較常用的詞嵌入的方法是諸如Word2Vec和GloVe這種,但這些詞嵌入的訓(xùn)練方式一般都是上下文無關(guān)的,并且對于同一個詞,不管它處于什么樣的語境,它的詞向量都是一樣的,這樣對于那些有歧義的詞非常不友好。因此,論文就考慮到了要根據(jù)輸入的句子作為上下文,來具體計算每個詞的表征,提出了ELMo(Embeddings from Language Model)。它的基本思想,用大白話來說就是,還是用訓(xùn)練語言模型的套路,然后把語言模型中間隱含層的輸出提取出來,作為這個詞在當(dāng)前上下文情境下的表征,簡單但很有用!

1. ELMo整體模型結(jié)構(gòu)
對于ELMo的模型結(jié)構(gòu),其實論文中并沒有給出具體的圖(這點對于筆者這種想象力極差的人來說很痛苦),筆者通過整合論文里面的蛛絲馬跡以及PyTorch的源碼,得出它大概是下面這么個東西(手殘黨畫的丑,勿怪):
?

?

?

?

?

?

?

5. 結(jié)合下游NLP任務(wù)
一般ELMo模型會在一個超大的語料庫上進行預(yù)訓(xùn)練,因為是訓(xùn)練語言模型,不需要任何的標(biāo)簽,純文本就可以,因而這里可以用超大的語料庫,這一點的優(yōu)勢是十分明顯的。訓(xùn)練完ELMo模型之后,就可以輸入一個新句子,得到其中每個單詞在當(dāng)前這個句子上下文下的ELMo詞向量了。

論文中提到,在訓(xùn)練的時候,發(fā)現(xiàn)使用合適的dropout和L2在ELMo模型上時會提升效果。

此時這個詞向量就可以接入到下游的NLP任務(wù)中,比如問答、情感分析等。從接入的位置來看,可以與下游NLP任務(wù)本身輸入的embedding拼接在一起,也可以與其輸出拼接在一起。而從模型是否固定來看,又可以將ELMo詞向量預(yù)先全部提取出來,即固定ELMo模型不讓其訓(xùn)練,也可以在訓(xùn)練下游NLP任務(wù)時順帶fine-tune這個ELMo模型??傊?#xff0c;使用起來非常的方便,可以插入到任何想插入的地方進行增補。

二. PyTorch實現(xiàn)
這里參考的主要是allennlp里面與ELMo本身有關(guān)的部分,涉及到biLMs的模型實現(xiàn),以及ELMo推理部分,會只列出核心的部分,細(xì)枝末節(jié)的代碼就不列舉了。至于如何與下游的NLP任務(wù)結(jié)合以及fine-tune,還需要讀者自己去探索和實踐,這里不做說明!

1. 字符編碼層
這里實現(xiàn)的就是前面提到的Char Encode Layer。

首先是multi-scale CNN的實現(xiàn):

# multi-scale CNN# 網(wǎng)絡(luò)定義
for i, (width, num) in enumerate(filters):conv = torch.nn.Conv1d(in_channels=char_embed_dim,out_channels=num,kernel_size=width,bias=True)self.add_module('char_conv_{}'.format(i), conv)# forward函數(shù)
def forward(sef, character_embedding)convs = []for i in range(len(self._convolutions)):conv = getattr(self, 'char_conv_{}'.format(i))convolved = conv(character_embedding)# (batch_size * sequence_length, n_filters for this width)convolved, _ = torch.max(convolved, dim=-1)convolved = activation(convolved)convs.append(convolved)# (batch_size * sequence_length, n_filters)token_embedding = torch.cat(convs, dim=-1)return token_embedding

?然后是highway的實現(xiàn):

# HighWay# 網(wǎng)絡(luò)定義
self._layers = torch.nn.ModuleList([torch.nn.Linear(input_dim, input_dim * 2)for _ in range(num_layers)])# forward函數(shù)
def forward(self, inputs):current_input = inputsfor layer in self._layers:projected_input = layer(current_input)linear_part = current_input# NOTE: if you modify this, think about whether you should modify the initialization# above, too.nonlinear_part, gate = projected_input.chunk(2, dim=-1)nonlinear_part = self._activation(nonlinear_part)gate = torch.sigmoid(gate)current_input = gate * linear_part + (1 - gate) * nonlinear_partreturn current_input

2. biLMs層

這部分實際上是兩個不同方向的BiLSTM訓(xùn)練,然后輸出經(jīng)過映射后直接進行拼接即可,代碼如下:(以單向單層的為例)

# 網(wǎng)絡(luò)定義
# input_size:輸入embedding的維度
# hidden_size:輸入和輸出hidden state的維度
# cell_size:LSTMCell的內(nèi)部維度。
# 一般input_size = hidden_size = D, hidden_size即為h。
self.input_linearity = torch.nn.Linear(input_size, 4 * cell_size, bias=False)
self.state_linearity = torch.nn.Linear(hidden_size, 4 * cell_size, bias=True)
self.state_projection = torch.nn.Linear(cell_size, hidden_size, bias=False)  # forward函數(shù)
def forward(self, inputs, batch_lengths, initial_state):for timestep in range(total_timesteps):# Do the projections for all the gates all at once.# Both have shape (batch_size, 4 * cell_size)projected_input = self.input_linearity(timestep_input)projected_state = self.state_linearity(previous_state)# Main LSTM equations using relevant chunks of the big linear# projections of the hidden state and inputs.input_gate = torch.sigmoid(projected_input[:, (0 * self.cell_size):(1 * self.cell_size)] +projected_state[:, (0 * self.cell_size):(1 * self.cell_size)])forget_gate = torch.sigmoid(projected_input[:, (1 * self.cell_size):(2 * self.cell_size)] +projected_state[:, (1 * self.cell_size):(2 * self.cell_size)])memory_init = torch.tanh(projected_input[:, (2 * self.cell_size):(3 * self.cell_size)] +projected_state[:, (2 * self.cell_size):(3 * self.cell_size)])output_gate = torch.sigmoid(projected_input[:, (3 * self.cell_size):(4 * self.cell_size)] +projected_state[:, (3 * self.cell_size):(4 * self.cell_size)])memory = input_gate * memory_init + forget_gate * previous_memory# shape (current_length_index, cell_size)pre_projection_timestep_output = output_gate * torch.tanh(memory)# shape (current_length_index, hidden_size)timestep_output = self.state_projection(pre_projection_timestep_output)output_accumulator[0:current_length_index + 1, index] = timestep_output# Mimic the pytorch API by returning state in the following shape:# (num_layers * num_directions, batch_size, ...). As this# LSTM cell cannot be stacked, the first dimension here is just 1.final_state = (full_batch_previous_state.unsqueeze(0),full_batch_previous_memory.unsqueeze(0))return output_accumulator, final_state      

3. 生成ELMo詞向量

這部分即為Scalar Mixer,其代碼如下:

# 參數(shù)定義
self.scalar_parameters = ParameterList([Parameter(torch.FloatTensor([initial_scalar_parameters[i]]),requires_grad=trainable) for iin range(mixture_size)])
self.gamma = Parameter(torch.FloatTensor([1.0]), requires_grad=trainable)# forward函數(shù)
def forward(tensors, mask):def _do_layer_norm(tensor, broadcast_mask, num_elements_not_masked):tensor_masked = tensor * broadcast_maskmean = torch.sum(tensor_masked) / num_elements_not_maskedvariance = torch.sum(((tensor_masked - mean) * broadcast_mask)**2) / num_elements_not_maskedreturn (tensor - mean) / torch.sqrt(variance + 1E-12)normed_weights = torch.nn.functional.softmax(torch.cat([parameter for parameterin self.scalar_parameters]), dim=0)normed_weights = torch.split(normed_weights, split_size_or_sections=1)if not self.do_layer_norm:pieces = []for weight, tensor in zip(normed_weights, tensors):pieces.append(weight * tensor)return self.gamma * sum(pieces)else:mask_float = mask.float()broadcast_mask = mask_float.unsqueeze(-1)input_dim = tensors[0].size(-1)num_elements_not_masked = torch.sum(mask_float) * input_dimpieces = []for weight, tensor in zip(normed_weights, tensors):pieces.append(weight * _do_layer_norm(tensor,broadcast_mask, num_elements_not_masked))return self.gamma * sum(pieces)

三. 實驗

這里主要列舉一些在實際下游任務(wù)上結(jié)合ELMo的表現(xiàn),分別是SQuAD(問答任務(wù))、SNLI(文本蘊含)、SRL(語義角色標(biāo)注)、Coref(共指消解)、NER(命名實體識別)以及SST-5(情感分析任務(wù)),其結(jié)果如下:

可見,基本都是在一個較低的baseline的情況下,用了ELMo后,達到了超越之前SoTA的效果!

四. 一些分析
論文中,作者也做了一些有趣的分析,從各個角度窺探ELMo的優(yōu)勢和特性。比如:

1. 使用哪些層的輸出?
作者探索了使用不同biLMs層帶來的效果,以及使用不同的L2范數(shù)的權(quán)重,如下表所示:

?

這里面的Last Only指的是只是用biLM最頂層的輸出,λ \lambdaλ 指的是L2范數(shù)的權(quán)重,可見使用所有層的效果普遍比較好,并且較低的L2范數(shù)效果也較好,因其讓每一層的表示都趨于不同,當(dāng)L2范數(shù)的權(quán)重較大時,會讓模型所有層的參數(shù)值趨于一致,導(dǎo)致模型每層的輸出也會趨于一致。

2. 在哪里加入ELMo?
前面提到過,可以在輸入和輸出的時候加入ELMo向量,作者比較了這兩者的不同:

?

在問答和文本蘊含任務(wù)上,是同時在輸入和輸出加入ELMo的效果較好,而在語義角色標(biāo)注任務(wù)上,則是只在輸入加入比較好。論文猜測這個原因可能是因為,在前兩個任務(wù)上,都需要用到attention,而在輸出的時候加入ELMo,能讓attention直接看到ELMo的輸出,會對整個任務(wù)有利。而在語義角色標(biāo)注上,與任務(wù)相關(guān)的上下文表征要比biLMs的通用輸出更重要一些。

3. 每層輸出的側(cè)重點是什么?
論文通過實驗得出,在biLMs的低層,表征更側(cè)重于諸如詞性等這種語法特征,而在高層的表征則更側(cè)重于語義特征。比如下面的實驗結(jié)果:

左邊的任務(wù)是語義消歧,右邊的任務(wù)是詞性標(biāo)注,可見在語義消歧任務(wù)上面,使用第二層的效果比第一層的要好;而在詞性標(biāo)注任務(wù)上面,使用第一層的效果反而比使用第二層的效果要好。

總體來看,還是使用所有層輸出的效果會更好,具體的weight讓模型自己去學(xué)就好了。

4. 效率分析
一般而言,用了預(yù)訓(xùn)練模型的網(wǎng)絡(luò)往往收斂的會更快,同時也可以使用更少的數(shù)據(jù)集。論文通過實驗驗證了這一點:

?

比如在SRL任務(wù)中,使用了ELMo的模型僅使用1%的數(shù)據(jù)集就能達到不使用ELMo模型在使用10%數(shù)據(jù)集的效果!

五. 總結(jié)
ELMo具有如下的優(yōu)良特性:

上下文相關(guān):每個單詞的表示取決于使用它的整個上下文。
深度:單詞表示組合了深度預(yù)訓(xùn)練神經(jīng)網(wǎng)絡(luò)的所有層。
基于字符:ELMo表示純粹基于字符,然后經(jīng)過CharCNN之后再作為詞的表示,解決了OOV問題,而且輸入的詞表也很小。
資源豐富:有完整的源碼、預(yù)訓(xùn)練模型、參數(shù)以及詳盡的調(diào)用方式和例子,又是一個造福伸手黨的好項目!而且:還有人專門實現(xiàn)了多語的,好像是哈工大搞的,戳這里看項目。
傳送門
論文:https://arxiv.org/pdf/1802.05365.pdf
項目首頁:https://allennlp.org/elmo
源碼:https://github.com/allenai/allennlp (PyTorch,關(guān)于ELMo的部分戳這里)
https://github.com/allenai/bilm-tf (TensorFlow)
多語言:https://github.com/HIT-SCIR/ELMoForManyLangs (哈工大CoNLL評測的多國語言ELMo,還有繁體中文的)

總結(jié)

以上是生活随笔為你收集整理的ELMo解读(论文 + PyTorch源码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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