По каким причинам Байесовская оптимизация может не сработать для CNN? - PullRequest
3 голосов
/ 17 января 2020

Я пытался применить байесовскую оптимизацию к простому CNN для набора рукописных цифр MNIST, и у меня мало признаков того, что он работает. Я пытался выполнить k-кратную проверку, чтобы сгладить шум, но все же не похоже, что оптимизация делает какие-либо шаги в направлении достижения оптимальных параметров. В целом, каковы основные причины, по которым Байесовская оптимизация может потерпеть неудачу? А в моем конкретном случае?

Остальное - просто контекст и фрагменты кода.

Определение модели:

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 эпох. (синий = обучение, желтый = проверка).

enter image description here

График прямоугольника и усов для точности в 5-кратной перекрестной проверке , с теми же гиперпараметрами, что и выше (чтобы получить представление о разбросе)

enter image description here

Поиск в сетке с batch_size, равным 32, и в соответствии с 10 эпохой. Я делал это на отдельных оценках, а не в 5 раз, так как спред был недостаточно большим, чтобы испортить результаты.

enter image description here enter image description here

Байесовская оптимизация . Как и выше, batch_size = 32 и 10 эпох. Поиск по тем же диапазонам. Но на этот раз с 5-кратной перекрестной проверкой, чтобы сгладить шум. Предполагается, что go из 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)

enter image description here

Испытанные скорости обучения enter image description here

Испытанные импульсы enter image description here

Это выглядело хорошо после 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)

1 Ответ

1 голос
/ 19 января 2020

Это обновление моего прогресса и несколько отвечает на мой вопрос. Заголовок гласит, что я не выполнял достаточное количество итераций.

  1. Счет за итерации и 2. Показ лучшего результата за итерации

    • Мы наблюдаем тенденцию к повышению точности, как это видно по подгонке. Вероятно, это меньше, потому что минимум улучшается, и больше, потому что алгоритм тратит меньше времени на оценку гиперпараметров, которые явно не являются кандидатами на оптимальную производительность.
  2. Скорость обучения в течение итерации и 4. соответствующие графики ящиков и усов

    • Странная вещь, которую мы здесь видим, - это сходимость и расхождение испытанных гиперпараметров. Я предполагаю, потому что шум от статистических отклонений не позволяет алгоритму надежно отобразить местность. Он не может установить минимум, потому что каждый раз, когда он проверяет определенный набор гиперпараметров, он получает немного другой ответ.
    • Тем не менее мы видим подсказки, что алгоритм ограничивает свое пространство поиска более узкой окрестностью, чем полная диапазон, как и ожидалось.
  3. Импульс за итерации и 6. соответствующие графики бокса и усов

    • Здесь мы делаем аналогичные наблюдения с темпами обучения. Что интересно, так это то, как средние имеют тенденцию сходиться и расходиться со скоростью обучения. Помните, я упоминал ранее, что по мере увеличения импульса нам необходимо снижать скорость обучения, чтобы поддерживать хорошие результаты обучения модели. Таким образом, существует некоторая связь между импульсом и скоростью обучения, если мы пытаемся поддерживать хорошую производительность. Это то, что алгоритм оптимизации демонстрирует для нас здесь!

enter image description here enter image description here enter image description here

...