本文是基于tensorflow2.2.0版本,介绍了模型的训练与评估。主要介绍了tf.keras的内置训练过程,包括compile、fit,其中compile中包含优化器、loss与metrics的使用,内置api中还包含了很多辅助工具,在Callback中进行介绍;除了简单的单输入单输出模型之外,本文还介绍了多输入、多输出模型的训练过程。本文中涉及的内容都是内置api,相关内容大都可以进行自定义,自定义相关内容会陆续在后续文章里介绍。
实战系列篇章中主要会分享,解决实际问题时的过程、遇到的问题或者使用的工具等等。如问题分解、bug排查、模型部署等等。相关代码实现开源在:/wellinxu/nlp_store ,更多内容关注知乎专栏(或微信公众号):NLP杂货铺。
简单文本分类模型示例训练与评估流程compilefitCallback多输入、多输出模型compilefit参考
简单文本分类模型示例
如下面代码所示,根据【NLP实战篇之tensorflow2.0快速入门】获取一个完整的文本分类示例,其中包含数据获取、数据简单预处理、模型构建、训练与评估。
#下载IMDB数据 vocab_size=10000#保留词的个数 imdb=tf.keras.datasets.imdb (train_data,train_labels),(test_data,test_labels)=imdb.load_data(num_words=vocab_size) #一个将单词映射到整数索引的词典 word_index=imdb.get_word_index()#索引从1开始 word_index={k:(v+3)fork,vinword_index.items()} word_index[""]=0 word_index[""]=1 word_index[""]=2#unknown word_index[""]=3 #统一文本序列长度 train_data=tf.keras.preprocessing.sequence.pad_sequences(train_data,value=word_index[""],padding="post",truncating="post",maxlen=256) test_data=tf.keras.preprocessing.sequence.pad_sequences(test_data,value=word_index[""],padding="post",truncating="post",maxlen=256) #模型构建 model=tf.keras.Sequential([ tf.keras.layers.Embedding(vocab_size,16),#[batch_size,seq_len,16] tf.keras.layers.GlobalAveragePooling1D(),#[batch_size,16] tf.keras.layers.Dense(16,activation='relu'),#[batch_size,16] tf.keras.layers.Dense(1,activation='sigmoid')#[batch_size,1] ]) #配置模型训练参数 #pile(optimizer='adam',loss='binary_crossentropy',metrics=['accuracy']) pile(optimizer=tf.keras.optimizers.Adam(),loss=tf.keras.losses.BinaryCrossentropy(),metrics=[tf.keras.metrics.BinaryAccuracy()]) #训练模型 history=model.fit(train_data,train_labels,epochs=40,batch_size=512) #评估测试集 model.evaluate(test_data,test_labels,verbose=2)importtensorflowastf
训练与评估流程
compile
如上面代码所示,要使用fit进行训练模型,需要制定优化器、损失函数和评价指标,通过compile方法传递给模型。除了这三个参数,compile还包含了其他参数:
optimizer: 字符串(优化器名称)或者优化器实例,具体可看tf.keras.optimizers
loss: 字符串(损失函数名称)、损失函数或损失实例,具体可看tf.keras.losses.Loss
与tf.keras.losses
metrics: 评价方法列表,列表中每个值可以是字符串(度量函数名称)、度量函数或者度量实例,具体可看tf.keras.metrics.Metric
与tf.keras.metrics
loss_weights: 列表或者字典格式,模型不同输出的loss权重,用于多输出模型sample_weight_mode:weighted_metrics: 通过样本权重或者类别权重计算的度量列表**kwargs: 其他关键字参数
其中优化器、loss和度量方法都有很多内置的api,如下表所示。除此之外,还支持自定义相关函数,此部分内容在后续文章中介绍。
optimizer优化器:Adadelta、Adagrad、Adam、Adamax、Ftrl、SGD、Nadam、RMSprop等loss损失:BinaryCrossentropy、CategoricalCrossentropy、CategoricalHinge、CosineSimilarity、Hinge、Huber、KLDivergence、LogCosh、MeanAbsoluteError、MeanAbsolutePercentageError、MeanSquaredError、MeanSquaredLogarithmicError、Poisson、SparseCategoricalCrossentropy、SquaredHinge、MAE、MAPE、MSE、MSLE等等metrics度量:AUC、Accuracy、BinaryAccuracy、BinaryCrossentropy、CategoricalAccuracy、CosineSimilarity、FalseNegatives、FalsePositives、MeanIoU、Mean、MeanAbsoluteError、MeanSquaredError、Precision、Recall、TopKCategoricalAccuracy等等
在训练神经网络的时候,有个比较重要的超参数:学习率,这个参数的大小或者变化,都严重影响着最终模型的效果。通过优化器中learning_rate参数可以设置学习率的大小与变化。learning_rate可以设置为静态的,比如2e-5,或者设置为动态的,tf.keras.optimizers.schedules
中已经提供了部分学习率衰减方法,如:ExponentialDecay、InverseTimeDecay、LearningRateSchedule、PiecewiseConstantDecay、PolynomialDecay等等。
fit
fit方法是tf.keras中内置的训练方法,其除了包含必要的输入数据与训练轮次之外,还有包含很多其他参数,如下所示:
batch_size: Integer或None
,每次进行梯度更新的样本数量,默认32epochs: Integer. 模型训练的轮次Number of epochs to train the model.verbose: 0, 1, or 2. 信息显示模式0 = silent, 1 = progress bar, 2 = one line per epochcallbacks:keras.callbacks.Callback
示例列表validation_split: 0-1之间的浮点数,将多少比例的训练数据用作验证数据validation_data: 评估数据shuffle: Boolean (每一轮训练之前是否扰乱训练数据) or str (for 'batch')class_weight: 字典,类别权重,类别索引为key,权重为值sample_weight: 样本权重initial_epoch: Integer,从第几轮次开始训练steps_per_epoch: Integer orNone
,每轮次训练多少步validation_steps:validation_batch_size:validation_freq:max_queue_size: Integer. 只用于keras.utils.Sequence
输入workers: Integer. 只用于keras.utils.Sequence
输入use_multiprocessing: Boolean. 只用于keras.utils.Sequence
输入
其中validation_split参数可以自动分离训练集留作验证数据,class_weight作为类权重,可以缓解类别不平衡的问题,样本权重sample_weight可以起到类似的作用,其控制程度更细致,能够进一步提高难样本的权重,或者降低简单/无效等样本。
Callback
Callback是训练或评估期间,在不同时间点(某个周期开始时、某个批次结束时、某个周期结束时)调用的对象,这些对象可以实现以下行为:
定义验证模型定期或者触发条件进行模型保存训练停滞时改变学习率训练停滞时微调结构训练结束或者触发条件时发送电子邮件或即时消息等
具体使用方式,如下所示:
#提前终止训练 tf.keras.callbacks.EarlyStopping(monitor="val_loss",min_delta=1e-2,patience=2,verbose=1), #保存中间模型 tf.keras.callbacks.ModelCheckpoint(filepath="mymodel_{epoch}",save_best_only=True,monitor="val_loss",verbose=1), #可视化化损失与指标 tf.keras.callbacks.TensorBoard(log_dir="/full_path_to_your_logs",histogram_freq=0,embeddings_freq=0,update_freq="epoch") ] model.fit(train_data,train_labels,epochs=40,batch_size=512,callbacks=callbacks)callbacks=[
tf.keras.callbacks
中提供了一些内置的callback,我们也可以进行自定义,自定义相关内容后续文章介绍。下面展示了keras中内置的callback:
BaseLogger:累积每轮训练的平均指标,这个Callback会被keras模型默认调用CSVLogger:将每轮的损失与度量结果数据流写入csv文件中EarlyStopping:当指定的度量指标停止改进时,停止训练History:将事件记录到History
对象中,这个Callback会被keras模型默认调用LearningRateScheduler:修改学习率ModelCheckpoint:以某种频率保存模型或权重ProgbarLogger:向stdout输出度量指标ReduceLROnPlateau:当某个指标停止改进时降低学习率RemoteMonitorTensorBoard:可视化工具TerminateOnNaN:当遇到NaN损失时终止训练
多输入、多输出模型
前面的示例中,模型都是单个输入与单个输出,但有很多模型是多个输入或输出,例如上图模型结构所示,我们用以下方法构建模型:
timeseries_input=tf.keras.Input(shape=(None,10),name="ts_input") x1=tf.keras.layers.Conv2D(3,3)(image_input) x1=tf.keras.layers.GlobalMaxPooling2D()(x1) x2=tf.keras.layers.Conv1D(3,3)(timeseries_input) x2=tf.keras.layers.GlobalMaxPooling1D()(x2) x=tf.keras.layers.concatenate([x1,x2]) score_output=tf.keras.layers.Dense(1,name="score_output")(x) class_output=tf.keras.layers.Dense(5,activation="softmax",name="class_output")(x) model=tf.keras.Model( inputs=[image_input,timeseries_input],outputs=[score_output,class_output] )image_input=tf.keras.Input(shape=(32,32,3),name="img_input")
compile
如果loss或者metrics参数只有单个传递给模型,则每一个输出都用一个loss或者metrics,但在很多情况下不同的输出需要不同的loss或者metrics,我们就需要对应每个输出给出不同的值,如下面所示:
optimizer=tf.keras.optimizers.RMSprop(1e-3), loss=[tf.keras.losses.MeanSquaredError(),tf.keras.losses.CategoricalCrossentropy()], metrics=[ [ tf.keras.metrics.MeanAbsolutePercentageError(), tf.keras.metrics.MeanAbsoluteError(), ], [tf.keras.metrics.CategoricalAccuracy()], ], )pile(
loss与metrics都是list的形式,按照output的顺序对应,而我们上面的模型中,已经给输出层进行了命名,则可以通过字典来制定loss与metrics,当输出超过2个的时候,尤其推荐字典的方式。同时,我们还可以使用loss_weights参数来给不同的输出指定权重,具体使用方法如下:
optimizer=tf.keras.optimizers.RMSprop(1e-3), loss={ "score_output":tf.keras.losses.MeanSquaredError(), "class_output":tf.keras.losses.CategoricalCrossentropy(), }, metrics={ "score_output":[ tf.keras.metrics.MeanAbsolutePercentageError(), tf.keras.metrics.MeanAbsoluteError(), ], "class_output":[tf.keras.metrics.CategoricalAccuracy()], }, loss_weights={"score_output":2.0,"class_output":1.0}, )pile(
除此之外,如果某些输出不为训练,只用来预测,则可以写成这样:
pile( optimizer=tf.keras.optimizers.RMSprop(1e-3), loss=[None,tf.keras.losses.CategoricalCrossentropy()], ) #或dict的形式 pile( optimizer=tf.keras.optimizers.RMSprop(1e-3), loss={"class_output":tf.keras.losses.CategoricalCrossentropy()}, )#list的形式
fit
fit在接受多输入的时候,跟上面loss类似,可以使用numpy数组的list或者dict形式,如下所示:
img_data=np.random.random_sample(size=(100,32,32,3)) ts_data=np.random.random_sample(size=(100,20,10)) score_targets=np.random.random_sample(size=(100,1)) class_targets=np.random.random_sample(size=(100,5)) #list形式 model.fit([img_data,ts_data],[score_targets,class_targets],batch_size=32,epochs=1) #或者dict形式 model.fit( {"img_input":img_data,"ts_input":ts_data}, {"score_output":score_targets,"class_output":class_targets}, batch_size=32, epochs=1, )#随机生成NumPy数据
当然可以将数据转换成Dataset格式,然后传给fit,如下面代码所示:
train_dataset=tf.data.Dataset.from_tensor_slices( ( {"img_input":img_data,"ts_input":ts_data}, {"score_output":score_targets,"class_output":class_targets}, ) ) train_dataset=train_dataset.shuffle(buffer_size=1024).batch(64) model.fit(train_dataset,epochs=1)#dataset格式
参考
/guide/keras/train_and_evaluate