说到lstm之前需要说一下循环神经网络(Recurrent Neural Network,RNN), RNN是一种用于处理序列数据的神经网络。相比一般的神经网络来说,他能够处理序列变化的数据,特别是时间序列数据。比如某个单词的意思会因为上文提到的内容不同而有不同的含义,RNN就能够很好地解决这类问题。
但RNN有个关键问题,在处理长序列后面时出现梯度消失和梯度爆炸的问题,lstm正好解决了这个问题。相比较RNN, lstm 在长序列数据上更容易取得更好表现。
lstm 还有一个类似的gru 模型,进一步精简了lstm的控制门数量,理论上表现应该更好。代码同lstm类似。此处不讲lstm的原理,只展示在tensorflow 2.0 中如何用lstm实现段落意义识别:
# 导入库
import tensorflow as tf
from tensorflow.keras import datasets, layers, optimizers, Sequential, metrics
from tensorflow import keras
import numpy as np
from scipy import sparse
import os
# 只使用gpu 0
os.environ["CUDA_VISIBLE_DEVICES"] = "1"
# 设置随机数种子
tf.random.set_seed(22)
np.random.seed(22)
assert tf.__version__.startswith('2.')
batchsz = 256 # batch size
# the most frequest words
total_words = 4096 # 要编码的字典中文字数目
max_review_len = 1995 # 序列最长包含多少词
embedding_len = 100 # 每个词编码的的长度
units = 64 # lstm layer中参数输出的维度
epochs = 100 #训练100个epches
# 读入数据,这儿是用稀疏矩阵储存的数据
matrixfile = "textword_numc_sparse.npz" # 导入自己的文字样本,文字已经转化为数字表示
targetfile = "target_5k6mer_tfidf.txt" # label,本次是二分类
allmatrix = sparse.load_npz(matrixfile).toarray()
target = np.loadtxt(targetfile)
print("allmatrix shape: {};target shape: {}".format(allmatrix.shape, target.shape))
x = tf.convert_to_tensor(allmatrix, dtype=tf.int32)
x = keras.preprocessing.sequence.pad_sequences(x, maxlen=max_review_len)
y = tf.convert_to_tensor(target, dtype=tf.int32)
idx = tf.range(allmatrix.shape[0])
idx = tf.random.shuffle(idx)
# 划分训练集,验证集,测试集,按7:1:2比例来划分
x_train, y_train = tf.gather(x, idx[:int(0.7 * len(idx))]), tf.gather(y, idx[:int(0.7 * len(idx))])
x_val, y_val = tf.gather(x, idx[int(0.7 * len(idx)):int(0.8 * len(idx))]), tf.gather(y, idx[int(0.7 * len(idx)):int(0.8 * len(idx))])
x_test, y_test = tf.gather(x, idx[int(0.8 * len(idx)):]), tf.gather(y, idx[int(0.8 * len(idx)):])
print(x_train.shape,x_val.shape,x_test.shape)
db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
db_train = db_train.shuffle(6000).batch(batchsz, drop_remainder=True).repeat()
db_val = tf.data.Dataset.from_tensor_slices((x_val, y_val))
db_val = db_val.batch(batchsz, drop_remainder=True)
db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
db_test = db_test.batch(batchsz, drop_remainder=True)
# 搭建模型
network = Sequential([layers.Embedding(total_words, embedding_len,input_length=max_review_len),
layers.LSTM(units, dropout=0.5, return_sequences=True, unroll=True),
layers.LSTM(units, dropout=0.5, unroll=True),
# 如果采用gru,只需要把上面两层换成
# layers.GRU(units, dropout=0.5, return_sequences=True, unroll=True),
# layers.GRU(units, dropout=0.5, unroll=True),
layers.Flatten(),
#layers.Dense(128, activation=tf.nn.relu),
#layers.Dropout(0.6),
layers.Dense(1, activation='sigmoid')])
# 查看模型sumaary
network.build(input_shape=(None, max_review_len))
network.summary()
# 编译
network.compile(optimizer=keras.optimizers.Adam(0.001),
loss=tf.losses.BinaryCrossentropy(),
metrics=['accuracy'])
#训练,注意此处设置了setps_per_epoches, db_train中需要repeat(),不然有warning,具体见本人文章:https://blog.csdn.net/weixin_44022515/article/details/103884654
network.fit(db_train, epochs=epochs, validation_data=db_val,steps_per_epoch=x_train.shape[0]//batchsz)
network.evaluate(db_test)
注意事项:
- 保重gpu 足够大,不然会一直停留在如下状态:
2020-01-26 21:08:37.544395: W tensorflow/core/common_runtime/process_function_library_runtime.cc:675] Ignoring multi-device function optimization failure: Deadline exceeded: meta_optimizer exceeded deadline.
- 序列长度
max_review_len
不能设置太长,使用imdb的数据字体长度设置为80可以取得很好效果。此例中我用max_review_len =1999或者1000效果都不是太好。使用max_review_len =4995 直接停留在1中的warning中,目前还没有好的解决办法。
如何把文字用数字唯一编码,输入tensorflow进行embeding
tensorflow要求embeding 层的输入为数字,如果‘我 爱 我 的 祖 国’ 可以用[1,2,1,3,4,5]这样每个数字代表一个字或者词组。可以用如下代码来编码
mydir=np.unique(total) # 获得字典,即文本中所有单词的唯一集合
# 为每个字命名一个数字,形成一个字典
kmerlist={
}
count=0
for kmer in mydir:
kmerlist[kmer] = count
count += 1
# 编码你的arrary或者文本,这儿是textword
textword_num=[[kmerlist[i] for i in text] for text in textword]