cloudpipe / cloudpipe/cloudpickle
gpytorch models can be pickled by dill but not by cloudpickle
- Dominant language
- Python
- Stars
- 1.9k
- Forks
- 195
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 1
Description
Cloudpickle is failing at dumping [gpytorch](https://github.com/cornellius-gp/gpytorch) models. However they can be dumped with dill.
The following reproducible example
```python
import math
import torch
import gpytorch
import cloudpickle
train_x = torch.linspace(0, 1, 100)
train_y = torch.sin(train_x * (2 * math.pi)) + \
torch.randn(train_x.size()) * math.sqrt(0.04)
class ExactGPModel(gpytorch.models.ExactGP):
def __init__(self, train_x, train_y, likelihood):
super(ExactGPModel, self).__init__(train_x, train_y, likelihood)
self.mean_module = gpytorch.means.ConstantMean()
self.covar_module = gpytorch.kernels.ScaleKernel(
gpytorch.kernels.RBFKernel())
def forward(self, x):
mean_x = self.mean_module(x)
covar_x = self.covar_module(x)
return gpytorch.distributions.MultivariateNormal(mean_x, covar_x)
# initialize likelihood and model
likelihood = gpytorch.likelihoods.GaussianLikelihood()
model = ExactGPModel(train_x, train_y, likelihood)
cloudpickle.dumps(model)
```
returns the following error
```python-tb
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\site-packages\torch\storage.py:34: FutureWarning: pickle support for Storage will be removed in 1.5. Use `torch.save` instead
warnings.warn("pickle support for Storage will be removed in 1.5. Use `torch.save` instead", FutureWarning)
---------------------------------------------------------------------------
PicklingError Traceback (most recent call last)
in
----> 1 pickled = cloudpickle.dumps(model)
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\site-packages\cloudpickle\cloudpickle.py in dumps(obj, protocol)
1081 try:
1082 cp = CloudPickler(file, protocol=protocol)
-> 1083 cp.dump(obj)
1084 return file.getvalue()
1085 finally:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\site-packages\cloudpickle\cloudpickle.py in dump(self, obj)
475 self.inject_addons()
476 try:
--> 477 return Pickler.dump(self, obj)
478 except RuntimeError as e:
479 if 'recursion' in e.args[0]:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in dump(self, obj)
435 if self.proto >= 4:
436 self.framer.start_framing()
--> 437 self.save(obj)
438 self.write(STOP)
439 self.framer.end_framing()
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
547
548 # Save the reduce() output and finally memoize the object
--> 549 self.save_reduce(obj=obj, *rv)
550
551 def persistent_id(self, obj):
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_reduce(self, func, args, state, listitems, dictitems, obj)
660
661 if state is not None:
--> 662 save(state)
663 write(BUILD)
664
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
502 f = self.dispatch.get(t)
503 if f is not None:
--> 504 f(self, obj) # Call unbound method with explicit self
505 return
506
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_dict(self, obj)
854
855 self.memoize(obj)
--> 856 self._batch_setitems(obj.items())
857
858 dispatch[dict] = save_dict
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in _batch_setitems(self, items)
880 for k, v in tmp:
881 save(k)
--> 882 save(v)
883 write(SETITEMS)
884 elif n:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
547
548 # Save the reduce() output and finally memoize the object
--> 549 self.save_reduce(obj=obj, *rv)
550
551 def persistent_id(self, obj):
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_reduce(self, func, args, state, listitems, dictitems, obj)
657
658 if dictitems is not None:
--> 659 self._batch_setitems(dictitems)
660
661 if state is not None:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in _batch_setitems(self, items)
880 for k, v in tmp:
881 save(k)
--> 882 save(v)
883 write(SETITEMS)
884 elif n:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
547
548 # Save the reduce() output and finally memoize the object
--> 549 self.save_reduce(obj=obj, *rv)
550
551 def persistent_id(self, obj):
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_reduce(self, func, args, state, listitems, dictitems, obj)
660
661 if state is not None:
--> 662 save(state)
663 write(BUILD)
664
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
502 f = self.dispatch.get(t)
503 if f is not None:
--> 504 f(self, obj) # Call unbound method with explicit self
505 return
506
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_dict(self, obj)
854
855 self.memoize(obj)
--> 856 self._batch_setitems(obj.items())
857
858 dispatch[dict] = save_dict
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in _batch_setitems(self, items)
880 for k, v in tmp:
881 save(k)
--> 882 save(v)
883 write(SETITEMS)
884 elif n:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
547
548 # Save the reduce() output and finally memoize the object
--> 549 self.save_reduce(obj=obj, *rv)
550
551 def persistent_id(self, obj):
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_reduce(self, func, args, state, listitems, dictitems, obj)
657
658 if dictitems is not None:
--> 659 self._batch_setitems(dictitems)
660
661 if state is not None:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in _batch_setitems(self, items)
885 k, v = tmp[0]
886 save(k)
--> 887 save(v)
888 write(SETITEM)
889 # else tmp is empty, and we're done
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
547
548 # Save the reduce() output and finally memoize the object
--> 549 self.save_reduce(obj=obj, *rv)
550
551 def persistent_id(self, obj):
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_reduce(self, func, args, state, listitems, dictitems, obj)
660
661 if state is not None:
--> 662 save(state)
663 write(BUILD)
664
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
502 f = self.dispatch.get(t)
503 if f is not None:
--> 504 f(self, obj) # Call unbound method with explicit self
505 return
506
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_dict(self, obj)
854
855 self.memoize(obj)
--> 856 self._batch_setitems(obj.items())
857
858 dispatch[dict] = save_dict
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in _batch_setitems(self, items)
880 for k, v in tmp:
881 save(k)
--> 882 save(v)
883 write(SETITEMS)
884 elif n:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
547
548 # Save the reduce() output and finally memoize the object
--> 549 self.save_reduce(obj=obj, *rv)
550
551 def persistent_id(self, obj):
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_reduce(self, func, args, state, listitems, dictitems, obj)
657
658 if dictitems is not None:
--> 659 self._batch_setitems(dictitems)
660
661 if state is not None:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in _batch_setitems(self, items)
885 k, v = tmp[0]
886 save(k)
--> 887 save(v)
888 write(SETITEM)
889 # else tmp is empty, and we're done
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
547
548 # Save the reduce() output and finally memoize the object
--> 549 self.save_reduce(obj=obj, *rv)
550
551 def persistent_id(self, obj):
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_reduce(self, func, args, state, listitems, dictitems, obj)
660
661 if state is not None:
--> 662 save(state)
663 write(BUILD)
664
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
502 f = self.dispatch.get(t)
503 if f is not None:
--> 504 f(self, obj) # Call unbound method with explicit self
505 return
506
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_dict(self, obj)
854
855 self.memoize(obj)
--> 856 self._batch_setitems(obj.items())
857
858 dispatch[dict] = save_dict
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in _batch_setitems(self, items)
880 for k, v in tmp:
881 save(k)
--> 882 save(v)
883 write(SETITEMS)
884 elif n:
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save(self, obj, save_persistent_id)
533 # Check for string returned by reduce(), meaning "save as global"
534 if isinstance(rv, str):
--> 535 self.save_global(obj, rv)
536 return
537
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\site-packages\cloudpickle\cloudpickle.py in save_global(self, obj, name, pack)
840 self._save_parametrized_type_hint(obj)
841 elif name is not None:
--> 842 Pickler.save_global(self, obj, name=name)
843 elif not _is_importable_by_name(obj, name=name):
844 self.save_dynamic_class(obj)
~\AppData\Local\Continuum\anaconda3\envs\gp_env\lib\pickle.py in save_global(self, obj, name)
955 raise PicklingError(
956 "Can't pickle %r: it's not found as %s.%s" %
--> 957 (obj, module_name, name)) from None
958 else:
959 if obj2 is not obj:
PicklingError: Can't pickle : it's not found as torch._C._nn.softplus
```
Using `pickle` returns the same `PicklingError`. But replacing `cloudpickle.dumps(model)` by `dill.dumps(model)` works. I was thus able to use `export LOKY_PICKLER=dill` to make my parallelization work with joblib but thought that I could report this in case this could also be pickled by a fix in cloudpickle.
I am using python 3.7.3, `cloudpickle` 1.4.1, `torch` 1.5.0, `gpytorch` 1.1.1.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.