“变形金刚”为何强大:从模型到代码全面解析Google Tensor2Tensor系统
歡迎大家前往騰訊云+社區(qū),獲取更多騰訊海量技術(shù)實(shí)踐干貨哦~
本文由張金超博士發(fā)表于云+社區(qū)專欄
導(dǎo)語: Google Tensor2Tensor系統(tǒng)是一套十分強(qiáng)大的深度學(xué)習(xí)系統(tǒng),在多個(gè)任務(wù)上的表現(xiàn)非常搶眼。尤其在機(jī)器翻譯問題上,單模型的表現(xiàn)就可以超過之前方法的集成模型。這一套系統(tǒng)的模型結(jié)構(gòu)、訓(xùn)練和優(yōu)化技巧等,可以被利用到公司的產(chǎn)品線上,直接轉(zhuǎn)化成生產(chǎn)力。本文對(duì)Tensor2Tensor系統(tǒng)從模型到代碼進(jìn)行了全面的解析,期望能夠給大家提供有用的信息。
第一章:概述
? Tensor2Tensor(T2T)是Google Brain Team在Github上開源出來的一套基于TensorFlow的深度學(xué)習(xí)系統(tǒng)。該系統(tǒng)最初是希望完全使用Attention方法來建模序列到序列(Sequence-to-Sequence,Seq2Seq)的問題,對(duì)應(yīng)于《Attention Is All You Need》這篇論文。該項(xiàng)工作有一個(gè)有意思的名字叫“Transformer”。隨著系統(tǒng)的不斷擴(kuò)展,T2T支持的功能變得越來越多,目前可以建模的問題包括:圖像分類,語言模型、情感分析、語音識(shí)別、文本摘要,機(jī)器翻譯。T2T在很多任務(wù)上的表現(xiàn)很好,并且模型收斂比較快,在TF平臺(tái)上的工程化代碼實(shí)現(xiàn)的也非常好,是一個(gè)十分值得使用和學(xué)習(xí)的系統(tǒng)。
? 如果是從工程應(yīng)用的角度出發(fā),想快速的上手使用T2T系統(tǒng),只需要對(duì)模型有一些初步的了解,閱讀一下workthrough文檔,很快就能做模型訓(xùn)練和數(shù)據(jù)解碼了。這就是該系統(tǒng)想要達(dá)到的目的,即降低深度學(xué)習(xí)模型的使用門檻。系統(tǒng)對(duì)數(shù)據(jù)處理、模型、超參、計(jì)算設(shè)備都進(jìn)行了較高的封裝,在使用的時(shí)候只需要給到數(shù)據(jù)路徑、指定要使用的模型和超參、說明計(jì)算設(shè)備就可以將系統(tǒng)運(yùn)行起來了。
? 如果想深入了解系統(tǒng)的實(shí)現(xiàn)細(xì)節(jié),在該系統(tǒng)上做二次開發(fā)或是實(shí)現(xiàn)一些研究性的想法,那就需要花費(fèi)一定的時(shí)間和精力來對(duì)模型和代碼進(jìn)行研究。T2T是一個(gè)較復(fù)雜的系統(tǒng),筆者近期對(duì)模型和代碼實(shí)現(xiàn)進(jìn)行了全面的學(xué)習(xí),同時(shí)對(duì)涉及到序列到序列功能的代碼進(jìn)行了剝離和重構(gòu),投入了較多的時(shí)間成本。因筆者是做自然語言處理研究的,這篇文章里主要關(guān)注的是Transformer模型。寫這篇文章一方面是總結(jié)和記錄一下這個(gè)過程中的一些收獲,另一方面是把自己對(duì)T2T的理解分享出來,希望能夠提供一些有用的信息給同學(xué)們。
第二章:序列到序列任務(wù)與Transformer模型
2.1 序列到序列任務(wù)與Encoder-Decoder框架
? 序列到序列(Sequence-to-Sequence)是自然語言處理中的一個(gè)常見任務(wù),主要用來做泛文本生成的任務(wù),像機(jī)器翻譯、文本摘要、歌詞/故事生成、對(duì)話機(jī)器人等。最具有代表性的一個(gè)任務(wù)就是機(jī)器翻譯(Machine Translation),將一種語言的序列映射到另一個(gè)語言的序列。例如,在漢-英機(jī)器翻譯任務(wù)中,模型要將一個(gè)漢語句子(詞序列)轉(zhuǎn)化成一個(gè)英語句子(詞序列)。
? 目前Encoder-Decoder框架是解決序列到序列問題的一個(gè)主流模型。模型使用Encoder對(duì)source sequence進(jìn)行壓縮表示,使用Decoder基于源端的壓縮表示生成target sequence。該結(jié)構(gòu)的好處是可以實(shí)現(xiàn)兩個(gè)sequence之間end-to-end方式的建模,模型中所有的參數(shù)變量統(tǒng)一到一個(gè)目標(biāo)函數(shù)下進(jìn)行訓(xùn)練,模型表現(xiàn)較好。圖1展示了Encoder-Decoder模型的結(jié)構(gòu),從底向上是一個(gè)機(jī)器翻譯的過程。
圖1: 使用Encoder-Decoder模型建模序列到序列的問題? Encoder和Decoder可以選用不同結(jié)構(gòu)的Neural Network,比如RNN、CNN。RNN的工作方式是對(duì)序列根據(jù)時(shí)間步,依次進(jìn)行壓縮表示。使用RNN的時(shí)候,一般會(huì)使用雙向的RNN結(jié)構(gòu)。具體方式是使用一個(gè)RNN對(duì)序列中的元素進(jìn)行從左往右的壓縮表示,另一個(gè)RNN對(duì)序列進(jìn)行從右向左的壓縮表示。兩種表示被聯(lián)合起來使用,作為最終序列的分布式表示。使用CNN結(jié)構(gòu)的時(shí)候,一般使用多層的結(jié)構(gòu),來實(shí)現(xiàn)序列局部表示到全局表示的過程。使用RNN建模句子可以看做是一種時(shí)間序列的觀點(diǎn),使用CNN建模句子可以看做一種結(jié)構(gòu)化的觀點(diǎn)。使用RNN結(jié)構(gòu)的序列到序列模型主要包括RNNSearch、GNMT等,使用CNN結(jié)構(gòu)的序列到序列模型主要有ConvS2S等。
2.2 神經(jīng)網(wǎng)絡(luò)模型與語言距離依賴現(xiàn)象
? Transformer是一種建模序列的新方法,序列到序列的模型依然是沿用了上述經(jīng)典的Encoder-Decoder結(jié)構(gòu),不同的是不再使用RNN或是CNN作為序列建模機(jī)制了,而是使用了self-attention機(jī)制。這種機(jī)制理論上的優(yōu)勢就是更容易捕獲“長距離依賴信息(long distance dependency)”。所謂的“長距離依賴信息”可以這么來理解:1)一個(gè)詞其實(shí)是一個(gè)可以表達(dá)多樣性語義信息的符號(hào)(歧義問題)。2)一個(gè)詞的語義確定,要依賴其所在的上下文環(huán)境。(根據(jù)上下文消岐)3)有的詞可能需要一個(gè)范圍較小的上下文環(huán)境就能確定其語義(短距離依賴現(xiàn)象),有的詞可能需要一個(gè)范圍較大的上下文環(huán)境才能確定其語義(長距離依賴現(xiàn)象)。
? 舉個(gè)例子,看下面兩句話:“山上有很多杜鵑,春天到了的時(shí)候,會(huì)漫山遍野的開放,非常美麗?!?“山上有很多杜鵑,春天到了的時(shí)候,會(huì)漫山遍野的啼鳴,非常婉轉(zhuǎn)。”在這兩句話中,“杜鵑”分別指花(azalea)和鳥(cuckoo)。在機(jī)器翻譯問題中,如果不看距其比較遠(yuǎn)的距離的詞,很難將“杜鵑”這個(gè)詞翻譯正確。該例子是比較明顯的一個(gè)例子,可以明顯的看到詞之間的遠(yuǎn)距離依賴關(guān)系。當(dāng)然,絕大多數(shù)的詞義在一個(gè)較小范圍的上下文語義環(huán)境中就可以確定,像上述的例子在語言中占的比例會(huì)相對(duì)較小。我們期望的是模型既能夠很好的學(xué)習(xí)到短距離的依賴知識(shí),也能夠?qū)W習(xí)到長距離依賴的知識(shí)。
? 那么,為什么Transformer中的self-attention理論上能夠更好的捕獲這種長短距離的依賴知識(shí)呢?我們直觀的來看一下,基于RNN、CNN、self-attention的三種序列建模方法,任意兩個(gè)詞之間的交互距離上的區(qū)別。圖2是一個(gè)使用雙向RNN來對(duì)序列進(jìn)行建模的方法。由于是對(duì)序列中的元素按順序處理的,兩個(gè)詞之間的交互距離可以認(rèn)為是他們之間的相對(duì)距離。W1和Wn之間的交互距離是n-1。帶有門控(Gate)機(jī)制的RNN模型理論上可以對(duì)歷史信息進(jìn)行有選擇的存儲(chǔ)和遺忘,具有比純RNN結(jié)構(gòu)更好的表現(xiàn),但是門控參數(shù)量一定的情況下,這種能力是一定的。隨著句子的增長,相對(duì)距離的增大,存在明顯的理論上限。
圖2 使用雙向RNN對(duì)序列進(jìn)行建模? 圖3展示了使用多層CNN對(duì)序列進(jìn)行建模的方法。第一層的CNN單元覆蓋的語義環(huán)境范圍較小,第二層覆蓋的語義環(huán)境范圍會(huì)變大,依次類推,越深層的CNN單元,覆蓋的語義環(huán)境會(huì)越大。一個(gè)詞首先會(huì)在底層CNN單元上與其近距離的詞產(chǎn)生交互,然后在稍高層次的CNN單元上與其更遠(yuǎn)一些詞產(chǎn)生交互。所以,多層的CNN結(jié)構(gòu)體現(xiàn)的是一種從局部到全局的特征抽取過程。詞之間的交互距離,與他們的相對(duì)距離成正比。距離較遠(yuǎn)的詞只能在較高的CNN節(jié)點(diǎn)上相遇,才產(chǎn)生交互。這個(gè)過程可能會(huì)存在較多的信息丟失。
圖3 使用多層CNN對(duì)序列進(jìn)行建模? 圖4展示的是基于self-attention機(jī)制的序列建模方法。注意,為了使圖展示的更清晰,少畫了一些連接線,圖中“sentence”層中的每個(gè)詞和第一層self-attention layer中的節(jié)點(diǎn)都是全連接的關(guān)系,第一層self-attention layer和第二層self-attention layer之間的節(jié)點(diǎn)也都是全連接的關(guān)系。我們可以看到在這種建模方法中,任意兩個(gè)詞之間的交互距離都是1,與詞之間的相對(duì)距離不存在關(guān)系。這種方式下,每個(gè)詞的語義的確定,都考慮了與整個(gè)句子中所有的詞的關(guān)系。多層的self-attention機(jī)制,使得這種全局交互變的更加復(fù)雜,能夠捕獲到更多的信息。
圖4 使用self-attention對(duì)序列進(jìn)行建模? 綜上,self-attention機(jī)制在建模序列問題時(shí),能夠捕獲長距離依賴知識(shí),具有更好的理論基礎(chǔ)。
2.3 self-attention機(jī)制的形式化表達(dá)
? 上面小節(jié)介紹了self-attention機(jī)制的好處,本小結(jié)來介紹一下self-attention機(jī)制的的數(shù)學(xué)形式化表達(dá)。首先,從attention機(jī)制講起??梢詫ttention機(jī)制看做一種query機(jī)制,即用一個(gè)query來檢索一個(gè)memory區(qū)域。我們將query表示為key_q,memory是一個(gè)鍵值對(duì)集合(a set of key-value pairs),共有M項(xiàng),其中的第i項(xiàng)我們表示為<key_m[i], value_m[i]>。通過計(jì)算query和key_m[i]的相關(guān)度,來決定查詢結(jié)果中,value_m[i]所占的權(quán)重比例。注意,這里的key_q,key_m,value_m都是vector。
? Attention的計(jì)算概括起來分三步:1)計(jì)算query和memory中每個(gè)key_m的相關(guān)度。2)對(duì)所有的相關(guān)度結(jié)果使用softmax函數(shù)進(jìn)行概率歸一化處理。3)根據(jù)概率歸一化結(jié)果對(duì)memory中的所有value_m進(jìn)行加權(quán)平均,得到最終的查詢結(jié)果。計(jì)算過程,形式化為:
? 常用的相關(guān)度計(jì)算函數(shù)有基于加法式(additive)的和乘法式(dot-product)的兩種。加法式的函數(shù),先要經(jīng)過一個(gè)前向神經(jīng)網(wǎng)絡(luò)單元,再經(jīng)過一個(gè)線性變換,得到一個(gè)實(shí)數(shù)值。乘法式的函數(shù)則是兩個(gè)向量的直接點(diǎn)乘,得到一個(gè)實(shí)數(shù)值。
? 在Encoder-Decoder框架中,attention機(jī)制一般用于連接Encoder和Decoder,即以Decoder的狀態(tài)作為key,以源語言句子的分布式表示作為memory,從中查找出相關(guān)的源語言信息,生成目標(biāo)語言的詞語。在該機(jī)制中,memory中的key_m和value_m是相同的。在self-attention機(jī)制中,每個(gè)詞匯以自己的embedding為query,查詢由所有詞匯的embedding構(gòu)成的memory空間,得到查詢結(jié)果作為本詞的表示。假如句子長度為n,所有的詞分別查詢一遍memory得到的結(jié)果長度依然會(huì)是n。這些詞的查詢過程是可以并行的。如果relation函數(shù)是乘法式的,那么這個(gè)查詢的過程就是矩陣的乘法,可以形式化為:
在self-attention中,Q=K=V,是一個(gè)由所有詞的詞向量構(gòu)成的一個(gè)矩陣。
綜上,self-attention是一種序列建模的方式,在對(duì)句子進(jìn)行分布式表示的時(shí)候,句子中的所有的詞都會(huì)發(fā)生直接的交互關(guān)系。
2.4 “Attention is All You Need”
? 《Attention Is All You Need》這篇文章,描述了一個(gè)基于self-attention的序列到序列的模型,即“Transformer”。該模型將WMT2014英-德翻譯任務(wù)的BLEU值推到了新高,在英-法翻譯任務(wù)上,接近于之前報(bào)出的最好成績,而這僅僅是Transformer單模型的表現(xiàn)。之前報(bào)出的最好成績都是基于集成方法的,需要訓(xùn)練多個(gè)模型,最后做集成。同時(shí)該模型也被用在英語的成分句法分析任務(wù)上,表現(xiàn)也基本接近于之前報(bào)出的最好模型成績。該模型的收斂速度也非常的快,在英-法3600萬句對(duì)的訓(xùn)練集上,只需要8卡并行3.5天就可以收斂。
? 該模型的表現(xiàn)的如此好的原因,其實(shí)不僅僅是一個(gè)self-attention機(jī)制導(dǎo)致的,實(shí)際上Transformer模型中使用了非常多有效的策略來使得模型對(duì)數(shù)據(jù)的擬合能力更強(qiáng),收斂速度更快。整個(gè)Transformer的模型是一套解決方案,而不僅僅是對(duì)序列建模機(jī)制的改進(jìn)。下面我們對(duì)其進(jìn)行一一講解。
2.4.1 Self-attention機(jī)制的變種
? 首先,還是來講一下Transformer中的self-attention機(jī)制。上面講到了self-attention的基本形式,但是Transformer里面的self-attention機(jī)制是一種新的變種,體現(xiàn)在兩點(diǎn),一方面是加了一個(gè)縮放因子(scaling factor),另一方面是引入了多頭機(jī)制(multi-head attention)。
? 縮放因子體現(xiàn)在Attention的計(jì)算公式中多了一個(gè)向量的維度作為分母,目的是想避免維度過大導(dǎo)致的點(diǎn)乘結(jié)果過大,進(jìn)入softmax函數(shù)的飽和域,引起梯度過小。Transformer中的self-attention計(jì)算公式如下:
多頭機(jī)制是指,引入多組的參數(shù)矩陣來分別對(duì)Q、K、V進(jìn)行線性變換求self-attention的結(jié)果,然后將所有的結(jié)果拼接起來作為最后的self-attention輸出。這樣描述可能不太好理解,一看公式和示意圖就會(huì)明白了,如下:
圖5 單頭和多頭的Attention結(jié)構(gòu)? 這種方式使得模型具有多套比較獨(dú)立的attention參數(shù),理論上可以增強(qiáng)模型的能力。
2.4.2 位置編碼(Positional Encoding)
? self-attention機(jī)制建模序列的方式,既不是RNN的時(shí)序觀點(diǎn),也不是CNN的結(jié)構(gòu)化觀點(diǎn),而是一種詞袋(bag of words)的觀點(diǎn)。進(jìn)一步闡述的話,應(yīng)該說該機(jī)制視一個(gè)序列為扁平的結(jié)構(gòu),因?yàn)椴徽摽瓷先ゾ嚯x多遠(yuǎn)的詞,在self-attention機(jī)制中都為1。這樣的建模方式,實(shí)際上會(huì)丟失詞之間的相對(duì)距離關(guān)系。舉個(gè)例子就是,“牛 吃了 草”、“草 吃了 牛”,“吃了 牛 草”三個(gè)句子建模出來的每個(gè)詞對(duì)應(yīng)的表示,會(huì)是一致的。
? 為了緩解這個(gè)問題,Transformer中將詞在句子中所處的位置映射成vector,補(bǔ)充到其embedding中去。該思路并不是第一次被提出,CNN模型其實(shí)也存在同樣的難以建模相對(duì)位置(時(shí)序信息)的缺陷,Facebook提出了位置編碼的方法。一種直接的方式是,直接對(duì)絕對(duì)位置信息建模到embedding里面,即將詞Wi的i映射成一個(gè)向量,加到其embedding中去。這種方式的缺點(diǎn)是只能建模有限長度的序列。Transformer文章中提出了一種非常新穎的時(shí)序信息建模方式,就是利用三角函數(shù)的周期性,來建模詞之間的相對(duì)位置關(guān)系。具體的方式是將絕對(duì)位置作為三角函數(shù)中的變量做計(jì)算,具體公式如下:
? 該公式的設(shè)計(jì)非常先驗(yàn),尤其是分母部分,不太好解釋。從筆者個(gè)人的觀點(diǎn)來看,一方面三角函數(shù)有很好的周期性,也就是隔一定的距離,因變量的值會(huì)重復(fù)出現(xiàn),這種特性可以用來建模相對(duì)距離;另一方面,三角函數(shù)的值域是[-1,1],可以很好的提供embedding元素的值。
2.4.3 多層結(jié)構(gòu)
? Transformer中的多層結(jié)構(gòu)非常強(qiáng)大,使用了之前已經(jīng)被驗(yàn)證過的很多有效的方法,包括:residual connection、layer normalization,另外還有self-attention層與Feed Forward層的堆疊使用,也是非常值得參考的結(jié)構(gòu)。圖6展示了Transformer的Encoder和Decoder一層的結(jié)構(gòu)。
圖6 Transformer模型結(jié)構(gòu)? 圖6中,左側(cè)的Nx代表一層的Encoder,這一層中包含了兩個(gè)子層(sub-layer),第一個(gè)子層是多頭的self-attention layer,第二個(gè)子層是一個(gè)Feed Forward層。每個(gè)子層的輸入和輸出都存在著residual connection,這種方式理論上可以很好的回傳梯度。Layer Normalization的使用可以加快模型的收斂速度。self-attention子層的計(jì)算,我們前面用了不少的篇幅講過了,這里就不再贅述了。Feed Forward子層實(shí)現(xiàn)中有兩次線性變換,一次Relu非線性激活,具體計(jì)算公式如下:
文章的附頁中將這種計(jì)算方式也看做是一種attention的變種形式。
圖6中,右側(cè)是Decoder中一層的結(jié)構(gòu),這一層中存在三個(gè)子層結(jié)構(gòu),第一層是self-attention layer用來建模已經(jīng)生成的目標(biāo)端句子。在訓(xùn)練的過程中,需要一個(gè)mask矩陣來控制每次self-attention計(jì)算的時(shí)候,只計(jì)算到前t-1個(gè)詞,具體的實(shí)現(xiàn)方式,我們會(huì)在后面講代碼實(shí)現(xiàn)的時(shí)候進(jìn)行說明。第二個(gè)子層是Encoder和Decoder之間的attention機(jī)制,也就是去源語言中找相關(guān)的語義信息,這部分的計(jì)算與其他序列到序列的注意力計(jì)算一致,在Transformer中使用了dot-product的方式。第三個(gè)子層是Feed Forward層,與Encoder中的子層完全一致。每個(gè)子層也都存在著residual connection和layer normalization操作,以加快模型收斂。
Transformer中的這種多層-多子層的機(jī)制,可以使得模型的復(fù)雜度和可訓(xùn)練程度都變高,達(dá)到非常強(qiáng)的效果,值得我們借鑒。
2.4.4 優(yōu)化方法與正則策略
? 模型的訓(xùn)練采用了Adam方法,文章提出了一種叫warm up的學(xué)習(xí)率調(diào)節(jié)方法,如公式所示:
公式比較先驗(yàn),看上去比較復(fù)雜,其實(shí)邏輯表達(dá)起來比較清楚,需要預(yù)先設(shè)置一個(gè)warmup_steps超參。當(dāng)訓(xùn)練步數(shù)step_num小于該值時(shí),以括號(hào)中的第二項(xiàng)公式?jīng)Q定學(xué)習(xí)率,該公式實(shí)際是step_num變量的斜率為正的線性函數(shù)。當(dāng)訓(xùn)練步數(shù)step_num大于warm_steps時(shí),以括號(hào)中的第一項(xiàng)決定學(xué)習(xí)率,該公式就成了一個(gè)指數(shù)為負(fù)數(shù)的冪函數(shù)。所以整體來看,學(xué)習(xí)率呈先上升后下降的趨勢,有利于模型的快速收斂。
模型中也采用了兩項(xiàng)比較重要的正則化方法,一個(gè)就是常用的dropout方法,用在每個(gè)子層的后面和attention的計(jì)算中。另一個(gè)就是label smoothing方法,也就是訓(xùn)練的時(shí)候,計(jì)算交叉熵的時(shí)候,不再是one-hot的標(biāo)準(zhǔn)答案了,而是每個(gè)0值處也填充上一個(gè)非0的極小值。這樣可以增強(qiáng)模型的魯棒性,提升模型的BLEU值。這個(gè)思路其實(shí)也是一定程度在解決訓(xùn)練和解碼過程中存在的exposure bias的問題。
2.4.5 本章小結(jié)
? Transformer系統(tǒng)的強(qiáng)大表現(xiàn),不僅僅是self-attention機(jī)制,還需要上述的一系列配合使用的策略。設(shè)計(jì)該系統(tǒng)的研究者對(duì)深度學(xué)習(xí)模型和優(yōu)化算法有著非常深刻的認(rèn)識(shí)和敏銳的感覺,很多地方值得我們借鑒學(xué)習(xí)。Transformer的代碼實(shí)現(xiàn)工程化比較好,但是也存在一些地方不方便閱讀和理解,后面的章節(jié)中會(huì)對(duì)Transformer的代碼實(shí)現(xiàn)進(jìn)行詳細(xì)講解,將整體結(jié)構(gòu)講清楚,把其中的疑難模塊點(diǎn)出來。
第三章:Tensor2Tensor系統(tǒng)實(shí)現(xiàn)深度解析
? Tensor2Tensor的系統(tǒng)存在一些特點(diǎn),導(dǎo)致使用和理解的時(shí)候可能會(huì)存在一些需要時(shí)間來思考和消化的地方,在此根據(jù)個(gè)人的理解,寫出一些自己曾經(jīng)花費(fèi)時(shí)間的地方。
3.1 使用篇
? Tensor2Tensor的使用是比較方便的,對(duì)于系統(tǒng)中可以支持的問題,直接給系統(tǒng)設(shè)置好下面的信息就可以運(yùn)行了:數(shù)據(jù),問題(problem),模型,超參集合,運(yùn)行設(shè)備。這里的實(shí)現(xiàn)其實(shí)是采用了設(shè)計(jì)模型中的工廠模式,即給定一個(gè)問題名字,返回給相應(yīng)的處理類;給定一個(gè)超參名,返回一套超參的對(duì)象。實(shí)現(xiàn)這種方式的一個(gè)重點(diǎn)文件是utils/registry.py。在系統(tǒng)啟動(dòng)的時(shí)候,所有的問題和超參都會(huì)在registry中注冊(cè),保存到_MODELS,_HPAPAMS,_RANGED_HPARAMS中等待調(diào)用。
? 在此主要以序列到序列的系統(tǒng)使用和實(shí)現(xiàn)為主線進(jìn)行講解。系統(tǒng)的運(yùn)行分三個(gè)階段:數(shù)據(jù)處理,訓(xùn)練,解碼。對(duì)應(yīng)著三個(gè)入口:t2t-datagen,t2t-trainer,t2t-decoder。
數(shù)據(jù)處理的過程包括:
? 1.(下載)讀取訓(xùn)練和開發(fā)數(shù)據(jù)。如果需要使用自己的數(shù)據(jù)的話,可以在問題中指定。
? 2.(讀取)構(gòu)造詞匯表??梢允褂米约侯A(yù)先構(gòu)造好的詞匯表。系統(tǒng)也提供構(gòu)建BPE詞匯表的方法。注意,這里有個(gè)實(shí)現(xiàn)細(xì)節(jié)是系統(tǒng)在抽取BPE詞匯表的時(shí)候,有個(gè)參數(shù),默認(rèn)并非使用全量的數(shù)據(jù)。通過多次迭代嘗試,得到最接近預(yù)設(shè)詞匯表規(guī)模的一個(gè)詞匯表。在大數(shù)據(jù)量的時(shí)候,這個(gè)迭代過程會(huì)非常慢。
? 3. 使用詞匯表將單詞映射成id,每個(gè)句子后會(huì)加EOS_ID,每個(gè)平行句對(duì)被構(gòu)造成一個(gè)dict對(duì)象({‘inputs’:value,‘targets’:value}),將所有對(duì)象序列化,寫入到文件中,供后面訓(xùn)練和評(píng)價(jià)使用。
模型訓(xùn)練的過程的過程主要通過高級(jí)的Tensorflow API來管理,只是需要指定數(shù)據(jù)、問題名、模型名、超參名、設(shè)備信息就可以運(yùn)行了。比較關(guān)鍵的一個(gè)文件是utils/trainer_lib.py文件,在這個(gè)文件中,構(gòu)建Experiment、Estimator、Monitor等來控制訓(xùn)練流程。使用者主要需要設(shè)置的就是訓(xùn)練過程的一些參數(shù),比如訓(xùn)練最大迭代次數(shù),模型評(píng)估的頻率,模型評(píng)估的指標(biāo)等。超參可以直接使用系統(tǒng)已有的參數(shù)集,也可以通過字符串的形式向內(nèi)傳參。簡單的任務(wù)不太需要?jiǎng)映瑓?#xff0c;因?yàn)橄到y(tǒng)中的超參集合基本上都是經(jīng)過實(shí)驗(yàn)效果驗(yàn)證的。需要注意的就是batch_size過大的時(shí)候,可能會(huì)導(dǎo)致顯存不足,導(dǎo)致程序錯(cuò)誤。一般是使用continuous_train_and_eval模式,使模型的訓(xùn)練和評(píng)估間隔進(jìn)行,隨時(shí)可以監(jiān)控模型的表現(xiàn)。
解碼的過程,可以提供整體文件、也可以是基于Dataset的,同時(shí)系統(tǒng)也提供server的方式,可以提供在線的服務(wù),并沒有什么特別好講的。
3.2 深度掌握篇
3.2.1 Tensor2Tensor系統(tǒng)實(shí)現(xiàn)的特點(diǎn)
? 下面列出了要深度掌握Tensor2Tensor系統(tǒng)時(shí),可能因?yàn)槠鋵?shí)現(xiàn)特點(diǎn),會(huì)遇到的一些問題:
? 1. 系統(tǒng)支持多任務(wù),任務(wù)混雜,導(dǎo)致代碼結(jié)構(gòu)比較復(fù)雜。在實(shí)現(xiàn)的時(shí)候,要考慮到整體的結(jié)構(gòu),所以會(huì)存在各種封裝、繼承、多態(tài)的實(shí)現(xiàn)??赡苣阒幌胗闷渲械囊粋€(gè)功能,理解該功能對(duì)應(yīng)的代碼,但是卻需要排除掉大量的不相關(guān)的代碼。
? 2. 系統(tǒng)基于Tensorflow封裝較高的API。使用了Tensorflow中比較高的API來管理模型的訓(xùn)練和預(yù)測,Experiment,Monitor,Estimator,Dataset對(duì)象的使用隱藏了比較多的控制流程,對(duì)于側(cè)重應(yīng)用的用戶來說,可能是是好事情,設(shè)一設(shè)參數(shù)就能跑。但是對(duì)于想了解更多的開發(fā)人員來說,TF該部分的文檔實(shí)在很少,說的也不清楚,很多時(shí)候需要去閱讀源代碼才能知道實(shí)驗(yàn)到底是不是按照自己預(yù)期的進(jìn)行的。這種方式也不太方便找bug和調(diào)試。
? 3. 某些方法調(diào)用比較深。原因應(yīng)該還是出于整體結(jié)構(gòu)和擴(kuò)展性的考慮。這導(dǎo)致了實(shí)現(xiàn)一點(diǎn)很小功能的方法A,需要再調(diào)一個(gè)其他方法B,B再去調(diào)用方法C,實(shí)際上每個(gè)方法中就幾行代碼,甚至有的方法就是空操作。
? 4. 多層繼承和多態(tài)也降低了代碼的可讀性。追溯一個(gè)類的某個(gè)方法的時(shí)候,需要看到其父類的父類的父類。。。這些父類和子類之間的方法又存在著調(diào)來調(diào)去的關(guān)系,同名方法又存在著覆蓋的關(guān)系,所以要花一些時(shí)間來確定當(dāng)前的方法名到底是調(diào)用的的哪個(gè)類中的方法。
? 5. 要求開發(fā)者有模型層面的理解和與代碼實(shí)現(xiàn)的掛鉤??隙ㄊ且岣邔?duì)模型邏輯的理解,但在讀代碼的過程中,會(huì)遇到兩種問題:第一個(gè),代碼實(shí)現(xiàn)的是論文中的功能,但不是論文中的原始公式,可能要做變形以規(guī)避溢出的問題,或是實(shí)現(xiàn)更高的效率;第二個(gè),某些代碼實(shí)現(xiàn)與其論文中的表述存在不一致的情況。
3.2.2 總體邏輯模塊
總體來說,對(duì)T2T系統(tǒng)的代碼邏輯劃分如下,共包括三個(gè)大的模塊:
這里不會(huì)對(duì)代碼做追蹤式的分析,會(huì)分條的講解一些閱讀Tensor2Tensor系統(tǒng)代碼時(shí)可能遇到的問題,點(diǎn)出一些重要的功能所在的位置和實(shí)現(xiàn)邏輯。
9.Estimator對(duì)象。可以理解為模型對(duì)象,可以通過Estimator執(zhí)行模型的訓(xùn)練、評(píng)估、解碼。Estimator對(duì)象最重要的一個(gè)形參是model_fn,也就是具體執(zhí)行訓(xùn)練、評(píng)估、解碼的函數(shù)入口。三個(gè)入口分別對(duì)應(yīng)著三個(gè)EstimatorSpec對(duì)象,如圖9,10所示。
圖9 Estimator中最重要的形參是model_fn 圖10 Estimator中的三種model_fn,實(shí)現(xiàn)三種功能? 從圖10可以看出,用于訓(xùn)練的EstimatorSpec對(duì)象需要描述計(jì)算圖中feature和(loss,train_op)之間的關(guān)系;用于評(píng)估的EstimatorSpec對(duì)象需要描述計(jì)算圖中feature和(loss,eval_metrics_ops)之間的關(guān)系;用于評(píng)估的EstimatorSpec對(duì)象需要描述features和predictions之間的關(guān)系。
\11. Positional encoding的實(shí)現(xiàn)。論文中的實(shí)現(xiàn)和代碼中的實(shí)現(xiàn)存在公式變形和不一致的情況,可能會(huì)導(dǎo)致困惑,故在此指出。論文中Positional encoding中三角函數(shù)的參數(shù)部分公式如下:
? 代碼中的實(shí)現(xiàn)需要對(duì)該公式做變形,以規(guī)避數(shù)值溢出的風(fēng)險(xiǎn),公式變形過程如下:
? 還需要指出的是,論文中根據(jù)維度下標(biāo)的奇偶性來交替使用sin和cos函數(shù)的說法,在代碼中并不是這樣實(shí)現(xiàn)的,而是前一半的維度使用sin函數(shù),后一半的維度使用cos函數(shù),并沒有考慮奇偶性
? 12. **以token數(shù)量作為batch size。**這種方式比起以句子個(gè)數(shù)作為batch size的方式來,能到batch占顯存的空間更加平均,不會(huì)導(dǎo)致因?yàn)橛?xùn)練數(shù)據(jù)導(dǎo)致的顯存占用忽上忽下,造成顯存空間不夠用,導(dǎo)致程序崩潰。
\13. 如何做mask。由于模型是以batch為單位進(jìn)行訓(xùn)練的,batch的句長以其中最長的那個(gè)句子為準(zhǔn),其他句子要做padding。padding項(xiàng)在計(jì)算的過程中如果不處理的話,會(huì)引入噪音,所以就需要mask,來使padding項(xiàng)不對(duì)計(jì)算起作用。mask在attention機(jī)制中的實(shí)現(xiàn)非常簡單,就是在softmax之前,把padding位置元素加一個(gè)極大的負(fù)數(shù),強(qiáng)制其softmax后的概率結(jié)果為0。舉個(gè)例子,[1,1,1]經(jīng)過softmax計(jì)算后結(jié)果約為[0.33,0.33,0.33],[1,1,-1e9] softmax的計(jì)算結(jié)果約為[0.5, 0.5,0]。這樣就相當(dāng)于mask掉了數(shù)組中的第三項(xiàng)元素。在對(duì)target sequence進(jìn)行建模的時(shí)候,需要保證每次只attention到前t-1個(gè)單詞,這個(gè)地方也需要mask,整體的mask是一個(gè)上三角矩陣,非0元素值為一個(gè)極大的負(fù)值。
\14. 基于batch的解碼。解碼的時(shí)候,如果是基于文件的,那么就會(huì)將句子組成batch來并行解碼。這里有個(gè)小trick,就是先對(duì)句子進(jìn)行排序,然后從長的句子開始組batch,翻譯,再把句子恢復(fù)成原先的順序返回。這種方式可以很好的檢測到顯存不足的錯(cuò)誤,因?yàn)榻饩渥幼铋L的一個(gè)batch的時(shí)候,顯存都是夠得,那其他的batch也不存在問題。
總結(jié)
? 本文對(duì)Google的Tensor2Tensor系統(tǒng)進(jìn)行了深度的解讀,涉及到了比較多的方面,筆者也還需要對(duì)其進(jìn)行更加深入的學(xué)習(xí)和研究,希望能夠與對(duì)該模型以及DL for NLP技術(shù)感興趣的同學(xué)們一起交流,共同進(jìn)步!
問答
docker和docker-compose有什么不同?
相關(guān)閱讀
深度學(xué)習(xí)之神經(jīng)網(wǎng)絡(luò)核心原理與算法-歸一化與參數(shù)初始化
啟發(fā)式尋路算法
深度學(xué)習(xí)(5)——RBF算法簡介
此文已由作者授權(quán)騰訊云+社區(qū)發(fā)布,原文鏈接:https://cloud.tencent.com/developer/article/1116709?fromSource=waitui
歡迎大家前往騰訊云+社區(qū)或關(guān)注云加社區(qū)微信公眾號(hào)(QcloudCommunity),第一時(shí)間獲取更多海量技術(shù)實(shí)踐干貨哦~
海量技術(shù)實(shí)踐經(jīng)驗(yàn),盡在云加社區(qū)! https://cloud.tencent.com/developer?fromSource=waitui
總結(jié)
以上是生活随笔為你收集整理的“变形金刚”为何强大:从模型到代码全面解析Google Tensor2Tensor系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c# 对文件的操作
- 下一篇: 多维数据库介绍【转】