1. 程式人生 > >Tensorflow建立迴圈神經網路

Tensorflow建立迴圈神經網路

雖然已經接觸deep learning很長一段時間了,也看了很久rnn相關的程式碼,但是突然想用tensorflow實現一些功能的時候,突然發現絲毫沒有頭緒,找了一些資料,學習了一波,記錄一下。

一、tensorflow實現RNN cell

tensorflow由於不同的版本改動較大,在1.0版本之後,可以使用如下語句來建立一個cell:
from tensorflow.contrib import rnn
cell_fun = rnn.GRUCell(rnn_hidden_size)

在tensorflow中,上述GRUCell的實現如下(可以在GitHub上看到原始碼):

class GRUCell(RNNCell):
  """Gated Recurrent Unit cell (cf. http://arxiv.org/abs/1406.1078)."""

  def __init__(self, num_units, input_size=None, activation=tanh):
    if input_size is not None:
      logging.warn("%s: The input_size parameter is deprecated.", self)
    self._num_units = num_units
    self._activation = activation

  @property
def state_size(self): return self._num_units @property def output_size(self): return self._num_units def __call__(self, inputs, state, scope=None): """Gated recurrent unit (GRU) with nunits cells.""" with vs.variable_scope(scope or "gru_cell"): with vs.variable_scope("gates"
): # Reset gate and update gate. # We start with bias of 1.0 to not reset and not update. r, u = array_ops.split( value=_linear( [inputs, state], 2 * self._num_units, True, 1.0, scope=scope), num_or_size_splits=2, axis=1) r, u = sigmoid(r), sigmoid(u) with vs.variable_scope("candidate"): c = self._activation(_linear([inputs, r * state], self._num_units, True, scope=scope)) new_h = u * state + (1 - u) * c return new_h, new_h

注意到這裡面有一個call函式,這個函式表示的意思就是,把類的物件可以當做函式來使用,比如上面的GRUCell這個類有個物件gru,那麼我們可以直接使用 ’ gru(input, last_state) ‘;

其實一開始並不知道tensorflow中有這個,所以還自己寫了一個GRU的cell,僅供參考:

# -*- coding: utf-8 -*-
# @Last Modified    : 5/23/2017 1:56 PM
# @Author  : SummmerSnow
# @Description:

import tensorflow as tf

class GRU(object):

    def __init__(self, name, input_len, hidden_len):
        self.name = name
        self.input_len = input_len
        self.hidden_len = hidden_len

    def define_param(self):
        self.W = tf.Variable("_W", self.input_len, 3*self.hidden_len)
        self.U = tf.Variable("_U", self.hidden_len, 3*self.hidden_len)
        self.B = tf.Variable("_B", 3*self.hidden_len)

    def build_net(self, input_data, last_hidden):
        xW = tf.add(tf.matmul(input_data, self.W), self.B)
        hU = tf.matmul(last_hidden, self.U)
        xw1, xw2, xw3 = tf.split(xW, 3, 1)
        hu1, hu2, hu3 = tf.split(hU, 3, 1)
        r = tf.sigmoid(xw1 + hu1)
        z = tf.sigmoid(xw2 + hu2)
        h1 = tf.tanh(xw3, r*hu3)
        h = (h1 - last_hidden) * z + last_hidden

        return h

二、tensorflow建立RNN

  • 上一章其實只是建立了一個rnncell, 那麼問題就在於如何寫出一個迴圈的神經網路,loss如何計算。【注意,這裡這是在講述如何實現RNN,假設的是已經瞭解RNN的原理,如果對原理還是很懂,可以看相關資料】

  • 幾種實現的方法:
    [轉載自: http://www.what21.com/article/b_android_1491375010268.html]
    在 tensorflow 中實現 LSTM 結構的迴圈神經網路的前向傳播過程,即使用 BasicLSTMCell:

# 定義一個 LSTM 結構,LSTM 中使用的變數會在該函式中自動被宣告
lstm = tf.contrib.rnn.BasicLSTMCell(lstm_hidden_size)

# 將 LSTM 中的狀態初始化為全 0 陣列,batch_size 給出一個 batch 的大小
state = lstm.zero_state(batch_size, tf.float32)

# 定義損失函式
loss = 0.0

# num_steps 表示最大的序列長度
for i in range(num_steps):
  # 在第一個時刻宣告 LSTM 結構中使用的變數,在之後的時刻都需要服用之前定義好的變數
  if i>0:
    tf.get_variable_scope().reuse_variables()
  # 每一步處理時間序列中的一個時刻。將當前輸入(current_input)和前一時刻狀態(state)傳入定義的 LSTM 結構就可以得到當前 LSTM 結構的輸出 lstm_output 和更新後的狀態 state
  lstm_output, state = lstm(current_input, state)

  # 將當前時刻 LSTM 結構的輸出傳入一個全連線層得到最後的輸出
  final_output = fully_connected(lstm_output)

  # 計算當前時刻輸出的損失
  loss += calc_loss(final_output, expected_output)

在 tensorflow中實現雙向RNN(BiRNN),使用 MultiRNNCell:

lstm = tf.contrib.rnn.BasicLSTMCell(lstm_hidden_size)
# 使用 MultiRNNCell 類實現深層迴圈網路中每一個時刻的前向傳播過程,number_of_layers 表示有多少層
stacked_lstm = tf.contrib.rnn.MultiRNNCell([lstm] * number_of_layers)

state = stacked_lstm.zero_state(batch_size, tf.float32)

for i in range(len(num_steps)):
  if i>0:
    tf.get_variable_scope().reuse_variables()
  stacked_lstm_output, state = stacked_lstm(current_input, state)
  final_output = fully_connected(stacked_lstm_output)
  loss += calc_loss(final_output, expected_output)

迴圈神經網路 RNN 中的 dropout, 使用 DropoutWrapper:

# 定義 LSTM 結構
lstm = tf.contrib.rnn.BasicLSTMCell(lstm_hidden_size)

# 使用 DropoutWrapper 類來實現 dropout 功能,input_keep_prob 控制輸出的 dropout 概率
dropout_lstm = tf.contrib.rnn.DropoutWrapper(lstm, input_keep_prob=0.5)

stacked_lstm = tf.contrib.rnn.MultiRNNCell([dropout_lstm] * number_of_layers)
  • 上面是自定義實現的方法,其實還可以使用tf.nn自定義的實現方法:
    tf.nn.dynamic(), 具體使用方法: