Manopt.jl
|
Страница в процессе перевода. |
Manopt.jl — это пакет, предоставляющий решатели для задач оптимизации, определенных на римановых многообразиях. Реализация основана на интерфейсе ManifoldsBase.jl и, следовательно, может использоваться для всех многообразий, определенных в Manifolds, или любых других многообразий, реализованных с использованием этого интерфейса.
Установка: OptimizationManopt.jl
Чтобы использовать интерфейс Optimization.jl для Manopt, установите пакет OptimizationManopt:
import Pkg;
Pkg.add("OptimizationManopt");
Методы
Для пакета OptimizationManopt доступны следующие методы:
-
GradientDescentOptimizer: соответствует методуgradient_descentв Manopt. -
NelderMeadOptimizer: соответствует методуNelderMeadв Manopt. -
ConjugateGradientDescentOptimizer: соответствует методуconjugate_gradient_descentв Manopt. -
ParticleSwarmOptimizer: соответствует методуparticle_swarmв Manopt. -
QuasiNewtonOptimizer: соответствует методуquasi_Newtonв Manopt. -
CMAESOptimizer: соответствует методуcma_esв Manopt. -
ConvexBundleOptimizer: соответствует методуconvex_bundle_methodв Manopt. -
FrankWolfeOptimizer: соответствует методуFrankWolfeв Manopt.
Общие именованные аргументы maxiters, maxtime и abstol поддерживаются всеми оптимизаторами. Специфичные для решателей именованные аргументы из Manopt можно передать в функцию solve или в OptimizationProblem.
|
Note Многообразие должно передаваться в |
Примеры
Функцию Розенброка на евклидовом многообразии можно оптимизировать с помощью GradientDescentOptimizer следующим образом:
using Optimization, OptimizationManopt, Manifolds, LinearAlgebra
rosenbrock(x, p) = (p[1] - x[1])^2 + p[2] * (x[2] - x[1]^2)^2
x0 = zeros(2)
p = [1.0, 100.0]
R2 = Euclidean(2)
stepsize = Manopt.ArmijoLinesearch(R2)
opt = OptimizationManopt.GradientDescentOptimizer()
optf = OptimizationFunction(rosenbrock, Optimization.AutoZygote())
prob = OptimizationProblem(
optf, x0, p; manifold = R2, stepsize = stepsize)
sol = Optimization.solve(prob, opt)
retcode: Failure
u: 2-element Vector{Float64}:
0.8165527190561593
0.6672818138967234
Задачу Кархера о нахождении среднего значения с прямоугольными ограничениями на многообразии SPD можно решить с помощью алгоритма Франка-Вульфа следующим образом:
M = SymmetricPositiveDefinite(5)
m = 100
σ = 0.005
q = Matrix{Float64}(I, 5, 5) .+ 2.0
data2 = [exp(M, q, σ * rand(M; vector_at = q)) for i in 1:m]
f(x, p = nothing) = sum(distance(M, x, data2[i])^2 for i in 1:m)
optf = OptimizationFunction(f, Optimization.AutoZygote())
prob = OptimizationProblem(optf, data2[1]; manifold = M, maxiters = 1000)
function closed_form_solution!(M::SymmetricPositiveDefinite, q, L, U, p, X)
# извлекаем p^1/2 и p^{-1/2}
(p_sqrt_inv, p_sqrt) = Manifolds.spd_sqrt_and_sqrt_inv(p)
# Вычисляем D и Q
e2 = eigen(p_sqrt_inv * X * p_sqrt_inv) # разлагаем Sk = QDQ'
D = Diagonal(1.0 .* (e2.values .< 0))
Q = e2.vectors
Uprime = Q' * p_sqrt_inv * U * p_sqrt_inv * Q
Lprime = Q' * p_sqrt_inv * L * p_sqrt_inv * Q
P = cholesky(Hermitian(Uprime - Lprime))
z = P.U' * D * P.U + Lprime
copyto!(M, q, p_sqrt * Q * z * Q' * p_sqrt)
return q
end
N = m
U = mean(data2)
L = inv(sum(1 / N * inv(matrix) for matrix in data2))
optf = OptimizationFunction(f, Optimization.AutoZygote())
prob = OptimizationProblem(optf, U; manifold = M, maxiters = 1000)
sol = Optimization.solve(
prob, opt, sub_problem = (M, q, p, X) -> closed_form_solution!(M, q, L, U, p, X))
retcode: Failure
u: 5×5 Matrix{Float64}:
2.99909 1.9993 1.99918 1.9994 1.99959
1.9993 2.99959 1.99939 1.99956 1.99968
1.99918 1.99939 2.99923 1.99942 1.99954
1.9994 1.99956 1.99942 2.99963 1.99984
1.99959 1.99968 1.99954 1.99984 2.9999
Этот пример основан на примере в Manopt и статье Вебер и Сра, 2022.
Следующий пример адаптирован из примера отношения Релея в ManoptExamples.jl. Мы решаем задачу отношения Релея на сферическом многообразии:
using Optimization, OptimizationManopt
using Manifolds, LinearAlgebra
using Manopt
n = 1000
A = Symmetric(randn(n, n) / n)
manifold = Sphere(n - 1)
cost(x, p = nothing) = -x' * A * x
egrad(G, x, p = nothing) = (G .= -2 * A * x)
optf = OptimizationFunction(cost, grad = egrad)
x0 = rand(manifold)
prob = OptimizationProblem(optf, x0, manifold = manifold)
sol = solve(prob, GradientDescentOptimizer())
retcode: Failure
u: 1000-element Vector{Float64}:
0.01762169728569332
0.036453437409565484
-0.07994375379576305
0.017944451655274165
-0.09196598746916287
-0.009986191362713108
0.01745879680206771
-0.01212935641985748
-0.007594723449626095
-0.011600811811304991
⋮
-0.011948665669623807
-0.010008666373949848
-0.021777767128275824
0.01509374676118785
0.06237839083527088
-0.00657276323355566
-0.03315533312952052
0.008965243051950903
-0.037907481632190904
Проверим, действительно ли это соответствует минимальному собственному значению матрицы A.
@show eigmin(A)
@show sol.objective
-0.06285476047155444