TensorFlow深度學習筆記 循環神經網絡實踐


轉載請注明作者:夢里風林
Github工程地址:https://github.com/ahangchen/GDLnotes
歡迎star,有問題可以到Issue區討論
官方教程地址
視頻/字幕下載

加載數據

  • 使用text8作為訓練的文本數據集

text8中只包含27種字符:小寫的從a到z,以及空格符。如果把它打出來,讀起來就像是去掉了所有標點的wikipedia。

  • 直接調用lesson1中maybe_download下載text8.zip
  • 用zipfile讀取zip內容為字符串,並拆分成單詞list
  • 用connections模塊統計單詞數量並找出最常見的單詞

達成隨機取數據的目標

構造計算單元

embeddings = tf.Variable(
        tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
  • 構造一個vocabulary_size x embedding_size的矩陣,作為embeddings容器,
  • 有vocabulary_size個容量為embedding_size的向量,每個向量代表一個vocabulary,
  • 每個向量的中的分量的值都在-1到1之間隨機分布
embed = tf.nn.embedding_lookup(embeddings, train_dataset)
  • 調用tf.nn.embedding_lookup,索引與train_dataset對應的向量,相當於用train_dataset作為一個id,去檢索矩陣中與這個id對應的embedding
loss = tf.reduce_mean(
        tf.nn.sampled_softmax_loss(softmax_weights, softmax_biases, embed,
                                   train_labels, num_sampled, vocabulary_size))
  • 采樣計算訓練損失
optimizer = tf.train.AdagradOptimizer(1.0).minimize(loss)
  • 自適應梯度調節器,調節embedding列表的數據,使得偏差最小

  • 預測,並用cos值計算預測向量與實際數據的夾角作為預測准確度(相似度)指標

傳入數據進行訓練

  • 切割數據用於訓練,其中:
data_index = (data_index + 1) % len(data)
  • 依舊是每次取一部分隨機數據傳入
    • 等距離截取一小段文本
    • 構造訓練集:每個截取窗口的中間位置作為一個train_data
    • 構造標簽:每個截取窗口中,除了train_data之外的部分,隨機取幾個成為一個list,作為label(這里只隨機取了一個)
    • 這樣就形成了根據目標詞匯預測上下文的機制,即Skip-gram
  • 訓練100001次,每2000次輸出這兩千次的平均損失
  • 每10000次計算相似度,並輸出與驗證集中的詞最接近的詞匯列表
  • 用tSNE降維呈現詞匯接近程度
  • 用matplotlib繪制結果

實現代碼見word2vec.py

CBOW

上面訓練的是Skip-gram模型,是根據目標詞匯預測上下文,而word2vec還有一種方式,CBOW,根據上下文預測目標詞匯。

實際上就是將Skip-gram中的輸入輸出反過來。

  • 修改截取數據的方式

    • 構造標簽:每個截取窗口的中間位置作為一個train_label
    • 構造訓練集:每個截取窗口中,除了train_label之外的部分,作為train_data(這里只隨機取了一個)
    • 這樣就形成了根據上下文預測目標詞匯的機制,即CBOW
  • 分別從embeding里找到train_data里每個word對應的vector,用tf.reduce_sum將其相加,將相加結果與train_label比較

# Look up embeddings for inputs.
embed = tf.nn.embedding_lookup(embeddings, train_dataset)
# sum up vectors on first dimensions, as context vectors
embed_sum = tf.reduce_sum(embed, 0)
  • 訓練中依舊是調節embeding的參數來優化loss
  • 訓練結果如下圖,可以看到不同單詞的接近程度

代碼見:
cbow.py

RNN 造句

整體思路是,以一個文本中的一個詞作為train data,后續的所有詞作為train label,從而能夠根據一個給定詞,預測后續的片段。

訓練數據

  • BatchGenerator
  • text: 全部的文本數據
  • text_size:全部文本的字符串長度
  • batch_size:每段訓練數據的大小
  • num_unrollings:要生成的訓練數據段的數目
  • segment:整個訓練數據集可以分成幾個訓練數據片段
  • cursor:重要,
    • 一開始記錄每個訓練數據片段的起始位置坐標,即這個片段位於text的哪個index
    • 執行next_batch生成一個訓練數據的時候,游標會從初始位置自增,直到取夠batch_size個數據
  • last_batch:上一個訓練數據片段
  • 每調用一次next,生成一個num_unrollings長的array,以last_batch開頭,跟着num_unrollings個batch
  • 每個batch的作為train_input,每個batch后面的一個batch作為train_label,每個step訓練num_unrolling個batch

lstm-cell

  • 為了解決消失的梯度問題,引入lstm-cell,增強model的記憶能力
  • 根據這篇論文設計lstm-cell: http://arxiv.org/pdf/1402.1128v1.pdf
  • 分別有三個門:輸入門,遺忘門,輸出門,構成一個cell
    • 輸入數據是num_nodes個詞,可能有vocabulary_size種詞
    • 輸入門:
  input_gate = sigmoid(i * ix + o * im + ib)
- 給輸入乘一個vocabulary_size * num_nodes大小的矩陣,給輸出乘一個num_nodes * num_nodes大小的矩陣;
- 用這兩個矩陣調節對輸入數據的取舍程度
- 用sigmoid這個非線性函數進行激活
  • 遺忘門:
  forget_gate = sigmoid(i * fx + o * fm + fb)

思路同輸入門,用以對歷史數據做取舍

  • 輸出門:
  output_gate = sigmoid(i * ox + o * om + ob)

思路同輸入門,用以對輸出狀態做取舍

  • 組合:
  update = i * cx + o * cm + cb
  state = forget_gate * state + input_gate * tanh(update)
  lstm_cell = output_gate * tanh(state)
- 用同樣的方式構造新狀態update
- 用遺忘門處理歷史狀態state
- 用tanh激活新狀態update
- 用輸入門處理新狀態update
- 整合新舊狀態,再用tanh激活狀態state
- 用輸出門處理state

lstm優化

上面的cell中,update,output_gate,forget_gate,input_gate計算方法都是一樣的,
可以把四組參數分別合並,一次計算,再分別取出:

values = tf.split(1, gate_count, tf.matmul(i, input_weights) + tf.matmul(o, output_weights) + bias)
input_gate = tf.sigmoid(values[0])
forget_gate = tf.sigmoid(values[1])
update = values[2]

再將lstm-cell的輸出扔到一個WX+b中調整作為輸出

實現代碼見singlew_lstm.py

Optimizer

  • 采用one-hot encoding作為label預測
  • 采用交叉熵計算損失
  • 引入learning rate decay

Flow

  • 填入訓練數據到placeholder中
  • 驗證集的准確性用logprob來計算,即對可能性取對數
  • 每10次訓練隨機挑取5個字母作為起始詞,進行造句測試
  • 你可能注意到輸出的sentence是由sample得到的詞組成的,而非選擇概率最高的詞,這是因為,如果一直取概率最高的詞,最后會一直重復這個概率最高的詞

實現代碼見lstm.py

上面的流程里,每次都是以一個字符作為單位,可以使用多一點的字符做預測,取最高概率的那個,防止特殊情況導致的誤判

在這里我們增加字符為2個,形成bigram,代碼見:bigram_lstm.py

主要通過BigramBatchGenerator類實現

Embedding look up

由於bigram情況下,vocabulary_size變為 27*27個,使用one-hot encoding 做predict的話會產生非常稀疏的矩陣,浪費算力,計算速度慢

因此引入embedding_lookup,代碼見embed_bigram_lstm.py

  • 數據輸入:BatchGenerator不再生成one-hot-encoding的向量作為輸入,而是直接生成bigram對應的index列表
  • embedding look up調整embedding,使bigram與vector對應起來
  • 將embedding look up的結果喂給lstm cell即可
  • 輸出時,需要將label和output都轉為One-hot-encoding,才能用交叉熵和softmax計算損失
  • 在tensor里做data到one-hot-encoding轉換時,主要依賴tf.gather函數
  • 在對valid數據做轉換時,主要依賴one_hot_voc函數

Drop out

  • 在lstm cell中對input和output做drop out
  • Refer to this article

Seq2Seq

  • 最后一個問題是,將一個句子中每個詞轉為它的逆序字符串,也就是一個seq到seq的轉換
  • 正經的實現思路是,word 2 vector 2 lstm 2 vector 2 word
  • 不過tensorflow已經有了這樣一個模型來做這件事情:Seq2SeqModel,關於這個模型可以看這個分析
    以及tensorflow的example
  • 只需要從batch中,根據字符串逆序的規律生成target sequence,放到seq2seqmodel里即可,主要依賴rev_id函數
  • 實現見seq2seq.py
  • 注意,用Seq2SeqModel的時候,size和num_layer會在學習到正確的規律前就收斂,我把它調大了一點
def create_model(sess, forward_only):
    model = seq2seq_model.Seq2SeqModel(source_vocab_size=vocabulary_size,
                                       target_vocab_size=vocabulary_size,
                                       buckets=[(20, 21)],
                                       size=256,
                                       num_layers=4,
                                       max_gradient_norm=5.0,
                                       batch_size=batch_size,
                                       learning_rate=1.0,
                                       learning_rate_decay_factor=0.9,
                                       use_lstm=True,
                                       forward_only=forward_only)
    return model
  • 參數含義
    • source_vocab_size: size of the source vocabulary.
    • target_vocab_size: size of the target vocabulary.
    • buckets: a list of pairs (I, O), where I specifies maximum input length
      that will be processed in that bucket, and O specifies maximum output
      length. Training instances that have inputs longer than I or outputs
      longer than O will be pushed to the next bucket and padded accordingly.
      We assume that the list is sorted, e.g., [(2, 4), (8, 16)].
    • size: number of units in each layer of the model.
    • num_layers: number of layers in the model.
    • max_gradient_norm: gradients will be clipped to maximally this norm.
    • batch_size: the size of the batches used during training;
      the model construction is independent of batch_size, so it can be
      changed after initialization if this is convenient, e.g., for decoding.
    • learning_rate: learning rate to start with.
    • learning_rate_decay_factor: decay learning rate by this much when needed.
    • use_lstm: if true, we use LSTM cells instead of GRU cells.
    • num_samples: number of samples for sampled softmax.
    • forward_only: if set, we do not construct the backward pass in the model.

參考鏈接

覺得我的文章對您有幫助的話,不妨點個star

土豪可以打賞支持,一分也是愛:

圖片名稱


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM