Press "Enter" to skip to content

Tensorflow——循环神经网络(二)序列式问题

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

 

在上一篇文章中,我们介绍了数据padding,Embedding与变长输入的处理的问题,并且使用Embedding解决文本分类的问题

 

今天我们来解释为什幺需要循环神经网络和循环神经网络的结构,并且使用循环神经网络来进行文本分类。

 

2.1 序列问题

2.1.1 为什幺需要循环神经网络——合并+padding的缺点?

信息丢失

多个embedding合并
Pad噪音、无主次

无效计算太多、抵消

太多的padding

2.1.2 为什幺需要循环神经网络——序列式问题

普通神经网络
1对多:图片生成描述
多对1:文本分类(文本情感分析)
多对多:encoding-decoding机器翻译

实时多对多:视频解说

2.1.3 循环神经网络

维护一个状态作为下一步的额外输出
每一步使用同样的激活函数和参数

最简单的循环神经网络

循环神经网络的列子

2.2 循环神经网络文本分类

2.2.1 定义一个1层单层单向的rnn,2层全连接层的模型

embedding_dim = 16
batch_size = 512
single_rnn_model = keras.models.Sequential([
    # 1. define matrix: [vocab_size, embedding_dim]
    # 2. [1,2,3,4..], max_length * embedding_dim
    # 3. batch_size * max_length * embedding_dim
    keras.layers.Embedding(vocab_size, embedding_dim,
                           input_length = max_length),
    # return_sequences: 决定你返回的输出(False)是最后一步的输出,还是所有的输出
    keras.layers.SimpleRNN(units = 64, return_sequences = False),
    keras.layers.Dense(64, activation = 'relu'),
    keras.layers.Dense(1, activation='sigmoid'),
])
single_rnn_model.summary()
single_rnn_model.compile(optimizer = 'adam',
                         loss = 'binary_crossentropy',
                         metrics = ['accuracy'])

 

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, 500, 16)           160000    
_________________________________________________________________
simple_rnn (SimpleRNN)       (None, 64)                5184      
_________________________________________________________________
dense (Dense)                (None, 64)                4160      
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 65        
=================================================================
Total params: 169,409
Trainable params: 169,409
Non-trainable params: 0

 

训练模型:

 

history_single_rnn = single_rnn_model.fit(
    train_data, train_labels,
    epochs = 30,
    batch_size = batch_size,
    validation_split = 0.2)

 

在训练30次之后,发现accuracy是0.4990,这对于一个二分类问题来说是没有进展的,因为做随机猜测的话,accuracy也有50%。

 

这说明普通的单层rnn并没有效果。

 

打印学习曲线

 

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_single_rnn, 'accuracy', 30, 0, 1)
plot_learning_curves(history_single_rnn, 'loss', 30, 0, 1)

 

运行结果:

 

 

在测试集上的效果:

 

single_rnn_model.evaluate(
    test_data, test_labels,
    batch_size = batch_size,
    verbose = 0)

 

运行结果:

 

[0.7533659934997559, 0.5001599788665771]

2.2.2 实现一个双层双向的rnn,2层全连接层的模型

只需要使用Bidirectional对RNN进行一个封装,封装完之后就是一个双向的RNN

embedding_dim = 16
batch_size = 512
model = keras.models.Sequential([
    # 1. define matrix: [vocab_size, embedding_dim]
    # 2. [1,2,3,4..], max_length * embedding_dim
    # 3. batch_size * max_length * embedding_dim
    keras.layers.Embedding(vocab_size, embedding_dim,
                           input_length = max_length),
    keras.layers.Bidirectional(
        keras.layers.SimpleRNN(
            units = 64, return_sequences = True)),
    # return_sequences改为True的原因:下一个RNN的输入是序列,而不是单个的输入
    keras.layers.Bidirectional(
        keras.layers.SimpleRNN(
            units = 64, return_sequences = False)),
    keras.layers.Dense(64, activation = 'relu'),
    keras.layers.Dense(1, activation='sigmoid'),
])
model.summary()
model.compile(optimizer = 'adam',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])

 

运行结果:

 

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, 500, 16)           160000    
_________________________________________________________________
bidirectional (Bidirectional (None, 500, 128)          10368     
_________________________________________________________________
bidirectional_1 (Bidirection (None, 128)               24704     
_________________________________________________________________
dense (Dense)                (None, 64)                8256      
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 65        
=================================================================
Total params: 203,393
Trainable params: 203,393
Non-trainable params: 0
_________________________________________________________________

 

训练模型:

 

history = model.fit(
    train_data, train_labels,
    epochs = 30,
    batch_size = batch_size,
    validation_split = 0.2)

 

可以发现,在训练集上的accuracy是1.0,但是在验证集上的accuracy只有0.5572,也只比单层RNN好了一点点

 

打印学习曲线:

 

plot_learning_curves(history, 'accuracy', 30, 0, 1)
plot_learning_curves(history, 'loss', 30, 0, 3.8)

 

运行结果:

 

发现在训练集上accuracy非常好,但是在验证集上的accuracy不太好,这说明模型在训练集上过拟合了

 

这次的模型定义的是一个双层双向的RNN,模型太复杂了

2.2.3 实现一个单层双向的rnn,2层全连接层的模型

embedding_dim = 16
batch_size = 512
bi_rnn_model = keras.models.Sequential([
    # 1. define matrix: [vocab_size, embedding_dim]
    # 2. [1,2,3,4..], max_length * embedding_dim
    # 3. batch_size * max_length * embedding_dim
    keras.layers.Embedding(vocab_size, embedding_dim,
                           input_length = max_length),
    keras.layers.Bidirectional(
        keras.layers.SimpleRNN(
            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, 500, 16)           160000    
_________________________________________________________________
bidirectional (Bidirectional (None, 64)                3136      
_________________________________________________________________
dense (Dense)                (None, 32)                2080      
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 33        
=================================================================
Total params: 165,249
Trainable params: 165,249
Non-trainable params: 0
_________________________________________________________________

 

训练模型:

 

history = bi_rnn_model.fit(
    train_data, train_labels,
    epochs = 30,
    batch_size = batch_size,
    validation_split = 0.2)

 

可以发现:在训练集上的accuracy达到了1.0,在测试集上的accur达到了0.7888,比双层双向的模型要好很多

 

打印学习曲线:

 

plot_learning_curves(history, 'accuracy', 30, 0, 1.1)
plot_learning_curves(history, 'loss', 30, 0, 2.5)

 

运行结果:

 

 

 

虽然在验证集上的效果要好很多,但是依然由过拟合的现象存在。

 

在测试集上进行评估:

 

bi_rnn_model.evaluate(test_data, test_labels, batch_size = batch_size, verbose = 0)

 

运行结果:

 

[1.404372215270996, 0.7716000080108643]

 

可以发现:训练集上的accuracy是0.7716,相较于之前的简单模型的accur是0.85,那幺这是说明循环神经网络比普通的神经网络还要弱吗?

 

可以仔细看一下loss的曲线图,发现循环神经网络在训练第5次的时候,val_loss急剧上升,而在普通神经网络中在训练第10次的时候,val_loss急剧上升,这说明循环神经网络的过拟合更加明显,它的过拟合更加明显反而说明了这个模型更加强大。

 

在搭建模型的过程中,使用了一种方法来缓解过拟合,就是降低模型尺寸,把两层循环神经网络变成单层的;在搭建模型的时候,还有其他手段来缓解过拟合,比如dropout,正则化项等。

 

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。