- 全部代碼:點選這裡檢視
- 本文個人部落格位址:點選這裡檢視
- 關于
實作一個簡單的二進制序列的例子可以點選這裡檢視Tensorflow
- 關于
和RNN
的基礎可以檢視這裡LSTM
- 這篇部落客要包含以下内容
- 訓練一個
模型逐字元生成文本資料(最後的部分)RNN
- 使用
的Tensorflow
函數實作scan
動态建立的效果dynamic_rnn
- 使用
建立多層的multiple RNN
RNN
- 實作
和Dropout
的功能Layer Normalization
- 訓練一個
一、模型說明和資料處理
1、模型說明
- 我們要使用
學習一個語言模型(RNN
)去生成字元序列language model
-
上有别人實作好的githbub
-
中的實作:https://github.com/karpathy/char-rnnTorch
-
中的實作:https://github.com/sherjilozair/char-rnn-tensorflowTensorflow
-
- 接下來我們來看如何實作
2、資料處理
- 資料集使用莎士比亞的一段文集,點選這裡檢視, 實際也可以使用别的
- 大小寫字元視為不同的字元
- 下載下傳并讀取資料
'''下載下傳資料并讀取資料'''
file_url = 'https://raw.githubusercontent.com/jcjohnson/torch-rnn/master/data/tiny-shakespeare.txt'
file_name = 'tinyshakespeare.txt'
if not os.path.exists(file_name):
urllib.request.urlretrieve(file_url, filename=file_name)
with open(file_name, 'r') as f:
raw_data = f.read()
print("資料長度", len(raw_data))
- 處理字元資料,轉換為數字
- 使用
去重,得到所有的唯一字元set
- 然後一個字元對應一個數字(使用字典)
- 然後周遊原始資料,得到所有字元對應的數字
- 使用
'''處理字元資料,轉換為數字'''
vocab = set(raw_data) # 使用set去重,這裡就是去除重複的字母(大小寫是區分的)
vocab_size = len(vocab)
idx_to_vocab = dict(enumerate(vocab)) # 這裡将set轉為了字典,每個字元對應了一個數字0,1,2,3..........(vocab_size-1)
vocab_to_idx = dict(zip(idx_to_vocab.values(), idx_to_vocab.keys())) # 這裡将字典的(key, value)轉換成(value, key)
data = [vocab_to_idx[c] for c in raw_data] # 處理raw_data, 根據字元,得到對應的value,就是數字
del raw_data
- 生成
資料batch
-
給出的PTB模型:https://github.com/tensorflow/models/tree/master/tutorials/rnn/ptbTensorflow models
-
'''超參數'''
num_steps= # 學習的步數
batch_size=
state_size= # cell的size
num_classes = vocab_size
learning_rate =
def gen_epochs(num_epochs, num_steps, batch_size):
for i in range(num_epochs):
yield reader.ptb_iterator_oldversion(data, batch_size, num_steps)
-
- ptb_iterator函數實作:
- 傳回資料
的X,Y
shape=[batch_size, num_steps]
- 傳回資料
- ptb_iterator函數實作:
def ptb_iterator_oldversion(raw_data, batch_size, num_steps):
"""Iterate on the raw PTB data.
This generates batch_size pointers into the raw PTB data, and allows
minibatch iteration along these pointers.
Args:
raw_data: one of the raw data outputs from ptb_raw_data.
batch_size: int, the batch size.
num_steps: int, the number of unrolls.
Yields:
Pairs of the batched data, each a matrix of shape [batch_size, num_steps].
The second element of the tuple is the same data time-shifted to the
right by one.
Raises:
ValueError: if batch_size or num_steps are too high.
"""
raw_data = np.array(raw_data, dtype=np.int32)
data_len = len(raw_data)
batch_len = data_len // batch_size
data = np.zeros([batch_size, batch_len], dtype=np.int32)
for i in range(batch_size):
data[i] = raw_data[batch_len * i:batch_len * (i + )]
epoch_size = (batch_len - ) // num_steps
if epoch_size == :
raise ValueError("epoch_size == 0, decrease batch_size or num_steps")
for i in range(epoch_size):
x = data[:, i*num_steps:(i+)*num_steps]
y = data[:, i*num_steps+:(i+)*num_steps+]
yield (x, y)
二、使用 tf.scan
函數和 dynamic_rnn
tf.scan
dynamic_rnn
1、為什麼使用 tf.scan
和 dynamic_rnn
tf.scan
dynamic_rnn
- 之前我們實作的第一個例子中沒有用
的部分是将輸入的三維資料dynamic_rnn
按[batch_size,num_steps, state_size]
次元進行拆分,然後每計算一步都存到num_steps
清單中,如下圖list
- 這種建構方式很耗時,在我們例子中沒有展現出來,但是如果我們要學習的步數很大(
num_steps
,也可以說要學習的依賴關系很長),如果再使用深層的RNN,這種就不合适了
- 為了友善比較和
dynamic_rnn
的運作耗時,下面還是給出使用
list
2、使用 list
的方式( static_rnn
)
list
static_rnn
- 建構計算圖
- 我這裡
的版本是tensorflow
,與1.2.0
些許不一樣1.0
- 和之前的例子差不多,這裡不再累述
- 我這裡
'''使用list的方式'''
def build_basic_rnn_graph_with_list(
state_size = state_size,
num_classes = num_classes,
batch_size = batch_size,
num_steps = num_steps,
num_layers = ,
learning_rate = learning_rate):
reset_graph()
x = tf.placeholder(tf.int32, [batch_size, num_steps], name='x')
y = tf.placeholder(tf.int32, [batch_size, num_steps], name='y')
x_one_hot = tf.one_hot(x, num_classes) # (batch_size, num_steps, num_classes)
'''這裡按第二維拆開num_steps*(batch_size, num_classes)'''
rnn_inputs = [tf.squeeze(i,squeeze_dims=[]) for i in tf.split(x_one_hot, num_steps, )]
cell = tf.nn.rnn_cell.BasicRNNCell(state_size)
init_state = cell.zero_state(batch_size, tf.float32)
'''使用static_rnn方式'''
rnn_outputs, final_state = tf.contrib.rnn.static_rnn(cell=cell, inputs=rnn_inputs,
initial_state=init_state)
#rnn_outputs, final_state = tf.nn.rnn(cell, rnn_inputs, initial_state=init_state) # tensorflow 1.0的方式
with tf.variable_scope('softmax'):
W = tf.get_variable('W', [state_size, num_classes])
b = tf.get_variable('b', [num_classes], initializer=tf.constant_initializer())
logits = [tf.matmul(rnn_output, W) + b for rnn_output in rnn_outputs]
y_as_list = [tf.squeeze(i, squeeze_dims=[]) for i in tf.split(y, num_steps, )]
#loss_weights = [tf.ones([batch_size]) for i in range(num_steps)]
losses = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y_as_list,
logits=logits)
#losses = tf.nn.seq2seq.sequence_loss_by_example(logits, y_as_list, loss_weights) # tensorflow 1.0的方式
total_loss = tf.reduce_mean(losses)
train_step = tf.train.AdamOptimizer(learning_rate).minimize(total_loss)
return dict(
x = x,
y = y,
init_state = init_state,
final_state = final_state,
total_loss = total_loss,
train_step = train_step
)
- 訓練神經網絡函數
- 和之前例子類似
'''訓練rnn網絡的函數'''
def train_rnn(g, num_epochs, num_steps=num_steps, batch_size=batch_size, verbose=True, save=False):
tf.set_random_seed()
with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
training_losses = []
for idx, epoch in enumerate(gen_epochs(num_epochs, num_steps, batch_size)):
training_loss =
steps =
training_state = None
for X, Y in epoch:
steps +=
feed_dict = {g['x']: X, g['y']: Y}
if training_state is not None:
feed_dict[g['init_state']] = training_state
training_loss_, training_state, _ = sess.run([g['total_loss'],
g['final_state'],
g['train_step']],
feed_dict=feed_dict)
training_loss += training_loss_
if verbose:
print('epoch: {0}的平均損失值:{1}'.format(idx, training_loss/steps))
training_losses.append(training_loss/steps)
if isinstance(save, str):
g['saver'].save(sess, save)
return training_losses
- 調用執行:
start_time = time.time()
g = build_basic_rnn_graph_with_list()
print("建構圖耗時", time.time()-start_time)
start_time = time.time()
train_rnn(g, )
print("訓練耗時:", time.time()-start_time)
- 運作結果
- 建構計算圖耗時:
113.43532419204712
-
個3
運作耗時:epoch
- 建構計算圖耗時:
epoch: 的平均損失值:
epoch: 的平均損失值:
epoch: 的平均損失值:
訓練耗時:
- 可以看出在建構圖的時候非常耗時,這裡僅僅一層的cell
3、 dynamic_rnn
的使用
dynamic_rnn
- 之前在我們第一個例子中實際已經使用過了,這裡使用
實作多層cell,具體下面再講MultiRNNCell
- 構模組化型:
-
函數是在tf.nn.embedding_lookup(params, ids)
中查找params
的表示, 和在ids
中用matrix
索引類似, 這裡是在二維embeddings中找二維的ids,array
每一行中的一個數對應ids
中的一行,是以最後是embeddings
,關于具體的輸出可以檢視這裡[batch_size, num_steps, state_size]
- 這裡我認為就是某個字母的表示,之前上面我們的
就是statci_rnn
來表示的one-hot
-
'''使用dynamic_rnn方式
- 之前我們自己實作的cell和static_rnn的例子都是将得到的tensor使用list存起來,這種方式建構計算圖時很慢
- dynamic可以在運作時建構計算圖
'''
def build_multilayer_lstm_graph_with_dynamic_rnn(
state_size = state_size,
num_classes = num_classes,
batch_size = batch_size,
num_steps = num_steps,
num_layers = ,
learning_rate = learning_rate
):
reset_graph()
x = tf.placeholder(tf.int32, [batch_size, num_steps], name='x')
y = tf.placeholder(tf.int32, [batch_size, num_steps], name='y')
embeddings = tf.get_variable(name='embedding_matrix', shape=[num_classes, state_size])
'''這裡的輸入是三維的[batch_size, num_steps, state_size]
- embedding_lookup(params, ids)函數是在params中查找ids的表示, 和在matrix中用array索引類似,
這裡是在二維embeddings中找二維的ids, ids每一行中的一個數對應embeddings中的一行,是以最後是[batch_size, num_steps, state_size]
'''
rnn_inputs = tf.nn.embedding_lookup(params=embeddings, ids=x)
cell = tf.nn.rnn_cell.LSTMCell(num_units=state_size, state_is_tuple=True)
cell = tf.nn.rnn_cell.MultiRNNCell(cells=[cell]*num_layers, state_is_tuple=True)
init_state = cell.zero_state(batch_size, dtype=tf.float32)
'''使用dynamic_rnn方式'''
rnn_outputs, final_state = tf.nn.dynamic_rnn(cell=cell, inputs=rnn_inputs,
initial_state=init_state)
with tf.variable_scope('softmax'):
W = tf.get_variable('W', [state_size, num_classes])
b = tf.get_variable('b', [num_classes], initializer=tf.constant_initializer())
rnn_outputs = tf.reshape(rnn_outputs, [-, state_size]) # 轉成二維的矩陣
y_reshape = tf.reshape(y, [-])
logits = tf.matmul(rnn_outputs, W) + b # 進行矩陣運算
total_loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=y_reshape))
train_step = tf.train.AdamOptimizer(learning_rate).minimize(total_loss)
return dict(x = x,
y = y,
init_state = init_state,
final_state = final_state,
total_loss = total_loss,
train_step = train_step)
- 調用執行即可
start_time = time.time()
g = build_multilayer_lstm_graph_with_dynamic_rnn()
print("建構圖耗時", time.time()-start_time)
start_time = time.time()
train_rnn(g, )
print("訓練耗時:", time.time()-start_time)
- 運作結果(注意這是3層的LSTM):
- 建構計算圖耗時
,相比第一種7.616888523101807
很快static_rnn
- 訓練耗時(這是3層的LSTM,是以還是挺慢的):
- 建構計算圖耗時
epoch: 的平均損失值:
epoch: 的平均損失值:
epoch: 的平均損失值:
訓練耗時:
4、 tf.scan
實作的方式
tf.scan
- 如果你不了解
,建議看下官方API, 還是有點複雜的。tf.scan
- 或者Youtube上有個介紹,點選這裡檢視
-
是個高階函數,一般的計算方式是:給定一個序列 [x0,x1,.....,xn] 和初試狀态 y−1 ,根據 yt=f(xt,yt−1) 計算得到最終序列 [y0,y1,......,yn]scan
- 建構計算圖
-
是将tf.transpose(rnn_inputs, [1,0,2])
的第一個和第二個次元調換,即變成rnn_inputs
, 在[num_steps,batch_size, state_size]
函數有個time_major參數,就是指定dynamic_rnn
是否在第一個次元上,預設是num_steps
的,即不在第一維false
-
會将tf.scan
按照第一維拆開,是以一次就是一個elems
的資料(和我們step
的例子類似)static_rnn
- 參數a的結構和initializer的結構一緻,是以
就是對應的a[1]
,state
需要傳入cell
和x
計算state
- 每次疊代
傳回的是一個cell
和對應的rnn_output, shape=(batch_size,state_size)
,state
之後的num_steps
的rnn_outputs
就是shape
,(num_steps, batch_size, state_size)
同理state
- 每次輸入的
都會得到的x
,我們隻要的最後的state-->(final_states)
final_state
-
'''使用scan實作dynamic_rnn的效果'''
def build_multilayer_lstm_graph_with_scan(
state_size = state_size,
num_classes = num_classes,
batch_size = batch_size,
num_steps = num_steps,
num_layers = ,
learning_rate = learning_rate
):
reset_graph()
x = tf.placeholder(tf.int32, [batch_size, num_steps], name='x')
y = tf.placeholder(tf.int32, [batch_size, num_steps], name='y')
embeddings = tf.get_variable(name='embedding_matrix', shape=[num_classes, state_size])
'''這裡的輸入是三維的[batch_size, num_steps, state_size]'''
rnn_inputs = tf.nn.embedding_lookup(params=embeddings, ids=x)
'''建構多層的cell, 先建構一個cell, 然後使用MultiRNNCell函數建構即可'''
cell = tf.nn.rnn_cell.LSTMCell(num_units=state_size, state_is_tuple=True)
cell = tf.nn.rnn_cell.MultiRNNCell(cells=[cell]*num_layers, state_is_tuple=True)
init_state = cell.zero_state(batch_size, dtype=tf.float32)
'''使用tf.scan方式
- tf.transpose(rnn_inputs, [1,0,2]) 是将rnn_inputs的第一個和第二個次元調換,即[num_steps,batch_size, state_size],
在dynamic_rnn函數有個time_major參數,就是指定num_steps是否在第一個次元上,預設是false的,即不在第一維
- tf.scan會将elems按照第一維拆開,是以一次就是一個step的資料(和我們static_rnn的例子類似)
- a的結構和initializer的結構一緻,是以a[1]就是對應的state,cell需要傳入x和state計算
- 每次疊代cell傳回的是一個rnn_output(batch_size,state_size)和對應的state,num_steps之後的rnn_outputs的shape就是(num_steps, batch_size, state_size)
- 每次輸入的x都會得到的state(final_states),我們隻要的最後的final_state
'''
def testfn(a, x):
return cell(x, a[])
rnn_outputs, final_states = tf.scan(fn=testfn, elems=tf.transpose(rnn_inputs, [,,]),
initializer=(tf.zeros([batch_size,state_size]),init_state)
)
'''或者使用lambda的方式'''
#rnn_outputs, final_states = tf.scan(lambda a,x: cell(x, a[1]), tf.transpose(rnn_inputs, [1,0,2]),
#initializer=(tf.zeros([batch_size, state_size]),init_state))
final_state = tuple([tf.nn.rnn_cell.LSTMStateTuple(
tf.squeeze(tf.slice(c, [num_steps-,,], [,batch_size,state_size])),
tf.squeeze(tf.slice(h, [num_steps-,,], [,batch_size,state_size]))) for c, h in final_states])
with tf.variable_scope('softmax'):
W = tf.get_variable('W', [state_size, num_classes])
b = tf.get_variable('b', [num_classes], initializer=tf.constant_initializer())
rnn_outputs = tf.reshape(rnn_outputs, [-, state_size])
y_reshape = tf.reshape(y, [-])
logits = tf.matmul(rnn_outputs, W) + b
total_loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=y_reshape))
train_step = tf.train.AdamOptimizer(learning_rate).minimize(total_loss)
return dict(x = x,
y = y,
init_state = init_state,
final_state = final_state,
total_loss = total_loss,
train_step = train_step)
- 運作結果
- 建構計算圖耗時:
(比8.685610055923462
稍微慢一點)dynamic_rnn
- 訓練耗時(和
耗時差不多)dynamic_rnn
- 建構計算圖耗時:
- 使用
的方式隻比scan
慢一點點,但是對我們來說更加靈活和清楚執行的過程。也友善我們修改代碼(比如從dynamic_rnn
的state
時刻跳過一個時刻直接到t-2
)t
epoch: 的平均損失值:
epoch: 的平均損失值:
epoch: 的平均損失值:
訓練耗時:
三、關于多層 RNN
RNN
1、結構
-
中包含兩個LSTM
,一個是state
記憶單元(c
),另外一個是memory cell
隐藏狀态(h
), 在hidden state
中是以Tensorflow
元組的形式,是以才有上面建構tuple
時的參數dynamic_rnn
的參數,這種方式執行更快state_is_tuple
- 多層的結構如下圖
- 我們可以将其包裝起來, 看起來像一個
一樣cell
2、代碼
-
中的實作就是使用Tensorflow
tf.nn.rnn_cell.MultiRNNCell
- 聲明一個
cell
-
中傳入MultiRNNCell
就可以了[cell]*num_layers
- 注意如果是
,定義參數LSTM
state_is_tuple=True
- 聲明一個
cell = tf.nn.rnn_cell.LSTMCell(num_units=state_size, state_is_tuple=True)
cell = tf.nn.rnn_cell.MultiRNNCell(cells=[cell]*num_layers, state_is_tuple=True)
init_state = cell.zero_state(batch_size, dtype=tf.float32)
四、Dropout操作
- 應用在一層
的輸入和輸出,不應用在循環的部分cell
1、一層的 cell
cell
-
中實作static_rnn
- 聲明
:placeholder
keep_prob = tf.placeholder(tf.float32, name='keep_prob')
- 輸入:
rnn_inputs = [tf.nn.dropout(rnn_input, keep_prob) for rnn_input in rnn_inputs]
- 輸出:
rnn_outputs = [tf.nn.dropout(rnn_output, keep_prob) for rnn_output in rnn_outputs]
-
中加入即可:feed_dict
feed_dict = {g['x']: X, g['y']: Y, g['keep_prob']: keep_prob}
- 聲明
-
或者dynamic_rnn
中實作scan
- 直接添加即可,其餘類似:
rnn_inputs = tf.nn.dropout(rnn_inputed, keep_prob)
- 直接添加即可,其餘類似:
2、多層 cell
cell
- 我們之前說使用
将多層MultiRNNCell
看作一個cell
, 那麼怎麼實作對每層cell
使用cell
呢dropout
- 可以使用
來實作tf.nn.rnn_cell.DropoutWrapper
- 方式一:
cell = tf.nn.rnn_cell.DropoutWrapper(cell, input_keep_prob=input_keep_prob, output_keep_prob=output_drop_prob)
- 如果同時使用了
和input_keep_prob
都是output_keep_prob
, 那麼層之間的0.9
drop_out=0.9*0.9=0.81
- 如果同時使用了
- 方式二: 對于
隻使用一個basic cell
或者input_keep_prob
,對output_keep_prob
也使用一個MultiRNNCell
或者input_keep_prob
output_keep_prob
cell = tf.nn.rnn_cell.LSTMCell(num_units=state_size, state_is_tuple=True)
cell = tf.nn.rnn_cell.DropoutWrapper(cell, input_keep_prob=keep_prob)
cell = tf.nn.rnn_cell.MultiRNNCell(cells=[cell]*num_layers, state_is_tuple=True)
cell = tf.nn.rnn_cell.DropoutWrapper(cell,output_keep_prob=keep_prob)
五、層标準化 ( Layer Normalization
)
Layer Normalization
1、說明
-
是受Layer Normalization
的啟發而來,針對于RNN,可以檢視相關論文Batch Normalization
-
主要針對于傳統的深度神經網絡和CNN,關于Batch Normalization
的操作和推導可以看我之前的部落格Batch Normalization
- 可以加快訓練的速度,得到更好的結果等
2、代碼
- 找到
的源碼拷貝一份修改即可LSTMCell
-
函數layer normalization
- 傳入的
是二維的,對其進行tensor
操作batch normalization
-
是計算tf.nn.moment
的tensor
和mean value
variance value
- 然後對其進行縮放(
)和平移(scale
)shift
- 傳入的
'''layer normalization'''
def ln(tensor, scope=None, epsilon=):
assert(len(tensor.get_shape()) == )
m, v = tf.nn.moments(tensor, [], keep_dims=True)
if not isinstance(scope, str):
scope = ''
with tf.variable_scope(scope+'layer_norm'):
scale = tf.get_variable(name='scale',
shape=[tensor.get_shape()[]],
initializer=tf.constant_initializer())
shift = tf.get_variable('shift',
[tensor.get_shape()[]],
initializer=tf.constant_initializer())
LN_initial = (tensor - m) / tf.sqrt(v + epsilon)
return LN_initial*scale + shift
-
中的LSTMCell
方法call
調用i,j,f,o
操作layer normalization
-
函數中的_linear
設為bias
, 因為False
會加上BN
shift
-
'''這裡bias設定為false, 因為bn會加上shift'''
lstm_matrix = _linear([inputs, m_prev], * self._num_units, bias=False)
i, j, f, o = array_ops.split(
value=lstm_matrix, num_or_size_splits=, axis=)
'''執行ln'''
i = ln(i, scope = 'i/')
j = ln(j, scope = 'j/')
f = ln(f, scope = 'f/')
o = ln(o, scope = 'o/')
- 建構計算圖
- 可以選擇
RNN GRU LSTM
-
Dropout
-
Layer Normalization
- 可以選擇
'''最終的整合模型,
- 普通RNN,GRU,LSTM
- dropout
- BN
'''
from LayerNormalizedLSTMCell import LayerNormalizedLSTMCell # 導入layer normalization的LSTMCell 檔案
def build_final_graph(
cell_type = None,
state_size = state_size,
num_classes = num_classes,
batch_size = batch_size,
num_steps = num_steps,
num_layers = ,
build_with_dropout = False,
learning_rate = learning_rate):
reset_graph()
x = tf.placeholder(tf.int32, [batch_size, num_steps], name='x')
y = tf.placeholder(tf.int32, [batch_size, num_steps], name='y')
keep_prob = tf.placeholder(tf.float32, name='keep_prob')
embeddings = tf.get_variable('embedding_matrix', [num_classes, state_size])
rnn_inputs = tf.nn.embedding_lookup(embeddings, x)
if cell_type == 'GRU':
cell = tf.nn.rnn_cell.GRUCell(state_size)
elif cell_type == 'LSTM':
cell = tf.nn.rnn_cell.LSTMCell(state_size, state_is_tuple=True)
elif cell_type == 'LN_LSTM':
cell = LayerNormalizedLSTMCell(state_size) # 自己修改的代碼,導入對應的檔案
else:
cell = tf.nn.rnn_cell.BasicRNNCell(state_size)
if build_with_dropout:
cell = tf.nn.rnn_cell.DropoutWrapper(cell, input_keep_prob=keep_prob)
init_state = cell.zero_state(batch_size, tf.float32)
'''dynamic_rnn'''
rnn_outputs, final_state = tf.nn.dynamic_rnn(cell, rnn_inputs, initial_state=init_state)
with tf.variable_scope('softmax'):
W = tf.get_variable('W', [state_size, num_classes])
b = tf.get_variable('b', [num_classes], initializer=tf.constant_initializer())
rnn_outputs = tf.reshape(rnn_outputs, [-, state_size])
y_reshaped = tf.reshape(y, [-])
logits = tf.matmul(rnn_outputs, W) + b
predictions = tf.nn.softmax(logits)
total_loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=y_reshaped))
train_step = tf.train.AdamOptimizer(learning_rate).minimize(total_loss)
return dict(
x = x,
y = y,
keep_prob = keep_prob,
init_state = init_state,
final_state = final_state,
total_loss = total_loss,
train_step = train_step,
preds = predictions,
saver = tf.train.Saver()
)
六、生成文本
1、說明
- 訓練完成之後将計算圖儲存到本地磁盤,下次直接讀取就可以了
- 我們給出第一個字元,
接着一個個生成字元,每次都是根據前一個字元RNN
- 是以
,num_steps=1
(可以想象生成batch_size=1
的prediction
是shape
中選擇一個機率,–>(1, num_classes)
)num_steps=1
- 是以
2、代碼
- 建構圖(直接傳入參數即可):
g = build_final_graph(cell_type='LN_LSTM', num_steps=1, batch_size=1)
- 生成文本
- 讀取訓練好的檔案
- 得到給出的第一個字元對應的數字
- 循環周遊要生成多少個字元, 每次循環生成一個字元
'''生成文本'''
def generate_characters(g, checkpoint, num_chars, prompt='A', pick_top_chars=None):
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
g['saver'].restore(sess, checkpoint) # 讀取檔案
state = None
current_char = vocab_to_idx[prompt] # 得到給出的字母對應的數字
chars = [current_char]
for i in range(num_chars): # 總共生成多少數字
if state is not None: # 第一次state為None,因為計算圖中定義了剛開始為0
feed_dict={g['x']: [[current_char]], g['init_state']: state} # 傳入目前字元
else:
feed_dict={g['x']: [[current_char]]}
preds, state = sess.run([g['preds'],g['final_state']], feed_dict) # 得到預測結果(機率)preds的shape就是(1,num_classes)
if pick_top_chars is not None: # 如果設定了機率較大的前多少個
p = np.squeeze(preds)
p[np.argsort(p)[:-pick_top_chars]] = # 其餘的置為0
p = p / np.sum(p) # 因為下面np.random.choice函數p的機率和要求是1,處理一下
current_char = np.random.choice(vocab_size, , p=p)[] # 根據機率選擇一個
else:
current_char = np.random.choice(vocab_size, , p=np.squeeze(preds))[]
chars.append(current_char)
chars = map(lambda x: idx_to_vocab[x], chars)
result = "".join(chars)
print(result)
return result
- 結果
- 由于訓練耗時很長,這裡使用
訓練了LSTM
個30
,結果如下epoch
- 可以自己調整參數,可能會得到更好的結果
- 由于訓練耗時很長,這裡使用
ANK
O: HFOFMFRone s the statlighte thithe thit.
BODEN --
I I's a tomir.
I't
shis and on ar tald the theand this he sile be cares hat s ond tho fo hour he singe sime shind and somante tat ond treang tatsing of the an the to to fook.. Ir ard the with ane she stale..
ANTE --
KINE
Show the ard and a beat the weringe be thing or.
Bo hith tho he melan to the mute steres.
The singer stis ard stis.
BACE CANKONS CORE
Sard the sids ing tho the the sackes tom the
IN
We stoe shit a dome thor
ate seomser hith.
That
thow ound
TANTONT. SEAT THONTITE SERTI
SHe the mathe a tomoner
ind is ingit ofres treacentit. Sher stard on this the tor an the candin he whor he sath heres and
stha dortour tit thas stand. I'd and or a
Reference
- https://r2rt.com/recurrent-neural-networks-in-tensorflow-ii.html
- https://karpathy.github.io/2015/05/21/rnn-effectiveness/
- http://jmlr.org/proceedings/papers/v37/ioffe15.pdf
-
:tensorflow scan
- https://www.tensorflow.org/api_docs/python/tf/scan
- https://www.youtube.com/watch?v=A6qJMB3stE4&t=621s