基於LSTM語言模型的文本生成
1. 文本生成
1.1 基於語言模型的文本生成
基於馬爾科夫的語言模型且在數據驅動下的自然語言生成。利用數據和文字間的對齊語料,使用N-gram語言模型生成文本。在語言模型上加入句法分析(關系抽取、實體識別、依存句法、短語結構等)還可以顯著改善生成效果。因為這些都建立在句子理解的基礎上,文本生成的過程需要考慮歷史信息,處理長距離的依賴關系情況,如語義連貫性。
標准定義:對於語言序列\(w_1,w_2,…… w_n\), 語言模型就是計算該序列出現的概率,即
也即是語言模型描述了這些單詞組成這個語言序列(句子)的分率分布。
馬爾可夫假設,當前詞只依賴前面n-1個詞。
應用:
-
候選句打分。常應用在文本糾錯、語音識別等場景中。比如
\[𝑃(𝐼\quad 𝑎𝑚\quad ℎ𝑎𝑝𝑝𝑦)>𝑃(𝐼\quad 𝑎𝑚\quad ℎ𝑎𝑝𝑝𝑒𝑛) \] -
文本生成。比如廣告文案、機器人寫作、機器翻譯。
1.2 使用深度學習方法的文本生成
按照輸入數據的區別,文本生成任務可以分成三類:文本到文本的生成,結構化數據生成文本,圖像到文本的生成。
基於深度學習的文本生成,常用的是Seq2Seq模型(encoder-decoder)。利用Attention機制的Seq2Seq模型可以加強單詞和特征之間的對齊,在生成文字的時候,模擬人看東西時關注點逐漸轉移的過程,以生成更符合人習慣的文本。
1.3 Sampling問題
基於Seq2Seq模型的文本生成有各種不同的decoding strategy。文本生成中的decoding strategy主要可以分為兩大類:
- Argmax Decoding: 主要包括beam search, class-factored softmax等
- Stochastic Decoding: 主要包括temperature sampling, top-k sampling等。
在Seq2Seq模型中,RNN Encoder對輸入句子進行編碼,生成一個大小固定的hidden state ;基於輸入句子的hidden state \(h_c\) 和先前生成的第1到t-1個詞\(x_{1:t-1}\),RNN Decoder會生成當前第t個詞的hidden state \(h_t\) ,最后通過softmax函數得到第t個詞 \(x_t\) 的vocabulary probability distribution \(P(x|x_{1:t-1})\)。
兩類decoding strategy的主要區別就在於,如何從vocabulary probability distribution \(P(x|x_{1:t-1})\)中選取一個詞 \(x_t\) :
- Argmax Decoding的做法是選擇詞表中probability最大的詞,即\(x_t=argmax\quad P(x|x_{1:t-1})\) ;
- Stochastic Decoding則是基於概率分布\(P(x|x_{1:t-1})\) 隨機sample一個詞 $x_t $,即 \(x_t \sim P(x|x_{1:t-1})\) 。
在做seq predcition時,需要根據假設模型每個時刻softmax的輸出概率來sample單詞,合適的sample方法可能會獲得更有效的結果。
1.3.1 貪婪采樣
-
Greedy Search
核心思想:每一步取當前最大可能性的結果,作為最終結果。
具體方法:獲得新生成的詞是vocab中各個詞的概率,取argmax作為需要生成的詞向量索引,繼而生成后一個詞。
-
Beam Search
核心思想: beam search嘗試在廣度優先基礎上進行進行搜索空間的優化(類似於剪枝)達到減少內存消耗的目的。
具體方法:在decoding的每個步驟,我們都保留着 top K 個可能的候選單詞,然后到了下一個步驟的時候,我們對這 K 個單詞都做下一步 decoding,分別選出 top K,然后對這 K^2 個候選句子再挑選出 top K 個句子。以此類推一直到 decoding 結束為止。當然 Beam Search 本質上也是一個 greedy decoding 的方法,所以我們無法保證自己一定可以得到最好的 decoding 結果。
Greedy Search和Beam Search存在的問題:
- 容易出現重復的、可預測的詞;
- 句子/語言的連貫性差。
1.3.2 隨機采樣
核心思想: 根據單詞的概率分布隨機采樣。
-
Temperature Sampling:
具體方法:在softmax中引入一個temperature來改變vocabulary probability distribution,使其更偏向high probability words:
\[P(x|x_{1:t-1})=\frac{exp(u_t/temperature)}{\sum_{t'}exp(u_{t'}/temperature)},temperature\in[0,1) \]另一種表示:假設\(p(x)\)為模型輸出的原始分布,給定一個 temperature 值,將按照下列方法對原始概率分布(即模型的 softmax 輸出) 進行重新加權,計算得到一個新的概率分布。
\[\pi(x_{k})=\frac{e^{log(p(x_k))/temperature}} {\sum_{i=1}^{n}e^{log(p(x_i))/temperature}},temperature\in[0,1) \]當\(temperature \to 0\),就變成greedy search;當\(temperature \to \infty\),就變成均勻采樣(uniform sampling)。詳見論文:The Curious Case of Neural Text Degeneration
-
Top-k Sampling:
可以緩解生成罕見單詞的問題。比如說,我們可以每次只在概率最高的50個單詞中按照概率分布做采樣。我只保留top-k個probability的單詞,然后在這些單詞中根據概率做sampling。
核心思想:對概率進行降序排序,然后對第k個位置之后的概率轉換為0。
具體方法:在decoding過程中,從 \(P(x|x_{1:t-1})\) 中選取probability最高的前k個tokens,把它們的probability加總得到 \(p'=\sum P(x|x_{1:t-1})\) ,然后將 \(P(x|x_{1:t-1})\) 調整為 \(P'(x|x_{1:t-1})=P(x|x_{1:t-1})/p'\) ,其中 \(x\in V^{(k)}\)! ,最后從 \(P'(x|x_{1:t-1})\) 中sample一個token作為output token。詳見論文:Hierarchical Neural Story Generation
但Top-k Sampling存在的問題是,常數k是提前給定的值,對於長短大小不一,語境不同的句子,我們可能有時需要比k更多的tokens。
-
Top-p Sampling (Nucleus Sampling ):
核心思想:通過對概率分布進行累加,然后當累加的值超過設定的閾值p,則對之后的概率進行置0。
具體方法:提出了Top-p Sampling來解決Top-k Sampling的問題,基於Top-k Sampling,它將 \(p'=\sum P(x|x_{1:t-1})\) 設為一個提前定義好的常數\(p'\in(0,1)\) ,而selected tokens根據句子history distribution的變化而有所不同。詳見論文:The Curious Case of Neural Text Degeneration
本質上Top-p Sampling和Top-k Sampling都是從truncated vocabulary distribution中sample token,區別在於置信區間的選擇。
隨機采樣存在的問題:
- 生成的句子容易不連貫,上下文比較矛盾。
- 容易生成奇怪的句子,出現罕見詞。
2. RNN技術選型
應用:
- 點對點 :特征到特征,特征變換
- 點到面:圖像文本生成,圖像描述(圖像到文本的生成)
- 序列分類:文本分類(結構化數據生成文本),多模態文本分類
- 適用序列不對齊,長度不相等,沒有一一對應關系:機器翻譯(通過調節Encoder-Decoder隱含層的長度來控制輸出長度不同)(文本到文本的生成)
- 適用序列里一一對應:序列標注,NER(文本到文本的生成)
3. 實戰:基於字符使用LSTM生成文本
- data_utils.py:數據預處理:產生批數據、構建word2id詞典。
- model.py:構建多層LSTM堆疊的模型,定義采樣函數temperature sampling、top-k sampling。
- train.py:主要是訓練LSTM模型,流程包括讀取訓練文本、加載/生成詞典、生成批數據、定義模型框架和模型訓練。
- inference.py:根據訓練好的LSTM模型,給出一小段文本,通過反復采樣下一個字符/單詞,生成固定長度的文本。
3.1 如何生成序列數據
用深度學習生成序列數據的通用方法,就是使用前面的標記作為輸入,訓練一個網絡(通常是循環神經網絡或卷積神經網絡)來預測序列中接下來的一個或多個標記。例如,給定輸入the cat is on the ma,訓練網絡來預測目標 t,即下一個字符。與前面處理文本數據時一樣, 標記( token)通常是單詞或字符,給定前面的標記,能夠對下一個標記的概率進行建模的任何網絡都叫作語言模型( language model)。語言模型能夠捕捉到語言的潛在空間( latent space),即語言的統計結構。
一旦訓練好了這樣一個語言模型,就可以從中采樣( sample,即生成新序列)。向模型中輸入一個初始文本字符串[即條件數據( conditioning data)],要求模型生成下一個字符或下一個單詞(甚至可以同時生成多個標記),然后將生成的輸出添加到輸入數據中,並多次重復這一過程(見圖 8-1)。這個循環可以生成任意長度的序列,這些序列反映了模型訓練數據的結構,它們與人類書寫的句子幾乎相同。
在實戰示例中,我們將會用到一個 LSTM 層,向其輸入從文本語料中提取的 N 個字符組成的字符串,然后訓練模型來生成第 N+1 個字符。模型的輸出是對所有可能的字符做 softmax,得到下一個字符的概率分布。這個 LSTM 叫作字符級的神經語言模型( character-level neural language model)。
3.2 采樣策略
生成文本時,如何選擇下一個字符至關重要。
-
貪婪采樣( greedy sampling),就是始終選擇可能性最大的下一個字符。但這種方法會得到重復的、可預測的字符串,看起來不像是連貫的語言。
-
隨機采樣( stochastic sampling),在采樣過程中引入隨機性,即從下一個字符的概率分布中進行采樣。這種從模型的softmax輸出中進行概率采樣的方法有一個問題:在采樣過程中無法控制隨機性的大小。假設\(p(x)\)為模型輸出的原始分布,則基於softmax采樣得到的新分布:
\[\pi(x_{k})=\frac{e^{log(p(x_k))}}{\sum_{i=1}^{n}e^{log(p(x_i))}} \]在這種情況下,根據模型結果,如果下一個字符是 e 的概率為0.3,那么你會有 30% 的概率選擇它。注意,貪婪采樣也可以被看作從一個概率分布中進行采樣,即某個字符的概率為 1,其他所有字符的概率都是 0 。
為了在采樣過程中控制隨機性的大小,我們引入一個叫作 softmax 溫度( softmax temperature)的參數,用於表示采樣概率分布的熵,即表示所選擇的下一個字符會有多么出人意料或多么可預測。給定一個 temperature 值,將按照下列方法對原始概率分布(即模型的 softmax 輸出) 進行重新加權,計算得到一個新的概率分布。
\[ \pi(x_{k})=\frac{e^{log(p(x_k))/temperature}} {\sum_{i=1}^{n}e^{log(p(x_i))/temperature}},temperature\in[0,1) \]更高的temperature得到的是熵更大的采樣分布,會生成更加出人意料、更加無結構的生成數據,而更低的temperature對應更小的隨機性,以及更加可預測的生成數據。
3.3 實現字符級的LSTM文本生成
文本序列生成的程序流程:
-
准備並解析初始樣本
-
讀取訓練樣本
-
加載/生成詞典
建立word2index,index2word表。
-
數據預處理:生成批次(Batch generation)
數據格式的預處理:batch_generator(data, batch_size, n_steps).
數據的連續采樣,要求相鄰批次的序列是連續的。需要設置一個批次/周期內的序列個數(batch_size)以及每個序列中所含字符數(n_steps),這樣可以得到一個批次/周期數量。
def batch_generator(data, batch_size, n_steps): data = copy.copy(data) batch_steps = batch_size * n_steps n_batches = int(len(data) / batch_steps) data = data[:batch_size * n_batches] data = data.reshape((batch_size, -1)) while True: np.random.shuffle(data) for n in range(0, data.shape[1], n_steps): x = data[:, n:n + n_steps] y = np.zeros_like(x) y[:, :-1], y[:, -1] = x[:, 1:], x[:, 0] yield x, y
假設訓練集含有30個字符,調用batch_generator(data, 2, 6).
每個batch的行數就是每個周期的句子數,列數就是 len(data) // batch_size得到的數值。
\[batch\_size=2:\begin{cases} [[\overbrace{0.,1.,2.,3.,4.,5.},\overbrace{6.,7.,8.,9.,10.,11.},12.,13.,14.],\\ [\underbrace{15.,16.,17.,18.,19.,20.},\underbrace{21.,22.,23.,24.,25.,26.},27.,28.,29.]] \end{cases} \] -
構建神經網絡模型
這個網絡是由多層LSTM堆疊組成,然后根據所有時刻的輸出lstm_outputs,對詞典中所有詞的softmax得到概率。
-
訓練語言模型並采樣
采樣策略:貪婪采樣,隨機采樣
采樣函數可以選擇Temperature Sampling或Top-k Sampling,分別根據模型得到的原始概率分布進行重新加權或限定top-k個概率構建新的概率分布,並從中抽取一個字符索引。
-
用模型生成文本
給定一個訓練好的模型和一個種子文本片段,可以通過重復以下操作生成新的文本。
- 給定目前已生成的文本,從模型中得到下一個字符的概率。
- 根據某個溫度對分布進行重新加權。
- 根據重新加權后的分布對下一個字符進行隨機采樣。
- 將新字符添加至文本末尾。
3.4 模型評價
如何對生成的文本進行評價也是文本生成研究中重要的一環。
3.4.1 文本內在評價
內在評價關注文本的正確性、流暢度和易理解性。常見的內在評價方法又可分為兩類:1)采用BLEU、NIST和ROUGE等進行自動化評價,評估生成文本和參考文本間相似度來衡量生成質量。2)通過人工評價,從有用性等對文本進行打分。
-
BLEU
找出輸出句子與參考句子之間的 n-gram重疊部分並對(比參考句子)更短的輸出句子施以懲罰的評價方法。
論文地址:BLEU: a Method for Automatic Evaluation of Machine Translation
-
NIST
它基於 n-gram 的稀缺性對其進行加權。這就意味着對某個稀缺 n-gram的正確匹配能提高的分數,要多於對某個常見的 n-gram的正確匹配。
論文地址:Automatic Evaluation of Machine Translation QualityUsing N-gram Co-Occurrence Statistics
-
ROUGE
由於BLEU只考慮了精確率而沒有考慮召回率,因此,在2004年,Chin-Yew Lin提出了一種新的評估方法ROUGE,該方法主要是從召回率的角度計算生成文本與參考文本之間的相似性,比較適用於文本摘要任務,因為文本摘要我們更考察生成文本包括了多少參考文本中包含的信息。作者在論文中總共提出了4種不同的計算方式:ROUGE-N、ROUGE-L、ROUGE-W、ROUGE-S。
它對 BLEU 進行了修改,聚焦於召回率而非准確率。換句話說,該方法看重的是參考翻譯句中有多少 n-gram出現在輸出句中,而不是輸出句中有多少 n-gram出現在參考翻譯句中。
-
METROR
BLEU只考慮精確率,METEOR則同時考慮精確率和召回率,采用加權的F值來作為評估指標。
論文地址:Meteor: An Automatic Metric for MT Evaluation with High Levels of Correlation with Human Judgments
3.4.2 外在評價
外在評價則關注生成文本在實際應用中的可用性。
3.4.3 其他
困惑度(perplexity):是交叉熵的指數形式。給定一個包含n個詞的測試文本\(W=(w_1,w_2,...,w_n)\)和語言模型N-gram:\(P(w_1,w_2,...,w_n)=\prod_{i=1}^{n}P(w_i|w_{i-N+1},...,w_{i-1})\) 的困惑度perplexity可定義為交叉熵的指數形式:
perplexity和交叉熵一樣都可以用來評價語言模型的好壞。 對於測試集其困惑度越小,准確率也就越高,語言模型也就越好。
perplexity刻畫的是語言模型預測一個語言樣本的能力,比如已經知道了 \(W=(w_1,w_2,...,w_n)\) 這句話會出現在語料庫之中,那么通過語言模型計算得到這句話的概率越高,說明語言模型對這個語料庫擬合的越好。
4. 參考
LSTM文本生成:《Python深度學習》第8章第1節:8.1 使用LSTM生成文本P228-P234。