Skip to content

Commit fd81697

Browse files
committed
Retain Newtown update only if objective function improved #455
1 parent 499b02f commit fd81697

File tree

4 files changed

+36
-34
lines changed

4 files changed

+36
-34
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: sdmTMB
33
Title: Spatial and Spatiotemporal SPDE-Based GLMMs with 'TMB'
4-
Version: 0.7.2.9003
4+
Version: 0.7.2.9004
55
Authors@R: c(
66
person(c("Sean", "C."), "Anderson", , "sean@seananderson.ca",
77
role = c("aut", "cre"),

NEWS.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
## Minor improvements and fixes
44

5+
* Only retain Newton update parameters if they improve the objective function.
6+
#455
7+
58
* Suppress `nlminb()` warnings by default, which can usually be ignored by the
69
user and may be confusing. This can be controlled via
710
`sdmTMB(..., control = sdmTMBcontrol(suppress_nlminb_warnings = FALSE))`.
11+
This option now mirrors tinyVAST.
812

9-
* Only run Newton optimization steps if maximum absolute gradient is >= -1e6
10-
to save time.
11-
12-
* Fix reported gradient if Newton loops used in optimization. Previously,
13-
the gradients would have looked overly pessimistic for some models. #455
13+
* Only run Newton updates if maximum absolute gradient is >= 1e-9 to save time.
1414

1515
* Round time-varying AR(1) rho to 2 decimals in model printing/summary.
1616

R/extra-optimization.R

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,37 @@ run_extra_optimization <- function(object,
5050
}
5151
}
5252

53-
for (i in seq_len(newton_loops)) {
54-
g <- as.numeric(new_obj$tmb_obj$gr(tmb_opt$par))
55-
h <- stats::optimHess(
56-
tmb_opt$par,
57-
fn = new_obj$tmb_obj$fn,
58-
gr = new_obj$tmb_obj$gr,
59-
lower = object$lower,
60-
upper = object$upper
61-
)
62-
tmb_opt$par <- tmb_opt$par - solve(h, g)
63-
tmb_opt$objective <- new_obj$tmb_obj$fn(tmb_opt$par)
64-
if (i == newton_loops) {
65-
new_obj$tmb_obj$fn(tmb_opt$par) # call once to update environment
66-
}
67-
}
53+
tmb_opt <- run_newton_loops(newton_loops = newton_loops, tmb_opt, new_obj, silent = FALSE)
6854
new_obj$model <- tmb_opt
69-
new_obj$sd_report <- TMB::sdreport(new_obj$tmb_obj, par.fixed = tmb_opt$par,
55+
new_obj$sd_report <- TMB::sdreport(new_obj$tmb_obj,
7056
getJointPrecision = "jointPrecision" %in% names(object$sd_report))
7157
conv <- get_convergence_diagnostics(new_obj$sd_report)
7258
new_obj$gradients <- conv$final_grads
7359
new_obj$bad_eig <- conv$bad_eig
7460
new_obj
7561
}
62+
63+
run_newton_loops <- function(newton_loops, opt, obj, silent = TRUE) {
64+
if (newton_loops > 0) {
65+
if (!silent) cli_inform("attempting to improve convergence with a Newton update\n")
66+
for (i in seq_len(newton_loops)) {
67+
g <- as.numeric(obj$gr(opt$par))
68+
if (max(abs(g)) < 1e-9) {
69+
if (!silent) cli_inform(c("maximum absolute gradient is already < 1e-9;",
70+
"skipping any remaining Newton updates for speed\n"))
71+
break
72+
}
73+
h <- stats::optimHess(opt$par, fn = obj$fn, gr = obj$gr)
74+
new_par <- opt$par - solve(h, g)
75+
new_objective <- obj$fn(new_par) # also updates obj$env$last.par and obj$env$last.par.best!
76+
if (new_objective < opt$objective) {
77+
if (!silent) cli_inform("accepting parameters from Newton update\n")
78+
opt$par <- new_par
79+
opt$objective <- new_objective
80+
} else {
81+
if (!silent) cli_inform("retaining parameters from before Newton update\n")
82+
}
83+
}
84+
}
85+
opt
86+
}

R/fit.R

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,21 +1609,12 @@ sdmTMB <- function(
16091609
cli_inform("Upper or lower limits were set. `stats::optimHess()` will ignore these limits. Set `control = sdmTMBcontrol(newton_loops = 0)` to avoid the `stats::optimHess()` optimization if desired.")
16101610
}
16111611
}
1612-
if (newton_loops > 0) {
1613-
if (!silent) cli_inform("attempting to improve convergence with optimHess\n")
1614-
for (i in seq_len(newton_loops)) {
1615-
g <- as.numeric(tmb_obj$gr(tmb_opt$par))
1616-
if (max(abs(g)) < 1e-6) break
1617-
h <- stats::optimHess(tmb_opt$par, fn = tmb_obj$fn, gr = tmb_obj$gr)
1618-
tmb_opt$par <- tmb_opt$par - solve(h, g)
1619-
tmb_opt$objective <- tmb_obj$fn(tmb_opt$par)
1620-
}
1621-
}
1612+
1613+
tmb_opt <- run_newton_loops(newton_loops = newton_loops, tmb_opt, tmb_obj, silent)
16221614
check_bounds(tmb_opt$par, lim$lower, lim$upper)
16231615

16241616
if (!silent) cli_inform("running TMB sdreport\n")
1625-
sd_report <- TMB::sdreport(tmb_obj, par.fixed = tmb_opt$par,
1626-
getJointPrecision = get_joint_precision)
1617+
sd_report <- TMB::sdreport(tmb_obj, getJointPrecision = get_joint_precision)
16271618
conv <- get_convergence_diagnostics(sd_report)
16281619

16291620
## save params that families need to grab from environments:

0 commit comments

Comments
 (0)