【问题标题】:Keras modification in place - how to train multiple models in Keras correctlyKeras 修改到位——如何在 Keras 中正确训练多个模型
【发布时间】:2020-04-17 08:34:08
【问题描述】:

这是关于 R 中的 Keras,但据我了解,它也适用于 python。

Keras 模型是modified-in-place。最初不明白这意味着什么让我很困惑,所以我想我会写下这对在同一会话中训练多个模型意味着什么,这样其他人就可以避免犯我犯的错误。

意思是不能复制模型对象,比如:

model = keras_model_sequential()
model %>%
   layer_dense(
      units = 50,
      input_shape = 100
   )
model_copy = model

现在,如果您尝试修改modelmodel_copy,另一个也会被修改。下面的答案解释了原因。

【问题讨论】:

    标签: r tensorflow keras


    【解决方案1】:

    简介

    R 既可以就地修改,即在内存中修改对象,也可以在修改对象时创建对象的新副本。这是解释here。如果您创建一个对象,以及另一个指向该第一个对象的对象,它们将指向内存中的同一位置。但是,这意味着修改一个会修改另一个。

    为避免这种情况,R 会跟踪是否有 1 或 > 1 个名称指向内存中的同一位置。如果为 1,那么修改内存值是安全的。这是就地修改。但是,如果它 > 1,则修改一个对象将修改另一个对象。因此,被修改的对象实际上被复制到了新的内存部分,这样两个对象就不再指向同一块内存了。这意味着修改一个对象不会影响另一个对象。

    这不是在 R 的 Keras 中执行的,据我了解(尽管我还没有在 python 中使用 Keras)它也没有在 python 中执行。 Keras 总是使用就地修改,无论有多少名称指向内存中的位置。因此,对一个模型所做的任何事情也会对另一个模型进行,因为实际上它们只是同一个模型的两个名称——两个“对象”实际上只是一个对象。

    错误代码示例

    为了说明这会在哪里绊倒您,下面是一个通过比较两个 RMSProp 学习率来训练 mnist 分类网络的示例。如果不了解 Keras 中的就地修改,可能会编写代码:

    library(keras)
    
    # data
    mnist = dataset_mnist()
    x_train = mnist$train$x
    y_train = mnist$train$y
    x_train = array_reshape(x_train, c(nrow(x_train), 784))
    x_train = x_train / 255
    y_train = to_categorical(y_train, 10)
    
    # model
    model = keras_model_sequential() 
    model %>% 
      layer_dense(units = 256, activation = 'relu', input_shape = c(784)) %>% 
      layer_dropout(rate = 0.4) %>% 
      layer_dense(units = 128, activation = 'relu') %>%
      layer_dropout(rate = 0.3) %>%
      layer_dense(units = 10, activation = 'softmax')
    
    # compile and train a model, given a learning rate
    comp_train = function(learning_rate) {
      model_copy = model
      model_copy %>% compile(
        loss = 'categorical_crossentropy',
        optimizer = optimizer_rmsprop(
          lr = learning_rate
        ),
        metrics = c('accuracy')
      )
      training_history = model_copy %>% fit(
        x_train, y_train, 
        epochs = 30, batch_size = 128, 
        validation_split = 0.2
      )
      return(
        as.data.frame(training_history)
      )
    }
    
    # test two learning rates
    lr_0.001 = comp_train(0.001)
    lr_0.0001 = comp_train(0.0001)
    

    结果对于 0.001 的学习率是有意义的:

    但是,对于 0.0001 的学习率,结果非常出乎意料:

    如果人们意识到第二张图像只是第一张图像的 30 个 epoch 的延续,那么这些结果并不出人意料。所以,放在一起,这两张图片只是显示了同一个神经网络在 60 个 epoch 上的训练。这是因为就地修改——当你训练“第二个”网络时,你实际上只是在训练第一个,即使它已经被训练过。

    示例工作代码

    那么应该做些什么不同的事情呢?对于 Keras,不同的模型必须分别使用 keras_model_sequential()keras_model()(无论您使用哪种类型)进行初始化。所以我们分别定义每个模型:

    library(keras)
    
    # data
    mnist = dataset_mnist()
    x_train = mnist$train$x
    y_train = mnist$train$y
    x_train = array_reshape(x_train, c(nrow(x_train), 784))
    x_train = x_train / 255
    y_train = to_categorical(y_train, 10)
    
    # models
    model_lr0.001 = keras_model_sequential() 
    model_lr0.0001 = keras_model_sequential() 
    
    model_lr0.001 %>% 
      layer_dense(units = 256, activation = 'relu', input_shape = c(784)) %>% 
      layer_dropout(rate = 0.4) %>% 
      layer_dense(units = 128, activation = 'relu') %>%
      layer_dropout(rate = 0.3) %>%
      layer_dense(units = 10, activation = 'softmax')
    model_lr0.0001 %>% 
      layer_dense(units = 256, activation = 'relu', input_shape = c(784)) %>% 
      layer_dropout(rate = 0.4) %>% 
      layer_dense(units = 128, activation = 'relu') %>%
      layer_dropout(rate = 0.3) %>%
      layer_dense(units = 10, activation = 'softmax')
    
    # compile and train a given model, also given a learning rate
    comp_train = function(model, learning_rate) {
      model %>% compile(
        loss = 'categorical_crossentropy',
        optimizer = optimizer_rmsprop(
          lr = learning_rate
        ),
        metrics = c('accuracy')
      )
      training_history = model %>% fit(
        x_train, y_train, 
        epochs = 30, batch_size = 128, 
        validation_split = 0.2
      )
      return(
        as.data.frame(training_history)
      )
    }
    
    # test two learning rates
    lr_0.001 = comp_train(model_lr0.001, 0.001)
    lr_0.0001 = comp_train(model_lr0.0001, 0.0001)
    

    这一次,我们得到了预期的结果:

    我们现在可以成功比较两个学习率。 “更好”的工作代码是在函数中定义模型(使用keras_model_sequential()),这也给出了预期的结果。这留给读者作为练习。

    【讨论】:

      猜你喜欢
      • 2017-09-28
      • 1970-01-01
      • 2020-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多