这里用Tensorflow中LSTM+Attention模型训练一个中文标题党的分类模型,并最后用Java调用训练好的模型。
数据预处理
首先根据语料和实验数据训练词向量word2vec模型,这个有很多教程,这么不再叙述。之后根据训练好的词向量生成我们需要的词典文件。保存的词典map为每行一个词和词的编号。
import gensim
import numpy as np
def load_words_embedding(model, embedding_dim, word_map_path):
"""
获取word2vec词向量中的词表
:param model: 训练好的word2vec模型
:param embedding_dim: word2vec模型的维度
:param word_map_path: word2vec中的词保存为词典编号
:return:
vocab_dict 词典编号
vectors_array 词向量转成数组,索引为0的位置填充了一个随机初始化向量,表示未知词
"""
# load word2vec
w2v_model = gensim.models.KeyedVectors.load_word2vec_format(w2v_path, binary=True)
vocab = model.wv.vocab
word_keys = list(vocab.keys())
vocab_dict = {
"UNKNOW": 0} # 0表示未知词
fw = open(word_map_path, "w", encoding="utf8")
for i in range(len(word_keys)):
vocab_dict[word_keys[i]] = i+1
fw.write(word_keys[i] + " " + str(i+1) + "\n")
fw.close()
vector_list = list()
vector_list.append(np.random.rand(embedding_dim))
for word in word_keys:
try:
vector_list.append(model[word])
except:
vector_list.append(np.random.rand(embedding_dim).astype(np.float32))
vectors_array = np.array(vector_list)
print("dict_size:", len(vocab_dict))
print("embedding_sizes:", len(vectors_array))
return vocab_dict, vectors_array
处理实验数据集,我们的数据是中文已经分好词的标题党数据,每行一个标签(1为标题党,0为正常标题)和一条数据,中间制表符隔开("\t"),实例如下图所示:
我们需要根据上面的词典文件,把分词序列转成词典编号序列,并记录每个样本的长度。
def read_data(data_path, vocab_dict, sequence_length):
"""
读取并处理实验数据集
:param data_path: 数据集路径
:param vocab_dict: 前面产生的词典
:param sequence_length: 输入模型最大长度控制,多则阶段,少则填充
:return:
datas_index: 由词序列转成的编号序列
datas_length:每条数据的长度
labels:每条数据的标签
"""
fo = open(data_path, "r", encoding='utf8')
all_data = fo.readlines()
fo.close()
random.shuffle(all_data) # 打乱顺序
datas_index = []
datas_length = []
labels = []
for line in all_data:
line = line.strip().split("\t")
label = int(line[0])
title = line[1]
data_index = []
for word in title.split(" "):
try:
data_index.append(vocab_dict[word])
except:
data_index.append(0)
length = len(title.split(" "))
if length > sequence_length:
length = sequence_length
datas_index.append(data_index)
datas_length.append(length)
labels.append(label)
return datas_index, datas_length, labels
对于长度不一致的情况,需要进行数据填充。还对标签进行one-hot编码。
def pad_sequences(data_index, maxlen):
"""
数据填充
:param data_index: 输入数据的词索引
:param maxlen: 最大长度
:return: 填充后的数据
"""
data_pad_index = []
for sentence in data_index:
if len(sentence) >= maxlen:
padded_seq = sentence[0: maxlen]
else:
padded_seq = sentence + [0] * (maxlen - len(sentence))
data_pad_index.append(padded_seq)
data_pad = np.array(data_pad_index)
return data_pad
def make_one_hot(label, n_label):
"""
label表转成one-hot向量
:param label: 输入标签值
:param n_label: 标签及分类的总数
:return: one-hot标签向量
"""
values = np.array(label)
label_vec = np.eye(n_label)[values]
return label_vec