欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python使用循環(huán)神經(jīng)網(wǎng)絡(luò)解決文本分類問題的方法詳解

 更新時間:2020年01月16日 10:05:08   作者:theVicTory  
這篇文章主要介紹了Python使用循環(huán)神經(jīng)網(wǎng)絡(luò)解決文本分類問題的方法,結(jié)合實例形式詳細(xì)分析了Python神經(jīng)網(wǎng)絡(luò)相關(guān)概念、原理及解決文本分類具體操作技巧,需要的朋友可以參考下

本文實例講述了Python使用循環(huán)神經(jīng)網(wǎng)絡(luò)解決文本分類問題的方法。分享給大家供大家參考,具體如下:

1、概念

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

循環(huán)神經(jīng)網(wǎng)絡(luò)(Recurrent Neural Network, RNN)是一類以序列數(shù)據(jù)為輸入,在序列的演進(jìn)方向進(jìn)行遞歸且所有節(jié)點(diǎn)(循環(huán)單元)按鏈?zhǔn)竭B接的遞歸神經(jīng)網(wǎng)絡(luò)。

卷積網(wǎng)絡(luò)的輸入只有輸入數(shù)據(jù)X,而循環(huán)神經(jīng)網(wǎng)絡(luò)除了輸入數(shù)據(jù)X之外,每一步的輸出會作為下一步的輸入,如此循環(huán),并且每一次采用相同的激活函數(shù)和參數(shù)。在每次循環(huán)中,x0乘以系數(shù)U得到s0,再經(jīng)過系數(shù)W輸入到下一次,以此循環(huán)構(gòu)成循環(huán)神經(jīng)網(wǎng)絡(luò)的正向傳播。

          

在反向傳播中要求損失函數(shù)E對參數(shù)W的導(dǎo)數(shù),通過鏈?zhǔn)角髮?dǎo)法則可以得到右下的公式

  

循環(huán)神經(jīng)網(wǎng)絡(luò)與卷積神經(jīng)網(wǎng)絡(luò)作比較,卷積神經(jīng)網(wǎng)絡(luò)是一個輸出經(jīng)過網(wǎng)絡(luò)產(chǎn)生一個輸出。而循環(huán)神經(jīng)網(wǎng)絡(luò)可以實現(xiàn)一個輸入多個輸出(生成圖片描述)、多個輸入一個輸出(文本分類)、多輸入多輸出(機(jī)器翻譯、視頻解說)。

RNN使用的是tan激活函數(shù),輸出在-1到1之間,容易梯度消失。距離輸出較遠(yuǎn)的步驟對于梯度貢獻(xiàn)很小。

將底層的輸出作為高層的輸入就構(gòu)成了多層的RNN網(wǎng)絡(luò),而且高層之間也可以進(jìn)行傳遞,并且可以采用殘差連接防止過擬合。

1.2、長短期記憶網(wǎng)絡(luò)

RNN的每次傳播之間只有一個參數(shù)W,用這一個參數(shù)很難描述大量的、復(fù)雜的信息需求,為了解決這個問題引入了長短期記憶網(wǎng)絡(luò)(Long Short Term Memory,LSTM)。這個網(wǎng)絡(luò)可以進(jìn)行選擇性機(jī)制,選擇性的輸入、輸出需要使用的信息以及選擇性地遺忘不需要的信息。選擇性機(jī)制的實現(xiàn)是通過Sigmoid門實現(xiàn)的,sigmoid函數(shù)的輸出介于0到1之間,0代表遺忘,1代表記憶,0.5代表記憶50%

LSTM網(wǎng)絡(luò)結(jié)構(gòu)如下圖所示,

   

如上右圖所示為本輪運(yùn)算的隱含狀態(tài)state,當(dāng)前狀態(tài)由上一狀態(tài)和遺忘門結(jié)果作點(diǎn)積,再加上傳入們結(jié)果得到

如下左圖所示為遺忘門結(jié)構(gòu),上一輪的輸出ht-1和數(shù)據(jù)xt在經(jīng)過遺忘門選擇是否遺忘之后,產(chǎn)生遺忘結(jié)果ft

如下中圖所示為傳入門結(jié)構(gòu),ht-1和xt在經(jīng)過遺忘門的結(jié)果it和tanh的結(jié)果Ct作點(diǎn)積運(yùn)算得到本次運(yùn)算的輸入

如下右圖所示為輸出門結(jié)構(gòu),ht-1和xt經(jīng)過遺忘門的結(jié)果ot與當(dāng)狀態(tài)作點(diǎn)積產(chǎn)生本次的輸出

   

如下實現(xiàn)LSTM網(wǎng)絡(luò),首先定義_generate_params函數(shù)用于生成每個門所需的參數(shù),調(diào)用該函數(shù)定義輸入門、輸出門、遺忘門、和中間狀態(tài)tanh的參數(shù)。每個門的參數(shù)都是三個,輸入x、h的權(quán)重和偏置值。

接著開始進(jìn)行LSTM的每輪循環(huán)計算,輸入門計算就是將輸入embedded_input矩陣乘以輸入門參數(shù)x_in,再加上h和對應(yīng)參數(shù)相乘的結(jié)果,最后再加上偏置值b_in經(jīng)過sigmoid便得到輸入門結(jié)果。

同理進(jìn)行矩陣相乘加偏置操作得到遺忘門、輸出門的結(jié)果。中間態(tài)tanh與三個門的操作類似,只不過最后經(jīng)過tanh函數(shù)。

將上一個隱含態(tài)state乘以遺忘門加上輸入門乘以中間態(tài)的結(jié)果就得到當(dāng)前的隱含態(tài)state

將當(dāng)前的state經(jīng)過tanh函數(shù)再加上輸出門就得到本輪的輸出h

經(jīng)過多輪輸入循環(huán)得到的就是LSTM網(wǎng)絡(luò)的最后輸出。

# 實現(xiàn)LSTM網(wǎng)絡(luò)
  # 生成Cell網(wǎng)格所需參數(shù)
  def _generate_paramas(x_size, h_size, b_size):
    x_w = tf.get_variable('x_weight', x_size)
    h_w = tf.get_variable('h_weight', h_size)
    bias = tf.get_variable('bias', b_size, initializer=tf.constant_initializer(0.0))
    return x_w, h_w, bias
 
  scale = 1.0 / math.sqrt(embedding_size + lstm_nodes[-1]) / 3.0
  lstm_init = tf.random_uniform_initializer(-scale, scale)
  with tf.variable_scope('lstm_nn', initializer=lstm_init):
    # 輸入門參數(shù)
    with tf.variable_scope('input'):
      x_in, h_in, b_in = _generate_paramas(
        x_size=[embedding_size, lstm_nodes[0]],
        h_size=[lstm_nodes[0], lstm_nodes[0]],
        b_size=[1, lstm_nodes[0]]
      )
    # 輸出門參數(shù)
    with tf.variable_scope('output'):
      x_out, h_out, b_out = _generate_paramas(
        x_size=[embedding_size, lstm_nodes[0]],
        h_size=[lstm_nodes[0], lstm_nodes[0]],
        b_size=[1, lstm_nodes[0]]
      )
    # 遺忘門參數(shù)
    with tf.variable_scope('forget'):
      x_f, h_f, b_f = _generate_paramas(
        x_size=[embedding_size, lstm_nodes[0]],
        h_size=[lstm_nodes[0], lstm_nodes[0]],
        b_size=[1, lstm_nodes[0]]
      )
    # 中間狀態(tài)參數(shù)
    with tf.variable_scope('mid_state'):
      x_m, h_m, b_m = _generate_paramas(
        x_size=[embedding_size, lstm_nodes[0]],
        h_size=[lstm_nodes[0], lstm_nodes[0]],
        b_size=[1, lstm_nodes[0]]
      )
 
    # 兩個初始化狀態(tài),隱含狀態(tài)state和初始輸入h
    state = tf.Variable(tf.zeros([batch_size, lstm_nodes[0]]), trainable=False)
    h = tf.Variable(tf.zeros([batch_size, lstm_nodes[0]]), trainable=False)
    # 遍歷LSTM每輪循環(huán),即每個詞的輸入過程
    for i in range(max_words):
      # 取出每輪輸入,三維數(shù)組embedd_inputs的第二維代表訓(xùn)練的輪數(shù)
      embedded_input = embedded_inputs[:, i, :]
      # 將取出的結(jié)果reshape為二維
      embedded_input = tf.reshape(embedded_input, [batch_size, embedding_size])
      # 遺忘門計算
      forget_gate = tf.sigmoid(tf.matmul(embedded_input, x_f) + tf.matmul(h, h_f) + b_f)
      # 輸入門計算
      input_gate = tf.sigmoid(tf.matmul(embedded_input, x_in) + tf.matmul(h, h_in) + b_in)
      # 輸出門
      output_gate = tf.sigmoid(tf.matmul(embedded_input, x_out) + tf.matmul(h, h_out) + b_out)
      # 中間狀態(tài)
      mid_state = tf.tanh(tf.matmul(embedded_input, x_m) + tf.matmul(h, h_m) + b_m)
      # 計算隱含狀態(tài)state和輸入h
      state = state * forget_gate + input_gate * mid_state
      h = output_gate + tf.tanh(state)
    # 最后遍歷的結(jié)果就是LSTM的輸出
    last_output = h

1.3、文本分類

文本分類問題就是對輸入的文本字符串進(jìn)行分析判斷,之后再輸出結(jié)果。字符串無法直接輸入到RNN網(wǎng)絡(luò),因此在輸入之前需要先對文本拆分成單個詞組,將詞組進(jìn)行embedding編碼成一個向量,每輪輸入一個詞組,當(dāng)最后一個詞組輸入完畢時得到輸出結(jié)果也是一個向量。embedding將一個詞對應(yīng)為一個向量,向量的每一個維度對應(yīng)一個浮點(diǎn)值,動態(tài)調(diào)整這些浮點(diǎn)值使得embedding編碼和詞的意思相關(guān)。這樣網(wǎng)絡(luò)的輸入輸出都是向量,再最后進(jìn)行全連接操作對應(yīng)到不同的分類即可。

RNN網(wǎng)絡(luò)不可避免地帶來問題就是最后的輸出結(jié)果受最近的輸入較大,而之前較遠(yuǎn)的輸入可能無法影響結(jié)果,這就是信息瓶頸問題,為了解決這個問題引入了雙向LSTM。雙向LSTM不僅增加了反向信息傳播,而且每一輪的都會有一個輸出,將這些輸出進(jìn)行組合之后再傳給全連接層。

另一個文本分類模型就是HAN(Hierarchy Attention Network),首先將文本分為句子、詞語級別,將輸入的詞語進(jìn)行編碼然后相加得到句子的編碼,然后再將句子編碼相加得到最后的文本編碼。而attention是指在每一個級別的編碼進(jìn)行累加前,加入一個加權(quán)值,根據(jù)不同的權(quán)值對編碼進(jìn)行累加。

        

由于輸入的文本長度不統(tǒng)一,所以無法直接使用神經(jīng)網(wǎng)絡(luò)進(jìn)行學(xué)習(xí),為了解決這個問題,可以將輸入文本的長度統(tǒng)一為一個最大值,勉強(qiáng)采用卷積神經(jīng)網(wǎng)絡(luò)進(jìn)行學(xué)習(xí),即TextCNN。文本卷積網(wǎng)絡(luò)的卷積過程采用的是多通道一維卷積,與二維卷積相比一維卷積就是卷積核只在一個方向上移動。例如下左圖所示,1×1+5×2+2×2+4×3+3×3+3×4=48,之后卷積核向下移動一格得到45,以此類推。如下右圖所示,輸入長短不一的多個詞匯。首先將其全部填充為六通道的embedding數(shù)組,然后采用六通道的一維卷積核從上到下進(jìn)行卷積,得到一維的數(shù)組,然后再經(jīng)過池化層和全連接層后輸出。

    

可以看到CNN網(wǎng)絡(luò)不能完美處理輸入長短不一的序列式問題,但是它可以并行處理多個詞組,效率更高,而RNN可以更好地處理序列式的輸入,將兩者的優(yōu)勢結(jié)合起來就構(gòu)成了R-CNN模型。首先通過雙向RNN網(wǎng)絡(luò)對輸入進(jìn)行特征提取,再使用CNN進(jìn)一步提取,之后通過池化層將每一步的特征融合在一起,最后經(jīng)過全連接層進(jìn)行分類。

無論什么模型都需要使用embedding將輸入轉(zhuǎn)化為一個向量,當(dāng)輸入過大時,轉(zhuǎn)化的embedding層參數(shù)就會過大,不僅不利于存儲,還會造成過擬合,因此需要對embedding層進(jìn)行壓縮。原來的embedding編碼是一個參數(shù)對應(yīng)一個輸入,例如wait對應(yīng)參數(shù)x1,for對應(yīng)x2,the對應(yīng)x3。如果輸入過多,編碼參數(shù)就會很大,可以采用兩個參數(shù)對組合的方式來編碼輸入,例如wait對應(yīng)(x1,x2),for對應(yīng)(x1,x3)...,這樣就可以極大的節(jié)省參數(shù)的數(shù)量,這就是共享壓縮。

2、通過Text RNN進(jìn)行文本分類

2.1、數(shù)據(jù)預(yù)處理

在網(wǎng)上下載的文本分類數(shù)據(jù)集文件如下,分為測試集和訓(xùn)練集數(shù)據(jù),每個訓(xùn)練集下有四個文件夾,每個文件夾是一個分類,每個分類有1000個txt文件,每個文件中有一條該分類的文本

     

通過os.walk遍歷所有訓(xùn)練集文件,將分類文本通過jieba庫拆分成單個詞組,用空格分隔。然后將分類文本添加到開頭,并用制表符分隔,最后將結(jié)果輸出到train_segment.txt,

# 將文件中的句子通過jieba庫拆分為單個詞
def segment_word(input_file, output_file):
  # 循環(huán)遍歷訓(xùn)練數(shù)據(jù)集的每一個文件
  for root, folders, files in os.walk(input_file):
    print('root:', root)
    for folder in folders:
      print('dir:', folder)
    for file in files:
      file_dir = os.path.join(root, file)
      with open(file_dir, 'rb') as in_file:
        # 讀取文件中的文本
        sentence = in_file.read()
        # 通過jieba函數(shù)庫將句子拆分為單個詞組
        words = jieba.cut(sentence)
        # 文件夾路徑最后兩個字即為分類名
        content = root[-2:] + '\t'
        # 去除詞組中的空格,排除為空的詞組
        for word in words:
          word = word.strip(' ')
          if word != '':
            content += word + ' '
      # 換行并將文本寫入輸出文件
      content += '\n'
      with open(output_file, 'a') as outfile:
        outfile.write(content.strip(' '))

結(jié)果如下:

由于一些詞組出現(xiàn)次數(shù)很少,不具有統(tǒng)計意義,所以需要排除,通過get_list()方法統(tǒng)計每個詞組出現(xiàn)的頻率。利用python自帶的dictionary數(shù)據(jù)類型可以輕易實現(xiàn)詞組數(shù)據(jù)統(tǒng)計,格式為{"keyword":frequency},frequency記錄keyword出現(xiàn)的次數(shù)。如果一個詞組是新出現(xiàn)的則作為新詞條加入詞典,否則將frequency值+1。

# 統(tǒng)計每個詞出現(xiàn)的頻率
def get_list(segment_file, out_file):
  # 通過詞典保存每個詞組出現(xiàn)的頻率
  word_dict = {}
  with open(segment_file, 'r') as seg_file:
    lines = seg_file.readlines()
    # 遍歷文件的每一行
    for line in lines:
      line = line.strip('\r\n')
      # 將一行按空格拆分為每個詞,統(tǒng)計詞典
      for word in line.split(' '):
        # 如果這個詞組沒有在word_dict詞典中出現(xiàn)過,則新建詞典項并設(shè)為0
        word_dict.setdefault(word, 0)
        # 將詞典word_dict中詞組word對應(yīng)的項計數(shù)加一
        word_dict[word] += 1
    # 將詞典中的列表排序,關(guān)鍵字為列表下標(biāo)為1的項,且逆序
    sorted_list = sorted(word_dict.items(), key=lambda d: d[1], reverse=True)
    with open(out_file, 'w') as outfile:
      # 將排序后的每條詞典項寫入文件
      for item in sorted_list:
        outfile.write('%s\t%d\n' % (item[0], item[1]))

統(tǒng)計結(jié)果如下:

2.2、數(shù)據(jù)讀入

直接使用詞組無法進(jìn)行編碼學(xué)習(xí),需要將詞組轉(zhuǎn)化為embedding編碼,根據(jù)剛才生成的train_list列表,按照從前往后的順序為每個詞組編號,如果詞組頻率小于閾值則排除掉。通過Word_list類來構(gòu)建訓(xùn)練數(shù)據(jù)、測試數(shù)據(jù)的詞組對象,在類的構(gòu)造函數(shù)__init__()實現(xiàn)詞組的編碼。并定義類方法sentence2id將拆分好的句子詞組轉(zhuǎn)化為對應(yīng)的id數(shù)組,如果詞組列表中沒有該詞,則將該值置為-1。

在定義類之前首先規(guī)定一些超參數(shù)供后續(xù)使用:

# 定義超參數(shù)
embedding_size = 32 # 每個詞組向量的長度
max_words = 10 # 一個句子最大詞組長度
lstm_layers = 2 # lstm網(wǎng)絡(luò)層數(shù)
lstm_nodes = [64, 64] # lstm每層結(jié)點(diǎn)數(shù)
fc_nodes = 64 # 全連接層結(jié)點(diǎn)數(shù)
batch_size = 100 # 每個批次樣本數(shù)據(jù)
lstm_grads = 1.0 # lstm網(wǎng)絡(luò)梯度
learning_rate = 0.001 # 學(xué)習(xí)率
word_threshold = 10 # 詞表頻率門限,低于該值的詞語不統(tǒng)計
num_classes = 4 # 最后的分類結(jié)果有4類
class Word_list:
  def __init__(self, filename):
    # 用詞典類型來保存需要統(tǒng)計的詞組及其頻率
    self._word_dic = {}
    with open(filename, 'r',encoding='GB2312',errors='ignore') as f:
      lines = f.readlines()
    for line in lines:
      word, freq = line.strip('\r\n').split('\t')
      freq = int(freq)
      # 如果詞組的頻率小于閾值,跳過不統(tǒng)計
      if freq < word_threshold:
        continue
      # 詞組列表中每個詞組都是不重復(fù)的,按序添加到word_dic中即可,下一個詞組id就是當(dāng)前word_dic的長度
      word_id = len(self._word_dic)
      self._word_dic[word] = word_id
 
  def sentence2id(self, sentence):
    # 將以空格分割的句子返回word_dic中對應(yīng)詞組的id,若不存在返回-1
    sentence_id = [self._word_dic.get(word, -1)
            for word in sentence.split()]
    return sentence_id
 
 
train_list = Word_list(train_list_dir)

定義TextData類來完成數(shù)據(jù)的讀入和管理,在__init__()函數(shù)中讀取剛才處理好的train_segment.txt文件,根據(jù)制表符分割類別標(biāo)記和句子詞組,將類別和句子分別轉(zhuǎn)化為數(shù)字id。如果句子的詞組超過了最大閾值,則截去后面多余的,如果不夠則用-1填充。定義類函數(shù)_shuffle_data()用于清洗數(shù)據(jù),next_batch()用于按批次返回數(shù)據(jù)和標(biāo)簽,get_size()用于返回詞組總條數(shù)。

class TextData:
  def __init__(self, segment_file, word_list):
    self.inputs = []
    self.labels = []
    # 通過詞典管理文本類別
    self.label_dic = {'體育': 0, '校園': 1, '女性': 2, '出版': 3}
    self.index = 0
 
    with open(segment_file, 'r') as f:
      lines = f.readlines()
      for line in lines:
        # 文本按制表符分割,前面為類別,后面為句子
        label, content = line.strip('\r\n').split('\t')[0:2]
        self.content_size = len(content)
        # 將類別轉(zhuǎn)換為數(shù)字id
        label_id = self.label_dic.get(label)
        # 將句子轉(zhuǎn)化為embedding數(shù)組
        content_id = word_list.sentence2id(content)
        # 如果句子的詞組長超過最大值,截取max_words長度以內(nèi)的id值
        content_id = content_id[0:max_words]
        # 如果不夠則填充-1,直到max_words長度
        padding_num = max_words - len(content_id)
        content_id = content_id + [-1 for i in range(padding_num)]
        self.inputs.append(content_id)
        self.labels.append(label_id)
    self.inputs = np.asarray(self.inputs, dtype=np.int32)
    self.labels = np.asarray(self.labels, dtype=np.int32)
    self._shuffle_data()
 
  # 對數(shù)據(jù)按照(input,label)對來打亂順序
  def _shuffle_data(self):
    r_index = np.random.permutation(len(self.inputs))
    self.inputs = self.inputs[r_index]
    self.labels = self.labels[r_index]
 
  # 返回一個批次的數(shù)據(jù)
  def next_batch(self, batch_size):
    # 當(dāng)前索引+批次大小得到批次的結(jié)尾索引
    end_index = self.index + batch_size
    # 如果結(jié)尾索引大于樣本總數(shù),則打亂所有樣本從頭開始
    if end_index > len(self.inputs):
      self._shuffle_data()
      self.index = 0
      end_index = batch_size
    # 按索引返回一個批次的數(shù)據(jù)
    batch_inputs = self.inputs[self.index:end_index]
    batch_labels = self.labels[self.index:end_index]
    self.index = end_index
    return batch_inputs, batch_labels
 
  # 獲取詞表數(shù)目
  def get_size(self):
    return self.content_size
 
# 訓(xùn)練數(shù)據(jù)集對象
train_set = TextData(train_segment_dir, train_list)
# print(data_set.next_batch(10))
# 訓(xùn)練數(shù)據(jù)集詞組條數(shù)
train_list_size = train_set.get_size()

2.3、構(gòu)建計算圖模型

定義函數(shù)create_model來實現(xiàn)計算圖模型的構(gòu)建。首先定義模型輸入的占位符,分別為輸入文本inputs、輸出標(biāo)簽outputs、Dropout的比率keep_prob。

首先構(gòu)建embedding層,將輸入的inputs編碼抽取出來拼接成一個矩陣,例如輸入[1,8,3]則抽取embeding[1]、embedding[8]和embedding[3]拼接成一個矩陣

接下來構(gòu)建LSTM網(wǎng)絡(luò),這里構(gòu)建了兩層網(wǎng)絡(luò),每層的結(jié)點(diǎn)數(shù)在之前的參數(shù)lstm_node[]數(shù)組中定義。每個cell的構(gòu)建通過函數(shù)tf.contrib.rnn.BasicLSTMCell實現(xiàn),之后經(jīng)過Dropout操作。再將兩個cell合并為一個LSTM網(wǎng)絡(luò),通過函數(shù)tf.nn.dynamic_rnn將輸入embedded_inputs輸入到LSTM網(wǎng)絡(luò)中進(jìn)行訓(xùn)練得到輸出rnn_output。這是一個三維數(shù)組,第二維表示訓(xùn)練的步數(shù),我們只取最后一維的結(jié)果,即下標(biāo)值為-1.

接下來構(gòu)建全連接層,通過tf.layers.dense函數(shù)定義全連接層,再經(jīng)過一個dropout操作后將輸出映射到類別上,類別的種類的參數(shù)num_classes,得到估計值logits

接下來就可以求損失、精確率等評估值了。計算算預(yù)測值logits與標(biāo)簽值outputs之間的交叉熵?fù)p失值,接下來通過arg_max計算預(yù)測值,進(jìn)而求準(zhǔn)確率

接下來定義訓(xùn)練方法,通過梯度裁剪應(yīng)用到變量上以防止梯度消失。

最后將輸入占位符、損失等評估值、其他訓(xùn)練參數(shù)返回到調(diào)用函數(shù)的外部。

# 創(chuàng)建計算圖模型
def create_model(list_size, num_classes):
  # 定義輸入輸出占位符
  inputs = tf.placeholder(tf.int32, (batch_size, max_words))
  outputs = tf.placeholder(tf.int32, (batch_size,))
  # 定義是否dropout的比率
  keep_prob = tf.placeholder(tf.float32, name='keep_rate')
  # 記錄訓(xùn)練的總次數(shù)
  global_steps = tf.Variable(tf.zeros([], tf.float32), name='global_steps', trainable=False)
 
  # 將輸入轉(zhuǎn)化為embedding編碼
  with tf.variable_scope('embedding',
              initializer=tf.random_normal_initializer(-1.0, 1.0)):
    embeddings = tf.get_variable('embedding', [list_size, embedding_size], tf.float32)
    # 將指定行的embedding數(shù)值抽取出來
    embedded_inputs = tf.nn.embedding_lookup(embeddings, inputs)
 
  # 實現(xiàn)LSTM網(wǎng)絡(luò)
  scale = 1.0 / math.sqrt(embedding_size + lstm_nodes[-1]) / 3.0
  lstm_init = tf.random_uniform_initializer(-scale, scale)
  with tf.variable_scope('lstm_nn', initializer=lstm_init):
    # 構(gòu)建兩層的lstm,每層結(jié)點(diǎn)數(shù)為lstm_nodes[i]
    cells = []
    for i in range(lstm_layers):
      cell = tf.contrib.rnn.BasicLSTMCell(lstm_nodes[i], state_is_tuple=True)
      # 實現(xiàn)Dropout操作
      cell = tf.contrib.rnn.DropoutWrapper(cell, output_keep_prob=keep_prob)
      cells.append(cell)
    # 合并兩個lstm的cell
    cell = tf.contrib.rnn.MultiRNNCell(cells)
    # 將embedded_inputs輸入到RNN中進(jìn)行訓(xùn)練
    initial_state = cell.zero_state(batch_size, tf.float32)
    # runn_output:[batch_size,num_timestep,lstm_outputs[-1]
    rnn_output, _ = tf.nn.dynamic_rnn(cell, embedded_inputs, initial_state=initial_state)
    last_output = rnn_output[:, -1, :]
 
  # 構(gòu)建全連接層
  fc_init = tf.uniform_unit_scaling_initializer(factor=1.0)
  with tf.variable_scope('fc', initializer=fc_init):
    fc1 = tf.layers.dense(last_output, fc_nodes, activation=tf.nn.relu, name='fc1')
    fc1_drop = tf.contrib.layers.dropout(fc1, keep_prob)
    logits = tf.layers.dense(fc1_drop, num_classes, name='fc2')
 
  # 定義評估指標(biāo)
  with tf.variable_scope('matrics'):
    # 計算損失值
    softmax_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=outputs)
    loss = tf.reduce_mean(softmax_loss)
    # 計算預(yù)測值,求第1維中最大值的下標(biāo),例如[1,1,5,3,2] argmax=> 2
    y_pred = tf.argmax(tf.nn.softmax(logits), 1, output_type=tf.int32)
    # 求準(zhǔn)確率
    correct_prediction = tf.equal(outputs, y_pred)
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
 
  # 定義訓(xùn)練方法
  with tf.variable_scope('train_op'):
    train_var = tf.trainable_variables()
    # for var in train_var:
    #   print(var)
    # 對梯度進(jìn)行裁剪防止梯度消失或者梯度爆炸
    grads, _ = tf.clip_by_global_norm(tf.gradients(loss, train_var), clip_norm=lstm_grads)
    # 將梯度應(yīng)用到變量上去
    optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
    train_op = optimizer.apply_gradients(zip(grads, train_var), global_steps)
 
  # 以元組的方式將結(jié)果返回
  return ((inputs, outputs, keep_prob),
      (loss, accuracy),
      (train_op, global_steps))
 
# 調(diào)用構(gòu)建函數(shù),接收解析返回的參數(shù)
placeholders, matrics, others = create_model(train_list_size, num_classes)
inputs, outputs, keep_prob = placeholders
loss, accuracy = matrics
train_op, global_steps = others

2.4、進(jìn)行訓(xùn)練

通過Session運(yùn)行計算圖模型,從train_set中按批次獲取訓(xùn)練集數(shù)據(jù)并填充占位符,運(yùn)行sess.run,獲取損失值、準(zhǔn)確率等中間值打印

# 進(jìn)行訓(xùn)練
init_op = tf.global_variables_initializer()
train_keep_prob = 0.8    # 訓(xùn)練集的dropout比率
train_steps = 10000
 
with tf.Session() as sess:
  sess.run(init_op)
 
  for i in range(train_steps):
    # 按批次獲取訓(xùn)練集數(shù)據(jù)
    batch_inputs, batch_labels = train_set.next_batch(batch_size)
    # 運(yùn)行計算圖
    res = sess.run([loss, accuracy, train_op, global_steps],
            feed_dict={inputs: batch_inputs, outputs: batch_labels,
                 keep_prob: train_keep_prob})
    loss_val, acc_val, _, g_step_val = res
    if g_step_val % 20 == 0:
      print('第%d輪訓(xùn)練,損失:%3.3f,準(zhǔn)確率:%3.5f' % (g_step_val, loss_val, acc_val))

在我的數(shù)據(jù)集進(jìn)行一萬輪訓(xùn)練后,訓(xùn)練集的準(zhǔn)確率在90%左右徘徊

 

源代碼及相關(guān)數(shù)據(jù)文件:https://github.com/SuperTory/MachineLearning/tree/master/TextRNN

更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python加密解密算法與技巧總結(jié)》、《Python編碼操作技巧總結(jié)》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》及《Python入門與進(jìn)階經(jīng)典教程

希望本文所述對大家Python程序設(shè)計有所幫助。

相關(guān)文章

  • 關(guān)于Theano和Tensorflow多GPU使用問題

    關(guān)于Theano和Tensorflow多GPU使用問題

    這篇文章主要介紹了關(guān)于Theano和Tensorflow多GPU使用問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • Pyinstaller打包.py生成.exe的方法和報錯總結(jié)

    Pyinstaller打包.py生成.exe的方法和報錯總結(jié)

    今天小編就為大家分享一篇關(guān)于Pyinstaller打包.py生成.exe的方法和報錯總結(jié),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • Python Traceback異常代碼排錯利器使用指南

    Python Traceback異常代碼排錯利器使用指南

    這篇文章主要為大家介紹了Python Traceback異常代碼排錯利器使用指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Python中不同數(shù)據(jù)對象的空值校驗的方法小結(jié)

    Python中不同數(shù)據(jù)對象的空值校驗的方法小結(jié)

    Python中有多種數(shù)據(jù)對象,每種都有其特定的空值表示方法和校驗方式,本文將深入探討這些空值校驗的方法,有需要的小伙伴可以參考一下
    2024-04-04
  • 用Python自動發(fā)郵件提醒你周末吃啥

    用Python自動發(fā)郵件提醒你周末吃啥

    大家好,本篇文章主要講的是用Python自動發(fā)郵件提醒你周末吃啥,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • Python中死鎖的形成示例及死鎖情況的防止

    Python中死鎖的形成示例及死鎖情況的防止

    由于Python中允許創(chuàng)建多個線程,那么互斥鎖或者線程同時獲取多個鎖的情況就有可能發(fā)生,這里我們就來看一下Python中死鎖的形成示例及死鎖情況的防止:
    2016-06-06
  • 基于Python實現(xiàn)一鍵獲取電腦瀏覽器的賬號密碼

    基于Python實現(xiàn)一鍵獲取電腦瀏覽器的賬號密碼

    發(fā)現(xiàn)很多人在學(xué)校圖書館喜歡用電腦占座,而且出去的時候經(jīng)常不鎖屏,為了讓大家養(yǎng)成良好的習(xí)慣,本文將分享一個小程序,可以快速獲取你存儲在電腦瀏覽器中的所有賬號和密碼,感興趣的可以了解一下
    2022-05-05
  • PyTorch平方根報錯的處理方案

    PyTorch平方根報錯的處理方案

    這篇文章主要介紹了PyTorch平方根報錯的處理方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • PyCharm 2020.2下配置Anaconda環(huán)境的方法步驟

    PyCharm 2020.2下配置Anaconda環(huán)境的方法步驟

    這篇文章主要介紹了PyCharm 2020.2下配置Anaconda環(huán)境的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 在Python中進(jìn)行自動化單元測試的教程

    在Python中進(jìn)行自動化單元測試的教程

    這篇文章主要介紹了在Python中進(jìn)行自動化單元測試的教程,本文來自于IBM官方文檔,需要的朋友可以參考下
    2015-04-04

最新評論