携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
在上一篇文章中,我们介绍了LSTM模型,并且使用LSTM模型完成了文本分类和文本生成的实战。
今天我们将使用tensorflow_datasets中的imdb数据使用subword_level来进行文本分类的方法
-
在这个实战中,我们使用的是imdb的数据集,在这个数据集中,我们是使用词为单位来表达所有的句子和语料,对词来做embedding,对embedding来输入我们的循环神经网络,去做文本分类。
-
但是,在NLP领域,我们很多时候是不使用词为单位的,因为词为单位有两个缺点,
- 一个是词的词表比较大,因而我们就需要一个比较大的词表,那么我们的model_size就会比较大;
- 第二个原因就是,我的词表再大,它还是有一个上限的,而对于语言来说,它的词语会非常多,很多次都不在词表中,我遇到它就只能用UNK表示。
-
那么怎么解决这个问题呢?
- 一个方法就是使用char-level model, char-level就是字符级别的,对于英文来说就是a-z这26个字母加0-9这10个数字
- 一种就是使用subword-level model,subword-level是介于char-level和word-level之间的一个level;例如:对于‘hello’就使用‘he’、‘ll’、‘o'三个subword-level来表示
接下来,我们就来看一个如何使用subword-level来训练一个文本分类模型。
-
5.1 我们先介绍一个新的库:Tensorflow_datasets在这个库中,tensorflow是帮我们定义好了许许多多的公开的数据集,这些数据集都是以dataset的格式去存储的,可以通过一个string字符串去载入进来
- 5.1.1 载入数据
- as_supervised:数据集是否有监督
import tensorflow_datasets as tfds
dataset, info = tfds.load('imdb_reviews/subwords8k', with_info = True,
as_supervised=True)
train_dataset, test_dataset = dataset['train'], dataset['test']
5.1.2 对数据集进行操作:
- encoder:可以将词语转成subword
tokenizer = info.features['text'].encoder
print('vocabulary size: {}'.format(tokenizer.vocab_size))
运行结果:
vocabulary size: 8185
5.1.3 接下来,我们测试一下对于一个句子来说tokenizer会把它变成什么样子:
- 使用tokenizer.encode方法对句子进行处理
- 使用tokenizer.decode在把句子转回去
sample_string = 'Tensorflow is cool.'
tokenized_string = tokenizer.encode(sample_string)
print('Tokenized string is {}'.format(tokenized_string))
original_string = tokenizer.decode(tokenized_string)
print('Original string is {}'.format(original_string))
assert original_string == sample_string
运行结果:
Tokenized string is [6307, 2327, 2934, 7961, 9, 2724, 7975]
Original string is Tensorflow is cool.
看一下句子对应的字母是什么:
for token in tokenized_string:
print('{} --> {}'.format(token, tokenizer.decode([token])))
运行结果:
6307 --> Ten
2327 --> sor
2934 --> flow
7961 -->
9 --> is
2724 --> cool
7975 --> .
5.1.4 对数据集进行变换,包括shuffle,batch
padded_batch:对于每一个batch分别做padding,找到batch中最长的样本,根据最长的样本做padding,当然,你也可以自己设置最长的长度
buffer_size = 10000
batch_size = 64
print(tf.compat.v1.data.get_output_shapes(train_dataset))
print(tf.compat.v1.data.get_output_shapes(test_dataset))
train_dataset = train_dataset.shuffle(buffer_size)
train_dataset = train_dataset.padded_batch(batch_size, tf.compat.v1.data.get_output_shapes(train_dataset))
test_dataset = test_dataset.padded_batch(batch_size, tf.compat.v1.data.get_output_shapes(test_dataset))
5.1.5 建立模型:
vocab_size = tokenizer.vocab_size
embedding_dim = 16
batch_size = 512
bi_rnn_model = keras.models.Sequential([
keras.layers.Embedding(vocab_size, embedding_dim),
keras.layers.Bidirectional(
keras.layers.LSTM(
units = 32, return_sequences = False)),
keras.layers.Dense(32, activation = 'relu'),
keras.layers.Dense(1, activation='sigmoid'),
])
bi_rnn_model.summary()
bi_rnn_model.compile(optimizer = 'adam',
loss = 'binary_crossentropy',
metrics = ['accuracy'])
运行结果:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding (Embedding) (None, None, 16) 130960
_________________________________________________________________
bidirectional (Bidirectional (None, 64) 12544
_________________________________________________________________
dense (Dense) (None, 32) 2080
_________________________________________________________________
dense_1 (Dense) (None, 1) 33
=================================================================
Total params: 145,617
Trainable params: 145,617
Non-trainable params: 0
_________________________________________________________________
训练模型,打印学习曲线:
history = bi_rnn_model.fit(
train_dataset,
epochs = 10,
validation_data = test_dataset)
def plot_learning_curves(history, label, epochs, min_value, max_value):
data = {}
data[label] = history.history[label]
data['val_'+label] = history.history['val_'+label]
pd.DataFrame(data).plot(figsize=(8, 5))
plt.grid(True)
plt.axis([0, epochs, min_value, max_value])
plt.show()
plot_learning_curves(history, 'accuracy', 10, 0, 1)
plot_learning_curves(history, 'loss', 10, 0, 1)
运行结果:
在tfds中导入的数据和keras中导入的数据有些区别,所以并不能和之前的模型进行对比,但是经过图像可以发现,我们的模型过拟合现象比之前要弱一些。
因而,我们可以看到,通过使用subword这种机制可以是词表变小,词表变小参数就会变少,参数变少过拟合的风险就变低了一些。