7.1 不用Sequential模型的解决方案:Keras函数式API
在前面的模型构建中,我们都是基于Sequential()来进行层堆积,但是在除单个输入输出的线性堆叠之外,还有许多其他情况,例如多输入,单输出;单输入多输出等。基于此,本章将介绍利用Keras函数式API来进行模型的构建。
7.1.1 Sequential vs API
# API
from keras import Input,layers
from keras.models import Sequential,Model
seq_model = Sequential()
seq_model.add(layers.Dense(32,activation='relu',input_shape=(64,)))
seq_model.add(layers.Dense(32,activation='relu'))
seq_model.add(layers.Dense(10,activation='softmax'))
input_tensor = Input(shape=(64,))
x = layers.Dense(32,activation='relu')(input_tensor)
x = layers.Dense(32,activation='relu')(x)
output_tensor = layers.Dense(10,activation='softmax')(x)
model = Model(input_tensor,output_tensor)
model.summary()
从代码中可以看出,seq_model和model所构造的模型相同,区别在于seq_model在Dense层指定了input_shape,但是model在一开始是利用Input()函数进行指定。对比如下所示。
7.1.2 多输入模型
根据该图片写出下面所述的代码:
# 双输入模型
from keras.layers import LSTM
import tensorflow as tf
text_vocabulary_size = 10000
question_vocabulary_size = 10000
answer_vocabulary_size = 500
text_input = Input(shape=(None,),dtype='int32',name='text')
embedded_text = layers.Embedding(text_vocabulary_size,64)(text_input)
encoded_text = layers.LSTM(32)(embedded_text)
question_input = Input(shape=(None,),dtype='int32',name='question')
embedded_question = layers.Embedding(question_vocabulary_size,32)(question_input)
encoded_question = layers.LSTM(16)(embedded_question)
concatenated = layers.concatenate([encoded_text,encoded_question],axis=-1)
answer = layers.Dense(answer_vocabulary_size,activation='softmax')(concatenated)
model = Model([text_input,question_input],answer)
model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['acc'])
# 训练双输入模型
import numpy as np
num_samples = 1000
max_length = 100
text = np.random.randint(1,text_vocabulary_size,size=(num_samples,max_length))
question = np.random.randint(1,question_vocabulary_size,size=(num_samples,max_length))
answers = np.random.randint(answer_vocabulary_size,size=(num_samples))
answers = keras.utils.to_categorical(answers,answer_vocabulary_size)
model.fit([text,question],answers,epochs=10,batch_size=128)
model.fit({'text':text,'question':question},answers,epochs=10,batch_size=128)
训练结果很差,原因是我们所给出的是随机数,模型很难学习到其中有什么规律。
针对于代码部分,在“堆叠”这部分处理时,需要注意是哪个轴进行的累加操作,通过Embedding层和LSTM层的输出形式来进行辅助,有助于理解其层次结构。
7.1.3 多输出模型
from keras import layers
from keras import Input
from keras.models import Model
vocabulary_size = 50000
num_income_groups = 10
posts_input = Input(shape=(None,),dtype='int32',name='posts')
embedded_posts = layers.Embedding(256,vocabulary_size)(posts_input)
x = layers.Conv1D(128,5,activation='relu')(embedded_posts)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256,5,activation='relu')(x)
x = layers.Conv1D(256,5,activation='relu')(x)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256,5,activation='relu')(x)
x = layers.Conv1D(256,5,activation='relu')(x)
x = layers.GlobalMaxPooling1D()(x)
x = layers.Dense(128,activation='relu')(x)
age_prediction = layers.Dense(1,name='age')(x)
income_prediction = layers.Dense(num_income_groups,activation='softmax',name='income')(x)
gender_prediction = layers.Dense(1,activation='sigmoid',name='gender')(x)
model = Model(posts_input,[age_prediction,income_prediction,gender_prediction])
7.1.4 层组成的有向无环图
I. Inception模块
本质上是模块的堆叠,模块本身是小型的独立网络,被分为多个并行分支。
II.残差连接层
解决了困扰所有大规模深度学习模型的两个共性问题:梯度消失和表示瓶颈。
表示瓶颈:指的是Sequential模型中,每一个连续的表示层都构建与前一层之上,他只能访问前一层激活中包含的信息。如果某一层太小,模型会受限于该层。
梯度消失:返向传播在神经网络中经常被用到,原理是将来自输出损失的反馈信号向下传播到更底部的层。如果这个反馈信号的传播需要经过很多层,那么这个信号可能会变得十分微弱,导致网络无法进行训练。
7.1.5 共享层权重
本质上是重复使用相同的权重。例如模型中有两个语句,需要评估两个句子之间的语义相似度,只需要用一个模型来分别处理两个句子即可。
from keras import layers
from keras import Input
from keras.models import Model
lstm = layers.LSTM(32)
left_input = Input(shape=(None,128))
left_output = lstm(left_input)
right_input = Input(shape=(None,128))
right_output = lstm(right_input)
merged = layers.concatenate([left_output,right_output],axis=-1)
predictions = layers.Dense(1,activation='sigmoid')(merged)
model = Model([left_input,right_input],predictions)
7.2 使用Keras回调函数和TensorBoard来检查并监控深度学习
7.2.1 部分内置回调函数介绍
I.ModelCheckpoint与EarlyStopping回调函数
EarlyStopping:当监控的目标指标在设定的轮数内不在改善,使用该回调函数可以中断训练。
ModelCheckpoint:在训练过程中不断的保存模型。
II.ReduceLROnPlateu回调函数
该函数主要是进行学习率的调整。
7.2.2 编写自己的回调函数
# 编写自己的callback函数
import keras
import numpy as np
class ActivationLogger(keras.callbacks.Callback):
def set_model(self,model):
self.model = model
layer_outputs = [layer.output for layer in model.layers]
self.activations_model = keras.models.Model(model.input,layer_outputs) #模型实例,返回每层的激活
def on_epoch_end(self,epoch,logs=None):
if self.validation_data is None:
raise RuntimeError('Require validation_data')
validation_sample = self.validation_data[0][0:1]
activations = self.activations_model.predict(validation_sample)
f = open('activations_at_epochs_' + str(epoch) + '.npz','w')
np.savez(f,activations) #保存激活值
f.close()
7.2.3 TensorBoard(Based on ie:localhost:6006)
概念介绍:在训练过程中帮助可视化模型内部发生的一切。包括 在训练过程中以可视化的方式监控指标;将模型架构可视化;将激活和梯度的直方图可视化;以三维的形式研究嵌入。
import keras
from keras import layers
from keras.datasets import imdb
from keras.preprocessing import sequence
max_features = 2000
max_len = 500
(x_train,y_train),(x_test,y_test) = imdb.load_data(num_words=max_features)
x_train = sequence.pad_sequences(x_train,maxlen=max_len)
x_test = sequence.pad_sequences(x_test,maxlen=max_len)
model = keras.models.Sequential()
model.add(layers.Embedding(max_features,128,input_length=max_len,name='embed'))
model.add(layers.Conv1D(32,7,activation='relu'))
model.add(layers.MaxPooling1D(5))
model.add(layers.Conv1D(32,7,activation='relu'))
model.add(layers.GlobalMaxPooling1D())
model.add(layers.Dense(1))
model.summary()
model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['acc'])
callbacks = [keras.callbacks.TensorBoard(log_dir='my_log_dir/',histogram_freq=1,embeddings_freq=1)]
history = model.fit(x_train,y_train,epochs=20,batch_size=128,validation_split=0.2,callbacks=callbacks)
需要利用cmd进行启动,找到文件位置,定位文件即可。
7.3 让模型性能发挥到极致
7.3.1 批标准化
工作原理:训练过程中在内部保存已读取每批数据均值和方差的指数移动平均值。
效果:有助于梯度传播,允许更深的网络。
7.3.2 深度可分离卷积
效果:替代conv2D,让模型更加轻量、速度更快,提高任务性能。
原理:对输入的每个通道分别执行空间卷积,然后通过逐点卷积(1*1)将输出通道混合,相当于将空间特征学习和通道特征学习分开。
7.3.3 超参数优化
优化过程:
(1)选择一组超参数(自动选择)。
(2)构建相应的模型。
(3)将模型在训练数据上拟合,并衡量其在验证数据上的最终性能。
(4)选择要尝试的下一组超参数(自动选择)。
(5)重复上述过程。
(6)衡量模型在测试数据上的性能。
7.3.4 模型集成
分类器集成:通常使用加权平均,更好的分类器被赋予更大的权重,较差的分类器被赋予较小的权重。在进行集成权重的寻找时,通常使用随机搜索或者简单的优化算法。