Skip to content

Commit 4d4abc0

Browse files
authored
Merge branch 'master' into sample_SMC
2 parents 9efa89c + 12d68a1 commit 4d4abc0

18 files changed

+1441
-747
lines changed

RELEASE-NOTES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
- Improve error message `NaN occurred in optimization.` during ADVI
1414
- Save and load traces without `pickle` using `pm.save_trace` and `pm.load_trace`
1515
- Add `Kumaraswamy` distribution
16+
- Rewrite parallel sampling of multiple chains on py3. This resolves
17+
long standing issues when tranferring large traces to the main process,
18+
avoids pickleing issues on UNIX, and allows us to show a progress bar
19+
for all chains. If parallel sampling is interrupted, we now return
20+
partial results.
1621

1722
### Fixes
1823

benchmarks/benchmarks/benchmarks.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import time
2+
import timeit
23

34
import numpy as np
45
import pandas as pd
@@ -63,6 +64,7 @@ class OverheadSuite(object):
6364
samplers
6465
"""
6566
params = [pm.NUTS, pm.HamiltonianMC, pm.Metropolis, pm.Slice]
67+
timer = timeit.default_timer
6668

6769
def setup(self, step):
6870
self.n_steps = 10000
@@ -78,6 +80,7 @@ def time_overhead_sample(self, step):
7880
class ExampleSuite(object):
7981
"""Implements examples to keep up with benchmarking them."""
8082
timeout = 360.0 # give it a few minutes
83+
timer = timeit.default_timer
8184

8285
def time_drug_evaluation(self):
8386
drug = np.array([101, 100, 102, 104, 102, 97, 105, 105, 98, 101,

docs/source/notebooks/dependent_density_regression.ipynb

Lines changed: 722 additions & 686 deletions
Large diffs are not rendered by default.

pymc3/backends/text.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ def record(self, point):
9999
self._fh.write(','.join(columns) + '\n')
100100

101101
def close(self):
102-
self._fh.close()
103-
self._fh = None # Avoid serialization issue.
102+
if self._fh is not None:
103+
self._fh.close()
104+
self._fh = None # Avoid serialization issue.
104105

105106
# Selection methods
106107

pymc3/distributions/mixture.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -158,18 +158,33 @@ def random_choice(*args, **kwargs):
158158
return np.random.choice(k, p=w, *args, **kwargs)
159159

160160
w = draw_values([self.w], point=point)[0]
161-
161+
comp_tmp = self._comp_samples(point=point, size=None)
162+
if self.shape.size == 0:
163+
distshape = np.asarray(np.broadcast(w, comp_tmp).shape)[..., :-1]
164+
else:
165+
distshape = self.shape
162166
w_samples = generate_samples(random_choice,
163167
w=w,
164168
broadcast_shape=w.shape[:-1] or (1,),
165-
dist_shape=self.shape,
169+
dist_shape=distshape,
166170
size=size).squeeze()
167-
comp_samples = self._comp_samples(point=point, size=size)
168-
169-
if comp_samples.ndim > 1:
170-
return np.squeeze(comp_samples[np.arange(w_samples.size), w_samples])
171+
if (size is None) or (distshape.size == 0):
172+
comp_samples = self._comp_samples(point=point, size=size)
173+
if comp_samples.ndim > 1:
174+
samples = np.squeeze(comp_samples[np.arange(w_samples.size), ..., w_samples])
175+
else:
176+
samples = np.squeeze(comp_samples[w_samples])
171177
else:
172-
return np.squeeze(comp_samples[w_samples])
178+
samples = np.zeros((size,)+tuple(distshape))
179+
for i in range(size):
180+
w_tmp = w_samples[i, :]
181+
comp_tmp = self._comp_samples(point=point, size=None)
182+
if comp_tmp.ndim > 1:
183+
samples[i, :] = np.squeeze(comp_tmp[np.arange(w_tmp.size), ..., w_tmp])
184+
else:
185+
samples[i, :] = np.squeeze(comp_tmp[w_tmp])
186+
187+
return samples
173188

174189

175190
class NormalMixture(Mixture):
@@ -197,22 +212,22 @@ class NormalMixture(Mixture):
197212
the component standard deviations
198213
tau : array of floats
199214
the component precisions
215+
comp_shape : shape of the Normal component
216+
notice that it should be different than the shape
217+
of the mixture distribution, with one axis being
218+
the number of components.
200219
201220
Note: You only have to pass in sd or tau, but not both.
202221
"""
203222

204-
def __init__(self, w, mu, *args, **kwargs):
223+
def __init__(self, w, mu, comp_shape=(), *args, **kwargs):
205224
_, sd = get_tau_sd(tau=kwargs.pop('tau', None),
206225
sd=kwargs.pop('sd', None))
207226

208-
distshape = np.broadcast(mu, sd).shape
209227
self.mu = mu = tt.as_tensor_variable(mu)
210228
self.sd = sd = tt.as_tensor_variable(sd)
211229

212-
if not distshape:
213-
distshape = np.broadcast(mu.tag.test_value, sd.tag.test_value).shape
214-
215-
super(NormalMixture, self).__init__(w, Normal.dist(mu, sd=sd, shape=distshape),
230+
super(NormalMixture, self).__init__(w, Normal.dist(mu, sd=sd, shape=comp_shape),
216231
*args, **kwargs)
217232

218233
def _repr_latex_(self, name=None, dist=None):

pymc3/gp/util.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,42 @@ def setter(self, val):
6969
return gp_wrapper
7070

7171

72-
def plot_gp_dist(ax, samples, x, plot_samples=True, palette="Reds"):
73-
""" A helper function for plotting 1D GP posteriors from trace """
72+
def plot_gp_dist(ax, samples, x, plot_samples=True, palette="Reds", fill_alpha=0.8, samples_alpha=0.1, fill_kwargs=None, samples_kwargs=None):
73+
""" A helper function for plotting 1D GP posteriors from trace
74+
75+
Parameters
76+
----------
77+
ax : axes
78+
Matplotlib axes.
79+
samples : trace or list of traces
80+
Trace(s) or posterior predictive sample from a GP.
81+
x : array
82+
Grid of X values corresponding to the samples.
83+
plot_samples: bool
84+
Plot the GP samples along with posterior (defaults True).
85+
palette: str
86+
Palette for coloring output (defaults to "Reds").
87+
fill_alpha : float
88+
Alpha value for the posterior interval fill (defaults to 0.8).
89+
samples_alpha : float
90+
Alpha value for the sample lines (defaults to 0.1).
91+
fill_kwargs : dict
92+
Additional arguments for posterior interval fill (fill_between).
93+
samples_kwargs : dict
94+
Additional keyword arguments for samples plot.
95+
96+
Returns
97+
-------
98+
99+
ax : Matplotlib axes
100+
"""
74101
import matplotlib.pyplot as plt
75102

103+
if fill_kwargs is None:
104+
fill_kwargs = {}
105+
if samples_kwargs is None:
106+
samples_kwargs = {}
107+
76108
cmap = plt.get_cmap(palette)
77109
percs = np.linspace(51, 99, 40)
78110
colors = (percs - np.min(percs)) / (np.max(percs) - np.min(percs))
@@ -82,8 +114,11 @@ def plot_gp_dist(ax, samples, x, plot_samples=True, palette="Reds"):
82114
upper = np.percentile(samples, p, axis=1)
83115
lower = np.percentile(samples, 100-p, axis=1)
84116
color_val = colors[i]
85-
ax.fill_between(x, upper, lower, color=cmap(color_val), alpha=0.8)
117+
ax.fill_between(x, upper, lower, color=cmap(color_val), alpha=fill_alpha, **fill_kwargs)
86118
if plot_samples:
87119
# plot a few samples
88120
idx = np.random.randint(0, samples.shape[1], 30)
89-
ax.plot(x, samples[:,idx], color=cmap(0.9), lw=1, alpha=0.1)
121+
ax.plot(x, samples[:,idx], color=cmap(0.9), lw=1, alpha=samples_alpha,
122+
**samples_kwargs)
123+
124+
return ax

0 commit comments

Comments
 (0)