Skip to content

Commit 8db6408

Browse files
authored
Merge branch 'main' into qqy/sghmc
2 parents a279425 + a8c0ee7 commit 8db6408

23 files changed

+330
-129
lines changed

.buildkite/pipeline.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
env:
2+
# SECRET_CODECOV_TOKEN can be added here if needed for coverage reporting
3+
4+
steps:
5+
- label: "Julia v{{matrix.version}}, {{matrix.label}}"
6+
plugins:
7+
- JuliaCI/julia#v1:
8+
version: "{{matrix.version}}"
9+
# - JuliaCI/julia-coverage#v1:
10+
# dirs:
11+
# - src
12+
# - ext
13+
command: julia --eval='println(pwd()); println(readdir()); include("test/CUDA/cuda.jl")'
14+
agents:
15+
queue: "juliagpu"
16+
cuda: "*"
17+
if: build.message !~ /\[skip tests\]/
18+
timeout_in_minutes: 60
19+
env:
20+
LABEL: "{{matrix.label}}"
21+
TEST_TYPE: ext
22+
matrix:
23+
setup:
24+
version:
25+
- "1"
26+
- "1.10"
27+
label:
28+
- "cuda"

HISTORY.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# AdvancedHMC Changelog
2+
3+
## v0.7.1
4+
5+
- README has been simplified, many docs transfered to docs: https://turinglang.org/AdvancedHMC.jl/dev/.
6+
- ADTypes.jl can be used for specifying the AD backend in `Hamiltonian(metric, ℓπ, AutoForwardDiff())`.
7+
- SimpleUnpack.jl and Requires.jl are removed from the dependency.
8+
- `find_good_stepsize` now has fewer allocations.
9+
10+
## v0.7.0
11+
12+
- Type piracies of Base.rand and Base.randn for vectors of RNGs are removed: Replace `rand(rngs::AbstractVector{<:Random.AbstractRNG})` with `map(rand, rngs)`, `randn(rngs::AbstractVector{<:Random.AbstractRNG})` with `map(randn, rngs)`, `rand(rngs::AbstractVector{<:Random.AbstractRNG}, T, n::Int) (for n == length(rngs))` with `map(Base.Fix2(rand, T), rngs)`, and `randn(rngs::AbstractVector{<:Random.AbstractRNG}, T, m::Int, n::Int) (for n == length(rngs))` with eg `reduce(hcat, map(rng -> randn(rng, T, m), rngs))`.
13+
- Type piracy `Base.isfinite(x::AbstractVecOrMat)` is removed: Switch to `all(isfinite, x)` if you (possibly implicitly) relied on this definition
14+
- Abstract fields of `NesterovDualAveraging`, `HMCDA`, `SliceTS`, and `MultinomialTS` are made concrete by adding type parameters: Update occurrences of these types (eg. in function signatures) if necessary
15+
- Definitions of Base.rand for metrics are removed: Use the (internal) `AdvancedHMC.rand_momentum` function if you depend on this functionality and open an issue to further discuss the API
16+
17+
## v0.5.0
18+
19+
Convenience constructors for common samplers changed to:
20+
21+
- `HMC(leapfrog_stepsize::Real, n_leapfrog::Int)`
22+
- `NUTS(target_acceptance::Real)`
23+
- `HMCDA(target_acceptance::Real, integration_time::Real)`
24+
25+
## v0.2.22
26+
27+
Three functions are renamed.
28+
29+
- `Preconditioner(metric::AbstractMetric)` -> `MassMatrixAdaptor(metric)` and
30+
- `NesterovDualAveraging(δ, integrator::AbstractIntegrator)` -> `StepSizeAdaptor(δ, integrator)`
31+
- `find_good_eps` -> `find_good_stepsize`
32+
33+
## v0.2.15
34+
35+
`n_adapts` is no longer needed to construct `StanHMCAdaptor`; the old constructor is deprecated.
36+
37+
## v0.2.8
38+
39+
Two Hamiltonian trajectory sampling methods are renamed to avoid a name clash with Distributions.
40+
41+
- `Multinomial` -> `MultinomialTS`
42+
- `Slice` -> `SliceTS`
43+
44+
## v0.2.0
45+
46+
The gradient function passed to `Hamiltonian` is supposed to return a value-gradient tuple now.

Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
1818

1919
[weakdeps]
2020
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
21+
ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66"
2122
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
2223
MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d"
2324
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
2425

2526
[extensions]
2627
AdvancedHMCADTypesExt = "ADTypes"
28+
AdvancedHMCComponentArraysExt = "ComponentArrays"
2729
AdvancedHMCCUDAExt = "CUDA"
2830
AdvancedHMCMCMCChainsExt = "MCMCChains"
2931
AdvancedHMCOrdinaryDiffEqExt = "OrdinaryDiffEq"
@@ -32,6 +34,7 @@ AdvancedHMCOrdinaryDiffEqExt = "OrdinaryDiffEq"
3234
ADTypes = "1"
3335
AbstractMCMC = "5.6"
3436
ArgCheck = "1, 2"
37+
ComponentArrays = "0.15"
3538
CUDA = "3, 4, 5"
3639
DocStringExtensions = "0.8, 0.9"
3740
LinearAlgebra = "<0.1, 1"

docs/make.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ makedocs(;
2020
"Detailed API" => "api.md",
2121
"Interfaces" => "interfaces.md",
2222
"News" => "news.md",
23-
"Change Log" => "changelog.md",
2423
"References" => "references.md",
2524
],
2625
)

docs/src/autodiff.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Gradient in AdvancedHMC.jl
22

3-
AdvancedHMC.jl supports automatic differentiation using [`LogDensityProblemsAD`](https://github.com/tpapp/LogDensityProblemsAD.jl) across various AD backends and allows user-specified gradients. While the default AD backend for AdvancedHMC.jl is ForwardDiff.jl, we can seamlessly change to other backend like Mooncake.jl using various syntax like `Hamiltonian(metric, ℓπ, AutoZygote())`. Different AD backend can also be pluged in using `Hamiltonian(metric, ℓπ, Zygote)`, `Hamiltonian(metric, ℓπ, Val(:Zygote))` but we recommend using ADTypes since that would allow you to have more freedom for specifying the AD backend.
3+
AdvancedHMC.jl supports automatic differentiation using [`LogDensityProblemsAD`](https://github.com/tpapp/LogDensityProblemsAD.jl) across various AD backends and allows user-specified gradients. While the default AD backend for AdvancedHMC.jl is ForwardDiff.jl, we can seamlessly change to other backend like Mooncake.jl using various syntax like `Hamiltonian(metric, ℓπ, AutoMooncake(; config = nothing))`. While some AD backends support syntax like `Hamiltonian(metric, ℓπ, Zygote)`, `Hamiltonian(metric, ℓπ, Val(:Zygote))`, we recommend using ADTypes since that would allow you to have more freedom for specifying the AD backend:
4+
5+
```julia
6+
using AdvancedHMC, ADTypes, DifferentiationInterface, Mooncake, Zygote
7+
hamiltonian = Hamiltonian(metric, ℓπ, AutoMooncake(; config=nothing))
8+
hamiltonian = Hamiltonian(metric, ℓπ, AutoZygote())
9+
```
410

511
In order to use user-specified gradients, please replace ForwardDiff.jl with `ℓπ_grad` in the `Hamiltonian` constructor as `Hamiltonian(metric, ℓπ, ℓπ_grad)`, where the gradient function `ℓπ_grad` should return a tuple containing both the log-posterior and its gradient, for example `ℓπ_grad(x) = (log_posterior, grad)`.

docs/src/changelog.md

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module AdvancedHMCComponentArraysExt
2+
3+
using AdvancedHMC: AdvancedHMC, __axes
4+
using ComponentArrays: ComponentVecOrMat, getaxes
5+
6+
AdvancedHMC.__axes(r::ComponentVecOrMat) = getaxes(r)
7+
8+
end # module

src/AdvancedHMC.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,12 @@ function Hamiltonian(metric::AbstractMetric, ℓπ, kind::Union{Symbol,Val,Modul
172172
),
173173
)
174174
end
175-
= LogDensityProblemsAD.ADgradient(
176-
kind isa Val ? kind : Val(Symbol(kind)), ℓπ; kwargs...
177-
)
175+
_kind = if kind isa Val || kind isa Symbol
176+
kind
177+
else
178+
Symbol(kind)
179+
end
180+
= LogDensityProblemsAD.ADgradient(_kind, ℓπ; kwargs...)
178181
return Hamiltonian(metric, ℓ)
179182
end
180183

src/adaptation/massmatrix.jl

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function adapt!(
1313
α::AbstractScalarOrVec{<:AbstractFloat},
1414
is_update::Bool=true,
1515
)
16-
resize!(adaptor, θ)
16+
resize_adaptor!(adaptor, size(θ))
1717
push!(adaptor, θ)
1818
is_update && update!(adaptor)
1919
return nothing
@@ -29,7 +29,7 @@ UnitMassMatrix() = UnitMassMatrix{Float64}()
2929

3030
Base.string(::UnitMassMatrix) = "I"
3131

32-
Base.resize!(pc::UnitMassMatrix, θ::AbstractVecOrMat) = nothing
32+
resize_adaptor!(pc::UnitMassMatrix, size_θ::Tuple) = nothing
3333

3434
reset!(::UnitMassMatrix) = nothing
3535

@@ -78,15 +78,16 @@ function get_estimation(nv::NaiveVar)
7878
end
7979

8080
# Ref: https://github.com/stan-dev/math/blob/develop/stan/math/prim/mat/fun/welford_var_estimator.hpp
81-
mutable struct WelfordVar{T<:AbstractFloat,E<:AbstractVecOrMat{T}} <: DiagMatrixEstimator{T}
81+
mutable struct WelfordVar{T<:AbstractFloat,E<:AbstractVecOrMat{T},V<:AbstractVecOrMat{T}} <:
82+
DiagMatrixEstimator{T}
8283
n::Int
8384
n_min::Int
8485
μ::E
8586
M::E
8687
δ::E # cache for diff
87-
var::E # cache for variance
88-
function WelfordVar(n::Int, n_min::Int, μ::E, M::E, δ::E, var::E) where {E}
89-
return new{eltype(E),E}(n, n_min, μ, M, δ, var)
88+
var::V # cache for variance
89+
function WelfordVar(n::Int, n_min::Int, μ::E, M::E, δ::E, var::V) where {E,V}
90+
return new{eltype(E),E,V}(n, n_min, μ, M, δ, var)
9091
end
9192
end
9293

@@ -102,20 +103,31 @@ function WelfordVar(sz::Union{Tuple{Int},Tuple{Int,Int}}; kwargs...)
102103
return WelfordVar{Float64}(sz; kwargs...)
103104
end
104105

105-
function Base.resize!(wv::WelfordVar, θ::AbstractVecOrMat{T}) where {T<:AbstractFloat}
106-
if size(θ) != size(wv.var)
106+
function resize_adaptor!(wv::WelfordVar{T}, size_θ::Tuple{Int,Int}) where {T<:AbstractFloat}
107+
if size_θ != size(wv.var)
107108
@assert wv.n == 0 "Cannot resize a var estimator when it contains samples."
108-
wv.μ = zeros(T, size(θ))
109-
wv.M = zeros(T, size(θ))
110-
wv.δ = zeros(T, size(θ))
111-
wv.var = ones(T, size(θ))
109+
wv.μ = zeros(T, size_θ)
110+
wv.M = zeros(T, size_θ)
111+
wv.δ = zeros(T, size_θ)
112+
wv.var = ones(T, size_θ)
113+
end
114+
end
115+
116+
function resize_adaptor!(wv::WelfordVar{T}, size_θ::Tuple{Int}) where {T<:AbstractFloat}
117+
length_θ = first(size_θ)
118+
if length_θ != size(wv.var, 1)
119+
@assert wv.n == 0 "Cannot resize a var estimator when it contains samples."
120+
fill!(resize!(wv.μ, length_θ), T(0))
121+
fill!(resize!(wv.M, length_θ), T(0))
122+
fill!(resize!(wv.δ, length_θ), T(0))
123+
fill!(resize!(wv.var, length_θ), T(1))
112124
end
113125
end
114126

115127
function reset!(wv::WelfordVar{T}) where {T<:AbstractFloat}
116128
wv.n = 0
117-
wv.μ .= zero(T)
118-
wv.M .= zero(T)
129+
fill!(wv.μ, zero(T))
130+
fill!(wv.M, zero(T))
119131
return nothing
120132
end
121133

@@ -159,8 +171,6 @@ end
159171

160172
NaiveCov{T}(sz::Tuple{Int}) where {T<:AbstractFloat} = NaiveCov(Vector{Vector{T}}())
161173

162-
NaiveCov(sz::Union{Tuple{Int},Tuple{Int,Int}}; kwargs...) = NaiveCov{Float64}(sz; kwargs...)
163-
164174
Base.push!(nc::NaiveCov, s::AbstractVector) = push!(nc.S, s)
165175

166176
reset!(nc::NaiveCov{T}) where {T} = resize!(nc.S, 0)
@@ -171,13 +181,13 @@ function get_estimation(nc::NaiveCov)
171181
end
172182

173183
# Ref: https://github.com/stan-dev/math/blob/develop/stan/math/prim/mat/fun/welford_covar_estimator.hpp
174-
mutable struct WelfordCov{F<:AbstractFloat} <: DenseMatrixEstimator{F}
184+
mutable struct WelfordCov{F<:AbstractFloat,C<:AbstractMatrix{F}} <: DenseMatrixEstimator{F}
175185
n::Int
176186
n_min::Int
177187
μ::Vector{F}
178188
M::Matrix{F}
179189
δ::Vector{F} # cache for diff
180-
cov::Matrix{F}
190+
cov::C
181191
end
182192

183193
Base.show(io::IO, ::WelfordCov) = print(io, "WelfordCov")
@@ -191,20 +201,21 @@ end
191201

192202
WelfordCov(sz::Tuple{Int}; kwargs...) = WelfordCov{Float64}(sz; kwargs...)
193203

194-
function Base.resize!(wc::WelfordCov, θ::AbstractVector{T}) where {T<:AbstractFloat}
195-
if length(θ) != size(wc.cov, 1)
204+
function resize_adaptor!(wc::WelfordCov{T}, size_θ::Tuple{Int}) where {T<:AbstractFloat}
205+
length_θ = first(size_θ)
206+
if length_θ != size(wc.cov, 1)
196207
@assert wc.n == 0 "Cannot resize a var estimator when it contains samples."
197-
wc.μ = zeros(T, length))
198-
wc.δ = zeros(T, length))
199-
wc.M = zeros(T, length(θ), length(θ))
200-
wc.cov = LinearAlgebra.diagm(0 => ones(T, length(θ)))
208+
fill!(resize!(wc.μ, length_θ), T(0))
209+
fill!(resize!(wc.δ, length_θ), T(0))
210+
wc.M = zeros(T, length_θ, length_θ)
211+
wc.cov = LinearAlgebra.diagm(0 => ones(T, length_θ))
201212
end
202213
end
203214

204215
function reset!(wc::WelfordCov{T}) where {T<:AbstractFloat}
205216
wc.n = 0
206-
wc.μ .= zero(T)
207-
wc.M .= zero(T)
217+
fill!(wc.μ, zero(T))
218+
fill!(wc.M, zero(T))
208219
return nothing
209220
end
210221

src/adaptation/stan_adaptor.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ function adapt!(
117117

118118
adapt!(tp.ssa, θ, α)
119119

120-
resize!(tp.pc, θ) # Resize pre-conditioner if necessary.
120+
resize_adaptor!(tp.pc, size(θ)) # Resize pre-conditioner if necessary.
121121

122122
# Ref: https://github.com/stan-dev/stan/blob/develop/src/stan/mcmc/hmc/nuts/adapt_diag_e_nuts.hpp
123123
if is_in_window(tp)

0 commit comments

Comments
 (0)