keras版本模型的训练

1、模型的构建与训练
import tensorflow as tf
inputs = tf.keras.Input(shape=(32,))  #(输入的数据维度为32)
x = tf.keras.layers.Dense(64, activation='relu')(inputs) #(64个神经元)
x = tf.keras.layers.Dense(64, activation='relu')(x)#(64个神经元)
predictions = tf.keras.layers.Dense(10)(x) #(预测值或者说输出是10类)
#- inputs(模型输入)
#- output(模型输出)
model = tf.keras.Model(inputs=inputs, outputs=predictions)
#函数式建模方法必须标注model = tf.keras.Model(inputs=输入,outputs=输出)
#指定损失函数 (loss) tf.keras.optimizers.RMSprop
#优化器 (optimizer) tf.keras.losses.SparseCategoricalCrossentropy
#指标 (metrics) ['accuracy'] 
model.compile(optimizer=tf.keras.optimizers.Adam(0.001), #优化器
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), #损失函数
              metrics=['accuracy']) #评估函数
#构建训练用的数据集
import numpy as np
x_train = np.random.random((1000, 32))
y_train = np.random.randint(10, size=(1000, ))
#训练集
x_val = np.random.random((200, 32))
y_val = np.random.randint(10, size=(200, ))
#验证集
x_test = np.random.random((200, 32))
y_test = np.random.randint(10, size=(200, ))
#测试集
model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_val, y_val))

在这里我们使用validation_data参数将Numpy数组的元组传递(x_val, y_val)给模型,以在每个时期结束时评估验证损失和验证指标。
此外我们也可以用参数validation_split保留部分训练数据以供验证。参数值代表要保留用于验证的数据的一部分,因此应将其设置为大于0且小于1的数字。例如,validation_split=0.2表示“使用20%的数据进行验证”,而validation_split=0.6表示“使用60%的数据用于验证”。
验证的计算方法是在进行任何改组之前,对fit调用接收到的数组进行最后x%的采样。
注意,只能validation_split在使用Numpy数据进行训练时使用。

model.fit(x_train, y_train, batch_size=64, validation_split=0.2, epochs=1)
#使用20%的数据进行验证。

对训练的理解:针对整个训练集,训练"epoch"次,每一次通过将数据切成大小为“ batch_size”的“批”来训练模型。

2、模型的验证与预测

验证:model.evaluate
预测:model.predict
两者之间的不同

# Evaluate the model on the test data using `evaluate`
print('\n# Evaluate on test data')
results = model.evaluate(x_test, y_test, batch_size=128)
print('test loss, test acc:', results)
#evaluate返回的是损失与精度
# Generate predictions (probabilities -- the output of the last layer)
# on new data using `predict`
print('\n# Generate predictions for 3 samples')
predictions = model.predict(x_test[:3])
#predict返回的是预测值
print('predictions shape:', predictions.shape)

3、类别加权与样本加权

类别加权:class_weight
样本加权:sample_weight
更进一步的介绍

class_weight仅仅是解决类不平衡;sample_weights则是解决类内样本之间的不平衡。

例子:

import tensorflow as tf
#构建模型
def get_uncompiled_model():
    inputs = tf.keras.Input(shape=(32,), name='digits')
    x = tf.keras.layers.Dense(64, activation='relu', name='dense_1')(inputs)
    x = tf.keras.layers.Dense(64, activation='relu', name='dense_2')(x)
    outputs = tf.keras.layers.Dense(10, name='predictions')(x)
    model = tf.keras.Model(inputs=inputs, outputs=outputs)
    return model

def get_compiled_model():
    model = get_uncompiled_model()
    model.compile(optimizer=tf.keras.optimizers.RMSprop(learning_rate=1e-3),
                  loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
                  metrics=['sparse_categorical_accuracy'])
    return model
#准备训练数据
import numpy as np
#给类别5增加加权重
class_weight = {0: 1., 1: 1., 2: 1., 3: 1., 4: 1.,
                5: 2.,
                6: 1., 7: 1., 8: 1., 9: 1.} #class_weight为字典的形式
print('Fit with class weight')
model = get_compiled_model()
model.fit(x_train, y_train,
          class_weight=class_weight,
          batch_size=64,
          epochs=4)

#用样本加权的方式给所有类别为5的样本增加权重
#sample_weight = np.ones(shape=(len(y_train),)) #sample_class为numpy数组形式
#sample_weight[y_train == 5] = 2.
#print('\nFit with sample weight')
#model = get_compiled_model()
#model.fit(x_train, y_train,
#          sample_weight=sample_weight,
#          batch_size=64,
#          epochs=4)

4、一些回调函数

Keras中的回调是在训练期间(在某个时期开始时,在批处理结束时,在某个时期结束时等)在不同时间点调用的对象,这些对象可用于实现以下行为:

EarlyStopping(早停)
monitor: 被监测的数据。
min_delta: 在被监测的数据中被认为是提升的最小变化,例如,小于 min_delta 的绝对变化会被认为没有提升。
patience: 没有进步的训练轮数,在这之后训练就会被停止。
verbose: 详细信息模式。
mode: {auto, min, max} 其中之一。 在 min 模式中,当被监测的数据停止下降,训练就会停止;在 max 模式中,当被监测的数据停止上升,训练就会停止;在 auto模式中,方向会自动从被监测的数据的名字中判断出来。

model = get_compiled_model()
#callbacks以列表的形式给出
callbacks = [
    tf.keras.callbacks.EarlyStopping(
        # 当‘val_loss’不再下降时候停止训练 
        monitor='val_loss',
        # “不再下降”被定义为“减少不超过1e-2”
        min_delta=1e-2,
        # “不再改善”进一步定义为“至少2个epoch”
        patience=2,
        #代表显示详细信息
        verbose=1
	)
]
model.fit(x_train, y_train,
          epochs=20,
          batch_size=64,
          callbacks=callbacks,
          validation_split=0.2)

checkpoint模型
在相对较大的数据集上训练模型时,至关重要的是要定期保存模型的checkpoint。
最简单的方法是使用ModelCheckpoint回调:

model = get_compiled_model()

callbacks = [
    tf.keras.callbacks.ModelCheckpoint(
        filepath='mymodel_{epoch}',
        # 模型保存路径
        # 下面的两个参数意味着当且仅当`val_loss`分数提高时,我们才会覆盖当前检查点。
        save_best_only=True,
        monitor='val_loss',
        save_weights_only=True,#仅仅保存模型权重
        verbose=1)
]
model.fit(x_train, y_train,
          epochs=3,
          batch_size=64,
          callbacks=callbacks,
          validation_split=0.2)

ReduceLROnPlateau
monitor: 被监测的指标。
factor: 学习速率被降低的因数。新的学习速率 = 学习速率 * 因数
patience:没有进步的训练轮数,在这之后训练速率会被降低。
verbose: 整数。0:安静,1:更新信息。
mode: {auto, min,max} 其中之一。如果是 min 模式,学习速率会被降低如果被监测的数据已经停止下降; 在max模式,学习速率会被降低如果被监测的数据已经停止上升; 在 auto 模式,方向会被从被监测的数据中自动推断出来。
min_delta:衡量新的最佳阈值,仅关注重大变化。
cooldown: 在学习速率被降低之后,重新恢复正常操作之前等待的训练轮数量。
min_lr:学习速率的下边界。

当检测指标未得到改善,进行n倍的学习率调整常常能获得较好的效果。

model = get_compiled_model()

callbacks = [
	#clssbacks列表中也可以保存多个回调函数,用逗号隔开
    tf.keras.callbacks.ModelCheckpoint(
        filepath='mymodel_{epoch}',
        # 模型保存路径
        # 下面的两个参数意味着当且仅当`val_loss`分数提高时,我们才会覆盖当前检查点。
        save_best_only=True,
        monitor='val_loss',
        #加入这个仅仅保存模型权重
        save_weights_only=True,
        verbose=1),
           
    tf.keras.callbacks.ReduceLROnPlateau(monitor="val_sparse_categorical_accuracy", 
                                         verbose=1, 
                                         mode='max', 
                                         factor=0.5, 
                                         patience=3)
   #注意这里的“监视对象”是验证指标 
]
model.fit(x_train, y_train,
          epochs=30,
          batch_size=64,
          callbacks=callbacks,
          validation_split=0.2
         )

5、多输入,多输出模型

考虑以下模型,该模型具有形状的图像输入(32, 32, 3)(即(height, width, channels))和形状的时间序列输入(None, 10)(即(timesteps, features))。我们的模型将具有根据这些输入的组合计算出的两个输出:“得分”(形状(1,))和五类(形状(5,))的概率分布。

image_input = tf.keras.Input(shape=(32, 32, 3), name='img_input')
timeseries_input = tf.keras.Input(shape=(20, 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])
#layers.concatenate(a,b,axis=i) 为将a张量与b张量沿着第i个下标变化的方向拼接
#设axis=i,则numpy沿着第i个下标变化的方向进行操作
#axis=-1时,沿着最后一个下标变化的方向进行操作
score_output = tf.keras.layers.Dense(1, name='score_output')(x) #输出一,得分
class_output = tf.keras.layers.Dense(5, name='class_output')(x) #输出二,类别

model = tf.keras.Model(inputs=[image_input, timeseries_input],
                    outputs=[score_output, class_output])#在这里进行拼接
model.compile(
    optimizer=tf.keras.optimizers.RMSprop(1e-3),
    loss=[tf.keras.losses.MeanSquaredError(),
          tf.keras.losses.CategoricalCrossentropy(from_logits=True)]
    #在编译时,通过将损失函数作为列表传递,我们可以为不同的输出指定不同的损失
    #如果我们仅将单个损失函数传递给模型,则将相同的损失函数应用于每个输出,这在此处不合适。
	metrics=[
        [tf.keras.metrics.MeanAbsolutePercentageError(),
              tf.keras.metrics.MeanAbsoluteError()],
    #这里第一个输出对应两个评估指标,第二个输出对应一个评估指标    
             [tf.keras.metrics.CategoricalAccuracy()]
    ]
)
#model.compile(
#    optimizer=tf.keras.optimizers.RMSprop(1e-3),
#    loss={'score_output': tf.keras.losses.MeanSquaredError(),
#          'class_output': tf.keras.losses.CategoricalCrossentropy(from_logits=True)
#         },
#    metrics={'score_output': [tf.keras.metrics.MeanAbsolutePercentageError(),
#                              tf.keras.metrics.MeanAbsoluteError()],
#             
#             'class_output': [tf.keras.metrics.CategoricalAccuracy()]}
#	 loss_weights={'score_output': 2., 'class_output': 1.}
#)   
#可以用字典的形式设置损失函数与评估指标,如果您有两个以上的输出,我们建议使用显式名称和字典。
#可以使用loss_weight对不同的特定于输出的损失赋予不同的权重(例如,在我们的示例中,我们可能希望通过将某类损失函数赋予更高的权重)

layers.concatenate用法

6、完整代码

import tensorflow as tf
#构建模型
image_input = tf.keras.Input(shape=(32, 32, 3), name='img_input')
timeseries_input = tf.keras.Input(shape=(20, 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, name='class_output')(x)

model = tf.keras.Model(inputs=[image_input, timeseries_input],
                    outputs=[score_output, class_output])
#编译
model.compile(
    optimizer=tf.keras.optimizers.RMSprop(1e-3),
    loss=[tf.keras.losses.MeanSquaredError(),
          tf.keras.losses.CategoricalCrossentropy(from_logits=True)])

#构建训练集
import numpy as np
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))

#训练
model.fit([img_data, ts_data], [score_targets, class_targets],
          batch_size=32,
          epochs=3)

# 另外一种训练方式
#model.fit({'img_input': img_data, 'ts_input': ts_data},
#          {'score_output': score_targets, 'class_output': class_targets},
#          batch_size=32,
#          epochs=3)