Hi I’ve been trying to use DynamicHMC to sample my model written in Python. The problem I’m encountering is that I don’t know how to structure the output of my log posterior function in julia correctly, so the MCMC sampler knows what to do with it.
In the examples provided it is suggested to use the following code
t = problem_transformation(p)
P = TransformedLogDensity(t, p)
∇P = ADgradient(:ForwardDiff, P);
https://www.tamaspapp.eu/DynamicHMCExamples.jl/latest/example_linear_regression/
However, because I use python output, the gradient of the likelihood is not calculated automatically anymore. So currently I only compute the log posterior without the gradients. And even if I would calculate these gradients myself. I am not sure how to give this all the proper structure so the sampler mcmc_with_warmup() can use it.
For context the function that computes the logposterior in the example linked above returns output such as (I printed it):
Dual{ForwardDiff.Tag{Base.Fix1{typeof(LogDensityProblems.logdensity), TransformedLogDensity{TransformVariables.TransformTuple{@NamedTuple{β::TransformVariables.ArrayTransformation{TransformVariables.Identity, 1}, σ::TransformVariables.ShiftedExp{true, Int64}}}, LinearRegressionProblem{Vector{Float64}, Matrix{Float64}, Float64}}}, Float64}}(-82.04794174652842,27.668542512145063,-19.965222890254054,-5.894398700546053,10.918972471706919)
This is my julia code:
ENV["JULIA_CONDAPKG_BACKEND"] = "Null"
import PythonCall
py_module = PythonCall.Core.pyimport("models_douwe")
using TransformVariables, TransformedLogDensities, LogDensityProblems, LogDensityProblemsAD,
DynamicHMC, DynamicHMC.Diagnostics, SimpleUnPack, Statistics, Random, Distributions,
ThreadTools, MCMCDiagnosticTools, BenchmarkTools
struct Model_Structure
y::Vector # hydraulic head observations
model_nr::Int # identifier of the model defined in FloPy
locations::Tuple # measurement locations
end
function create_model_structure(model_nr::Int, locations::Tuple)
y_py = py_module.observations(model_nr, locations)
y_jl = PythonCall.Core.pyconvert(Tuple, y_py)
y = collect(y_jl)
p = Model_Structure(y, model_nr, locations)
return p
end
function (problem::Model_Structure)(θ)
@unpack hk, vk = θ
@unpack y, model_nr, locations = problem
#create input suitable for python
if typeof(hk) == Float64
all_k = (hk, vk)
else
all_k = (hk.value, vk.value)
end
#calculate likelihood
model_output_py = py_module.model_output(model_nr, locations, K = all_k)
model_output_jl = PythonCall.pyconvert(Tuple, model_output_py) # julia Tuple
model_output = collect(model_output_jl) # hydrualic head measurements, as a vector
ϵ_distribution = Normal(0, 0.1)
ℓ_error = loglikelihood(ϵ_distribution, y - model_output)
# calculate prior density
ℓ_hk = loglikelihood(Normal(10, 10), hk)
ℓ_vk = loglikelihood(Normal(10, 10), vk)
return ℓ_error + ℓ_hk + ℓ_vk
end
function problem_transformation(p::Model_Structure)
as((hk = asℝ₊, vk = asℝ₊)) # hydraulic conductivity cannot be negative
end
p = create_model_structure(1, LOCATIONS) # redefine for clarity
trans = problem_transformation(p) #transforms all k's to real positive numbers
P = TransformedLogDensity(trans, p)
∇P = ADgradient(:ForwardDiff, P)
results = mcmc_with_warmup(Random.default_rng(), ∇P, 1000)
Any suggestions on correctly incorporating the gradients in my case?