LBFGS никогда не сходится в больших размерах в pytorch

Я играю с правилом 110 клеточных автоматов Wolfram. Учитывая строку нулей и единиц, вы можете вычислить следующую строку по этим правилам:

введите здесь описание изображения

Начиная с 00000000....1 в конце вы получите такую ​​последовательность:

введите здесь описание изображения

Просто из любопытства я решил аппроксимировать эти правила полиномом, чтобы ячейки могли быть не только 0 и 1, но и серым цветом между ними:

def triangle(x,y,z,v0):
    v=(y + y * y + y * y * y - 3. * (1. + x) * y * z + z * (1. + z + z * z)) / 3.
    return (v-v0)*(v-v0)

поэтому, если x, y, z и v0 соответствуют любому из этих правил из таблицы, он вернет 0 и положительное ненулевое значение в противном случае.

Затем я добавил все возможные группы из 4 соседей в единую сумму, которая будет равна нулю для целочисленных решений:

def eval():
    s = 0.
    for i in range(W - 1):
        for j in range(1, W + 1):
            xx = x[i, (j - 1) % W]
            yy = x[i, j % W]
            zz = x[i, (j + 1) % W]
            r = x[i + 1, j % W]
            s += triangle(xx, yy, zz, r)
    for j in range(W - 1): s += x[0, j] * x[0, j]
    s += (1 - x[0, W - 1]) * (1 - x[0, W - 1])
    return torch.sqrt(s)

Также внизу этой функции я добавляю обычные условия для первой строки, чтобы все элементы были равны 0, кроме последнего, который равен 1. Наконец, я решил минимизировать эту сумму квадратов на матрице W * W с помощью pytorch:

x = Variable(torch.DoubleTensor(W,W).zero_(), requires_grad=True)
opt = torch.optim.LBFGS([x],lr=.1)
for i in range(15500):
    def closure():
        opt.zero_grad()
        s=eval()
        s.backward()
        return s
    opt.step(closure)

Вот полный код, можете попробовать сами. Проблема в том, что для 10*10 он сходится к правильному решению примерно за 20 шагов:

введите здесь описание изображения

Но если я возьму доску 15*15, она никогда не закончит схождение:

введите здесь описание изображения

График справа показывает, как сумма квадратов меняется с каждой следующей итерацией, и вы можете видеть, что она никогда не достигает нуля. Мой вопрос в том, почему это происходит и как я могу это исправить. Пробовал разные оптимизаторы pytorch, но все они работают хуже, чем LBFGS. Пробовал разные скорости обучения. Любые идеи, почему это происходит и как я могу достичь конечной точки во время оптимизации?

UPD: улучшен график сходимости, лог SOS:

введите здесь описание изображения

UPD2: я также пытался сделать то же самое на C++ с dlib, и у меня нет проблем с конвергенцией, все идет намного глубже за гораздо меньшее время:

введите здесь описание изображения

Я использую этот код для оптимизации на С++:

find_min_using_approximate_derivatives(bfgs_search_strategy(),
        objective_delta_stop_strategy(1e-87),
        s, x, -1)

person Stepan Yakovenko    schedule 31.05.2018    source источник
comment
Это не выпуклая проблема, поэтому у вас нет гарантии сходимости с L-BFGS.   -  person Yngve Moe    schedule 31.05.2018
comment
хорошо, но что я могу с этим поделать?   -  person Stepan Yakovenko    schedule 31.05.2018


Ответы (1)


То, что вы пытаетесь сделать здесь, - это невыпуклая оптимизация, и это общеизвестно сложная проблема. Как только вы задумаетесь об этом, это обретет смысл, потому что практически любую практическую математическую задачу можно сформулировать как задачу оптимизации.

<сильный>1. Прелюдия
Итак, прежде чем дать вам подсказки о том, где найти решение вашей конкретной проблемы, я хочу проиллюстрировать, почему некоторые проблемы оптимизации легко решить.

Я собираюсь начать с обсуждения выпуклых задач. Их легко решить даже в случае с ограничениями, и причина этого в том, что при вычислении градиента вы на самом деле получаете много информации о том, где не может быть минимума (разложение Тейлора выпуклой функции f всегда является недооценка f), кроме того, имеется только один минимум и нет седловых точек. Если вам интересно узнать больше о выпуклой оптимизации, я рекомендую посмотреть курс Стивена Бойда по выпуклой оптимизации на YouTube.

Итак, если невыпуклая оптимизация настолько сложна, почему мы можем решить ее с помощью глубокого обучения? Ответ прост: невыпуклая функция, которую мы минимизируем в глубоком обучении, довольно хороша, как продемонстрировано Henaff et al.

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

<сильный>2. Ответьте на ваш вопрос
Теперь, чтобы ответить на вашу проблему, вы, вероятно, не найдете и быстрого решения, поскольку невыпуклая оптимизация является NP-полной. Но не бойтесь, у SciPy есть несколько алгоритмов глобальной оптимизации на выбор.
Вот ссылка на другое переполнение стека тему с хорошим ответом на ваш вопрос.

<сильный>3. Мораль этой истории
Наконец, я хочу напомнить вам, что гарантии конвергенции важны, забывая, что это привело к обрушение нефтяной вышки.

PS. Прошу прощения за опечатки, для этого я использую свой телефон.

Обновление: На то, почему BFGS работает с dlib, может быть две причины: во-первых, BFGS лучше использует информацию о кривизне, чем L-BFGS, а во-вторых, он использует линейный поиск для поиска оптимального размера шага. . Я бы рекомендовал проверить, разрешает ли PyTorch поиск строк, а если нет, установить уменьшающийся размер шага (или просто очень низкий).

person Yngve Moe    schedule 31.05.2018
comment
линейный поиск еще не реализован для BFGS в pytorch - person Stepan Yakovenko; 31.05.2018
comment
Он реализован в SciPy, вы должны заставить его работать, если перепишете свой код с помощью Numpy :) - person Yngve Moe; 31.05.2018