Remove pystan, leave backend abstraction for now (#2148)

This commit is contained in:
Brian Ward 2022-05-05 03:37:17 -04:00 committed by GitHub
parent 9968f8be41
commit df411c9192
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 15 additions and 114 deletions

View file

@ -69,7 +69,7 @@ jobs:
CIBW_ENVIRONMENT: >
STAN_BACKEND="${{ env.STAN_BACKEND }}"
PIP_CACHE_DIR="${{ env.PIP_DEFAULT_CACHE }}"
CIBW_BUILD: cp36-* cp37-* cp38-*
CIBW_BUILD: cp36-* cp37-* cp38-* cp39-* cp310-*
CIBW_ARCHS: native
CIBW_BUILD_FRONTEND: build
# CIBW_REPAIR_WHEEL_COMMAND: delvewheel repair -w {dest_dir} {wheel}
@ -142,7 +142,7 @@ jobs:
PIP_CACHE_DIR="/host/${{ env.PIP_DEFAULT_CACHE }}"
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
CIBW_BEFORE_ALL_LINUX: chmod -R a+rwx /host/${{ env.PIP_DEFAULT_CACHE }}
CIBW_BUILD: cp36-* cp37-* cp38-*
CIBW_BUILD: cp36-* cp37-* cp38-* cp39-* cp310-*
CIBW_SKIP: "*musllinux*"
CIBW_ARCHS: native
CIBW_BUILD_FRONTEND: build

View file

@ -78,13 +78,6 @@ $ CMDSTAN=/tmp/cmdstan-2.22.1 STAN_BACKEND=CMDSTANPY pip install prophet
Note that the `CMDSTAN` variable is directly related to `cmdstanpy` module and can be omitted if your CmdStan binaries are in your `$PATH`.
It is also possible to install Prophet with two backends:
```bash
# bash
$ CMDSTAN=/tmp/cmdstan-2.22.1 STAN_BACKEND=PYSTAN,CMDSTANPY pip install prophet
```
After installation, you can [get started!](https://facebook.github.io/prophet/docs/quick_start.html#python-api)
If you upgraded the version of PyStan installed on your system, you may need to reinstall prophet ([see here](https://github.com/facebook/prophet/issues/324)).

View file

@ -73,12 +73,8 @@ prophet_plot_components(m, forecast)
# Python
fig = m.plot_components(forecast)
```
![png](/prophet/static/uncertainty_intervals_files/uncertainty_intervals_11_0.png)
![png](/prophet/static/uncertainty_intervals_files/uncertainty_intervals_11_0.png)
You can access the raw posterior predictive samples in Python using the method `m.predictive_samples(future)`, or in R using the function `predictive_samples(m, future)`.
There are upstream issues in PyStan for Windows which make MCMC sampling extremely slow. The best choice for MCMC sampling in Windows is to use R, or Python in a Linux VM.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -227,70 +227,9 @@ class CmdStanPyBackend(IStanBackend):
return output
class PyStanBackend(IStanBackend):
@staticmethod
def get_type():
return StanBackendEnum.PYSTAN.name
def sampling(self, stan_init, stan_data, samples, **kwargs) -> dict:
args = dict(
data=stan_data,
init=lambda: stan_init,
iter=samples,
)
args.update(kwargs)
self.stan_fit = self.model.sampling(**args)
out = {}
for par in self.stan_fit.model_pars:
out[par] = self.stan_fit[par]
# Shape vector parameters
if par in ['delta', 'beta'] and len(out[par].shape) < 2:
out[par] = out[par].reshape((-1, 1))
return out
def fit(self, stan_init, stan_data, **kwargs) -> dict:
args = dict(
data=stan_data,
init=lambda: stan_init,
algorithm='Newton' if stan_data['T'] < 100 else 'LBFGS',
iter=1e4,
)
args.update(kwargs)
try:
self.stan_fit = self.model.optimizing(**args)
except RuntimeError as e:
# Fall back on Newton
if self.newton_fallback and args['algorithm'] != 'Newton':
logger.warning(
'Optimization terminated abnormally. Falling back to Newton.'
)
args['algorithm'] = 'Newton'
self.stan_fit = self.model.optimizing(**args)
else:
raise e
params = {}
for par in self.stan_fit.keys():
params[par] = self.stan_fit[par].reshape((1, -1))
return params
def load_model(self):
"""Load compiled Stan model"""
model_file = pkg_resources.resource_filename(
'prophet',
'stan_model/prophet_model.pkl',
)
with Path(model_file).open('rb') as f:
return pickle.load(f)
class StanBackendEnum(Enum):
PYSTAN = PyStanBackend
CMDSTANPY = CmdStanPyBackend
@staticmethod

View file

@ -1,6 +1,5 @@
Cython>=0.22
cmdstanpy>=1.0.0
pystan~=2.19.1.1
cmdstanpy>=1.0.1
numpy>=1.15.4
pandas>=1.0.4
matplotlib>=2.0.0

View file

@ -118,34 +118,17 @@ def build_cmdstan_model(target_dir):
prune_cmdstan(cmdstan_dir)
def build_pystan_model(target_dir):
"""
Compile the stan model using pystan and pickle it. The pickle is copied to {target_dir}/prophet_model.pkl.
"""
import pystan
import pickle
model_name = "prophet.stan"
target_name = "prophet_model.pkl"
with open(os.path.join(MODEL_DIR, model_name)) as f:
model_code = f.read()
sm = pystan.StanModel(model_code=model_code)
with open(os.path.join(target_dir, target_name), "wb") as f:
pickle.dump(sm, f, protocol=pickle.HIGHEST_PROTOCOL)
def get_backends_from_env() -> List[str]:
return os.environ.get("STAN_BACKEND", "CMDSTANPY").split(",")
def build_models(target_dir):
for backend in get_backends_from_env():
print(f"Compiling {backend} model")
if backend == "CMDSTANPY":
build_cmdstan_model(target_dir)
elif backend == "PYSTAN" and PLATFORM != "win":
build_pystan_model(target_dir)
print(f"Compiling cmdstanpy model")
build_cmdstan_model(target_dir)
if 'PYSTAN' in get_backends_from_env():
raise ValueError("PyStan backend is not supported for Prophet >= 1.1")
class BuildPyCommand(build_py):
"""Custom build command to pre-compile Stan models."""