贝叶斯优化可能不适用于 CNN 的一些原因是啥

Posted

技术标签:

【中文标题】贝叶斯优化可能不适用于 CNN 的一些原因是啥【英文标题】:What are some reasons Bayesian Optimization might not work for a CNN贝叶斯优化可能不适用于 CNN 的一些原因是什么 【发布时间】:2020-05-04 09:57:43 【问题描述】:

我尝试将贝叶斯优化应用于 MNIST 手写数字数据集的简单 CNN,但几乎没有迹象表明它有效。我已经尝试进行 k 折验证以消除噪声,但似乎优化似乎没有在向最佳参数收敛方面取得任何进展。一般来说,贝叶斯优化可能失败的主要原因是什么?在我的特殊情况下?

剩下的只是上下文和代码 sn-ps。

模型定义:

def define_model(learning_rate, momentum):
    model = Sequential()
    model.add(Conv2D(32, (3,3), activation = 'relu', kernel_initializer = 'he_uniform', input_shape=(28,28,1)))
    model.add(MaxPooling2D((2,2)))
    model.add(Flatten())
    model.add(Dense(100, activation='relu', kernel_initializer='he_uniform'))
    model.add(Dense(10, activation='softmax'))
    opt = SGD(lr=learning_rate, momentum=momentum)
    model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])
    return model

一次训练运行,超参数:batch_size = 32,学习率 = 1e-2,动量 = 0.9,10 个 epoch。 (蓝色 = 训练,黄色 = 验证)。

用于 5 倍交叉验证准确度的箱须图,具有与上述相同的超参数(以了解分布情况)

网格搜索将 batch_size 保持在 32,并保持 10 个 epoch。我在单次评估而不是 5 次评估中这样做,因为差值不足以破坏结果。

贝叶斯优化。如上,batch_size=32 和 10 个 epoch。搜索相同的范围。但这次使用 5 折交叉验证来消除噪音。它应该进行 100 次迭代,但这还需要 20 个小时。

space = 'lr': hp.loguniform('lr', np.log(np.sqrt(10)*1e-4), np.log(1e-1)), 'momentum': 1 - hp.loguniform('momentum', np.log(np.sqrt(10)*1e-3), np.log(np.sqrt(10)*1e-1))
tpe_best = fmin(fn=objective, space=space, algo=tpe.suggest, trials=Trials(), max_evals=100)

经过试验的学习率

久经考验的势头

从第 27 次迭代到第 49 次迭代看起来不错,但后来又失去了理智。

编辑

为提问者提供更多详细信息。

进口

# basic utility libraries
import numpy as np
import pandas as pd
import time
import datetime
import pickle
from matplotlib import pyplot as plt
%matplotlib notebook

# keras
from keras.datasets import mnist
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Input, BatchNormalization
from keras.optimizers import SGD
from keras.callbacks import Callback
from keras.models import load_model

# learning and optimisation helper libraries
from sklearn.model_selection import KFold
from hyperopt import fmin, tpe, Trials, hp, rand
from hyperopt.pyll.stochastic import sample

单次评价

def evaluate_model(trainX, trainY, testX, testY, max_epochs, learning_rate, momentum, batch_size, model=None, callbacks=[]):
    if model == None:
        model = define_model(learning_rate, momentum)
    history = model.fit(trainX, trainY, epochs=max_epochs, batch_size=batch_size, validation_data=(testX, testY), verbose=0, callbacks = callbacks)
    return model, history

交叉验证

def evaluate_model_cross_validation(trainX, trainY, max_epochs, learning_rate, momentum, batch_size, n_folds=5):
    scores, histories = list(), list()
    # prepare cross validation
    kfold = KFold(n_folds, shuffle=True, random_state=1)
    # enumerate splits
    for trainFold_ix, testFold_ix in kfold.split(trainX):
        # select rows for train and test
        trainFoldsX, trainFoldsY, testFoldX, testFoldY = trainX[trainFold_ix], trainY[trainFold_ix], trainX[testFold_ix], trainY[testFold_ix]
        # fit model
        model = define_model(learning_rate, momentum)
        history = model.fit(trainFoldsX, trainFoldsY, epochs=max_epochs, batch_size=batch_size, validation_data=(testFoldX, testFoldY), verbose=0)
        # evaluate model
        _, acc = model.evaluate(testFoldX, testFoldY, verbose=0)
        # stores scores
        scores.append(acc)
        histories.append(history)
    return scores, histories

我如何设置贝叶斯优化(或随机搜索)

def selective_search(kind, space, max_evals, batch_size=32):

    trainX, trainY, testX, testY = prep_data()

    histories = list()
    hyperparameter_sets = list()
    scores = list()

    def objective(params):
        lr, momentum = params['lr'], params['momentum']
        accuracies, _ = evaluate_model_cross_validation(trainX, trainY, max_epochs=10, learning_rate=lr, momentum=momentum, batch_size=batch_size, n_folds=5)
        score = np.log10(1 - np.mean(accuracies))
        scores.append(score)
        with open('_scores.pickle'.format(kind), 'wb') as file:
            pickle.dump(scores, file)
        hyperparameter_sets.append('learning_rate': lr, 'momentum': momentum, 'batch_size': batch_size)
        with open('_hpsets.pickle'.format(kind), 'wb') as file:
            pickle.dump(hyperparameter_sets, file)
        return score

    if kind == 'bayesian':
        tpe_best = fmin(fn=objective, space=space, algo=tpe.suggest, trials=Trials(), max_evals=max_evals)
    elif kind == 'random':
        tpe_best = fmin(fn=objective, space=space, algo=rand.suggest, trials=Trials(), max_evals=max_evals)
    else:
        raise BaseError('First parameter "kind" must be either "bayesian" or "random"')

    return histories, hyperparameter_sets, scores

然后我是如何实际运行贝叶斯优化的。

space = 'lr': hp.loguniform('lr', np.log(np.sqrt(10)*1e-4), np.log(1e-1)), 'momentum': 1 - hp.loguniform('momentum', np.log(np.sqrt(10)*1e-3), np.log(np.sqrt(10)*1e-1))

histories, hyperparameter_sets, scores = selective_search(kind='bayesian', space=space, max_evals=100, batch_size=32)

【问题讨论】:

您好,您能否上传贝叶斯优化步骤的完整代码和您的 ConvNN 的源代码? @AlexNe 我刚刚将其添加到末尾。希望够了。如果更容易,还可以通过私人聊天共享笔记本。感谢您的关注! 您好,在我测试这个时,这里有一个很好的贝叶斯推理理论总结:arxiv.org/pdf/1904.02063.pdf。在第 6 页,他们定义了问题。他们还对从第 6 页到第 21 页的故障模式进行了深入概述。 @AlexNe 查看下面的更新 【参考方案1】:

这是我的最新进展,并在一定程度上回答了我的问题。标题是我没有运行足够的迭代。

    迭代得分和 2. 迭代运行最佳得分

    如拟合线所示,我们确实观察到了提高准确性的趋势。这可能更少是因为最小值正在提高,而更多是因为算法花费更少的时间评估超参数,这些超参数显然不是最佳性能的候选者。

    迭代学习率和 4. 相应的箱须图

    我们在这里看到的一个奇怪的事情是试验超参数的收敛和发散。我的猜测是因为来自统计偏差的噪声不允许算法可靠地绘制地形图。它无法确定最小值,因为每次它测试一组特定的超参数时,它都会得到稍微不同的答案。 尽管如此,我们确实看到一些迹象表明该算法将其搜索空间限制在比整个范围更窄的邻域内,正如预期的那样。

    迭代动量和 6. 相应的箱须图

    在这里,我们对学习率进行了类似的观察。有趣的是,平均值随着学习率趋于收敛和发散的方式。记得我之前提到过,随着动量的增加,我们需要降低学习率来保持良好的模型训练性能。因此,如果我们试图保持良好的性能,动量和学习率之间会存在某种耦合。这就是优化算法在这里向我们展示的内容!

【讨论】:

@Alexander Soare 您的优化看起来不错。在进行 MCMC 时,图 3 和图 5 中的这些锯齿状轨迹是多峰后验分布的标志,即目标中有多个局部最小值,并且算法正在很好地探索它们。干得好! 另外,关于您找到明确答案的目标,贝叶斯优化设计估计不确定性。您可以使用最大后验密度,尽管在数学上正确的方法是每次重新训练和使用这些参数时从您的分布中抽取另一个样本。

以上是关于贝叶斯优化可能不适用于 CNN 的一些原因是啥的主要内容,如果未能解决你的问题,请参考以下文章

贝叶斯优化

贝叶斯和朴素贝叶斯是啥

Gridsearchcv 与贝叶斯优化

学习如何在 SSAS 中实现朴素贝叶斯分类器的最佳资源是啥?

实现用于文本分类的朴素贝叶斯的对数可能性

朴素贝叶斯(Naive Bayes)及python实现(sklearn)