Hello Team,
Today I was working on covariate modelling using Neural networks in the DeepPumas model. So initially while we do the traditional NLME model, we get the marginal likelihood of the fit displayed in the results and it matches with the optimization as well
But when I do the DeepPumas based model, with NN in it, we still go the loglikelihood values during the fit but it resembled the NLME values. But to my understanding since we use regularization in the DeepPumas model, while the likelihood is calculated, it has to be a combination of Marginal and the penalty right. Thats when I saw that at the last optimization process, we can see a different value of Log likelihood and the final printed results gave a different one and resembled the Marginal lieklihood of the NLME approach
So here we can see the last optmization step ends at 4.88e02 but the results we got was 504 which matched the marginal Likelihood results without the prior influence. I just wanted to confirm whether this is the scenario and what is the inference and how both these values are useful?
Also have attached the jl file codes I used for the reference:
using Pumas, DeepPumas
using DataFrames, Random, StableRNGs, Printf
Random.seed!(20250715)
# ββ constants ββββββββββββββββββββββββββββββββββββββββ
TV_CL, TV_VC = 10.0, 100.0 # CL (L/hr), Vc (L)
OM2 = 0.3^2 # IIV variance on CL & Vc
SIGMA = 0.1 # residual SD (exponential error)
NSUBJ = 50
TIMES = [1.75, 7.0] # 2 samples
DOSE = 1.0
BETA_COV = 0.5 # TRUE effect: +50% CL when c1 == 1
# ββ models βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# base: covariate-blind
basemodel = @model begin
@param begin
tvCL β RealDomain(; lower = 0.0, init = TV_CL)
tvVc β RealDomain(; lower = 0.0, init = TV_VC)
Ξ© β PDiagDomain(; init = [OM2, OM2])
Ο β RealDomain(; lower = 0.0, init = SIGMA)
end
@random Ξ· ~ MvNormal(Ξ©)
@covariates c1 c2
@pre begin
CL = tvCL * exp(Ξ·[1])
Vc = tvVc * exp(Ξ·[2])
end
@dynamics Central1
@derived begin
cp := @. Central / Vc
dv ~ @. LogNormal(log(cp), Ο)
end
end
# classical covariate model: CL = tvCL*(1 + ΞΈCOV*c1)*exp(Ξ·) (df = 1)
nlme_c1 = @model begin
@param begin
tvCL β RealDomain(; lower = 0.0, init = TV_CL)
ΞΈCOV β RealDomain(; init = 0.0)
tvVc β RealDomain(; lower = 0.0, init = TV_VC)
Ξ© β PDiagDomain(; init = [OM2, OM2])
Ο β RealDomain(; lower = 0.0, init = SIGMA)
end
@random Ξ· ~ MvNormal(Ξ©)
@covariates c1 c2
@pre begin
CL = tvCL * (1 + ΞΈCOV * c1) * exp(Ξ·[1])
Vc = tvVc * exp(Ξ·[2])
end
@dynamics Central1
@derived begin
cp := @. Central / Vc
dv ~ @. LogNormal(log(cp), Ο)
end
end
# DeepNLME: NN(c1,c2) -> CL shift, weights co-estimated. L2(1.0) prior on the NN.
deepnlme = @model begin
@param begin
tvCL β RealDomain(; lower = 0.0, init = TV_CL)
tvVc β RealDomain(; lower = 0.0, init = TV_VC)
NN β MLPDomain(2, 3, 3, (1, identity); reg = L2(1.0))
Ξ© β PDiagDomain(; init = [OM2, OM2])
Ο β RealDomain(; lower = 0.0, init = SIGMA)
end
@random Ξ· ~ MvNormal(Ξ©)
@covariates c1 c2
@pre begin
CL = tvCL * exp(NN(c1, c2)[1] + Ξ·[1])
Vc = tvVc * exp(Ξ·[2])
end
@dynamics Central1
@derived begin
cp := @. Central / Vc
dv ~ @. LogNormal(log(cp), Ο)
end
end
# ββ simulate from the TRUE model (nlme_c1 at ΞΈCOV = BETA_COV) ββββββββββββββββββ
rng = StableRNG(20250715)
c1v = [rand(rng) < 0.5 ? 1.0 : 0.0 for _ in 1:NSUBJ] # binary covariate (real)
c2v = randn(rng, NSUBJ) # continuous covariate (null decoy)
regimen = DosageRegimen(DOSE; cmt = 1, time = 0.0)
skel = [Subject(; id = i, events = regimen, covariates = (; c1 = c1v[i], c2 = c2v[i]))
for i in 1:NSUBJ]
truth = merge(init_params(nlme_c1), (; ΞΈCOV = BETA_COV))
pop = read_pumas(DataFrame(simobs(nlme_c1, skel, truth; obstimes = TIMES, rng = rng));
observations = [:dv], covariates = [:c1, :c2])
# ββ fits ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
fit_base = fit(basemodel, pop, init_params(basemodel), FOCE())
fit_nlme = fit(nlme_c1, pop, init_params(nlme_c1), FOCE())
# DeepNLME: random NN init, pin structural tv, MAP(FOCE)
init_deep = merge(sample_params(deepnlme; rng = StableRNG(20250715)),
(; tvCL = TV_CL, tvVc = TV_VC))
fit_deep = fit(deepnlme, pop, init_deep, MAP(FOCE()); ignore_numerical_error = true)
# ββ log-likelihoods βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
println("\n", "β"^60)
@printf("base loglikelihood(fpm) = %.4f\n", loglikelihood(fit_base))
@printf("nlme_c1 loglikelihood(fpm) = %.4f (ΞΈCOV = %.3f)\n",
loglikelihood(fit_nlme), coef(fit_nlme).ΞΈCOV)
println("β"^60)
# The question: for the MAP fit, is this the marginal or the penalised value?
@printf("deepnlme loglikelihood(fpm) = %.4f\n",
loglikelihood(fit_deep))
@printf("deepnlme loglikelihood(model, pop, coef, FOCE()) = %.4f <- plain-FOCE marginal\n",
loglikelihood(deepnlme, pop, coef(fit_deep), FOCE()))
println("β"^60)
```{julia}
Thank you
