facebook / prophet

Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth.

Home Page:https://facebook.github.io/prophet

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error pickling Prophet objects in Python 3.6.

arnaudvl opened this issue · comments

Attempting to pickle a Prophet object in Python 3.6 (3.6.10 to be precise) results in the following error:

TypeError: can't pickle _thread.RLock objects

Snippet to reproduce the error:

from fbprophet import Prophet
import pickle

with open('test.pickle', 'wb') as f:
   pickle.dump(Prophet(), f)

Trying to save with dill also does not help. The error does not occur in Python 3.7.

I'm seeing the same behavior

  • Centos 7
yum install centos-release-scl
yum-config-manager --enable rhel-server-rhscl-7-rpms
yum install devtoolset-7
scl enable devtoolset-7 bash
  • Python 3.6.9
  • gcc version 4.8.5
  • pystan-2.19.1.1
  • fbprophet-0.6
>>> import pickle
>>> with open("foo.pkl", "wb") as f:
...     pickle.dump(m, f)
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: can't pickle _thread.RLock objects`

I was able to reproduce this. It happens in fbprophet==0.6 but not fbprophet==0.5. v0.6 changed the Stan interface to enable using cmdstanpy, and this refactoring seems to be the source of the issue. There is now a class PyStanBackend:

class PyStanBackend(IStanBackend):

an instance of which is attached to the Prophet object:
self.stan_backend = StanBackendEnum.get_backend_class(stan_backend)(logger)

That is the object that cannot be pickled:

import logging
from fbprophet.models import PyStanBackend

logger = logging.getLogger('fbprophet')
b = PyStanBackend(logger=logger)

with open('test.pickle', 'wb') as f:
   pickle.dump(b, f)  # FAILS with error

The issue is that the stan backends are storing the logger as an attribute:

self.logger = logger

and you can't pickle loggers. So this works to pickle the backend.

b.logger = None
with open('test.pickle', 'wb') as f:
   pickle.dump(b, f)  # WORKS

Workaround:
Wipe the stan backend logger object prior to pickling.

m = Prophet()
m.stan_backend.logger = None

with open('test.pickle', 'wb') as f:
   pickle.dump(m, f)

(Or, of course, upgrading to Py 3.7 is a workaround, for those for whom this is possible).

The fix:
I can't think of any reason why the logger would need to be stored on the backend, so we can just remove that and instead use a logger defined in that file, something like fbprophet.models as is done for plotting here:

logger = logging.getLogger('fbprophet.plot')

Built-in json serialization is now pushed out in v0.7 and should be used instead of pickle as described here: https://facebook.github.io/prophet/docs/additional_topics.html#saving-models