在一些场景下,使用tensorflow默认的训练过程无法满足我们的需求,故需要自定义模型训练,以下是自定义模型及其训练的全过程。
def base_model():
inputs = tf.keras.layers.Input(shape=(len(train.columns)))
x = tf.keras.layers.Dense(128, activation='relu')(inputs)
x = tf.keras.layers.Dense(64, activation='relu')(x)
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
return model
model = base_model()
optimizer = tf.keras.optimizers.RMSprop(learning_rate=0.001)
loss_object = tf.keras.losses.BinaryCrossentropy()
outputs = model(norm_test_X.values)
loss_value = loss_object(y_true=test_Y.values, y_pred=outputs)
print("Loss before training %.4f" % loss_value.numpy())
class F1Score(tf.keras.metrics.Metric):
def __init__(self, name='f1_score', **kwargs):
super(F1Score, self).__init__(name=name, **kwargs)
self.tp = tf.Variable(0, dtype = 'int32')
self.fp = tf.Variable(0, dtype = 'int32')
self.tn = tf.Variable(0, dtype = 'int32')
self.fn = tf.Variable(0, dtype = 'int32')
def update_state(self, y_true, y_pred, sample_weight=None):
conf_matrix = tf.math.confusion_matrix(y_true, y_pred, num_classes=2)
self.tn.assign_add(conf_matrix[0][0])
self.tp.assign_add(conf_matrix[1][1])
self.fp.assign_add(conf_matrix[0][1])
self.fn.assign_add(conf_matrix[1][0])
def result(self):
if (self.tp + self.fp == 0):
precision = 1.0
else:
precision = self.tp / (self.tp + self.fp)
if (self.tp + self.fn == 0):
recall = 1.0
else:
recall = self.tp / (self.tp + self.fn)
# 返回 F1 Score
f1_score = 2 * ((precision * recall)/(precision + recall))
return f1_score
def reset_states(self):
self.tp.assign(0)
self.tn.assign(0)
self.fp.assign(0)
self.fn.assign(0)
train_f1score_metric = F1Score()
val_f1score_metric = F1Score()
train_acc_metric = tf.keras.metrics.BinaryAccuracy()
val_acc_metric = tf.keras.metrics.BinaryAccuracy()
def apply_gradient(optimizer, loss_object, model, x, y):
with tf.GradientTape() as tape:
logits = model(x)
loss_value = loss_object(y_true=y, y_pred=logits)
gradients = tape.gradient(loss_value, model.trainable_weights)
optimizer.apply_gradients(zip(gradients, model.trainable_weights))
return logits, loss_value
def train_data_for_one_epoch(train_dataset, optimizer, loss_object, model,
train_acc_metric, train_f1score_metric, verbose=True):
losses = []
# 遍历所有训练数据
for step, (x_batch_train, y_batch_train) in enumerate(train_dataset):
# 模型计算的预测值
logits, loss_value = apply_gradient(optimizer, loss_object, model, x_batch_train, y_batch_train)
losses.append(loss_value)
# 格式化
logits = tf.round(logits)
logits = tf.cast(logits, 'int64')
# 更新training metrics
train_acc_metric.update_state(y_batch_train, logits)
train_f1score_metric.update_state(y_batch_train, logits)
# 更新进度
if verbose:
print("Training loss for step %s: %.4f" % (int(step), float(loss_value)))
return losses
def perform_validation():
losses = []
# 遍历所有validation data.
for x_val, y_val in test_dataset:
# 计算validation的预测值及loss
val_logits = model(x_val)
val_loss = loss_object(y_true=y_val, y_pred=val_logits)
losses.append(val_loss)
# 格式化
val_logits = tf.cast(tf.round(model(x_val)), 'int64')
# 更新validation metrics
val_acc_metric.update_state(y_val, val_logits)
val_f1score_metric.update_state(y_val, val_logits)
return losses
# 循环epochs次
epochs = 5
epochs_val_losses, epochs_train_losses = [], []
for epoch in range(epochs):
print('Start of epoch %d' % (epoch,))
# 执行Train Loop
losses_train = train_data_for_one_epoch(train_dataset, optimizer, loss_object, model, train_acc_metric, train_f1score_metric)
# 获取训练结果
train_acc = train_acc_metric.result()
train_f1score = train_f1score_metric.result()
# 执行Validation Loop
losses_val = perform_validation()
# 获取Validation结果
val_acc = val_acc_metric.result()
val_f1score = val_f1score_metric.result()
# 计算train和validation的loss
losses_train_mean = np.mean(losses_train)
losses_val_mean = np.mean(losses_val)
epochs_val_losses.append(losses_val_mean)
epochs_train_losses.append(losses_train_mean)
print('\n Epcoh %s: Train loss: %.4f Validation Loss: %.4f, Train Accuracy: %.4f, Validation Accuracy %.4f, Train F1 Score: %.4f, Validation F1 Score: %.4f' % (epoch, float(losses_train_mean), float(losses_val_mean), float(train_acc), float(val_acc), train_f1score, val_f1score))
# 重置metrics
train_acc_metric.reset_states()
val_acc_metric.reset_states()
val_f1score_metric.reset_states()
train_f1score_metric.reset_states()