方法1:
在模型初始化方法中定义:
#说明,此处的vocab可以是词库路径,也可以是词库list
self.stringLookUp = tf.keras.layers.experimental.preprocessing.StringLookup(vocabulary=vocab,mask_token='SSSSSS')
self.embedding_dict = tf.Variable(
tf.random_uniform_initializer(-1.0, 1.0)([self.stringLookUp.vocab_size(), embedding_size]),
name="ebedding_dict"
)
在call方法中调用,
embed_word_vectors1 = tf.nn.embedding_lookup(self.embedding_dict, self.stringLookUp(inputs))
原理是,将输入的每一个字符串元素进行lookup,并根据lookup的位置序号,找到初始化的embedding向量,所以会增加维度;
缺点是,训练时模型无法直接根据模型的变量进行求导,否则报常数不能求导的错误,需要动态获取指定对应的变量,获取方法如下:
with tf.GradientTape() as tape:
y_predict = self.model(train_x)
outer_loss = self.loss(train_y, y_predict)
batch_step += 1
# 参数调整
self.variable = []
self.variable.extend(self.model.dense.variables)
self.variable.append(self.model.embedding_dict)
grads = tape.gradient(outer_loss, self.variable)
self.optimizer.apply_gradients(grads_and_vars=zip(grads, self.variable))
方法2:使用特征工程的方法,
在模型中初始化:
#说明,此处的vocab可以是词库路径,也可以是词库list
ind = tf.feature_column.categorical_column_with_vocabulary_file("sentence_vocab", vocabulary_file = vocab,default_value=0)
self.embedding_size = embedding_size
self.sentence_length = sentence_length
self.dense_feature_layer = tf.keras.layers.DenseFeatures([tf.feature_column.embedding_column(ind, dimension=embedding_size)])
self.embedding_dict = tf.Variable(
tf.random_uniform_initializer(-1.0, 1.0)([self.stringLookUp.vocab_size(), embedding_size]),
name="ebedding_dict"
)
在call中调用:
inputs_tensor = tf.reshape(tf.constant(inputs),(-1,1))
embed_word_vectors = self.dense_feature_layer({"sentence_vocab":inputs_tensor})
embed_word_vectors = tf.reshape(embed_word_vectors,(-1,self.sentence_length,self.embedding_size))
方法二中,输入必须为二维向量,并且会对最里层的维度进行特征转换以及embedding;所以希望对每一个元素进行embedding的话,需要小技巧维度转换一下。推荐使用方法二
下面是全部的模型代码:
import tensorflow as tf
'''
使用标准RNN处理短文本分类问题;lstm可以用来处理长文本分类
'''
class SingleRNNModel(tf.keras.Model):
def __init__(self, vocab=None, embedding_size=256,sentence_length=20, dropout=0.5, recurrent_dropout=0.5):
'''
:param vocab: 字符串对应的list 或者一个字符串文件路径
:param embedding_size:
:param dropout:
:param recurrent_dropout:
'''
super(SingleRNNModel,self).__init__()
ind = tf.feature_column.categorical_column_with_vocabulary_file("sentence_vocab", vocabulary_file = vocab,default_value=0)
self.embedding_size = embedding_size
self.sentence_length = sentence_length
self.dense_feature_layer = tf.keras.layers.DenseFeatures([tf.feature_column.embedding_column(ind, dimension=embedding_size)])
lstm1_forward = tf.keras.layers.LSTM(64, dropout=dropout, recurrent_dropout=recurrent_dropout,
go_backwards=False, return_sequences=False, return_state=False)
lstm1_backward = tf.keras.layers.LSTM(64, dropout=dropout, recurrent_dropout=recurrent_dropout,
go_backwards=True, return_sequences=False, return_state=False)
self.bilstm = tf.keras.layers.Bidirectional(lstm1_forward, backward_layer=lstm1_backward)
self.dense = tf.keras.layers.Dense(1, activation='sigmoid')
@tf.function(input_signature=(tf.TensorSpec(shape=(None,None), dtype=tf.dtypes.string),))
def call(self, inputs):
'''
为了支持批量处理,输入分好的词长度
:param inputs: 输入为分好词的输入 [[a,b,c],[c,d,e]],支持批量输入,输入的维度(batch_size,20,embedding_size),其中20表示最大句子分词数量,超过则截断,不足填充
:return:
'''
inputs_tensor = tf.reshape(inputs,(-1,1))
embed_word_vectors = self.dense_feature_layer({"sentence_vocab":inputs_tensor})
embed_word_vectors = tf.reshape(embed_word_vectors,(-1,self.sentence_length,self.embedding_size))
lstm_result = self.bilstm(embed_word_vectors)
return self.dense(lstm_result)
其中,tf.function可以自定义tf方法,可以用于增加模型方法和加快模型训练速度。但是被并不是任何函数都可以被?@tf.function ?修饰!@tf.function ?使用静态编译将函数内的代码转换成计算图,因此对函数内可使用的语句有一定限制(仅支持Python语言的一个子集)。TensorFlow常用模块 - @tf.function :Graph Execution模式 * - 《简单粗暴 TensorFlow 2.0》 - 书栈网 · BookStack
|