【问题标题】:Keras - Hyper Tuning the initial state of the modelKeras - Hyper Tuning 模型的初始状态
【发布时间】:2021-06-25 01:52:14
【问题描述】:

我编写了一个 LSTM 模型来预测顺序数据。

def get_model(config, num_features, output_size):
    opt = Adam(learning_rate=get_deep(config, 'hp.learning_rate'), beta_1=get_deep(config, 'hp.beta_1'))

    inputs = Input(shape=[None, num_features], dtype=tf.float32, ragged=True)
    layers = LSTM(get_deep(config, 'hp.lstm_neurons'), activation=get_deep(config, 'hp.lstm_activation'))(
        inputs.to_tensor(), mask=tf.sequence_mask(inputs.row_lengths()))

    layers = BatchNormalization()(layers)
    if 'dropout_rate' in config['hp']:
        layers = Dropout(get_deep(config, 'hp.dropout_rate'))(layers)

    for layer in get_deep(config, 'hp.dense_layers'):
        layers = Dense(layer['neurons'], activation=layer['activation'])(layers)
        layers = BatchNormalization()(layers)
        if 'dropout_rate' in layer:
            layers = Dropout(layer['dropout_rate'])(layers)

    layers = Dense(output_size, activation='sigmoid')(layers)
    model = Model(inputs, layers)
    model.compile(loss='mse', optimizer=opt, metrics=['mse'])
    model.summary()
    return model

我已经使用 AWS SageMaker 调整了层的一些参数。在验证模型时,我已经多次运行具有特定配置的模型。大多数时候结果是相似的,但是,一次运行比其他运行好得多,这让我认为模型的初始状态可能对于获得最佳性能至关重要。

正如this video 中所建议的,权重初始化可以提供一些性能提升。 我在谷歌上搜索并找到了layer weight initializers,但我不确定我应该调整什么范围。


更新: 正如一些 cmets / answers 中所建议的,我正在使用固定种子来“锁定”模型结果:

# Set `python` built-in pseudo-random generator at a fixed value
random.seed(seed_value)
# Set `numpy` pseudo-random generator at a fixed value
np.random.seed(seed_value)
# Set `tensorflow` pseudo-random generator at a fixed value
tf.random.set_seed(seed_value)

每个新火车的结果都会重复,但是,不同的种子可以产生比其他种子更好的结果。那么如何找到/调整最好的种子呢?

【问题讨论】:

  • @Shlomi 你没有在你的问题中说任何关于种子的东西,但只关心初始状态。请您对此进行 cpnfirn 吗?
  • 您之前在我的答案评论框中提到您确实使用了 sagamaker(也许),您能详细说明一下吗? (IDK 为什么删除那些评论,如果她/他是诚实的,举报者应该排在前面)。
  • @M.Innat 我不确定为什么我的 cmets 被删除了,不是我。我使用 SageMaker (docs.aws.amazon.com/sagemaker/latest/dg/…) 调整所有其他参数

标签: python tensorflow machine-learning keras


【解决方案1】:

我认为这个问题没有“一刀切”的解决方案。初始权重很大程度上取决于手头的问题类型以及我们用来解决该问题的数据。我们所能做的就是将您指向一个好的资源,您可以从中尝试查看提到的哪种方法适合您的问题。 以下article 是一个很好的资源,它不仅可以让您详细了解如何以及为什么要初始化权重,还可以指向有助于建立学术理解的同行评审研究。

【讨论】:

    【解决方案2】:

    ...这使我认为模型的初始状态对于获得最佳性能可能至关重要。 .....正如本视频中所建议的,权重初始化可以提供一些性能提升。我用谷歌搜索并找到了层权重初始化器,但我不确定我应该调整什么范围。

    首先,在该视频中,除了状态或权重初始化器,所有其他因素,例如学习率、调度、优化器、批量大小、损失函数、模型深度等是您应该与他们一起玩以找到最佳集合(我们稍后会讨论种子的作用)。通常,我们不需要调整默认权重或状态初始化器,因为它们是目前最好的;和往常一样,这种状态初始化是一个研究问题。

    其次,中,ConvolutionDenseRNN-GRU/LSTM的默认权重初始化器是glorot_uniform,也称为Xavier uniform initializer。默认的偏差初始化器是zeros。如果您关注LSTMsource code(在您的情况下),您会找到它们。关于它,根据doc

    [-limit, limit] 内的均匀分布中抽取样本,其中limit = sqrt(6 / (fan_in + fan_out))fan_in 是权重张量中输入单元的数量,fan_out 是输出单位数)。

    现在,你可能已经注意到这个初始化器继承自VarianceScaling;和GlorotUniform一样,GlorotNormal, LecunNormal, LecunUniform, HeNormal, HeUniform 也继承了它。关于VarianceScaling,列出了here 支持的参数。比如,从技术上来说,下面两个是一样的。

    # in case if you want to try various initializer - 
    # use VarianceScaling by passing proper parameter. 
    # ie. tf.keras.layers.LSTM(..., kernel_initializer=initializer)
    # bur recommended to stick with glorot_uniform (default)
    initializer = tf.keras.initializers.VarianceScaling(scale=1., 
                                                        mode='fan_avg', seed=101,
                                                        distribution='uniform')
    print(initializer(shape=(2, 2)))
    
    
    initializer = tf.keras.initializers.GlorotUniform(seed=101)
    print(initializer(shape=(2, 2)))
    
    tf.Tensor(
    [[-1.0027379  1.0746485]
     [-1.2234    -1.1489409]], shape=(2, 2), dtype=float32)
    tf.Tensor(
    [[-1.0027379  1.0746485]
     [-1.2234    -1.1489409]], shape=(2, 2), dtype=float32)
    

    简而言之,你可以玩tf.keras.initializers.VarianceScaling(在页面底部)。此外,您可以通过定义可调用函数或子类化Initializer 类来制作自己的初始化程序。例如:

    def conv_kernel_initializer(shape, dtype=None):
      kernel_height, kernel_width, _, out_filters = shape
      fan_out = int(kernel_height * kernel_width * out_filters)
      return tf.random.normal(
          shape, mean=0.0, stddev=np.sqrt(2.0 / fan_out), dtype=dtype)
    
    def dense_kernel_initializer(shape, dtype=None):
      init_range = 1.0 / np.sqrt(shape[1])
      return tf.random.uniform(shape, -init_range, init_range, dtype=dtype)
    

    这是一个很好的article关于初始化权重,你可能会喜欢阅读。再次对接,最好使用默认的。

    第三,对于设置不同的种子值和不同的超参数集等,我最好留下我的一个旧答案here,主要是第一个图表可能对你的实验有用.我遵循的一种方法是保持我的种子相同(假设前 5 次实验)并更改另一个因素并记录结果。在 5 次迭代之后,希望我们能得到一些最好的集合并进一步接近。


    更新

    查找/调整种子。在寻找最佳种子的方法之前,必须了解种子不是超参数,需要与学习率、调度器、优化器等其他超参数一起调整。

    这是一种情况,假设您使用种子 42 将数据随机分成两部分:训练集 (70%) 和测试集 (30%),在训练集上训练后,您在测试集上进行评估你的模型得到了 80 分。然后你把种子改成 101,再次做同样的事情,但现在你得到了 50 分。现在,这并不意味着选择 42 号种子更好;但这只是意味着您的模型不稳定,并且大多数类似的模型在 unseen 数据上表现不佳。如果有人随机拆分他们的数据集进行训练和测试,这实际上是一个众所周知的问题。为什么会发生?因为,当您随机拆分数据时,可能会出现类分布不匹配的情况。请检查以下两个非常相关的讨论:

    【讨论】:

      【解决方案3】:

      也许您搜索指数衰减学习率。 让我解释 例如,您的第一个 epoch 有时会损失 3000、4000 ,有时只有 500。 如果你经常运行一个模型,你可能会认识到一个“真正的障碍”,你不再说“那是因为初始状态”。 您想在那里快速前进,但不要保留高学习率的不良副作用(例如 1E-3),您更想要 1E-5。 那里出现了指数衰减。

      调用 myLr=tf.train.exponential_decay(...) 的实例并将其而不是数值学习率参数传递给优化器

      例如亚当(myLr)

      【讨论】:

        【解决方案4】:

        确实,模型的初始状态对于获得最佳性能至关重要。深度学习通过优化非凸损失函数来找到最佳局部最小值。

        初始权重将定义优化的起始位置。如下图所定义。起点由初始权重定义,训练模型将使其达到局部最小值。如您所见,有一个允许达到全局最小值的起始权重配置。

        有时可以通过迁移学习获得更好的权重初始化,迁移学习在下游任务上重用训练模型的权重。 (例如图像分类中的 VGG-16,或带有 BERT 的 NLP)。

        在您的情况下,您不应尝试微调权重初始化,因为这是随机的。更改神经网络的架构或其超参数肯定会带来更好的性能提升。

        【讨论】:

          【解决方案5】:

          简短的回答:您既不能有效地调整伪随机数生成器的种子,也不能有效地调整种子。这不仅由于极大的搜索空间不可行,而且由于许多其他原因也不切实际,包括伪随机数生成器的实现会不时发生变化,因此每次发生这种情况时您都需要重新开始。

          如果出于某种原因,您一心想要自己发现这一点,我建议您使用 NumPy 的 default_rng 对象作为算法中所有伪随机性的单一来源。然后,基于单个种子,您可以确定性地生成其他种子,以用于tf.random.set_seed

          【讨论】:

            猜你喜欢
            • 2020-11-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-05-08
            • 1970-01-01
            相关资源
            最近更新 更多