轉載請注明作者:夢里風林
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
Beam Search
上面的流程里,每次都是以一個字符作為單位,可以使用多一點的字符做預測,取最高概率的那個,防止特殊情況導致的誤判
在這里我們增加字符為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?
土豪可以打賞支持,一分也是愛:
