You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
TypeError: can't pickle Environment objects when num_workers > 0 for LSUN #689
The program fails to create an iterator for a DataLoader object when the used dataset is LSUN and the amount of workers is greater than zero. I do not have such an error when work with other datasets. Something tells me that the issue might be caused by lmdb. I run on Windows 10, CUDA 10.
This seems to be a Windows-specific issue.
But note that even if we address this particular issue (I have no idea how to do it though), you would probably hit another issue further on, which is #619
this issue also appear in linux, the reason is the opened lmdb env can not be pickled
Reacted by Haochen, Soheil, Umar Iqbal, xxxyyycc, meadow163, Rakshit Kothari, Asmita Khaneja, xiaotown123, Diego Francisco Valenzuela Iturra, Keuntaek Lee and 7 more
I think this is a limitation of LMDB in python (and LSUN which uses LMDB internally), and I think there is not much we can do on torchvision side unfortunately.
When set to fork it works fine, but when using spawn it seems to try to pickle the dataset object which has the self.env attribute which is a lmdb Environment.
Just use it and discard the reference in the init then instantiate it again in the getitem and save the reference in the class.
A possible solution is similar to the one for HDF5:
Do not open lmdb inside __init__
Open the lmdb at the first data iteration.
Here is an illustration:
classDataLoader(torch.utils.data.Dataset):
def__init__(self):
"""do not open lmdb here!!"""defopen_lmdb(self):
self.env=lmdb.open(self.lmdb_dir, readonly=True, create=False)
self.txn=self.env.begin(buffers=True)
def__getitem__(self, item: int):
ifnothasattr(self, 'txn'):
self.open_lmdb()
""" Then do anything you want with env/txn here. """
Reacted by Neill Byrne, Big-Brother-Pikachu, zhujian, Shuai Zhao, Christian Lillelund, Yongqing Liang, Kumara Kahatapitiya, Shen Chen(陈燊), CuthbertCai, Igor Terekhin and 32 more
Reacted by Neill Byrne, suzyahyah, Richie Goulazian, sarveshamberkarC, Bao, Rui Sun, USTC-JialunPeng, Ugur Gudelek, Ramith Hettiarachchi, singmal and 1 more
Reacted by Neill Byrne, Richie Goulazian, sarveshamberkarC, Bao, Rui Sun, Wangbo Yu, USTC-JialunPeng, Ramith Hettiarachchi, singmal and Daniel Vince
A possible solution is similar to the one for HDF5:
Do not open lmdb inside __init__
Open the lmdb at the first data iteration.
Here is an illustration:
classDataLoader(torch.utils.data.Dataset):
def__init__(self):
"""do not open lmdb here!!"""defopen_lmdb(self):
self.env=lmdb.open(self.lmdb_dir, readonly=True, create=False)
self.txn=self.env.begin(buffers=True)
def__getitem__(self, item: int):
ifnothasattr(self, 'txn'):
self.open_lmdb()
""" Then do anything you want with env/txn here. """
This solution works fine, however I'm struggling to find a way to set the self.size property on the Dataset without loading it in the __init__ function beforehand. I cannot instantiate the torch.utils.data.DataLoader without making sure that __len__ returns a valid value. Right now I save the number of samples in a meta data file and load that manually, but is there a smarter way to do this?
@thecml you can open an LMDB environment in __init__ just be sure to close it within __init__. So open it, assign a size variable which is called by __len__ and the close it
@thecml you can open an LMDB environment in __init__ just be sure to close it within __init__. So open it, assign a size variable which is called by __len__ and the close it
Activity
fmassa commentedon Dec 17, 2018
This seems to be a Windows-specific issue.
But note that even if we address this particular issue (I have no idea how to do it though), you would probably hit another issue further on, which is #619
Santiago810 commentedon Feb 6, 2020
this issue also appear in linux, the reason is the opened lmdb env can not be pickled
IsaacBerman commentedon Feb 11, 2020
@Santiago810 Do you know how to diagnose the issue of an un-pickleable lmdb env?
gebrahimi91 commentedon Feb 13, 2020
I have the same issue with dataloader when I do not use lmdb dataset.
fmassa commentedon Feb 14, 2020
I think this is a limitation of LMDB in python (and LSUN which uses LMDB internally), and I think there is not much we can do on torchvision side unfortunately.
4knahs commentedon Apr 29, 2020
I implemented my own LMDB dataset and had the same issue when using LMDB with num_workers > 0 and torch multiprocessing set to spawn.
It is very similar to this project's LSUN implementation, in my case the issue was with this line:
https://github.com/pytorch/vision/blob/master/torchvision/datasets/lsun.py#L18
When set to fork it works fine, but when using spawn it seems to try to pickle the dataset object which has the self.env attribute which is a lmdb Environment.
Just use it and discard the reference in the init then instantiate it again in the getitem and save the reference in the class.
fmassa commentedon May 4, 2020
@4knahs if you think you could send a PR fixing the LSUN implementation it would be great!
ruotianluo commentedon Jul 4, 2020
I saw a solution somewhere else by adding getstate and setstate.
This also doens't save self.env but instead of saving the txn.
Santiago810 commentedon Aug 4, 2020
Solution: open lmdb in worker_init_fn of torch.utils.data.DataLoader
RSKothari commentedon Sep 15, 2020
Could you elaborate or give an example @Santiago810 ?
airsplay commentedon Feb 28, 2021
A possible solution is similar to the one for HDF5:
__init__Here is an illustration:
Explanation
The multi-processing actually happens when you create the data iterator (e.g., when calling
for datum in dataloader:):https://github.com/pytorch/pytorch/blob/461014d54b3981c8fa6617f90ff7b7df51ab1e85/torch/utils/data/dataloader.py#L712-L720
In short, it would create multiple processes which "copy" the state of the current process. This copy involves a pickle of the LMDB's Env thus causes an issue. In our solution, we open it at the first data iteration and the opened lmdb file object would be dedicated to each subprocess.
neillbyrne commentedon Mar 2, 2021
Thank you @airsplay . Excellent solution. You just saved me about a months work !!!
thecml commentedon May 27, 2021
Hi airsplay,
This solution works fine, however I'm struggling to find a way to set the self.size property on the Dataset without loading it in the
__init__function beforehand. I cannot instantiate the torch.utils.data.DataLoader without making sure that__len__returns a valid value. Right now I save the number of samples in a meta data file and load that manually, but is there a smarter way to do this?neillbyrne commentedon May 27, 2021
@thecml you can open an LMDB environment in
__init__just be sure to close it within__init__. So open it, assign a size variable which is called by__len__and the close itthecml commentedon May 28, 2021
Excellent, thanks!