Обсуждение статьи "Глубокие нейросети (Часть V). Байесовская оптимизация гиперпараметров DNN"

 

Опубликована статья Глубокие нейросети (Часть V). Байесовская  оптимизация гиперпараметров DNN:

В статье рассматриваются возможности байесовской оптимизации гиперпараметров глубоких нейросетей, полученных различными вариантами обучения. Сравнивается качество классификации DNN с оптимальными гиперпараметрами при различных вариантах обучения. Форвард-тестами проверена глубина эффективности оптимальных гиперпараметров DNN. Определены возможные направления улучшения качества классификации.

Автор: Vladimir Perervenko

 

Поэкспериментировал с BayesianOptimization.
У вас самый большой набор состоял из 9 оптимизируемых параметров. И вы говорили что долго считает

Попробовал набор из 20 параметров оптимизировать при 10 первых случайных наборах. Считал 1,5 часа - это только расчет самих комбинаций в BayesianOptimization, без учета времени расчета самой НС (я НС заменил на простенькую мат. формулу для эксперимента).

А если захочется 50 или 100 параметров пооптимизировать, то она наверное и 1 набор будет сутками вычислять. Думаю быстрее нагенерить десятки случайных комбинаций и посчитать их в НС.И потом отобрать лучшие по Accuracy.

В обсуждении пакета об этой проблеме говорится. Год назад автор написал, что если найдет более быстрый пакет для расчетов - то применит его, но пока - как есть. Там дали пару ссылок на др. пакеты с бейесовской оптимизацией, но совсем не понятно как их применить, для аналогичной задачи, в примерах др. задачи решаются.
bigGp - не находит набор данных SN2011fe для примера (видимо он с инета качался, а страница не доступна). Попробовать пример не получилось. Да и по описанию - какие-то дополнительные матрицы требуются.
laGP - какая-то запутанная формула в фитнес функции, и делает сотни ее вызовов, а сотни расчетов НС делать неприемлемо по времени.
kofnGA - может искать только Х лучших из N. Например 10 из 100. Т.е. это не оптимизация набора из всех 100.

Генетические алгоритмы тоже не подойдут, т.к. они тоже генерят сотни вызовов фитнес функции (расчетов НС).

В общем аналога нет, а сам BayesianOptimization слишком долгий.

 
elibrarius:

Поэкспериментировал с BayesianOptimization.
У вас самый большой набор состоял из 9 оптимизируемых параметров. И вы говорили что долго считает

Попробовал набор из 20 параметров оптимизировать при 10 первых случайных наборах. Считал 1,5 часа - это только расчет самих комбинаций в BayesianOptimization, без учета времени расчета самой НС (я НС заменил на простенькую мат. формулу для эксперимента).

А если захочется 50 или 100 параметров пооптимизировать, то она наверное и 1 набор будет сутками вычислять. Думаю быстрее нагенерить десятки случайных комбинаций и посчитать их в НС.И потом отобрать лучшие по Accuracy.

В обсуждении пакета об этой проблеме говорится. Год назад автор написал, что если найдет более быстрый пакет для расчетов - то применит его, но пока - как есть. Там дали пару ссылок на др. пакеты с бейесовской оптимизацией, но совсем не понятно как их применить, для аналогичной задачи, в примерах др. задачи решаются.
bigGp - не находит набор данных SN2011fe для примера (видимо он с инета качался, а страница не доступна). Попробовать пример не получилось. Да и по описанию - какие-то дополнительные матрицы требуются.
laGP - какая-то запутанная формула в фитнес функции, и делает сотни ее вызовов, а сотни расчетов НС делать неприемлемо по времени.
kofnGA - может искать только Х лучших из N. Например 10 из 100. Т.е. это не оптимизация набора из всех 100.

Генетические алгоритмы тоже не подойдут, т.к. они тоже генерят сотни вызовов фитнес функции (расчетов НС).

В общем аналога нет, а сам BayesianOptimization слишком долгий.

Есть такая проблема. Связана с тем, что написан пакет вроде на чистом R. Но плюсы в его применении лично для меня перевешивают затраты время. Есть пакет hyperopt (Python)/ Не дошли руки попробовать, да и староват он.

Но думаю кто то все же перепишет Рпакет на С++. Можно конечно самому поковырять, перевести часть вычислений на GPU , но это море времени потребует. Только если сильно припрет.

Пока буду пользовать то что есть.

Удачи

 

Еще поэкспериментировал с примерами из самого пакета GPfit.
Вот пример оптимизации 1 параметра, который описывает кривую с 2 вершинами (ф-я из GPfit имеет больше вершин, я оставил 2):

Взято 2 случайных точки, а потом оптимизация. Видно, что сначала находит малую вершину, а потом большую. Всего 9 расчетов - 2 случайных и + 7 по оптимизации.

Другой пример в 2D - оптимизирую 2 параметра. Оригинальная ф-я выглядит так:

Оптимизация до 19 точек:

Всего 2 случайных точки + 17 найденных оптимизатором.

Сравнив эти 2 примера видно, что количество итераций нужных для нахождения максимума при добавлении 1 параметра удваивается. Для 1 параметра максимум нашелся за 9 расчитанных точек, для 2 параметров за 19.
Т.е. если оптимизировать 10 параметров, то может понадобиться 9 * 2^10 = 9000 вычислений.

Хотя на 14-точке алгоритм почти нашел максимум, это примерно в 1.5 раза увеличилось число расчетов. тогда 9* 1,5:10 = 518 вычислений. Тоже многовато, для приемлемого времени расчетов.

Результаты полученные в статье на 20 - 30 точках, могут оказаться далеки от реального максимума.

Думаю, что генетическим алгоритмам даже с этими простыми примерами понадобится намного больше точек просчитать. Так что лучшего варианта видимо все же нет.

 
elibrarius:

Еще поэкспериментировал с примерами из самого пакета GPfit.
Вот пример оптимизации 1 параметра, который описывает кривую с 2 вершинами (ф-я из GPfit имеет больше вершин, я оставил 2):

Взято 2 случайных точки, а потом оптимизация. Видно, что сначала находит малую вершину, а потом большую. Всего 9 расчетов - 2 случайных и + 7 по оптимизации.

Другой пример в 2D - оптимизирую 2 параметра. Оригинальная ф-я выглядит так:

Оптимизация до 19 точек:

Всего 2 случайных точки + 17 найденных оптимизатором.

Сравнив эти 2 примера видно, что количество итераций нужных для нахождения максимума при добавлении 1 параметра удваивается. Для 1 параметра максимум нашелся за 9 расчитанных точек, для 2 параметров за 19.
Т.е. если оптимизировать 10 параметров, то может понадобиться 9 * 2^10 = 9000 вычислений.

Хотя на 14-точке алгоритм почти нашел максимум, это примерно в 1.5 раза увеличилось число расчетов. тогда 9* 1,5:10 = 518 вычислений. Тоже многовато, для приемлемого времени расчетов.

1. Результаты полученные в статье на 20 - 30 точках, могут оказаться далеки от реального максимума.

Думаю, что генетическим алгоритмам даже с этими простыми примерами понадобится намного больше точек просчитать. Так что лучшего варианта видимо все же нет.

Браво.

Наглядно.

На Ютубе размещен ряд лекций поясняющих как работает Байесовская оптимизация. Если не смотрели, советую посмотреть. Очень познавательно.

Как вставляли анимацию? 

Стараюсь в последнее время использовать везде где возможно байесовские методы. Результаты очень хорошие.

1. Я делаю последовательную оптимизацию. Первая - инициализация 10 случайных точек, Вычисление 10-20 точек, последующие - инициализация 10 лучших результатов с предыдущей оптимизации, вычисления 10-20 точек. Как правило после второй итерации результаты не улучшаются значимо.

Удачи

 
Vladimir Perervenko:

На Ютубе размещен ряд лекций поясняющих как работает Байесовская оптимизация. Если не смотрели, советую посмотреть. Очень познавательно.

Я посмотрел код и результат в виде картинок (и вам показал). Самое важное это Gaussian Process из GPfit. А оптимизация - самая обычная - просто используется оптимизатор из стандартной поставки R и ищет максимум по кривой/фигуре которую придумала GPfit по 2м, 3м и т.д. точкам. А то, что она придумала - видно на анимированных картинках выше. Оптимизатор просто пытается выбраться наверх со 100 случайных точек.
Лекции может в будущем посмотрю, как время будет, а пока буду просто пользоваться GPfit как черным ящиком.

Vladimir Perervenko:

Как вставляли анимацию?

Просто пошагово отображал результат  GPfit::plot.GP(GP, surf_check = TRUE)     вставлял в фотошоп и там сохранил, как анимированный GIF.

Vladimir Perervenko:

последующие - инициализация 10 лучших результатов с предыдущей оптимизации, вычисления 10-20 точек.

По моим экспериментам - лучше все известные точки оставлять для будущих расчетов, т.к. если нижние удалить, то GPfit может подумать, что там есть интересные точки и захочет их просчитать, т.е. будут повторные запуски расчета НС. А с этими нижними точками GPfit будет знать, что в этих нижних областях искать нечего.

Хотя если результаты сильно не улучшаются, значит имеется обширное плато с небольшими колебаниями.

 

Здравствуйте Владимир,

не совсем понимаю, почему у вас  НС тренируется на обучающих данных, а ее оценка делается на тестовых (если не ошибаюсь вы его используете как валидационный).

    Score <- Evaluate(actual = yTest, predicted = Ypred)$Metrics[ ,2:5] %>%
      round(3)

Не получится ли в этом случае подгонка под тестовый участок, т.е. будет выбрана модель, которая именно на тестовом участке лучше всего отработала?
Еще надо учесть, что тестовый участок достаточно мал и можно подогнаться под одну из временных закономерностей, которая может перестать работать очень быстро.
Может быть лучше делать оценку на обучающем участке, или на сумме участков, или как в Darch, (при поданных валидационных данных) на Err = (ErrLeran * 0.37 + ErrValid * 0.63) - эти коэффициенты по умолчанию, но их можно менять.

Вариантов много и неясно, какой из них лучше. Интересны ваши аргументы в пользу тестового участка.

 

Интересные результаты оптимизации - ошибка на валидационной выборке вышла меньше, чем на тренировочной!

Другими словами, модель тренируясь на одних данных, научилась работать на других, т.е. извлекла из тренировочных данных больше информации, чем там ее было на самом деле - это научная фантастика или авантюра...?

Обращаюсь к автору - прекращайте штукарства и подтасовку, напишите наконец советник и покажите какой нибудь результат, хоть на демо.

 
revers45:

Другими словами, модель тренируясь на одних данных, научилась работать на других, т.е. извлекла из тренировочных данных больше информации, чем там ее было на самом деле - это научная фантастика или авантюра...?

Все модели обучались на тренировочном участке, т.е. стремились минимизировать ошибку именно на нем, но в конце отбор делался по тестовому участку, и если бы модель не нашла закономерности в данных, то были бы очень плохими результаты на обучающем или на участке после тестового. Но как показали результаты и там и там они не сильно отличаются от тестового, по которому делался отбор.
Т.е. НС не научилась работать на других, а нашла общие закономерности в обоих наборах данных.
Если бы результаты были менее стабильны, то отбор по тестовому участку (без учета ошибки обучающего) мог бы привести к подгонке под него. В данном случае не привел, но на других данных (если бы не нашлись закономерности) - мог бы. И тогда лучше было бы искать баланс между ошибками типа Err = (ErrLeran * 0.37 + ErrValid * 0.63)

 
elibrarius:

Здравствуйте Владимир,

не совсем понимаю, почему у вас  НС тренируется на обучающих данных, а ее оценка делается на тестовых (если не ошибаюсь вы его используете как валидационный).

Не получится ли в этом случае подгонка под тестовый участок, т.е. будет выбрана модель, которая именно на тестовом участке лучше всего отработала?
Еще надо учесть, что тестовый участок достаточно мал и можно подогнаться под одну из временных закономерностей, которая может перестать работать очень быстро.
Может быть лучше делать оценку на обучающем участке, или на сумме участков, или как в Darch, (при поданных валидационных данных) на Err = (ErrLeran * 0.37 + ErrValid * 0.63) - эти коэффициенты по умолчанию, но их можно менять.

Вариантов много и неясно, какой из них лучше. Интересны ваши аргументы в пользу тестового участка.

Добрый день.

Давайте уточним. Набор данных Х состоит из 4 поднаборов preptrain = 4001, train = 1000, test = 500 и test1= 100 баров. Для претренинга используются обучающий набор - pretrain, валидационный - train. 

# SRBM + upper Layer (backpropagation)
 pretrainSRBM_topLayer <- function(Ln, fact1, fact2, dr1, dr2, Lr.rbm, Lr.top) # SRBM + upper Layer (backpropagation)
  {
    darch( x = X$pretrain$x, y = X$pretrain$y,
          xValid = X$train$x, 
          yValid = X$train$y,
          #=====constant======================
......................................................

Для тонкой настройки в качестве обучающего используется набор train  , а валидационного - первые 250 баров набора test . 

fineTuneRP <- function(Ln, fact1, fact2, dr1, dr2, Dnn) # rpropagation
  {
    darch( x = X$train$x, y = X$train$y,
           #xValid = X$test$x, yValid = X$test$y,
           xValid = X$test$x %>% head(250), 
           yValid = X$test$y %>% head(250),
           #=====constant========
................................................

Поэтому для определения окончательного качества в качестве тестового набора используем последние 250 баров набора test. code

#---SRBM + upperLayer + RP----
  fitnes4.DNN <- function(n1, n2, fact1, fact2, dr1, dr2, Lr.rbm, Lr.top)
  {
    Ln <- c(0, 2*n1, 2*n2, 0)
    #--
    pretrainSRBM_topLayer(Ln, fact1, fact2, dr1, dr2, Lr.rbm, Lr.top) -> Dnn
    fineTuneRP(Ln, fact1, fact2, dr1, dr2, Dnn) -> Dnn
    predict(Dnn, newdata = X$test$x %>% tail(250) , type = "class") -> Ypred
    yTest <- X$test$y[ ,1] %>% tail(250)
    #numIncorrect <- sum(Ypred != yTest)
    #Score <- 1 - round(numIncorrect/nrow(xTest), 2)
    Score <- Evaluate(actual = yTest, predicted = Ypred)$Metrics$F1 %>%
      mean() 
    return(list(Score = Score, Pred = Ypred)
  }

Не вижу противоречий. Согласны?

Удачи

 
elibrarius:

Все модели обучались на тренировочном участке, т.е. стремились минимизировать ошибку именно на нем, но в конце отбор делался по тестовому участку, и если бы модель не нашла закономерности в данных, то были бы очень плохими результаты на обучающем или на участке после тестового. Но как показали результаты и там и там они не сильно отличаются от тестового, по которому делался отбор.
Т.е. НС не научилась работать на других, а нашла общие закономерности в обоих наборах данных.
Если бы результаты были менее стабильны, то отбор по тестовому участку (без учета ошибки обучающего) мог бы привести к подгонке под него. В данном случае не привел, но на других данных (если бы не нашлись закономерности) - мог бы. И тогда лучше было бы искать баланс между ошибками типа Err = (ErrLeran * 0.37 + ErrValid * 0.63)

По любому, общих закономерностей на обучающей участке должно быть не меньше чем на тестовом т.к. они вместе со всеми остальными там же были и найдены, а поэтому и НС на нем не должна работать хуже.

По-моему, это очевидно, так же, как и то, что знания учителя не должны быть меньше чем у ученика, хотя автор статьи, видимо пытается опровергнуть это, поскольку он писал в камментах, что не учёный и не программист, а упорно продолжает учить нас программировать нейросети.

Конечно, он запостил уже очень много R кода, но хотелось бы увидеть и адекватные результаты, а главное понять, сколько ещё он напишет таких статей, пока появится хоть один, нормальный советник.