Keras基础指南

建立一个简单的模型

SEQUENTIAL MODEL

在Keras中,可以通过组装层(layer)来构建模型(models)。模型(通常)是层的图形。最常见的模型类型是层的堆栈:序列模型(sequential model)。

下面的代码构建了一个简单的、完全连接(layer_dense)的网络(即一个多层感知器):

model %>% 
layer_dense(units = 64, activation = 'relu') %>% # Adds a densely-connected layer with 64 units to the model
layer_dense(units = 64, activation = 'relu') %>% # Add another densely-connected layer with 64 units to the model
layer_dense(units = 10, activation = 'softmax')  # Add a softmax layer with 10 output units

CONFIGURE THE LAYERS

有许多层可以使用一些常见的构造函数参数(constructor parameters):

  • activation: 设置层的激活函数(activation function),缺省情况下,未应用激活函数。

  • kernel_initializer 和 bias_initializer: 创建层的权重值(包括内核(kernek)和偏差(bias))的初始化方案。这默认为 Glorot uniform 初始化工具。

  • kernel_regularizer 和 bias_regularizer: 适用于层的权重值(核和偏差)的正则化(regularization)方案,如L1或L2正则化。缺省情况下,不应用正则化。

下面的例子使用构造函数参数来实例化一组密集层:

layer_dense(units = 64, activation ='sigmoid') 
# A linear layer with L1 regularization of factor 0.01 applied to the kernel matrix: 
layer_dense(units = 64, kernel_regularizer = regularizer_l1(0.01)) 
# A linear layer with L2 regularization of factor 0.01 applied to the bias vector: 
layer_dense(units = 64, bias_regularizer = regularizer_l2(0.01)) 
# A linear layer with a kernel initialized to a random orthogonal matrix: 
layer_dense(units = 64, kernel_initializer = 'orthogonal') 
# A linear layer with a bias vector initialized to 2.0
layer_dense(units = 64, kernel_initializer = c(2.0)) 

训练和评估

SET UP TRAINING

型构建完成后,通过调用compile方法配置其学习过程:

optimizer = 'adam', 
loss = 'categorical_crossentropy', 
metrics = list('accuracy')

compile接受三个重要参数:

  • optimizer: 优化器,设定用来加速训练的优化方法,基本都是基于梯度下降的,只是细 节上有些差异。常用的优化器有adam、rmsprop或sgd。

  • loss: 损失函数,指定优化过程中最小化的函数(即指示优化的指标)。常见的选择包括均方误差(mean square erro,mse)、分类交叉熵(categorical_crossentropy)和二进制交叉熵(binary_crossentropy)。

  • metrics: 用来监督训练过程,在分类问题中,通常设置为准确性(accuracy)。

以下是一些配置训练模型的示例:

model %>% compile( 
    optimizer = 'adam', 
     # mean squared error 
    loss = 'mse',
     # mean absolute error 
    metrics = list('mae')
    ) 
# Configure a model for categorical classification. 
model %>% compile( 
    optimizer = optimizer_rmsprop(lr = 0.01), 
    loss = "categorical_crossentropy", 
    metrics = list("categorical_accuracy")
)

INPUT DATA

您可以直接在R矩阵(matrices)和数组(array)(可能从R data.frames创建)上训练keras模型。使用fit方法对训练数据拟合模型:

labels <- matrix(rnorm(1000 * 10), nrow = 1000, ncol = 10) 
model %>% fit( data, labels, epochs = 10, batch_size = 32)

fit有三个重要的参数:

  • epochs: epoch是指对整个输入数据的一次迭代(以较小的批量完成),即当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一个 epoch。关于epochs,batchs和 iterations的区别,例如训练集有1000个样本,batchsize=10,那么对整个样本集进行1次epoch需要100次iteration。

  • batch_size: 当传递矩阵或数组数据时,模型将数据分割成指定大小的batch,并在训练期间迭代(iteration)这些batch。batch_size就是指定每个batch的大小。注意,如果样品总数不能被batch大小整除,最后一batch数据量可能会更小。

  • validation_data: 用来设定作为验证数据的训练数据的分比例。设计的函数确保数据以这样一种方式分离,即它总是针对每个epoch训练数据的相同部分。如果该选项被选择,那么所有的洗牌都是在两个epochs之间的训练样本内完成的。

下面是一个使用validation_data的例子:

labels <- matrix(rnorm(1000 * 10), nrow = 1000, ncol = 10) 
val_data <- matrix(rnorm(1000 * 32), nrow = 100, ncol = 32) 
val_labels <- matrix(rnorm(100 * 10), nrow = 100, ncol = 10) 

model %>% 
fit(data, labels, epochs = 10, batch_size = 32, validation_data = list(val_data, val_label))

EVALUATE AND PREDICT

与fit一样,评估(evaluate)和预测(predict)方法既可以使用原始数据,也可以使用数据集。

建立复杂的模型

FUNCTIONAL API

sequential 模型是一个简单的层堆栈,不能表示任意模型。使用Keras的 functional API 构建复杂的模型拓扑,例如:

  • 多输入模型(multi-input models)

  • 多输出模型(multi-output models)

  • 具有共享层的模型(同一层多次调用)(models with shared layers)

  • 具有非顺序数据流的模型(例如,剩余连接)(models with non-sequential data flows)

使用functional API构建模型的工作原理如下:

  1. 实例是可调用的,并返回一个张量。

  2. 输入张量和输出张量用于定义keras_model实例。

  3. 这个模型就像sequential模型一样进行训练。

下面的例子使用functional API来构建一个简单的、完全连接的网络:

predictions <- inputs %>%
 layer_dense(units = 64, activation = 'relu') %>% 
 layer_dense(units = 64, activation = 'relu') %>% 
 layer_dense(units = 10, activation = 'softmax') 
 
# Instantiate the model given inputs and outputs. 
model <- keras_model(inputs = inputs, outputs = predictions) 

# The compile step specifies the training configuration. 
model %>% 
compile( 
    optimizer = optimizer_rmsprop(lr = 0.001), 
    loss = 'categorical_crossentropy', 
    metrics = list('accuracy') ) 
    
# Trains for 5 epochs 
model %>% 
fit( data, labels, batch_size = 32, epochs = 5)

CUSTOM LAYERS

要创建自定义Keras层,需要创建从KerasLayer派生的R6类(R6 class)。有三个方法需要实现(所有类型的层只需要一个call()函数):

  • build(input_shape): 在这里,您将定义你的权重。 请注意,如果您的图层未定义可训练的权重,则无需实现此方法。

  • call(x): 这就是层的逻辑所在。 除非您希望您的图层支持遮罩,否则您只需关心传递给调用的第一个参数:输入张量。

  • compute_output_shape(input_shape): 如果您的图层修改了其输入的形状,则应在此处指定形状转换逻辑。 这使Keras可以进行自动形状推断。 如果您不修改输入的形状,则无需实现此方法。

下面是一个执行矩阵乘法的自定义层示例:

CustomLayer <- R6::R6Class("CustomLayer",
inherit = KerasLayer,
public = list(
    output_dim = NULL,
    kernel = NULL,
    initialize = function(output_dim) {
      self$output_dim <- output_dim
    },
    build = function(input_shape) {
      self$kernel <- self$add_weight(
          name = 'kernel',
          shape = list(input_shape[[2]], self$output_dim),
          initializer = initializer_random_normal(),
          trainable = TRUE)
    },
    call = function(x, mask = NULL) {
      k_dot(x, self$kernel)
    },
    compute_output_shape = function(input_shape) {
      list(input_shape[[1]], self$output_dim)
    }
))

为了在Keras模型中使用自定义层,您还需要创建一个包装器函数,该函数使用create_layer()函数实例化该层。例如:

layer_custom <- function(object, output_dim, name = NULL, trainable = TRUE) {
  create_layer(CustomLayer,
    object,
    list(output_dim = as.integer(output_dim),
    name = name,
    trainable = trainable))
}

您现在可以像往常一样在模型中使用该层

model %>% 
layer_dense(units = 32, input_shape = c(32,32)) %>%
layer_custom(units = 32, input_shape = c(32,32))

CUSTOM MODELS

除了创建自定义层之外,您还可以创建自定义模型。如果您想要将TensorFlow急切执行与命令式向前传递结合使用,这可能是必要的。

如果不需要这样做,但需要在构建体系结构时保持灵活性,那么建议只使用functional API。

自定义模型是通过调用keras_model_custom()传递一个函数来定义的,该函数指定要创建的层和要在向前传递时执行的操作。

# define and return a custom model 
keras_model_custom(name = name, function(self) {
  # create layers we'll need for the call (this code executes once) # note: the layers have to be created on the self object! 
  self$dense1 <- layer_dense(units = 64, activation = 'relu', input_shape = input_dim)
  self$dense2 <- layer_dense(units = 64, activation = 'relu')
  self$dense3 <- layer_dense(units = 10, activation = 'softmax') # implement call (this code executes during training & inference) 
  function(inputs, mask = NULL) {
    x <- inputs %>%
    self$dense1() %>%
    self$dense2() %>%
    self$dense3()
    x
  }
})

model <- my_model(input_dim = 32, output_dim = 10)

model %>% compile(
    optimizer = optimizer_rmsprop(lr = 0.001),
    loss = 'categorical_crossentropy',
    metrics = list('accuracy'))

# Trains for 5 epochs 
model %>% fit(data, labels, batch_size = 32, epochs = 5)

回调函数

回调函数(Callbacks),是传递给模型的对象,用于在训练期间定制和扩展模型的行为。你可以编写自己的自定义回调函数,或者使用内置的回调函数,包括:

  • callback_model_checkpoint:定期保存模型的检查点。

  • callback_learning_rate_scheduler:动态修改学习速率。

  • callback_early_stop:当验证性能停止改善时的中断训练。

  • callbacks_tensorboard:使用TensorBoard监视模型的行为。

要使用回调,请将它传递给模型的fit方法:

callbacks <- list(
    callback_early_stopping(patience = 2, monitor = 'val_loss'),
    callback_tensorboard(log_dir = './logs'))

model %>%
fit(data, labels,
batch_size = 32,
epochs = 5,
callbacks = callbacks,
validation_data = list(val_data, val_labels))

保存和恢复

WEIGHTS ONLY

使用save_model_weights_hdf5和 load_model_weights_hdf5 分别用来保存和加载模型的权重。

model %>% save_model_weights_tf('my_model/') # Restore the model's state, # this requires a model with the same architecture.

CONFIGURATION ONLY

模型的配置可以被保存——这样可以在没有任何权重的情况下序列化模型架构。保存的配置可以重新创建并初始化相同的模型,甚至不需要定义原始模型的代码。Keras支持JSON和YAML序列化格式:

json_string <- model %>% model_to_json() 
# Recreate the model (freshly initialized) 
fresh_model <- model_from_json(json_string) 
# Serializes a model to YAML format 
yaml_string <- model %>% model_to_yaml() 

注意:自定义的模型是不可序列化的,因为它们的体系结构是由传递给keras_model_custom的函数中的R代码定义的。

ENTIRE MODEL

可以将整个模型保存到包含权重值、模型配置甚至优化器配置的文件中。这允许您检查模型并在以后恢复训练——从完全相同的状态——而不需要访问原始代码。

model %>% save_model_tf('my_model/') # Recreate the exact same model, including weights and optimizer.
Written on November 18, 2020