I am interested in estimating the parameters M,D\in\mathbb{R}^{n\times n}, D\succeq0 of an OU process
from observed data at frequency \Delta t.
Is there a generalized likelihood inference procedure in the SDE DiffEq package that is similar to the one used for DiffEqs (Generalized Likelihood Inference · DiffEqParamEstim.jl) but with a single dataset (i.e., if we only have observed one “run” of the SDE)?
Here is my approach so far (following Parameter Estimation for Stochastic Differential Equations and Ensembles · DiffEqParamEstim.jl), but it doesn’t seem to work, as the optimization procedure just returns the initial point:
using DifferentialEquations
using DiffEqParamEstim
using LinearAlgebra
using RecursiveArrayTools
using Optim
using PyPlot
fig, ax = subplots()
# parameters
M = [-1.0; 0.0; -1.0]
D = [1.0; 0.1; 1.0]
μ = [5.0; 10.0]
p = [vec(M); vec(D); vec(μ)]
dt = 0.001
tspan = (0.0, 1.0)
# drift and diffusion
f(du, u, p, t) = begin
M = reshape([p[1:2]; p[2:3]], (2, 2))
μ = p[7:8]
du .= M * (u - μ)
end
g(du, u, p, t) = begin
D = reshape([p[4:5]; p[5:6]], (2, 2))
du .= D
end
Set up the problem
# problem
prob = SDEProblem(f, g, μ, tspan, p, noise_rate_prototype=zeros(2, 2))
sol = solve(prob, EM(), dt=dt)
ax.cla()
ax.plot(sol.u)
Set up the estimation
# data
t = collect(range(0, stop=1, length=200))
function generate_data(t)
sol = solve(prob, EM(), dt=dt)
randomized = VectorOfArray([(sol(t[i]) + 0.01randn(2)) for i in 1:length(t)])
data = convert(Array, randomized)
end
ntraj = 200 # for now, doing more trajectories than a single run
aggregate_data = convert(Array, VectorOfArray([generate_data(t) for i in 1:ntraj]))
# estimation
p0 = [0.4vec([-1.0; 0.1; -1.0]); 0.4vec([1.0; 0.1; 1.0]); 0.4vec([1.0; 1.0])]
monte_prob = EnsembleProblem(prob)
# obj = build_loss_objective(monte_prob, SOSRA2(), L2Loss(t, aggregate_data),
# maxiters=10000, verbose=false, trajectories=ntraj,
# parallel_type=:threads)
obj = build_loss_objective(monte_prob, EM(), dt=dt, L2Loss(t, aggregate_data),
maxiters=10000, verbose=false, trajectories=ntraj,
parallel_type=:threads)
result = Optim.optimize(obj, p0, Optim.BFGS())
Show the result
pstar = Optim.minimizer(result)
hcat(p0, pstar, p)
julia> hcat(p0, pstar, p)
8×3 Matrix{Float64}:
-0.4 -0.39996 -1.0
0.04 0.0400358 0.0
-0.4 -0.400066 -1.0
0.4 0.40028 1.0
0.04 0.0400151 0.1
0.4 0.40048 1.0
0.4 0.399804 5.0
0.4 0.400003 10.0