自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用TENSORFLOW訓(xùn)練循環(huán)神經(jīng)網(wǎng)絡(luò)語言模型

人工智能 深度學(xué)習(xí)
Language Model,即語言模型,其主要思想是,在知道前一部分的詞的情況下,推斷出下一個(gè)最有可能出現(xiàn)的詞。在本文中,我們更加關(guān)注的是,如何使用RNN來推測(cè)下一個(gè)詞。

讀了將近一個(gè)下午的TensorFlow Recurrent Neural Network教程,翻看其在PTB上的實(shí)現(xiàn),感覺晦澀難懂,因此參考了部分代碼,自己寫了一個(gè)簡(jiǎn)化版的Language Model,思路借鑒了Keras的LSTM text generation。

代碼地址:Github

轉(zhuǎn)載請(qǐng)注明出處:Gaussic

語言模型

Language Model,即語言模型,其主要思想是,在知道前一部分的詞的情況下,推斷出下一個(gè)最有可能出現(xiàn)的詞。例如,知道了 The fat cat sat on the,我們認(rèn)為下一個(gè)詞為mat的可能性比hat要大,因?yàn)樨埜锌赡茏谔鹤由?,而不是帽子上?/p>

這可能被你認(rèn)為是常識(shí),但是在自然語言處理中,這個(gè)任務(wù)是可以用概率統(tǒng)計(jì)模型來描述的。就拿The fat cat sat on the mat來說。我們可能統(tǒng)計(jì)出第一個(gè)詞The出現(xiàn)的概率p(The)p(The),The后面是fat的條件概率為p(fat|The)p(fat|The),The fat同時(shí)出現(xiàn)的聯(lián)合概率:

  1. p(The,fat)=p(The)⋅p(fat|The)p(The,fat)=p(The)·p(fat|The) 
這個(gè)聯(lián)合概率,就是The fat的合理性,即這句話的出現(xiàn)符不符合自然語言的評(píng)判標(biāo)準(zhǔn),通俗點(diǎn)表述就是這是不是句人話。同理,根據(jù)鏈?zhǔn)揭?guī)則,The fat cat的聯(lián)合概率可求:
 
  1. p(The,fat,cat)=p(The)⋅p(fat|The)⋅p(cat|The,fat)p(The,fat,cat)=p(The)·p(fat|The)·p(cat|The,fat) 
在知道前面的詞為The cat的情況下,下一個(gè)詞為cat的概率可以推導(dǎo)出來:
 
  1. p(cat|The,fat)=p(The,fat,cat)p(The,fat)p(cat|The,fat)=p(The,fat,cat)p(The,fat) 
分子是The fat cat在語料庫中出現(xiàn)的次數(shù),分母是The fat在語料庫中出現(xiàn)的次數(shù)。
因此,The fat cat sat on the mat整個(gè)句子的合理性同樣可以推導(dǎo),這個(gè)句子的合理性即為它的概率。公式化的描述如下:
 
  1. p(S)=p(w1,w2,⋅⋅⋅,wn)=p(w1)⋅p(w2|w1)⋅p(w3|w1,w2)⋅⋅⋅p(wn|w1,w2,w3,⋅⋅⋅,wn−1)p(S)=p(w1,w2,···,wn)=p(w1)·p(w2|w1)·p(w3|w1,w2)···p(wn|w1,w2,w3,···,wn−1) 
(公式后的n-1應(yīng)該為下標(biāo),插件問題,下同)
 
可以看出一個(gè)問題,每當(dāng)計(jì)算下一個(gè)詞的條件概率,需要計(jì)算前面所有詞的聯(lián)合概率。這個(gè)計(jì)算量相當(dāng)?shù)凝嫶蟆2⑶?,一個(gè)句子中大部分詞同時(shí)出現(xiàn)的概率往往少之又少,數(shù)據(jù)稀疏非常嚴(yán)重,需要一個(gè)非常大的語料庫來訓(xùn)練。
 
一個(gè)簡(jiǎn)單的優(yōu)化是基于馬爾科夫假設(shè),下一個(gè)詞的出現(xiàn)僅與前面的一個(gè)或n個(gè)詞有關(guān)。
 
最簡(jiǎn)單的情況,下一個(gè)詞的出現(xiàn)僅僅和前面一個(gè)詞有關(guān),稱之為bigram。
 
  1. p(S)=p(w1,w2,⋅⋅⋅,wn)=p(w1)⋅p(w2|w1)⋅p(w3|w2)⋅p(w4|w3)⋅⋅⋅p(wn|wn−1)p(S)=p(w1,w2,···,wn)=p(w1)·p(w2|w1)·p(w3|w2)·p(w4|w3)···p(wn|wn−1) 
再復(fù)雜點(diǎn),下一個(gè)詞的出現(xiàn)僅和前面兩個(gè)詞有關(guān),稱之為trigram。
 
  1. p(S)=p(w1,w2,⋅⋅⋅,wn)=p(w1)⋅p(w2|w1)⋅p(w3|w1,w2)⋅p(w4|w2,w3)⋅⋅⋅p(wn|wn−2,wn−1)p(S)=p(w1,w2,···,wn)=p(w1)·p(w2|w1)·p(w3|w1,w2)·p(w4|w2,w3)···p(wn|wn−2,wn−1) 

這樣的條件概率雖然好求,但是會(huì)丟失大量的前面的詞的信息,有時(shí)會(huì)對(duì)結(jié)果產(chǎn)生不良影響。因此如何選擇一個(gè)有效的n,使得既能簡(jiǎn)化計(jì)算,又能保留大部分的上下文信息。

以上均是傳統(tǒng)語言模型的描述。如果不太深究細(xì)節(jié),我們的任務(wù)就是,知道前面n個(gè)詞,來計(jì)算下一個(gè)詞出現(xiàn)的概率。并且使用語言模型來生成新的文本。

在本文中,我們更加關(guān)注的是,如何使用RNN來推測(cè)下一個(gè)詞。

數(shù)據(jù)準(zhǔn)備
 
TensorFlow的官方文檔使用的是Mikolov準(zhǔn)備好的PTB數(shù)據(jù)集。我們可以將其下載并解壓出來:
 
  1. $ wget http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz 
  2. $ tar xvf simple-examples.tgz 
部分?jǐn)?shù)據(jù)如下,不常用的詞轉(zhuǎn)換成了<unk>標(biāo)記,數(shù)字轉(zhuǎn)換成了N:
 
  1. we 're talking about years ago before anyone heard of asbestos having any questionable properties 
  2. there is no asbestos in our products now 
  3. neither <unk> nor the researchers who studied the workers were aware of any research on smokers of the kent cigarettes 
  4. we have no useful information on whether users are at risk said james a. <unk> of boston 's <unk> cancer institute 
  5. the total of N deaths from malignant <unk> lung cancer and <unk> was far higher than expected the researchers said 
讀取文件中的數(shù)據(jù),將換行符轉(zhuǎn)換為<eos>,然后轉(zhuǎn)換為詞的list:
 
  1. def _read_words(filename): 
  2.     with open(filename, 'r', encoding='utf-8'as f: 
  3.         return f.read().replace('\n''<eos>').split() 
  1. f = _read_words('simple-examples/data/ptb.train.txt'
  2. print(f[:20]) 
得到:
 
  1. ['aer''banknote''berlitz''calloway''centrust''cluett''fromstein''gitano''guterman''hydro-quebec''ipo''kia''memotec''mlx''nahb''punts''rake''regatta''rubens''sim'
構(gòu)建詞匯表,詞與id互轉(zhuǎn):
 
  1. def _build_vocab(filename): 
  2.     data = _read_words(filename) 
  3.  
  4.     counter = Counter(data) 
  5.     count_pairs = sorted(counter.items(), key=lambda x: -x[1]) 
  6.  
  7.     words, _ = list(zip(*count_pairs)) 
  8.     word_to_id = dict(zip(words, range(len(words)))) 
  9.  
  10.     return words, word_to_id 
  1. words, words_to_id = _build_vocab('simple-examples/data/ptb.train.txt'
  2. print(words[:10]) 
  3. print(list(map(lambda x: words_to_id[x], words[:10]))) 
輸出:
 
  1. ('the''<unk>''<eos>''N''of''to''a''in''and'"'s"
  2. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
將一個(gè)文件轉(zhuǎn)換為id表示:
 
  1. def _file_to_word_ids(filename, word_to_id): 
  2.     data = _read_words(filename) 
  3.     return [word_to_id[x] for x in data if x in word_to_id] 
  1. words_in_file = _file_to_word_ids('simple-examples/data/ptb.train.txt', words_to_id) 
  2. print(words_in_file[:20]) 
詞匯表已根據(jù)詞頻進(jìn)行排序,由于第一句話非英文,所以id靠后。
 
  1. [9980, 9988, 9981, 9989, 9970, 9998, 9971, 9979, 9992, 9997, 9982, 9972, 9993, 9991, 9978, 9983, 9974, 9986, 9999, 9990] 
將一句話從id列表轉(zhuǎn)換回詞:
 
  1. def to_words(sentence, words): 
  2.     return list(map(lambda x: words[x], sentence)) 
將以上函數(shù)整合:
 
  1. def ptb_raw_data(data_path=None): 
  2.     train_path = os.path.join(data_path, 'ptb.train.txt'
  3.     valid_path = os.path.join(data_path, 'ptb.valid.txt'
  4.     test_path = os.path.join(data_path, 'ptb.test.txt'
  5.  
  6.     words, word_to_id = _build_vocab(train_path) 
  7.     train_data = _file_to_word_ids(train_path, word_to_id) 
  8.     valid_data = _file_to_word_ids(valid_path, word_to_id) 
  9.     test_data = _file_to_word_ids(test_path, word_to_id) 
  10.  
  11.     return train_data, valid_data, test_data, words, word_to_id 
以上部分和官方的例子有一定的相似之處。接下來的處理和官方存在很大的不同,主要參考了Keras例程處理文檔的操作:
 
  1. def ptb_producer(raw_data, batch_size=64, num_steps=20, stride=1): 
  2.     data_len = len(raw_data) 
  3.  
  4.     sentences = [] 
  5.     next_words = [] 
  6.     for i in range(0, data_len - num_steps, stride): 
  7.         sentences.append(raw_data[i:(i + num_steps)]) 
  8.         next_words.append(raw_data[i + num_steps]) 
  9.  
  10.     sentences = np.array(sentences) 
  11.     next_words = np.array(next_words) 
  12.  
  13.     batch_len = len(sentences) // batch_size 
  14.     x = np.reshape(sentences[:(batch_len * batch_size)], \ 
  15.         [batch_len, batch_size, -1]) 
  16.  
  17.     y = np.reshape(next_words[:(batch_len * batch_size)], \ 
  18.         [batch_len, batch_size]) 
  19.  
  20.     return x, y 
參數(shù)解析:
  •     raw_data: 即ptb_raw_data()函數(shù)產(chǎn)生的數(shù)據(jù)
  •     batch_size: 神經(jīng)網(wǎng)絡(luò)使用隨機(jī)梯度下降,數(shù)據(jù)按多個(gè)批次輸出,此為每個(gè)批次的數(shù)據(jù)量
  •     num_steps: 每個(gè)句子的長(zhǎng)度,相當(dāng)于之前描述的n的大小,這在循環(huán)神經(jīng)網(wǎng)絡(luò)中又稱為時(shí)序的長(zhǎng)度。
  •     stride: 取數(shù)據(jù)的步長(zhǎng),決定數(shù)據(jù)量的大小。

代碼解析:

這個(gè)函數(shù)將一個(gè)原始數(shù)據(jù)list轉(zhuǎn)換為多個(gè)批次的數(shù)據(jù),即[batch_len, batch_size, num_steps]。

首先,程序每一次取了num_steps個(gè)詞作為一個(gè)句子,即x,以這num_steps個(gè)詞后面的一個(gè)詞作為它的下一個(gè)預(yù)測(cè),即為y。這樣,我們首先把原始數(shù)據(jù)整理成了batch_len * batch_size個(gè)x和y的表示,類似于已知x求y的分類問題。

為了滿足隨機(jī)梯度下降的需要,我們還需要把數(shù)據(jù)整理成一個(gè)個(gè)小的批次,每次喂一個(gè)批次的數(shù)據(jù)給TensorFlow來更新權(quán)重,這樣,數(shù)據(jù)就整理為[batch_len, batch_size, num_steps]的格式。

打印部分?jǐn)?shù)據(jù): 

  1. train_data, valid_data, test_data, words, word_to_id = ptb_raw_data('simple-examples/data'
  2. x_train, y_train = ptb_producer(train_data) 
  3. print(x_train.shape) 
  4. print(y_train.shape) 
輸出:
 
  1. (14524, 64, 20) 
  2. (14524, 64) 
可見我們得到了14524個(gè)批次的數(shù)據(jù),每個(gè)批次的訓(xùn)練集維度為[64, 20]。
 
  1. print(' '.join(to_words(x_train[100, 3], words))) 
第100個(gè)批次的第3句話為:
 
  1. despite steady sales growth <eos> magna recently cut its quarterly dividend in half and the company 's class a shares 
  1. print(words[np.argmax(y_train[100, 3])]) 
它的下一個(gè)詞為:
 
  1. the 
 
構(gòu)建模型
 
配置項(xiàng)
 
  1. class LMConfig(object): 
  2.     """language model 配置項(xiàng)""" 
  3.     batch_size = 64       # 每一批數(shù)據(jù)的大小 
  4.     num_steps = 20        # 每一個(gè)句子的長(zhǎng)度 
  5.     stride = 3            # 取數(shù)據(jù)時(shí)的步長(zhǎng) 
  6.  
  7.     embedding_dim = 64    # 詞向量維度 
  8.     hidden_dim = 128      # RNN隱藏層維度 
  9.     num_layers = 2        # RNN層數(shù) 
  10.  
  11.     learning_rate = 0.05  # 學(xué)習(xí)率 
  12.     dropout = 0.2         # 每一層后的丟棄概率 
讀取輸入
 
讓模型可以按批次的讀取數(shù)據(jù)。
 
  1. class PTBInput(object): 
  2.     """按批次讀取數(shù)據(jù)""" 
  3.     def __init__(self, config, data): 
  4.         self.batch_size = config.batch_size 
  5.         self.num_steps = config.num_steps 
  6.         self.vocab_size = config.vocab_size # 詞匯表大小 
  7.  
  8.         self.input_data, self.targets = ptb_producer(data, 
  9.             self.batch_size, self.num_steps) 
  10.  
  11.         self.batch_len = self.input_data.shape[0] # 總批次 
  12.         self.cur_batch = 0  # 當(dāng)前批次 
  13.  
  14.     def next_batch(self): 
  15.         """讀取下一批次""" 
  16.         x = self.input_data[self.cur_batch] 
  17.         y = self.targets[self.cur_batch] 
  18.  
  19.         # 轉(zhuǎn)換為one-hot編碼 
  20.         y_ = np.zeros((y.shape[0], self.vocab_size), dtype=np.bool) 
  21.         for i in range(y.shape[0]): 
  22.             y_[i][y[i]] = 1 
  23.  
  24.         # 如果到最后一個(gè)批次,則回到最開頭 
  25.         self.cur_batch = (self.cur_batch +1) % self.batch_len 
  26.  
  27.         return x, y_ 
模型
 
  1. class PTBModel(object): 
  2.     def __init__(self, config, is_training=True): 
  3.  
  4.         self.num_steps = config.num_steps 
  5.         self.vocab_size = config.vocab_size 
  6.  
  7.         self.embedding_dim = config.embedding_dim 
  8.         self.hidden_dim = config.hidden_dim 
  9.         self.num_layers = config.num_layers 
  10.         self.rnn_model = config.rnn_model 
  11.  
  12.         self.learning_rate = config.learning_rate 
  13.         self.dropout = config.dropout 
  14.  
  15.         self.placeholders()  # 輸入占位符 
  16.         self.rnn()           # rnn 模型構(gòu)建 
  17.         self.cost()          # 代價(jià)函數(shù) 
  18.         self.optimize()      # 優(yōu)化器 
  19.         self.error()         # 錯(cuò)誤率 
  20.  
  21.  
  22.     def placeholders(self): 
  23.         """輸入數(shù)據(jù)的占位符""" 
  24.         self._inputs = tf.placeholder(tf.int32, [None, self.num_steps]) 
  25.         self._targets = tf.placeholder(tf.int32, [None, self.vocab_size]) 
  26.  
  27.  
  28.     def input_embedding(self): 
  29.         """將輸入轉(zhuǎn)換為詞向量表示""" 
  30.         with tf.device("/cpu:0"): 
  31.             embedding = tf.get_variable( 
  32.                 "embedding", [self.vocab_size, 
  33.                     self.embedding_dim], dtype=tf.float32) 
  34.             _inputs = tf.nn.embedding_lookup(embedding, self._inputs) 
  35.  
  36.         return _inputs 
  37.  
  38.  
  39.     def rnn(self): 
  40.         """rnn模型構(gòu)建""" 
  41.         def lstm_cell():  # 基本的lstm cell 
  42.             return tf.contrib.rnn.BasicLSTMCell(self.hidden_dim, 
  43.                 state_is_tuple=True
  44.  
  45.         def gru_cell():   # gru cell,速度更快 
  46.             return tf.contrib.rnn.GRUCell(self.hidden_dim) 
  47.  
  48.         def dropout_cell():    # 在每個(gè)cell后添加dropout 
  49.             if (self.rnn_model == 'lstm'): 
  50.                 cell = lstm_cell() 
  51.             else
  52.                 cell = gru_cell() 
  53.             return tf.contrib.rnn.DropoutWrapper(cell, 
  54.                 output_keep_prob=self.dropout) 
  55.  
  56.         cells = [dropout_cell() for _ in range(self.num_layers)] 
  57.         cell = tf.contrib.rnn.MultiRNNCell(cells, state_is_tuple=True)  # 多層rnn 
  58.  
  59.         _inputs = self.input_embedding() 
  60.         _outputs, _ = tf.nn.dynamic_rnn(cell=cell, 
  61.             inputs=_inputs, dtype=tf.float32) 
  62.  
  63.         # _outputs的shape為 [batch_size, num_steps, hidden_dim] 
  64.         last = _outputs[:, -1, :]  # 只需要最后一個(gè)輸出 
  65.  
  66.         # dense 和 softmax 用于分類,以找出各詞的概率 
  67.         logits = tf.layers.dense(inputs=last, units=self.vocab_size)    
  68.         prediction = tf.nn.softmax(logits)   
  69.  
  70.         self._logits = logits 
  71.         self._pred = prediction 
  72.  
  73.     def cost(self): 
  74.         """計(jì)算交叉熵代價(jià)函數(shù)""" 
  75.         cross_entropy = tf.nn.softmax_cross_entropy_with_logits( 
  76.             logits=self._logits, labels=self._targets) 
  77.         cost = tf.reduce_mean(cross_entropy) 
  78.         self.cost = cost 
  79.  
  80.     def optimize(self): 
  81.         """使用adam優(yōu)化器""" 
  82.         optimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate) 
  83.         self.optim = optimizer.minimize(self.cost) 
  84.  
  85.     def error(self): 
  86.         """計(jì)算錯(cuò)誤率""" 
  87.         mistakes = tf.not_equal( 
  88.             tf.argmax(self._targets, 1), tf.argmax(self._pred, 1)) 
  89.         self.errors = tf.reduce_mean(tf.cast(mistakes, tf.float32)) 
訓(xùn)練
 
  1. def run_epoch(num_epochs=10): 
  2.     config = LMConfig()   # 載入配置項(xiàng) 
  3.  
  4.     # 載入源數(shù)據(jù),這里只需要訓(xùn)練集 
  5.     train_data, _, _, words, word_to_id = \ 
  6.         ptb_raw_data('simple-examples/data'
  7.     config.vocab_size = len(words) 
  8.  
  9.     # 數(shù)據(jù)分批 
  10.     input_train = PTBInput(config, train_data) 
  11.     batch_len = input_train.batch_len 
  12.  
  13.     # 構(gòu)建模型 
  14.     model = PTBModel(config) 
  15.  
  16.     # 創(chuàng)建session,初始化變量 
  17.     sess = tf.Session() 
  18.     sess.run(tf.global_variables_initializer()) 
  19.  
  20.     print('Start training...'
  21.     for epoch in range(num_epochs):  # 迭代輪次 
  22.         for i in range(batch_len):   # 經(jīng)過多少個(gè)batch 
  23.             x_batch, y_batch = input_train.next_batch() 
  24.  
  25.             # 取一個(gè)批次的數(shù)據(jù),運(yùn)行優(yōu)化 
  26.             feed_dict = {model._inputs: x_batch, model._targets: y_batch} 
  27.             sess.run(model.optim, feed_dict=feed_dict) 
  28.  
  29.             # 每500個(gè)batch,輸出一次中間結(jié)果 
  30.             if i % 500 == 0: 
  31.                 cost = sess.run(model.cost, feed_dict=feed_dict) 
  32.  
  33.                 msg = "Epoch: {0:>3}, batch: {1:>6}, Loss: {2:>6.3}" 
  34.                 print(msg.format(epoch + 1, i + 1, cost)) 
  35.  
  36.                 # 輸出部分預(yù)測(cè)結(jié)果 
  37.                 pred = sess.run(model._pred, feed_dict=feed_dict) 
  38.                 word_ids = sess.run(tf.argmax(pred, 1)) 
  39.                 print('Predicted:'' '.join(words[w] for w in word_ids)) 
  40.                 true_ids = np.argmax(y_batch, 1) 
  41.                 print('True:'' '.join(words[w] for w in true_ids)) 
  42.  
  43.     print('Finish training...'
  44.     sess.close() 

需要經(jīng)過多次的訓(xùn)練才能得到一個(gè)較為合理的結(jié)果。 

 

責(zé)任編輯:龐桂玉 來源: 36大數(shù)據(jù)
相關(guān)推薦

2017-03-27 16:18:30

神經(jīng)網(wǎng)絡(luò)TensorFlow人工智能

2017-08-29 13:50:03

TensorFlow深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)

2018-08-27 17:05:48

tensorflow神經(jīng)網(wǎng)絡(luò)圖像處理

2017-09-28 16:15:12

神經(jīng)網(wǎng)絡(luò)訓(xùn)練多層

2017-12-22 08:47:41

神經(jīng)網(wǎng)絡(luò)AND運(yùn)算

2018-02-27 09:32:13

神經(jīng)網(wǎng)絡(luò)自然語言初探

2018-03-22 13:34:59

TensorFlow神經(jīng)網(wǎng)絡(luò)

2022-12-05 10:08:59

2025-02-24 08:00:00

機(jī)器學(xué)習(xí)ML架構(gòu)

2017-08-22 16:20:01

深度學(xué)習(xí)TensorFlow

2023-05-06 12:47:41

2019-01-05 08:40:17

VGG神經(jīng)網(wǎng)絡(luò)

2018-07-29 06:46:07

神經(jīng)網(wǎng)絡(luò)RNN循環(huán)神經(jīng)網(wǎng)絡(luò)

2022-10-19 07:42:41

圖像識(shí)別神經(jīng)網(wǎng)絡(luò)

2018-12-14 08:02:55

神經(jīng)網(wǎng)絡(luò)機(jī)器學(xué)習(xí)二值模型

2023-01-11 07:28:49

TensorFlow分類模型

2019-07-24 05:36:32

神經(jīng)網(wǎng)絡(luò)語言模型NNLM

2018-07-03 16:10:04

神經(jīng)網(wǎng)絡(luò)生物神經(jīng)網(wǎng)絡(luò)人工神經(jīng)網(wǎng)絡(luò)

2017-07-19 11:39:25

深度學(xué)習(xí)人工智能boosting

2017-08-10 15:31:57

Apache Spar TensorFlow
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)