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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

NLP【07】transformer原理、实现及如何与词向量做对接进行文本分类(附代码详解)

發(fā)布時(shí)間:2023/12/16 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NLP【07】transformer原理、实现及如何与词向量做对接进行文本分类(附代码详解) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一篇:NLP【06】RCNN原理及文本分類實(shí)戰(zhàn)(附代碼詳解)

下一篇:NLP【08】深度學(xué)習(xí)模型在NLP中的發(fā)展——從Word2vec到Bert的演變過程

完整代碼下載:https://github.com/ttjjlw/NLP/tree/main/Classify%E5%88%86%E7%B1%BB/rnn-cnn/tf1.x/models

一、前言

當(dāng)前,bert橫行,而bert的基礎(chǔ)是transformer,自然,掌握transformer成為了基操。論文中的transformer是seq2seq模型,分為編碼和解碼,而在本文中,我所講的transformer主要是transformer中的attention,也就是利用transformer中的attention與位置編碼,替換cnn或者rnn部分完成文本分類。建議在看我這篇之前,先整體看一篇trnasformer的介紹,細(xì)節(jié)沒看明白的,再來瞧瞧我這篇。

二、transformer的簡(jiǎn)單介紹

transformer分為encoder和decoder,這里主要講encoder的三部分Positional Encoding、multi-head attention以及殘差連接。Positional Encoding即位置編碼也就是每個(gè)位置利用一個(gè)向量表示,具體公式如下:

這個(gè)公式怎么理解呢?pos就是詞的位置,2i或2i+1就是 詞向量的維度上的偶數(shù)或奇數(shù)的位置,舉個(gè)例子:定義一個(gè)長(zhǎng)度為100的位置向量,位置向量的維度為64,那么最終這個(gè)位置向量pos_embs的shape即為(100,64),那么這個(gè)位置向量表怎么得到呢,就是通過上面的公式。具體就是pos_embs[pos][i%2==0]=sin()這一串,而pos_embs[pos][i%2==1]=cos()這一串。而pos取值是從0到99,i取值是從0到63。我想看到這,應(yīng)該都明白了,如果沒明白,可以結(jié)合下面的代碼實(shí)現(xiàn)來理解。

第二部分就是multi-head attention,首先,對(duì)比一下以前self.attention的做法,在做文本分類時(shí),lookup詞嵌入矩陣后,再經(jīng)cnn或者rnn,會(huì)得到shape為(batch-size,seq_len,dim)的向量,記為M,然后我們是怎么做self.attention的呢?

1、先初始化一個(gè)可以訓(xùn)練的權(quán)重,shape為(batch_size, dim,1),記為W?

2、然后M和W做矩陣相乘就的得到shape為(batch_size,seq_len)然后經(jīng)softmax處理,就得到了每個(gè)詞的權(quán)重?

3、再把這個(gè)權(quán)重和原來的M做相乘(multiply),最后在seq_len的維度上做reduce_sum(),也就是output=reduce_sum(M,axis=1),則output的shape變?yōu)?#xff08;batch-size,dim),也就是attention的最后輸出,以上省略了所有的reshape過程。

該過程實(shí)現(xiàn)可參考https://github.com/ttjjlw/NLP/blob/main/Classify%E5%88%86%E7%B1%BB/rnn-cnn/tf1.x/models/bilstmatten.py。那transformer中的self.attention又是怎么做的呢?

1、把M復(fù)制三份,命名為query,key,value

2、分別初始化三個(gè)矩陣q_w,k_w,v_w,然后query,keyvalue與對(duì)應(yīng)的矩陣做矩陣相乘,得Q,K,V,此時(shí)三者的shape都為(batch_size,seq_len,dim)

3、如果head為1的話,那就是similarity=matmul(Q,K的轉(zhuǎn)置),所以similarity的shape為(batch_size,seq_len,seq_len),其這個(gè)矩陣記錄就是每個(gè)詞與所有詞的相似性

4、output=matmul(similarity,V),所以output 的shape為(batch_size,seq_len,dim)

第三部分殘差連接,殘差連接就簡(jiǎn)單了:公式為 :H(x) = F(x) + x,這里就是H(x)=query+output,然后給H(x)進(jìn)行層歸一化。

整個(gè)過程大概就是如此,其中省略些細(xì)節(jié),如similarity的計(jì)算其實(shí)還要除于根號(hào)dim,防止softmax(similarity)后非0即1,不利于參數(shù)學(xué)習(xí)。舉個(gè)例子就明白了,softmax([1,10]) —>?[1.2339458e-04, 9.9987662e-01] 而 softmax([0.1,1.0]) —>?[0.2890505, 0.7109495]。

?三、代碼詳解

1、位置編碼

def _position_embedding(self):"""生成位置向量:return:"""batch_size = self.config["batch_size"]sequence_length = self.config["sequence_length"]embedding_size = self.config["embedding_size"]# 生成位置的索引,并擴(kuò)張到batch中所有的樣本上position_index = tf.tile(tf.expand_dims(tf.range(sequence_length), 0), [batch_size, 1])position_embedding = np.zeros([sequence_length, embedding_size])for pos in range(sequence_length):for i in range(embedding_size):denominator = np.power(10000.0, i/ embedding_size)if i % 2 == 0:position_embedding[pos][i] = np.sin(pos / denominator)else:position_embedding[pos][i] = np.cos(pos / denominator)position_embedding = tf.cast(position_embedding, dtype=tf.float32)# 得到三維的矩陣[batchSize, sequenceLen, embeddingSize]embedded_position = tf.nn.embedding_lookup(position_embedding, position_index)return embedded_position

?lookup后的詞向量與位置向量相加形成新的向量

embedded_words = tf.nn.embedding_lookup(embedding_w, self.inputs) embedded_position = self._position_embedding() embedded_representation = embedded_words + embedded_position

?把添加了位置向量的詞向量,輸入到self._multihead_attention()中(該方法就是依次經(jīng)過attention,殘差連接與層歸一化得到最終的向量,就是上面詳細(xì)介紹的2,3步過程),然后再經(jīng)過self._feed_forward(), self._multihead_attention()與self._feed_forward()組成一層transformer

with tf.name_scope("transformer"):for i in range(self.config["num_blocks"]):with tf.name_scope("transformer-{}".format(i + 1)):with tf.name_scope("multi_head_atten"):# 維度[batch_size, sequence_length, embedding_size]multihead_atten = self._multihead_attention(inputs=self.inputs,queries=embedded_representation,keys=embedded_representation)with tf.name_scope("feed_forward"):# 維度[batch_size, sequence_length, embedding_size]embedded_representation = self._feed_forward(multihead_atten,[self.config["filters"],self.config["embedding_size"]])outputs = tf.reshape(embedded_representation,[-1, self.config["sequence_length"] * self.config["embedding_size"]])output_size = outputs.get_shape()[-1].value

其中num_blocks就是設(shè)置要過幾層transformer,output就是最終的結(jié)果。

完整代碼下載:https://github.com/ttjjlw/NLP/tree/main/Classify%E5%88%86%E7%B1%BB/rnn-cnn/tf1.x/models

總結(jié)

以上是生活随笔為你收集整理的NLP【07】transformer原理、实现及如何与词向量做对接进行文本分类(附代码详解)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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