Hi Torchtext,
It would be great to have a story for saving datasets. Things are currently not in a great place, and I would like to know where it might head.
1) Things are not serializable. In opennmt-py, we are hacking around this issue by serializing Dataset/Field objects. This doesn't really work out of the box because of the usage of defaultdict. However we can get around that issue by monkeypatching the __getstate__ of Vocab. Maybe this could be built in.
2) Datasets take a ton of memory. I like that datasets are so clean, but their internal storage is not cheap, storing the field names as strings along with all of the string data itself. It's cute that conversion/batching happens on the fly, but it might be nice to be able to turn that off, i.e. convert to tensors if you want.
3) It requires loading everything into memory. Dataset objects are currently monolithic. They assume that the universe stored directly in them. Ideally, datasets may require being stored on disc as shards. It would be great if the loading and usages of these shards could invisible to the user.
Thanks guys. As always great work. Cheers!
Sasha
We'd absolutely appreciate a PR for 1 -- currently I've been serializing Datasets by storing their examples attribute and then rebuilding using the default Dataset constructor.
For 2, do you mean that you would want to be able to serialize several epochs' worth of prebuilt batches (i.e., the output of an Iterator)? Or a tensor version of a Dataset that hasn't been batched at all?
Also I don't know much about sharding or disk-based formats; our only existing support for datasets that can't fit in memory is that you can define a Dataset that is based around a Python generator and whose examples attribute is never actually instantiated as a list (the generator could do things like lazily load from disk but I'm not sure if anyone's actually done this).
Hmm. My concern is that many NLP datasets are just too large to be kept in memory at all times. Particularly since python representations of dicts and string are large memory-wise. I don't feel like torchtext acknowledges this. We can hack our own thing, but I would prefer for the design of the library to reflect the following use case:
1) Stream data to construct fields.
2) Write data to disk in some compressed form.
3) Stream data out again to convert to batches.
This is something that needs to be fixed and Sasha's last comment is pretty good.
Since this is tagged as help wanted, I want to jump-in:
Haha nice. I haven't thought about this too much, but I guess, ideally the whole thing would be some sort of buffered streaming.
1) Preprocessing: Stream through the files (maybe with multprocessing), create fields and dictionaries, save to disk.
2) Train: At training time, shuffle file, stream through text data, and create batches on the fly.
The downside is (a) you might not be able to fully group mini-batches by length, (b) you might not know exactly how many batches are remaining. Maybe you can do some lookahead buffering so that you can find roughly length sentences.
@srush @soumith any progress on this? I can help out or start a basic implementation to give some push to the idea.
I haven't had a chance to work on this. We did hack around it in OpenNMT-py, by implementing our own sharding.
Ok, I'll start working on this along the guidelines you suggested a couple replies ago. I've checked out the OpenNMT-py implementation as a pointer, thanks!
This seems to be a sizeable chunk of work -- so shouldn't expect anything too fast.
Not sure if this relevant but MxNet has a nice binarization method for large data: https://mxnet.incubator.apache.org/faq/recordio.html The problem is that it is C/C++ but it might be helpful to convert it into python (?)
Hmm, I'm not sure we need to go that far, I'm okay with serializing python objects, but they just can't all be in memory at once.
However, it is true that python objects take a ton of disk space. Text data gets 10x larger.
Coming back to this with a general idea of a workflow and some issues:
Workflow:
Issues:
I'll get an alpha PR running in about two weeks time, and I'd appreciate some feedback (esp. with regard to efficient block storage)
Actually, I don't think you need to be this complicated. Block storage is hard, and doesn't buy us that much. The following would solve most of use cases and be more easily debugged:
1.2. exactly as you say.
Skip second pass entirely.
Train time. Load data by reading from text files. However, never construct all the examples in memory. Simply buffer enough examples from a file to construct reasonably sized batches. (This should be user controllable. Note this buffering line is bad: magic number 100):
https://github.com/pytorch/text/blob/master/torchtext/data/iterator.py#L271
The main contribution is that datasets should be inherently lazy. It should be easy to make one, but it shouldn't default to loading everything in. When you call build_vocab it should go line by line. When you make an iterator it should automatically buffer enough examples for tight batching. Currently both these operations take up a ton of memory.
Ok, that will speed things up.
I plan to simply add StreamingDataset / StreamingField classes which would essentially build everything required online. Thanks!
Any progress here?
Yeah, although I got sidetracked a bit since Repl4NLP got extended. Will get something up soon.
Is someone actively working on this still??
@abhinavkashyap92 yep, you can check out the current status here: #282
Most helpful comment
Hmm. My concern is that many NLP datasets are just too large to be kept in memory at all times. Particularly since python representations of dicts and string are large memory-wise. I don't feel like torchtext acknowledges this. We can hack our own thing, but I would prefer for the design of the library to reflect the following use case:
1) Stream data to construct fields.
2) Write data to disk in some compressed form.
3) Stream data out again to convert to batches.