【NLP】命名實體識別demo代碼解讀

代碼來源:flyai
深度學習框架:tensorflow
公衆號:深度學習視覺
完整代碼獲取:公衆號後臺回覆(命名實體識別demo代碼解讀)

主要部分

Embedding

input:

  1. 所有文字的字典文件,{index:word,…};
  2. 所有文字的embedding文件,{word:embedding,…};

output:
將字典中的文字全部用embedding表示,{index:embedding}。
tensorflow提供索引的方式,每次索引對應word的embedding向量。


Dataset

input_x:[batch_size,max_sentence_length,embedding]

  1. batch_size:每批次sentence的條數。
  2. max_sentence_length:max指的是本批次句子中最大的長度,其它不足該長度的句子做padding操作。
  3. embedding:對於每個word都會有對應的embedding。bs[sl[em]]

input_y:[batch_size,max_sentence_length]
4. batch_size:每批次sentence的條數。
5. max_sentence_length:max指的是本批次句子中最大的長度,其它不足該長度的句子做padding操作,length中所有位置都有label。
6. label:[‘B-LAW’,‘I-LOC’,…]

代碼解讀

config.py

# -*- coding: utf-8 -*-
import os
import json
import path

# 所有文字的字典{word:index}
src_vocab_file = os.path.join(path.DATA_PATH,'words.dict')
# 所有文字的向量表示{word:[embedding]}
word_embedding_file = os.path.join(path.DATA_PATH,'embedding.json')
# 字向量的維度
embeddings_size = 200
# 最大句子的長度,不足的padding,超過的截斷處理
max_sequence = 100
# 防止過擬合,dropout也是代價最小的ensemble操作。
dropout = 0.6
# 學習率
leanrate = 0.001

# 獲取文字數量
with open(os.path.join(path.DATA_PATH,'words.dict'), 'r') as vocab_file:
    vocab_size = len(json.load(vocab_file))

src_unknown_id = vocab_size
src_padding = vocab_size + 1
# 這是隻一種標記方式
# B(begin)就是開始位置的意思(inner)I-TIME的前一個標記只能是B-TIME
label_dic=['B-LAW','B-ROLE','B-TIME','I-LOC','I-LAW','B-PER','I-PER','B-ORG','I-ROLE','I-CRIME','B-CRIME','I-ORG','B-LOC','I-TIME','O','padding']
label_len=len(label_dic)

main.py

# -*- coding: utf-8 -*
import argparse
from flyai.dataset import Dataset
from tensorflow.contrib.rnn import DropoutWrapper
import tensorflow as tf
from model import Model
from path import MODEL_PATH, LOG_PATH
import config
from utils import load_word2vec_embedding
import numpy as np

# 超參
parser = argparse.ArgumentParser()
parser.add_argument("-e", "--EPOCHS", default=30, type=int, help="train epochs")
parser.add_argument("-b", "--BATCH", default=128, type=int, help="batch size")
args = parser.parse_args()
# 數據獲取輔助類
dataset = Dataset(epochs=args.EPOCHS, batch=args.BATCH)
# 模型操作輔助類
modelpp = Model(dataset)

# 得到訓練和測試的數據
unit_num = config.embeddings_size      # 默認詞向量的大小等於RNN(每個time step) 和 CNN(列) 中神經單元的個數, 爲了避免混淆model中全部用unit_num表示。
time_step = config.max_sequence      # 每個句子的最大長度和time_step一樣,爲了避免混淆model中全部用time_step表示。
DROPOUT_RATE = config.dropout
LEARN_RATE=config.leanrate
TAGS_NUM = config.label_len

# ——————————————————定義神經網絡變量——————————————————
class NER_net:
    def __init__(self,embedding, batch_size=args.BATCH):
        '''
        :param scope_name:
        :param iterator: 調用tensorflow DataSet API把數據feed進來。
        :param embedding: 提前訓練好的word embedding
        :param batch_size:
        '''
        self.batch_size = batch_size
        self.embedding = embedding
        # ——————————————————導入數據——————————————————————
        self.input= tf.placeholder(tf.int32, shape=[None,None],name="input")
        self.label = tf.placeholder(tf.int32, shape=[None,None],name="label")
        self.seq_length = tf.placeholder(tf.int32, shape=[None], name="max_sequence_in_batch")
        self._build_net()

    def _build_net(self):

        # embedding_lookup這個函數就是一個索引,抽取input句子中word對應的embedding,每個索引的長度都是一個embedding_size
        # 這裏總共有batch_size個句子,每個句子中有time_step(max_sentenc_length)個words,每個words的長度爲embedding_size
        # x: [batch_size, time_step, embedding_size], float32
        self.x = tf.nn.embedding_lookup(self.embedding,self.input)
        # time_step == max_sentenc_length
        # y: [batch_size, time_step]
        self.y = self.label

        cell_forward = tf.contrib.rnn.BasicLSTMCell(unit_num)
        cell_backward = tf.contrib.rnn.BasicLSTMCell(unit_num)
        if DROPOUT_RATE is not None:
            cell_forward = DropoutWrapper(cell_forward, input_keep_prob=1.0, output_keep_prob=DROPOUT_RATE)
            cell_backward = DropoutWrapper(cell_backward, input_keep_prob=1.0, output_keep_prob=DROPOUT_RATE)

        # time_major 可以適應輸入維度。
        outputs, bi_state = \
            tf.nn.bidirectional_dynamic_rnn(cell_forward, cell_backward, self.x, dtype=tf.float32)

        forward_out, backward_out = outputs
        outputs = tf.concat([forward_out, backward_out], axis=2)

        # projection:
        W = tf.get_variable("projection_w", [2 * unit_num, TAGS_NUM])
        b = tf.get_variable("projection_b", [TAGS_NUM])
        x_reshape = tf.reshape(outputs, [-1, 2 * unit_num])
        projection = tf.add(tf.matmul(x_reshape, W),b,name='projection')
        nsteps = tf.shape(outputs)[1]
        # -1 to time step
        self.outputs = tf.reshape(projection, [-1, nsteps, TAGS_NUM],name='output')

        self.log_likelihood, self.transition_params = tf.contrib.crf.crf_log_likelihood(
            self.outputs, self.y, self.seq_length)
        self.transition_params=tf.add(self.transition_params,0,name='transition_params')
        # Add a training op to tune the parameters.
        self.loss = tf.reduce_mean(-self.log_likelihood)
        self.train_op = tf.train.AdamOptimizer(LEARN_RATE).minimize(self.loss)
        tf.summary.scalar('loss', self.loss)

#訓練神經網絡
# 這裏主要將字典中所有的vocab單詞向量化,函數裏面有文件讀取
embedding = load_word2vec_embedding(config.vocab_size) 
net = NER_net(embedding)  # embedding所有詞的向量(vocab_size + 2=20000+2, embeddings_size=200)


with tf.Session() as sess:
    merged = tf.summary.merge_all()  # 將圖形、訓練過程等數據合併在一起
    writer = tf.summary.FileWriter(LOG_PATH, sess.graph)  # 將訓練日誌寫入到logs文件夾下
    sess.run(tf.global_variables_initializer())
    print(dataset.get_step())
    for i in range(dataset.get_step()):
        x_train, y_train, x_test, y_test= dataset.next_batch(args.BATCH)
        max_sentenc_length = max(map(len, x_train))
        sequence_len = np.asarray([len(x) for x in x_train])
        # padding
        # x_train: [batch_size, time_step, embedding_size], float32
        # 不足最大長度的部分用vocab_size+1這個數字表示,其實應該用"num"這個字符表示更好,不用數字
        # label不足的部分用TAGS_NUM-1這個數字表示,也應該改爲非數字的特殊字符表示。
        x_train = np.asarray([list(x[:]) + (max_sentenc_length - len(x)) * [config.src_padding] for x in x_train])
        y_train = np.asarray([list(y[:]) + (max_sentenc_length - len(y)) * [TAGS_NUM-1] for y in y_train])
        res,loss_,_= sess.run([merged,net.loss,net.train_op],
            feed_dict={net.input: x_train,net.label: y_train,net.seq_length: sequence_len})
        print('steps:{}loss:{}'.format(i,loss_))
        writer.add_summary(res, i)  # 將日誌數據寫入文件
        if i%50==0:
            modelpp.save_model(sess, MODEL_PATH, overwrite=True)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章