1. 程式人生 > >【tensorflow 學習】seq2seq模型程式碼解讀

【tensorflow 學習】seq2seq模型程式碼解讀

這裡寫圖片描述

1. sequence-to-sequence模型

官方教程使用seq2seq模型實現了英語-法語的翻譯系統。經典的sequence-to-sequence模型由兩個RNN網路構成,一個被稱為“encoder”,另一個則稱為“decoder”,前者負責把序列編碼成一個固定長度的向量,這個向量作為輸入傳給後者,輸出可變長度的向量,它的基本網路結構如下,
這裡寫圖片描述

其中每一個小圓圈代表一個cell,比如GRUcell、LSTMcell、multi-layer-GRUcell、multi-layer-GRUcell等。儘管“encoder”或者“decoder”內部存在權值共享,但encoder和decoder之間一般具有不同的一套引數。

2. 注意力機制(attention mechanism)

考慮到encoder將輸入seq編碼成一個向量,基本的decoder與encoder的互動僅在decoder初始的輸入上,這樣對於decoder而言,只能看到源資訊的一個總體概要,會限制encoder-decoder架構的效能。
基於這個缺點進行了改進, 在翻譯階段, 準備生成每個新的詞的時候, 注意力機制可以將注意力集中在輸入的某個或某幾個詞上,重點關注這幾個詞, 使得翻譯更精準。新的模型架構如下圖所示。
這裡寫圖片描述

3. seq2seq_model.py 解讀

機器學習模型的定義過程,一般包括輸入變數定義、輸入資訊的forward propagation和誤差資訊的backward propagation三個部分

,這三個部分在這個程式檔案中都得到了很好的體現,下面我們結合程式碼分別進行介紹。

先來看一下seq2seq函式

def seq2seq_f(encoder_inputs, decoder_inputs, do_decode):
    return tf.contrib.legacy_seq2seq.embedding_attention_seq2seq(
        encoder_inputs,# tensor of input seq
        decoder_inputs,# tensor of decoder seq
        cell, #自定義的cell,可以是GRU/LSTM, 設定multilayer等
num_encoder_symbols=source_vocab_size, # 英語詞典大小 40000 num_decoder_symbols=target_vocab_size, # 法語詞典大小 40000 embedding_size=size, # embedding 維度 output_projection=output_projection, # 不設定的話輸出維數可能很大(取決於詞表大小),設定的話投影到一個低維向量 feed_previous=do_decode, # false: 訓練 ;True: 測試 dtype=dtype)

3.1 輸入變數的定義

    # Feeds for inputs.
        self.encoder_inputs = []
        self.decoder_inputs = []
        self.target_weights = []
        for i in xrange(buckets[-1][0]):  # Last bucket is the biggest one.
            self.encoder_inputs.append(tf.placeholder(tf.int32, shape=[None],
                                                      name="encoder{0}".format(i)))
#encoder_inputs 這個列表物件中的每一個元素表示一個佔位符,其名字分別為encoder0, encoder1,…,encoder39,encoder{i}的幾何意義是編碼器在時刻i的輸入。
        for i in xrange(buckets[-1][1] + 1):
            self.decoder_inputs.append(tf.placeholder(tf.int32, shape=[None],
                                                      name="decoder{0}".format(i)))
            self.target_weights.append(tf.placeholder(dtype, shape=[None],
                                                      name="weight{0}".format(i)))
#target_weights 是一個與 decoder_outputs 大小一樣的 0-1 矩陣。該矩陣將目標序列長度以外的其他位置填充為標量值 0。
        # Our targets are decoder inputs shifted by one.
        targets = [self.decoder_inputs[i + 1]
                   for i in xrange(len(self.decoder_inputs) - 1)]
       # 跟language model類似,targets變數是decoder inputs平移一個單位的結果,

3.2 輸入資訊的forward propagation

# 區別在於seq2seq_f函式的引數feed previous是True還是false
if forward_only: # 測試階段
    self.outputs, self.losses = tf.contrib.legacy_seq2seq.model_with_buckets(#??
        self.encoder_inputs, self.decoder_inputs, targets,
        self.target_weights, buckets, lambda x, y: seq2seq_f(
            x, y, True),
        softmax_loss_function=softmax_loss_function)
    # If we use output projection, we need to project outputs for
    # decoding.
    if output_projection is not None:
        for b in xrange(len(buckets)):
            self.outputs[b] = [
                tf.matmul(output, output_projection[
                          0]) + output_projection[1]
                for output in self.outputs[b]
            ]
else:#訓練階段
    self.outputs, self.losses = tf.contrib.legacy_seq2seq.model_with_buckets(
        self.encoder_inputs, self.decoder_inputs, targets,
        self.target_weights, buckets,
        lambda x, y: seq2seq_f(x, y, False),
        softmax_loss_function=softmax_loss_function)

從程式碼中可以看到,輸入資訊的forward popagation分成了兩種情況,這是因為整個sequence to sequence模型在訓練階段和測試階段資訊的流向是不一樣的,這一點可以從seq2seqf函式的do_decode引數值體現出來,而do_decoder取值對應的就是tf.nn.seq2seq.embedding_attention_seq2seq函式中的feed_previous引數,forward_only為True也即feed_previous引數為True時進行模型測試,為False時進行模型訓練。

3.3 誤差資訊的backward propagation

params = tf.trainable_variables() 
if not forward_only:# 只有訓練階段才需要計算梯度和引數更新
    self.gradient_norms = []
    self.updates = []
    opt = tf.train.GradientDescentOptimizer(self.learning_rate) # 用梯度下降法優化
    for b in xrange(len(buckets)):
        gradients = tf.gradients(self.losses[b], params) #計算損失函式關於引數的梯度
        clipped_gradients, norm = tf.clip_by_global_norm(gradients, 
                                                         max_gradient_norm)# clip gradients 防止梯度爆炸
        self.gradient_norms.append(norm)
        self.updates.append(opt.apply_gradients(
            zip(clipped_gradients, params), global_step=self.global_step))#更新引數

這一段程式碼主要用於計算損失函式關於引數的梯度。因為只有訓練階段才需要計算梯度和引數更新,所以這裡有個if判斷語句。並且,由於當前定義除了length(buckets)個graph,故返回值self.updates是一個列表物件,尺寸為length(buckets),列表中第i個元素表示graph{i}的梯度更新操作。
訓練 RNN 的一個重要步驟是梯度截斷(gradient clipping)。這裡,我們使用全域性範數進行截斷操作。最大值 max_gradient_norm 通常設定為 5 或 1。

3.4 模型訓練

    # Input feed: encoder inputs, decoder inputs, target_weights, as
    # provided.
    input_feed = {}
    for l in xrange(encoder_size):
        input_feed[self.encoder_inputs[l].name] = encoder_inputs[l]
    for l in xrange(decoder_size):
        input_feed[self.decoder_inputs[l].name] = decoder_inputs[l]
        input_feed[self.target_weights[l].name] = target_weights[l]

    # Since our targets are decoder inputs shifted by one, we need one
    # more.
    last_target = self.decoder_inputs[decoder_size].name
    input_feed[last_target] = np.zeros([self.batch_size], dtype=np.int32)

    # Output feed: depends on whether we do a backward step or not.
    if not forward_only:
        output_feed = [self.updates[bucket_id],  # Update Op that does SGD.
                       self.gradient_norms[bucket_id],  # Gradient norm.
                       self.losses[bucket_id]]  # Loss for this batch.
    else:
        output_feed = [self.losses[bucket_id]]  # Loss for this batch.
        for l in xrange(decoder_size):  # Output logits.
            output_feed.append(self.outputs[bucket_id][l])

    outputs = session.run(output_feed, input_feed)
    if not forward_only:
        # Gradient norm, loss, no outputs.
        return outputs[1], outputs[2], None
    else:
        # No gradient norm, loss, outputs.
        return None, outputs[0], outputs[1:]

模型已經定義完成了,這裡便開始進行模型訓練了。上面的兩個for迴圈用於為之前定義的輸入佔位符賦予具體的數值,這些具體的數值源自於get_batch函式的返回值。當session.run函式開始執行時,當前session會對第bucket_id個graph進行引數更新操作。

相關推薦

tensorflow 學習seq2seq模型程式碼解讀

1. sequence-to-sequence模型 官方教程使用seq2seq模型實現了英語-法語的翻譯系統。經典的sequence-to-sequence模型由兩個RNN網路構成,一個被稱為“encoder”,另一個則稱為“decoder”,前者負責

ROS學習Solidworks模型轉化為URDF檔案格式+三連桿機械臂示例+逆運動學

URDF(Universal Robot Description Format)——通用機器人描述格式,它是ROS裡邊使用的一種機器人的描述檔案,包含的內容有:連桿、關節,運動學和動力學引數、視覺化模型、碰撞檢測模型等。 到目前為止,本文的主要內容有兩個:(1)將solidworks

機器學習生成模型和判別模型

定義: 生成方法由資料學習聯合概率分佈P(x, y),然後求出條件概率分佈P(y|x)作為預測的模型。 包括樸素貝葉斯,貝葉斯網路,高斯混合模型,隱馬爾科夫模型等。 判別方法由資料直接學習決策函式

tensorflow 學習tf.get_variable()和tf.Variable()的區別

1. tf.Variable() W = tf.Variable(<initial-value>, name=<optional-name>) 用於生成一個初始值為initial-value的變數。必須指定初始化值 2.tf.get_variab

Tensorflow學習 RNN

cell = tf.contrib.rnn.BasicLSTMCell(n_hidden_units)   init_state = cell.zero_state(batch_size, dtype=tf.float32) outputs, final_state =

tensorflow 學習 gpu使用

由於tensorflow預設搶佔伺服器所有GPU視訊記憶體,只允許一個小記憶體的程式也會佔用所有GPU資源。下面提出使用GPU執行tensorflow的幾點建議: 1.在執行之前先檢視GPU的使用情況: $ nvidia-smi # 檢視GPU此時的使用情況 或者 $

機器學習演算法模型效能中的偏差、方差概念

什麼時候模型的複雜程度該停止? 模型越複雜,單次預測出的結果與真實結果的偏差(bias)就越小。但很容易引發過擬合。 模型越簡單,預測不同資料,預測的準確性差別越小。預測不同資料,所得到的準確性構成序列,序列的方差(variance)也就越小。

深度學習CNN模型的視覺化-1

CNN模型學到的東西很適合視覺化,這裡介紹三種方法: 視覺化CNN模型的中間輸出(中間啟用):幫助我們理解CNN是如何對輸入進行變換,以及CNN每個卷積核的含義 視覺化CNN的卷積核:幫助我們理解卷積核容易接受的視覺模式或概念 客戶刷影象中類啟用的熱力圖:影象中哪

機器學習線性迴歸+程式碼實現

參考:《機器學習實戰》 原始碼地址以及資料:https://github.com/JieruZhang/MachineLearninginAction_src 1. 標準線性迴歸(LR) y

機器學習判別模型vs生成模型

判別模型vs生成模型 條件概率分佈p(y|x) 從概率的角度來看監督學習的話,其實就是從資料集中學習條件概率分佈p(y|x)。其中,x∈Rn表示n維資料特徵,y∈R表示資料對應的類別標籤。給定一個x,模型計算出x屬於各個類別標籤y的概率p(y|x),然後

tensorflow 學習 name_scope和variable_scope的區別

在tensorflow中,有兩個scope, 一個是name_scope一個是variable_scope,這兩個scope到底有什麼區別呢?  三個例子 先看第一個程式: with tf.name_scope("hello") as name_scope: a

SSH學習--Structs2模型驅動與屬性驅動

兩種方式 When:當你從jsp介面調到action時, 屬性驅動 屬性驅動需要你在action中定義屬性,這些屬性就是jsp表單屬性,當你從jsp介面跳到action,struts的攔截器就會呼叫你的action的setxx方法,將你表單的屬性注入act

tensorflow 學習tf.split()和tf.squeeze()

split( value, num_or_size_splits, axis=0, num=None, name='split' ) 輸入: value: 輸入的tensor num_or_size_splits:

機器學習KNN及程式碼實戰

一、KNN分類思想 二、例子一 1.情景 如下圖,這裡共有四個點,兩個B類,兩個A類。[1,1.1]-A 、[1,1]-A 、[0,0]-B 、[0,0.1]-B。現在我們輸入點[0,0],要求KNN分類器幫我們分類,判斷點[0,0]是A類

tensorflow 學習給LSTM加上L2正則化

首先,用tf.trainable_variables()得到所有weights和bias, 然後,用tf.nn.l2_loss()計算L2 norm, 求和之後作為正則項加給原來的cost function tv = tf.trainable_vari

深度學習ResNet解讀程式碼實現

簡介 ResNet是何凱明大神在2015年提出的一種網路結構,獲得了ILSVRC-2015分類任務的第一名,同時在ImageNet detection,ImageNet localization,COCO detection和COCO segmentation等任務中均獲得了第一名,在當

深度學習Ubuntu16.04+tensorflow+opencv+pygame 執行FlappyBird(畫素小鳥)程式碼(4)

一,安裝 Anaconda+tensorflow 我的系統環境: Ubuntu16.04, Anaconda(python 3.6) opencv3.1 二,下載程式碼+安裝opencv

機器學習seq2seq模型與attention機制,Beam Search

Beam Search一張圖來表示 貪心的做法:每次選擇輸出概率最大的那個單詞,但是這樣無法保證最終整體概率最大;而集束搜尋每次會選擇Beam個概率最大的單詞(Beam表示每次選擇單詞數,本例中為3),然後進行下一步...直到最後會得到Beam個句子,挑出概率最大的那句

機器學習隨機森林 Random Forest 得到模型後,評估參數重要性

img eas 一個 increase 裏的 sum 示例 增加 機器 在得出random forest 模型後,評估參數重要性 importance() 示例如下 特征重要性評價標準 %IncMSE 是 increase in MSE。就是對每一個變量 比如 X1

深度學習常用的模型評估指標

是我 初學者 cnblogs 沒有 線下 均衡 顯示 總數 效果 “沒有測量,就沒有科學。”這是科學家門捷列夫的名言。在計算機科學中,特別是在機器學習的領域,對模型的測量和評估同樣至關重要。只有選擇與問題相匹配的評估方法,我們才能夠快速的發現在模型選擇和訓練過程中可能出現的