2016-03-25 3 views
4

Мне нужно оптимизировать набор переменных относительно объектной функции. У меня есть аналитический градиент функции, и я хотел бы использовать его в подпрограмме оптимизации. Объект и градиент имеют некоторые общие вычисления, и я хотел бы определить функции наиболее эффективным способом. Следующий пример демонстрирует проблему.Оптимизация в R - эффективное вычисление цели и градиента

Пусть f_obj, f_grad и f_common - функции для объектного, градиентного и общего вычислений соответственно. Оптимизация выполняется над вектором x. В приведенном ниже коде найден корень полинома y^3 - 3*y^2 + 6*y + 1, где y является функцией от c(x[1], x[2]). Обратите внимание, что функция f_common вызывается как f_obj, так и f_grad. В моей реальной проблеме общее вычисление намного длиннее, поэтому я ищу способ определить f_obj и f_grad так, чтобы количество вызовов f_common было сведено к минимуму.

f_common <- function(x) x[1]^3*x[2]^3 - x[2] 

f_obj <- function(x) { 
    y <- f_common(x) 
    return ((y^3 - 3*y^2 + 6*y + 1)^2) 
} 

f_grad <- function(x) { 
    y <- f_common(x) 
    return (2 * (y^3 - 3*y^2 + 6*y + 1) * (3*y^2 - 6*y + 6)* c(3*x[1]^2*x[2]^3, 3*x[1]^3*x[2]^2 - 1)) 
} 

optim(par = c(100,100), fn = f_obj, gr = f_grad, method = "BFGS") 

UPDATE

Я считаю, что пакет nloptr предлагает средство для ввода целевой функции и ее градиента в виде списка. Есть ли способ определить другие оптимизаторы (optim, optimx, nlminb и т. Д.) Аналогичным образом?

Спасибо.

+0

Что вы хотите>? Код работает. Если вы хотите свести к минимуму вызов функции f_common, вы не должны называть его, а вместо этого - жестким кодом y в функции. –

+0

Жесткое кодирование общих вычислений в обеих функциях будет эквивалентным вызову f_common (с точки зрения времени выполнения). Я ищу способ устранить избыточные вычисления. С моим кодом, если подпрограмма оптимизации должна вычислять 'f_obj' в точке' x' и найти ее градиент в этой точке, ей нужно будет вызвать 'f_common' дважды, но нам нужно только вычислить' y' один раз. – user3294195

+3

Возможно, вы можете использовать пакет, например [memoise] (https://cran.r-project.org/web/packages/memoise/index.html) для кэширования результатов 'f_common'. – sgibb

ответ

1

магазин значение общей функции в глобальной переменной, чтобы сделать его доступным для последующего вызова функции, как в следующем:

f_common <- function(x) x[1]^3*x[2]^3 - x[2] 

f_obj <- function(x) { 
    y <<- f_common(x) # <<- operator stores in parent scope 
    return ((y^3 - 3*y^2 + 6*y + 1)^2) 
} 

f_grad <- function(x) { 
    return (2 * (y^3 - 3*y^2 + 6*y + 1) * (3*y^2 - 6*y + 6)* c(3*x[1]^2*x[2]^3, 3*x[1]^3*x[2]^2 - 1)) 
} 

y<<-0 

optim(par = c(100,100), fn = f_obj, gr = f_grad, method = "BFGS") 

Пару заметок стоит добавлять об этом решении.

1) Во-первых, используя оператор < <, строго говоря не назначает глобальную переменную, а скорее одну в родительской области функции (т. Е. Область, из которой она была вызвана). Как правило, это часто глобальный масштаб. Это прекрасно работает здесь, и это лучший подход. Также можно явно использовать глобальную область видимости с помощью функции assign(), но здесь нет необходимости.

2) Следует также отметить, что обычно не рекомендуется использовать глобальные переменные, поскольку они могут иметь неожиданные побочные эффекты, если одно и то же имя переменной используется в другом месте. Чтобы избежать возможных побочных эффектов, я бы предложил использовать переменное имя, такое как global.f_common, которое никогда не будет использоваться в другом месте и не имеет опасности побочных эффектов. Я просто использовал имя y в примере, чтобы оно соответствовало номенклатуре в исходном вопросе. Это один из редких случаев, когда предоставление переменной сферы вне ее функции может быть оправдано, потому что трудно добиться желаемого поведения другим способом. Просто убедитесь, что вы проявляете осторожность и используете уникальное имя (например, global.f_common), как было предложено выше.

+1

Мы уверены, что вызов функции градиента с x всегда сопровождается вызовом целевой функции с тем же x? Если, скажем, grad (x2) вычисляет сразу после вычисления obj (x1), то это вызовет проблему. Выглядит рискованно, если не понимать всю процедуру в функции 'optim'. –

+0

Я сделал несколько проверок по этому поводу: используя print (y) в рамках функций obj и grad и используя опцию trace в Optim. В результате этот подход следует тем же самым путём оптимизации, что и вычисление y в два раза, чем в OP. Кроме того, важно понять, что важно только, чтобы оптимизатор не вычислял градиент, кроме как в месте, где он уже рассчитал целевую функцию, что и есть. – dww

Смежные вопросы