通俗講解pytorch中nn.Embedding原理及使用

函數(shù)調(diào)用形式

torch.nn.Embedding(num_embeddings, embedding_dim, padding_idx=None,
 max_norm=None,  norm_type=2.0,   scale_grad_by_freq=False, 
 sparse=False,  _weight=None)

其為一個(gè)簡(jiǎn)單的存儲(chǔ)固定大小的詞典的嵌入向量的查找表,意思就是說(shuō),給一個(gè)編號(hào),嵌入層就能返回這個(gè)編號(hào)對(duì)應(yīng)的嵌入向量,嵌入向量反映了各個(gè)編號(hào)代表的符號(hào)之間的語(yǔ)義關(guān)系。

輸入為一個(gè)編號(hào)列表,輸出為對(duì)應(yīng)的符號(hào)嵌入向量列表。

參數(shù)解釋

  • num_embeddings (python:int) – 詞典的大小尺寸,比如總共出現(xiàn)5000個(gè)詞,那就輸入5000。此時(shí)index為(0-4999)
    embedding_dim (python:int) – 嵌入向量的維度,即用多少維來(lái)表示一個(gè)符號(hào)。
  • padding_idx (python:int, optional) – 填充id,比如,輸入長(zhǎng)度為100,但是每次的句子長(zhǎng)度并不一樣,后面就需要用統(tǒng)一的數(shù)字填充,而這里就是指定這個(gè)數(shù)字,這樣,網(wǎng)絡(luò)在遇到填充id時(shí),就不會(huì)計(jì)算其與其它符號(hào)的相關(guān)性。(初始化為0)
  • max_norm (python:float, optional) – 最大范數(shù),如果嵌入向量的范數(shù)超過(guò)了這個(gè)界限,就要進(jìn)行再歸一化。
  • norm_type (python:float, optional) – 指定利用什么范數(shù)計(jì)算,并用于對(duì)比max_norm,默認(rèn)為2范數(shù)。
  • scale_grad_by_freq (boolean, optional) – 根據(jù)單詞在mini-batch中出現(xiàn)的頻率,對(duì)梯度進(jìn)行放縮。默認(rèn)為False.
  • sparse (bool, optional) – 若為T(mén)rue,則與權(quán)重矩陣相關(guān)的梯度轉(zhuǎn)變?yōu)橄∈鑿埩俊?/li>

下面是關(guān)于Embedding的使用

torch.nn包下的Embedding,作為訓(xùn)練的一層,隨模型訓(xùn)練得到適合的詞向量。

#建立詞向量層
embed = torch.nn.Embedding(n_vocabulary,embedding_size)

找到對(duì)應(yīng)的詞向量放進(jìn)網(wǎng)絡(luò):詞向量的輸入應(yīng)該是什么樣子

實(shí)際上,上面通過(guò)隨機(jī)初始化建立了詞向量層后,建立了一個(gè)“二維表”,存儲(chǔ)了詞典中每個(gè)詞的詞向量。每個(gè)mini-batch的訓(xùn)練,都要從詞向量表找到mini-batch對(duì)應(yīng)的單詞的詞向量作為RNN的輸入放進(jìn)網(wǎng)絡(luò)。那么怎么把mini-batch中的每個(gè)句子的所有單詞的詞向量找出來(lái)放進(jìn)網(wǎng)絡(luò)呢,輸入是什么樣子,輸出是什么樣子?

首先我們知道肯定先要建立一個(gè)詞典,建立詞典的時(shí)候都會(huì)建立一個(gè)dict:word2id:存儲(chǔ)單詞到詞典序號(hào)的映射。假設(shè)一個(gè)mini-batch如下所示:

['I am a boy.','How are you?','I am very lucky.']

顯然,這個(gè)mini-batch有3個(gè)句子,即batch_size=3

第一步首先要做的是:將句子標(biāo)準(zhǔn)化,所謂標(biāo)準(zhǔn)化,指的是:大寫(xiě)轉(zhuǎn)小寫(xiě),標(biāo)點(diǎn)分離,這部分很簡(jiǎn)單就略過(guò)。經(jīng)處理后,mini-batch變?yōu)椋?/p>

[['i','am','a','boy','.'],['how','are','you','?'],['i','am','very','lucky','.']]

可見(jiàn),這個(gè)list的元素成了一個(gè)個(gè)list。還要做一步:將上面的三個(gè)list按單詞數(shù)從多到少排列。標(biāo)點(diǎn)也算單詞。至于為什么,后面會(huì)說(shuō)到。

那就變成了:

batch = [['i','am','a','boy','.'],['i','am','very','lucky','.'],['how','are','you','?']]

可見(jiàn),每個(gè)句子的長(zhǎng)度,即每個(gè)內(nèi)層list的元素?cái)?shù)為:5,5,4。這個(gè)長(zhǎng)度也要記錄。

lens = [5,5,4]

之后,為了能夠處理,將batch的單詞表示轉(zhuǎn)為在詞典中的index序號(hào),這就是word2id的作用。轉(zhuǎn)換過(guò)程很簡(jiǎn)單,假設(shè)轉(zhuǎn)換之后的結(jié)果如下所示,當(dāng)然這些序號(hào)是我編的。

batch = [[3,6,5,6,7],[6,4,7,9,5],[4,5,8,7]]

同時(shí),每個(gè)句子結(jié)尾要加EOS,假設(shè)EOS在詞典中的index是1。

batch = [[3,6,5,6,7,1],[6,4,7,9,5,1],[4,5,8,7,1]]

那么長(zhǎng)度要更新:

lens = [6,6,5]

很顯然,這個(gè)mini-batch中的句子長(zhǎng)度不一致!所以為了規(guī)整的處理,對(duì)長(zhǎng)度不足的句子,進(jìn)行填充。填充PAD假設(shè)序號(hào)是2,填充之后為:

batch = [[3,6,5,6,7,1],[6,4,7,9,5,1],[4,5,8,7,1,2]]

這樣就可以直接取詞向量訓(xùn)練了嗎?

不能!上面batch有3個(gè)樣例,RNN的每一步要輸入每個(gè)樣例的一個(gè)單詞,一次輸入batch_size個(gè)樣例,所以batch要按list外層是時(shí)間步數(shù)(即序列長(zhǎng)度),list內(nèi)層是batch_size排列。即batch的維度應(yīng)該是:

[seq_len,batch_size]
[seq_len,batch_size]
[seq_len,batch_size]

重要的問(wèn)題說(shuō)3遍!

怎么變換呢?變換方法可以是:使用itertools模塊的zip_longest函數(shù)。而且,使用這個(gè)函數(shù),連填充這一步都可以省略,因?yàn)檫@個(gè)函數(shù)可以實(shí)現(xiàn)填充!

batch = list(itertools.zip_longest(batch,fillvalue=PAD))
# fillvalue就是要填充的值,強(qiáng)制轉(zhuǎn)成list

經(jīng)變換,結(jié)果應(yīng)該是:

batch = [[3,6,4],[6,4,5],[5,7,8],[6,9,7],[7,5,1],[1,1,2]]

記得我們還記錄了一個(gè)lens:

lens = [6,6,5]

batch還要轉(zhuǎn)成LongTensor:

batch=torch.LongTensor(batch)

這里的batch就是詞向量層的輸入。

詞向量層的輸出是什么樣的?

好了,現(xiàn)在使用建立了的embedding直接通過(guò)batch取詞向量了,如:

embed_batch = embed (batch)

假設(shè)詞向量維度是6,結(jié)果是:

tensor([[[-0.2699,  0.7401, -0.8000,  0.0472,  0.9032, -0.0902],
         [-0.2675,  1.8021,  1.4966,  0.6988,  1.4770,  1.1235],
         [ 0.1146, -0.8077, -1.4957, -1.5407,  0.3755, -0.6805]],

        [[-0.2675,  1.8021,  1.4966,  0.6988,  1.4770,  1.1235],
         [ 0.1146, -0.8077, -1.4957, -1.5407,  0.3755, -0.6805],
         [-0.0387,  0.8401,  1.6871,  0.3057, -0.8248, -0.1326]],

        [[-0.0387,  0.8401,  1.6871,  0.3057, -0.8248, -0.1326],
         [-0.3745, -1.9178, -0.2928,  0.6510,  0.9621, -1.3871],
         [-0.6739,  0.3931,  0.1464,  1.4965, -0.9210, -0.0995]],

        [[-0.2675,  1.8021,  1.4966,  0.6988,  1.4770,  1.1235],
         [-0.7411,  0.7948, -1.5864,  0.1176,  0.0789, -0.3376],
         [-0.3745, -1.9178, -0.2928,  0.6510,  0.9621, -1.3871]],

        [[-0.3745, -1.9178, -0.2928,  0.6510,  0.9621, -1.3871],
         [-0.0387,  0.8401,  1.6871,  0.3057, -0.8248, -0.1326],
         [ 0.2837,  0.5629,  1.0398,  2.0679, -1.0122, -0.2714]],

        [[ 0.2837,  0.5629,  1.0398,  2.0679, -1.0122, -0.2714],
         [ 0.2837,  0.5629,  1.0398,  2.0679, -1.0122, -0.2714],
         [ 0.2242, -1.2474,  0.3882,  0.2814, -0.4796,  0.3732]]],
       grad_fn=<EmbeddingBackward>)

維度的前兩維和前面講的是一致的??梢?jiàn)多了一個(gè)第三維,這就是詞向量維度。所以,Embedding層的輸出是:

[seq_len,batch_size,embedding_size]

一些注意的點(diǎn)

  • nn.embedding的輸入只能是編號(hào),不能是隱藏變量,比如one-hot,或者其它,這種情況,可以自己建一個(gè)自定義維度的線性網(wǎng)絡(luò)層,參數(shù)訓(xùn)練可以單獨(dú)訓(xùn)練或者跟隨整個(gè)網(wǎng)絡(luò)一起訓(xùn)練(看實(shí)驗(yàn)需要)
  • 如果你指定了padding_idx,注意這個(gè)padding_idx也是在num_embeddings尺寸內(nèi)的,比如符號(hào)總共有500個(gè),指定了padding_idx,那么num_embeddings應(yīng)該為501
  • embedding_dim的選擇要注意,根據(jù)自己的符號(hào)數(shù)量,舉個(gè)例子,如果你的詞典尺寸是1024,那么極限壓縮(用二進(jìn)制表示)也需要10維,再考慮詞性之間的相關(guān)性,怎么也要在15-20維左右,雖然embedding是用來(lái)降維的,但是>- 也要注意這種極限維度,結(jié)合實(shí)際情況,合理定義
  • 其他的好像也沒(méi)啥要注意的啦~,歡迎評(píng)論區(qū)補(bǔ)充(●′ω`●)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容