Skip to content

Commit 0db6027

Browse files
authored
Merge pull request #23 from TuringLang/py/dppl-models
Add DPPL models
2 parents 2bf0fb4 + 056ff33 commit 0db6027

11 files changed

+227
-0
lines changed

.github/workflows/generate_website.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ permissions:
2323
actions: write
2424
contents: write
2525

26+
# Cancel existing tests on the same PR if a new commit is added to a pull request
27+
concurrency:
28+
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
29+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
30+
2631
jobs:
2732
setup-keys:
2833
runs-on: ubuntu-latest
@@ -53,6 +58,8 @@ jobs:
5358
- name: Setup keys
5459
id: keys
5560
run: uv run ad.py setup
61+
env:
62+
DATADEPS_ALWAYS_ACCEPT: "true"
5663

5764
run-models:
5865
runs-on: ubuntu-latest
@@ -88,6 +95,8 @@ jobs:
8895
env:
8996
ADTYPE_KEYS: ${{ needs.setup-keys.outputs.adtype_keys }}
9097
ADTESTS_MODELS_TO_LOAD: ${{ matrix.model }}
98+
DATADEPS_ALWAYS_ACCEPT: "true"
99+
PYTHONUNBUFFERED: "1"
91100

92101
- name: Output matrix values
93102
id: output-matrix

Project.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
[deps]
22
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
33
Chairmarks = "0ca39b1e-fe0b-4e98-acfc-b1656634c4de"
4+
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
45
DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63"
56
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
7+
DistributionsAD = "ced4e74d-a319-5a8a-b0ac-84af2272839c"
68
DynamicPPL = "366bfd00-2699-11ea-058f-f148b4cae6d8"
79
Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
810
FiniteDifferences = "26cc04aa-876d-5657-8c51-4c34ba976000"
911
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
12+
LazyArrays = "5078a376-72f3-5289-bfd5-ec5146d43c02"
1013
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1114
LogDensityProblems = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c"
15+
MLDatasets = "eb30cadb-4394-5ae3-aed4-317e484a6458"
1216
Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6"
17+
MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411"
1318
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1419
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
1520
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
21+
StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
1622
Turing = "fce5fe82-541a-59a6-adf8-730c64b5f9a0"
1723
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
1824

main.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ end
9696
@include_model "Distributions" "observe_bernoulli"
9797
@include_model "Distributions" "observe_categorical"
9898
@include_model "Distributions" "observe_von_mises"
99+
@include_model "DynamicPPL arXiV paper" "dppl_gauss_unknown"
100+
@include_model "DynamicPPL arXiV paper" "dppl_hier_poisson"
101+
@include_model "DynamicPPL arXiV paper" "dppl_high_dim_gauss"
102+
@include_model "DynamicPPL arXiV paper" "dppl_hmm_semisup"
103+
@include_model "DynamicPPL arXiV paper" "dppl_lda"
104+
@include_model "DynamicPPL arXiV paper" "dppl_logistic_regression"
105+
@include_model "DynamicPPL arXiV paper" "dppl_naive_bayes"
106+
@include_model "DynamicPPL arXiV paper" "dppl_sto_volatility"
99107
@include_model "DynamicPPL demo models" "demo_assume_dot_observe"
100108
@include_model "DynamicPPL demo models" "demo_assume_dot_observe_literal"
101109
@include_model "DynamicPPL demo models" "demo_assume_index_observe"

models/dppl_gauss_unknown.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
n = 10_000
2+
s = abs(rand()) + 0.5
3+
y = randn() .+ s * randn(n)
4+
5+
@model function dppl_gauss_unknown(y)
6+
N = length(y)
7+
m ~ Normal(0, 1)
8+
s ~ truncated(Cauchy(0, 5); lower=0)
9+
y ~ filldist(Normal(m, s), N)
10+
end
11+
12+
model = dppl_gauss_unknown(y)

models/dppl_hier_poisson.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using LazyArrays
2+
using Turing: LogPoisson
3+
4+
nd, ns = 5, 10
5+
a0, a1, a0_sig = 1.0, 0.5, 0.3
6+
n = nd * ns
7+
# simulate group level parameters
8+
a0s = rand(Normal(0, a0_sig), ns)
9+
logpop = rand(Normal(9, 1.5), ns)
10+
λ = exp.(a0 .+ a0s + (a1 * logpop))
11+
# and individual data
12+
y = mapreduce(λi -> rand(Poisson(λi), nd), vcat, λ)
13+
x = repeat(logpop, inner=nd)
14+
idx = repeat(collect(1:ns), inner=nd)
15+
16+
lazyarray(f, x) = LazyArray(Base.broadcasted(f, x))
17+
18+
@model function dppl_hier_poisson(y, x, idx, ns)
19+
a0 ~ Normal(0, 10)
20+
a1 ~ Normal(0, 1)
21+
a0_sig ~ truncated(Cauchy(0, 1); lower=0)
22+
a0s ~ filldist(Normal(0, a0_sig), ns)
23+
alpha = a0 .+ a0s[idx] .+ a1 * x
24+
y ~ arraydist(lazyarray(LogPoisson, alpha))
25+
end
26+
27+
model = dppl_hier_poisson(y, x, idx, ns)

models/dppl_high_dim_gauss.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@model function dppl_high_dim_gauss(D)
2+
m ~ filldist(Normal(0, 1), D)
3+
end
4+
5+
model = dppl_high_dim_gauss(10_000)

models/dppl_hmm_semisup.jl

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using StatsFuns: logsumexp
2+
3+
# Set up hyperparameters
4+
K, v, T, T_unsup = 5, 20, 100, 200
5+
alpha = fill(1.0, K)
6+
beta = fill(0.1, v)
7+
theta = rand(Dirichlet(alpha), K)
8+
phi = rand(Dirichlet(beta), K)
9+
10+
# Simulate data (supervised)
11+
w = Vector{Int}(undef, T)
12+
z = Vector{Int}(undef, T)
13+
z[1] = rand(1:K)
14+
w[1] = rand(Categorical(phi[:, z[1]]))
15+
for t in 2:T
16+
z[t] = rand(Categorical(theta[:, z[t - 1]]))
17+
w[t] = rand(Categorical(phi[:, z[t]]))
18+
end
19+
20+
# Unsupervised
21+
u = Vector{Int}(undef, T_unsup)
22+
y = Vector{Int}(undef, T_unsup)
23+
y[1] = rand(1:K)
24+
u[1] = rand(Categorical(phi[:, y[1]]))
25+
for t in 2:T_unsup
26+
y[t] = rand(Categorical(theta[:, y[t - 1]]))
27+
u[t] = rand(Categorical(phi[:, y[t]]))
28+
end
29+
30+
@model function dppl_hmm_semisup(K, T, T_unsup, w, z, u, alpha, beta)
31+
theta ~ filldist(Dirichlet(alpha), K)
32+
phi ~ filldist(Dirichlet(beta), K)
33+
for t in 1:T
34+
w[t] ~ Categorical(phi[:, z[t]]);
35+
end
36+
for t in 2:T
37+
z[t] ~ Categorical(theta[:, z[t - 1]]);
38+
end
39+
40+
TF = eltype(theta)
41+
acc = similar(alpha, TF, K)
42+
gamma = similar(alpha, TF, K)
43+
temp_gamma = similar(alpha, TF, K)
44+
for k in 1:K
45+
gamma[k] = log(phi[u[1],k])
46+
end
47+
for t in 2:T_unsup
48+
for k in 1:K
49+
for j in 1:K
50+
acc[j] = gamma[j] + log(theta[k, j]) + log(phi[u[t], k])
51+
end
52+
temp_gamma[k] = logsumexp(acc)
53+
end
54+
gamma .= temp_gamma
55+
end
56+
@addlogprob! logsumexp(gamma)
57+
end
58+
59+
model = dppl_hmm_semisup(K, T, T_unsup, w, z, u, alpha, beta)

models/dppl_lda.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
v = 100 # words
2+
k = 5 # topics
3+
m = 10 # number of docs
4+
alpha = ones(k)
5+
beta = ones(v)
6+
7+
phi = rand(Dirichlet(beta), k)
8+
theta = rand(Dirichlet(alpha), m)
9+
doc_lengths = rand(Poisson(1_000), m)
10+
n = sum(doc_lengths)
11+
12+
w = Vector{Int}(undef, n)
13+
doc = Vector{Int}(undef, n)
14+
for i in 1:m
15+
local idx = sum(doc_lengths[1:i-1]) # starting index for inner loop
16+
for j in 1:doc_lengths[i]
17+
z = rand(Categorical(theta[:, i]))
18+
w[idx + j] = rand(Categorical(phi[:, z]))
19+
doc[idx + j] = i
20+
end
21+
end
22+
23+
@model function dppl_lda(k, m, w, doc, alpha, beta)
24+
theta ~ filldist(Dirichlet(alpha), m)
25+
phi ~ filldist(Dirichlet(beta), k)
26+
log_phi_dot_theta = log.(phi * theta)
27+
@addlogprob! sum(log_phi_dot_theta[CartesianIndex.(w, doc)])
28+
end
29+
30+
model = dppl_lda(k, m, w, doc, alpha, beta)

models/dppl_logistic_regression.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using StatsFuns: logistic
2+
using LazyArrays
3+
4+
d, n = 100, 10_000
5+
X = randn(d, n)
6+
w = randn(d)
7+
y = Int.(logistic.(X' * w) .> 0.5)
8+
9+
function safelogistic(x::T) where {T}
10+
logistic(x) * (1 - 2 * eps(T)) + eps(T)
11+
end
12+
13+
lazyarray(f, x) = LazyArray(Base.broadcasted(f, x))
14+
15+
@model function dppl_logistic_regression(Xt, y)
16+
N, D = size(Xt)
17+
w ~ filldist(Normal(), D)
18+
y ~ arraydist(lazyarray(x -> Bernoulli(safelogistic(x)), Xt * w))
19+
end
20+
21+
model = dppl_logistic_regression(X', y)

models/dppl_naive_bayes.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using MLDatasets: MNIST
2+
using MultivariateStats: fit, PCA, transform
3+
4+
# Load MNIST images and labels
5+
features = MNIST(split=:train).features
6+
nrows, ncols, nimages = size(features)
7+
image_raw = Float64.(reshape(features, (nrows * ncols, nimages)))
8+
labels = MNIST(split=:train).targets .+ 1
9+
C = 10 # Number of labels
10+
11+
# Preprocess the images by reducing dimensionality
12+
D = 40
13+
pca = fit(PCA, image_raw; maxoutdim=D)
14+
image = transform(pca, image_raw)
15+
16+
# Take only the first 1000 images and vectorise
17+
N = 1000
18+
image_subset = image[:, 1:N]'
19+
image_vec = vec(image_subset[:, :])
20+
labels = labels[1:N]
21+
22+
@model function dppl_naive_bayes(image_vec, labels, C, D)
23+
m ~ filldist(Normal(0, 10), C, D)
24+
image_vec ~ MvNormal(vec(m[labels, :]), I)
25+
end
26+
27+
model = dppl_naive_bayes(image_vec, labels, C, D)

0 commit comments

Comments
 (0)