Title: Load text file for RoBERTa pre-training. 
Author: chiyuzhang94 (NONE)
State: closed
Created: 2020-09-10T18:41:38Z

I migrate my question from https://github.com/huggingface/transformers/pull/4009#issuecomment-690039444

I tried to train a Roberta from scratch using transformers. But I got OOM issues with loading a large text file. 
According to the suggestion from @thomwolf , I tried to implement `datasets` to load my text file. This test.txt is a simple sample where each line is a sentence.
```
from datasets import load_dataset
dataset = load_dataset('text', data_files='test.txt',cache_dir="./")
dataset.set_format(type='torch',columns=["text"])
dataloader = torch.utils.data.DataLoader(dataset, batch_size=8)
next(iter(dataloader))
```

But dataload cannot yield sample and error is:
```
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-12-388aca337e2f> in <module>
----> 1 next(iter(dataloader))

/Library/Python/3.7/site-packages/torch/utils/data/dataloader.py in __next__(self)
    361 
    362     def __next__(self):
--> 363         data = self._next_data()
    364         self._num_yielded += 1
    365         if self._dataset_kind == _DatasetKind.Iterable and \

/Library/Python/3.7/site-packages/torch/utils/data/dataloader.py in _next_data(self)
    401     def _next_data(self):
    402         index = self._next_index()  # may raise StopIteration
--> 403         data = self._dataset_fetcher.fetch(index)  # may raise StopIteration
    404         if self._pin_memory:
    405             data = _utils.pin_memory.pin_memory(data)

/Library/Python/3.7/site-packages/torch/utils/data/_utils/fetch.py in fetch(self, possibly_batched_index)
     42     def fetch(self, possibly_batched_index):
     43         if self.auto_collation:
---> 44             data = [self.dataset[idx] for idx in possibly_batched_index]
     45         else:
     46             data = self.dataset[possibly_batched_index]

/Library/Python/3.7/site-packages/torch/utils/data/_utils/fetch.py in <listcomp>(.0)
     42     def fetch(self, possibly_batched_index):
     43         if self.auto_collation:
---> 44             data = [self.dataset[idx] for idx in possibly_batched_index]
     45         else:
     46             data = self.dataset[possibly_batched_index]

KeyError: 0
```

`dataset.set_format(type='torch',columns=["text"])` returns a log says:
```
Set __getitem__(key) output type to torch for ['text'] columns (when key is int or slice) and don't output other (un-formatted) columns.
```

I noticed the dataset is `DatasetDict({'train': Dataset(features: {'text': Value(dtype='string', id=None)}, num_rows: 44)})`.
Each sample can be accessed by `dataset["train"]["text"]` instead of `dataset["text"]`. 

Could you please give me any suggestions on how to modify this code to load the text file?

Versions:
Python version 3.7.3
PyTorch version 1.6.0 
TensorFlow version 2.3.0 
datasets version: 1.0.1

Comments:
Could you try
```python
load_dataset('text', data_files='test.txt',cache_dir="./", split="train")
```
?

`load_dataset` returns a dictionary by default, like {"train": your_dataset}

Hi @lhoestq
Thanks for your suggestion.

I tried 
```
dataset = load_dataset('text', data_files='test.txt',cache_dir="./", split="train")
print(dataset)
dataset.set_format(type='torch',columns=["text"])
dataloader = torch.utils.data.DataLoader(dataset, batch_size=8)
next(iter(dataloader))
```

But it still doesn't work and got error:
```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-388aca337e2f> in <module>
----> 1 next(iter(dataloader))

/Library/Python/3.7/site-packages/torch/utils/data/dataloader.py in __next__(self)
    361 
    362     def __next__(self):
--> 363         data = self._next_data()
    364         self._num_yielded += 1
    365         if self._dataset_kind == _DatasetKind.Iterable and \

/Library/Python/3.7/site-packages/torch/utils/data/dataloader.py in _next_data(self)
    401     def _next_data(self):
    402         index = self._next_index()  # may raise StopIteration
--> 403         data = self._dataset_fetcher.fetch(index)  # may raise StopIteration
    404         if self._pin_memory:
    405             data = _utils.pin_memory.pin_memory(data)

/Library/Python/3.7/site-packages/torch/utils/data/_utils/fetch.py in fetch(self, possibly_batched_index)
     42     def fetch(self, possibly_batched_index):
     43         if self.auto_collation:
---> 44             data = [self.dataset[idx] for idx in possibly_batched_index]
     45         else:
     46             data = self.dataset[possibly_batched_index]

/Library/Python/3.7/site-packages/torch/utils/data/_utils/fetch.py in <listcomp>(.0)
     42     def fetch(self, possibly_batched_index):
     43         if self.auto_collation:
---> 44             data = [self.dataset[idx] for idx in possibly_batched_index]
     45         else:
     46             data = self.dataset[possibly_batched_index]

/Library/Python/3.7/site-packages/datasets-0.4.0-py3.7.egg/datasets/arrow_dataset.py in __getitem__(self, key)
   1069             format_columns=self._format_columns,
   1070             output_all_columns=self._output_all_columns,
-> 1071             format_kwargs=self._format_kwargs,
   1072         )
   1073 

/Library/Python/3.7/site-packages/datasets-0.4.0-py3.7.egg/datasets/arrow_dataset.py in _getitem(self, key, format_type, format_columns, output_all_columns, format_kwargs)
   1056                 format_columns=format_columns,
   1057                 output_all_columns=output_all_columns,
-> 1058                 format_kwargs=format_kwargs,
   1059             )
   1060         return outputs

/Library/Python/3.7/site-packages/datasets-0.4.0-py3.7.egg/datasets/arrow_dataset.py in _convert_outputs(self, outputs, format_type, format_columns, output_all_columns, format_kwargs)
    872                     continue
    873                 if format_columns is None or k in format_columns:
--> 874                     v = map_nested(command, v, **map_nested_kwargs)
    875                 output_dict[k] = v
    876         return output_dict

/Library/Python/3.7/site-packages/datasets-0.4.0-py3.7.egg/datasets/utils/py_utils.py in map_nested(function, data_struct, dict_only, map_list, map_tuple, map_numpy, num_proc, types)
    214     # Singleton
    215     if not isinstance(data_struct, dict) and not isinstance(data_struct, types):
--> 216         return function(data_struct)
    217 
    218     disable_tqdm = bool(logger.getEffectiveLevel() > INFO)

/Library/Python/3.7/site-packages/datasets-0.4.0-py3.7.egg/datasets/arrow_dataset.py in command(x)
    833                     if x.dtype == np.object:  # pytorch tensors cannot be instantied from an array of objects
    834                         return [map_nested(command, i, **map_nested_kwargs) for i in x]
--> 835                 return torch.tensor(x, **format_kwargs)
    836 
    837         elif format_type == "tensorflow":

TypeError: new(): invalid data type 'str'
```

I found type can be ['numpy', 'torch', 'tensorflow', 'pandas'] only, how can I deal with the string type?

You need to tokenize the string inputs to convert them in integers before you can feed them to a pytorch dataloader.

You can read the quicktour of the datasets or the transformers libraries to know more about that:
- transformers: https://huggingface.co/transformers/quicktour.html
- dataset: https://huggingface.co/docs/datasets/quicktour.html

Hey @chiyuzhang94, I was also having trouble in loading a large text file (11GB).
But finally got it working. This is what I did after looking into the documentation.

1. split the whole dataset file into smaller files
```bash
mkdir ./shards
split -a 4 -l 256000 -d full_raw_corpus.txt ./shards/shard_
````
2. Pass paths of small data files to `load_dataset`
```python
files = glob.glob('shards/*')
from datasets import load_dataset
dataset = load_dataset('text', data_files=files, split='train')
```
(On passing the whole dataset file (11GB) directly to `load_dataset` was resulting into RAM issue)

3. Tokenization
```python
def encode(examples):
  return tokenizer(examples['text'], truncation=True, padding='max_length')
dataset = dataset.map(encode, batched=True)
dataset.set_format(type='torch', columns=['input_ids', 'attention_mask'])
```
 Now you can pass `dataset` to `Trainer` or `pytorch DataLoader`
```python
dataloader = torch.utils.data.DataLoader(dataset, batch_size=4)
next(iter(dataloader))
```
Hope this helps


Thanks, @thomwolf  and @sipah00 ,

I tried to implement your suggestions in my scripts. 
Now, I am facing some connection time-out error. I am using my local file, I have no idea why the module request s3 database.

The log is:
```
Traceback (most recent call last):
  File "/home/.local/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
    raise err
  File "/home/.local/lib/python3.6/site-packages/urllib3/util/connection.py", line 74, in create_connection
    timeout=timeout
  File "/home/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 720, in urlopen
    sock.connect(sa)
TimeoutError: [Errno 110] Connection timed out

Traceback (most recent call last):
  File "/home/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 672, in urlopen
    method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
  File "/home/.local/lib/python3.6/site-packages/urllib3/util/retry.py", line 436, in increment
    chunked=chunked,
  File "/home/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 376, in _make_request
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='s3.amazonaws.com', port=443): Max retries exceeded with url: /datasets.huggingface.co/datasets/datasets/text/text.py (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection obj
ect at 0x7fff401e0e48>: Failed to establish a new connection: [Errno 110] Connection timed out',))

Traceback (most recent call last):
  File "/scratch/roberta_emohash/run_language_modeling.py", line 1019, in <module>
    main()
  File "/scratch/roberta_emohash/run_language_modeling.py", line 962, in main
    train_dataset = load_and_cache_examples(args, tokenizer, evaluate=False)
  File "/scratch/roberta_emohash/run_language_modeling.py", line 177, in load_and_cache_examples
    return HG_Datasets(tokenizer, file_path, args)
  File "/scratch/roberta_emohash/run_language_modeling.py", line 117, in HG_Datasets
    dataset = load_dataset('text', data_files=files, cache_dir = args.data_cache_dir, split="train")
  File "/arc/project/evn_py36/datasets/datasets/src/datasets/load.py", line 590, in load_dataset
    self._validate_conn(conn)
  File "/home/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 994, in _validate_conn
    conn.connect()
  File "/home/.local/lib/python3.6/site-packages/urllib3/connection.py", line 300, in connect
    conn = self._new_conn()
  File "/home/.local/lib/python3.6/site-packages/urllib3/connection.py", line 169, in _new_conn
    self, "Failed to establish a new connection: %s" % e
urllib3.exceptions.NewConnectionError: <urllib3.connection.VerifiedHTTPSConnection object at 0x7fff401e0da0>: Failed to establish a new connection: [Errno 110] Connection timed out

``` 

Do you have any experience on this issue?

No, I didn't encounter this problem, it seems to me a network problem

I noticed this is because I use a cloud server where does not provide for connections from our standard compute nodes to outside resources. 

For the `datasets` package, it seems that if the loading script is not already cached in the library it will attempt to connect to an AWS resource to download the dataset loading script. 

I am wondering why the package works in this way. Do you have any suggestions to solve this issue? 

I solved the above issue by downloading text.py manually and passing the path to the `load_dataset` function. 

Now, I have a new issue with the Read-only file system.

The error is: 
```
I0916 22:14:38.453380 140737353971520 filelock.py:274] Lock 140734268996072 acquired on /scratch/chiyuzh/roberta/text.py.lock
Found main folder for dataset /scratch/chiyuzh/roberta/text.py at /home/chiyuzh/.cache/huggingface/modules/datasets_modules/datasets/text
Creating specific version folder for dataset /scratch/chiyuzh/roberta/text.py at /home/chiyuzh/.cache/huggingface/modules/datasets_modules/datasets/text/512f465342e4f4cd07a8791428a629c043bb89d55ad7817cbf7fcc649178b014
I0916 22:14:38.530371 140737353971520 filelock.py:318] Lock 140734268996072 released on /scratch/chiyuzh/roberta/text.py.lock
Traceback (most recent call last):
  File "/scratch/chiyuzh/roberta/run_language_modeling_hg.py", line 1019, in <module>
    main()
  File "/scratch/chiyuzh/roberta/run_language_modeling_hg.py", line 962, in main
    train_dataset = load_and_cache_examples(args, tokenizer, evaluate=False)
  File "/scratch/chiyuzh/roberta/run_language_modeling_hg.py", line 177, in load_and_cache_examples
    return HG_Datasets(tokenizer, file_path, args)
  File "/scratch/chiyuzh/roberta/run_language_modeling_hg.py", line 117, in HG_Datasets
    dataset = load_dataset('/scratch/chiyuzh/roberta/text.py', data_files=files, cache_dir = args.data_cache_dir, split="train")
  File "/arc/project/chiyuzh/evn_py36/datasets/src/datasets/load.py", line 590, in load_dataset
    path, script_version=script_version, download_config=download_config, download_mode=download_mode, dataset=True
  File "/arc/project/chiyuzh/evn_py36/datasets/src/datasets/load.py", line 385, in prepare_module
    os.makedirs(hash_folder_path)
  File "/project/chiyuzh/evn_py36/lib/python3.6/os.py", line 220, in makedirs
    mkdir(name, mode)
OSError: [Errno 30] Read-only file system: '/home/chiyuzh/.cache/huggingface/modules/datasets_modules/datasets/text/512f465342e4f4cd07a8791428a629c043bb89d55ad7817cbf7fcc649178b014'

```

I installed datasets at /project/chiyuzh/evn_py36/datasets/src where is a writable directory.
I also tried change the environment variables to the writable directory:
`export HF_MODULES_PATH=/project/chiyuzh/evn_py36/datasets/cache_dir/`
`export HF_DATASETS_CACHE=/project/chiyuzh/evn_py36/datasets/cache_dir/`
 
In my scripts, I also changed to:
`dataset = load_dataset('/scratch/chiyuzh/roberta/text.py', data_files=files, cache_dir = args.data_cache_dir, split="train")`
`data_cache_dir = $TMPDIR/data/` that also a writable directory.
 
But it still try to make directory at /home/chiyuzh/.cache/huggingface/modules/.
Do you have any idea about this issue? @thomwolf 


> Hey @chiyuzhang94, I was also having trouble in loading a large text file (11GB).
> But finally got it working. This is what I did after looking into the documentation.
> 
> 1. split the whole dataset file into smaller files
> 
> ```shell
> mkdir ./shards
> split -a 4 -l 256000 -d full_raw_corpus.txt ./shards/shard_
> ```
> 
> 1. Pass paths of small data files to `load_dataset`
> 
> ```python
> files = glob.glob('shards/*')
> from datasets import load_dataset
> dataset = load_dataset('text', data_files=files, split='train')
> ```
> 
> (On passing the whole dataset file (11GB) directly to `load_dataset` was resulting into RAM issue)
> 
> 1. Tokenization
> 
> ```python
> def encode(examples):
>   return tokenizer(examples['text'], truncation=True, padding='max_length')
> dataset = dataset.map(encode, batched=True)
> dataset.set_format(type='torch', columns=['input_ids', 'attention_mask'])
> ```
> 
> Now you can pass `dataset` to `Trainer` or `pytorch DataLoader`
> 
> ```python
> dataloader = torch.utils.data.DataLoader(dataset, batch_size=4)
> next(iter(dataloader))
> ```
> 
> Hope this helps

When I run 'dataset = dataset.map(encode, batched=True)',
I encountered a problem like this:

> Testing the mapped function outputs
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/anaconda3/envs/torch-xla-1.6/lib/python3.6/site-packages/datasets/dataset_dict.py", line 300, in map
    for k, dataset in self.items()
  File "/anaconda3/envs/torch-xla-1.6/lib/python3.6/site-packages/datasets/dataset_dict.py", line 300, in <dictcomp>
    for k, dataset in self.items()
  File "/anaconda3/envs/torch-xla-1.6/lib/python3.6/site-packages/datasets/arrow_dataset.py", line 1224, in map
    update_data = does_function_return_dict(test_inputs, test_indices)
  File "/anaconda3/envs/torch-xla-1.6/lib/python3.6/site-packages/datasets/arrow_dataset.py", line 1195, in does_function_return_dict
    function(*fn_args, indices, **fn_kwargs) if with_indices else function(*fn_args, **fn_kwargs)
  File "<stdin>", line 3, in encode
TypeError: __init__() takes 1 positional argument but 2 were given

> > Hey @chiyuzhang94, I was also having trouble in loading a large text file (11GB).
> > But finally got it working. This is what I did after looking into the documentation.
> > 
> > 1. split the whole dataset file into smaller files
> > 
> > ```shell
> > mkdir ./shards
> > split -a 4 -l 256000 -d full_raw_corpus.txt ./shards/shard_
> > ```
> > 
> > 
> > 
> > 1. Pass paths of small data files to `load_dataset`
> > 
> > ```python
> > files = glob.glob('shards/*')
> > from datasets import load_dataset
> > dataset = load_dataset('text', data_files=files, split='train')
> > ```
> > 
> > 
> > (On passing the whole dataset file (11GB) directly to `load_dataset` was resulting into RAM issue)
> > 
> > 1. Tokenization
> > 
> > ```python
> > def encode(examples):
> >   return tokenizer(examples['text'], truncation=True, padding='max_length')
> > dataset = dataset.map(encode, batched=True)
> > dataset.set_format(type='torch', columns=['input_ids', 'attention_mask'])
> > ```
> > 
> > 
> > Now you can pass `dataset` to `Trainer` or `pytorch DataLoader`
> > ```python
> > dataloader = torch.utils.data.DataLoader(dataset, batch_size=4)
> > next(iter(dataloader))
> > ```
> > 
> > 
> > Hope this helps
> 
> When I run 'dataset = dataset.map(encode, batched=True)',
> I encountered a problem like this:
> 
> > Testing the mapped function outputs
> > Traceback (most recent call last):
> > File "", line 1, in 
> > File "/anaconda3/envs/torch-xla-1.6/lib/python3.6/site-packages/datasets/dataset_dict.py", line 300, in map
> > for k, dataset in self.items()
> > File "/anaconda3/envs/torch-xla-1.6/lib/python3.6/site-packages/datasets/dataset_dict.py", line 300, in 
> > for k, dataset in self.items()
> > File "/anaconda3/envs/torch-xla-1.6/lib/python3.6/site-packages/datasets/arrow_dataset.py", line 1224, in map
> > update_data = does_function_return_dict(test_inputs, test_indices)
> > File "/anaconda3/envs/torch-xla-1.6/lib/python3.6/site-packages/datasets/arrow_dataset.py", line 1195, in does_function_return_dict
> > function(*fn_args, indices, **fn_kwargs) if with_indices else function(*fn_args, **fn_kwargs)
> > File "", line 3, in encode
> > TypeError: **init**() takes 1 positional argument but 2 were given

What is your encoder function?

> ```python
> def encode(examples):
>   return tokenizer(examples['text'], truncation=True, padding='max_length')
> ```

It is the same as suggested:

> def encode(examples):
  return tokenizer(examples['text'], truncation=True, padding='max_length')

> > ```python
> > def encode(examples):
> >   return tokenizer(examples['text'], truncation=True, padding='max_length')
> > ```
> 
> It is the same as suggested:
> 
> > def encode(examples):
> > return tokenizer(examples['text'], truncation=True, padding='max_length')

Do you use this function in a `class` object?  

init() takes 1 positional argument but 2 were given. I guess the additional argument is self?

> > > ```python
> > > def encode(examples):
> > >   return tokenizer(examples['text'], truncation=True, padding='max_length')
> > > ```
> > 
> > 
> > It is the same as suggested:
> > > def encode(examples):
> > > return tokenizer(examples['text'], truncation=True, padding='max_length')
> 
> Do you use this function in a `class` object?
> 
> init() takes 1 positional argument but 2 were given. I guess the additional argument is self?

Thanks for your reply.
Could you provide some simple example here?
Currently, I do not use this function in a class object. 
I think you are right and I was wondering how to construct this class.
I try to modify it based on transformers' LineByLineTextDataset. Am I correct?

> class LineByLineTextDataset(Dataset):
    """
    This will be superseded by a framework-agnostic approach
    soon.
    """

    def __init__(self, tokenizer: PreTrainedTokenizer, file_path: str, block_size: int):
        assert os.path.isfile(file_path), f"Input file path {file_path} not found"
        # Here, we do not cache the features, operating under the assumption
        # that we will soon use fast multithreaded tokenizers from the
        # `tokenizers` repo everywhere =)
        #logger.info("Creating features from dataset file at %s", file_path)
        #with open(file_path, encoding="utf-8") as f:
        #    lines = [line for line in f.read().splitlines() if (len(line) > 0 and not line.isspace())]
        #batch_encoding = tokenizer(lines, add_special_tokens=True, truncation=True, max_length=block_size)

	import glob
	files = glob.glob('/home/mtzhang111/fairseq/cs_doc/shards/shard_003*')
	from datasets import load_dataset
	dataset = load_dataset('text', data_files=files)
        batch_encoding= dataset.map(encode, batched=True)
        self.examples = batch_encoding["input_ids"]
	

    def encode(examples):
        return tokenizer(examples['text'], truncation=True, padding='max_length')

    def __len__(self):
        return len(self.examples)

    def __getitem__(self, i) -> torch.Tensor:
        return torch.tensor(self.examples[i], dtype=torch.long)


> > > > ```python
> > > > def encode(examples):
> > > >   return tokenizer(examples['text'], truncation=True, padding='max_length')
> > > > ```
> > > 
> > > 
> > > It is the same as suggested:
> > > > def encode(examples):
> > > > return tokenizer(examples['text'], truncation=True, padding='max_length')
> > 
> > 
> > Do you use this function in a `class` object?
> > init() takes 1 positional argument but 2 were given. I guess the additional argument is self?
> 
> Thanks for your reply.
> Could you provide some simple example here?
> Currently, I do not use this function in a class object.
> I think you are right and I was wondering how to construct this class.
> I try to modify it based on transformers' LineByLineTextDataset. Am I correct?
> 
> > class LineByLineTextDataset(Dataset):
> > """
> > This will be superseded by a framework-agnostic approach
> > soon.
> > """
> 
> ```
> def __init__(self, tokenizer: PreTrainedTokenizer, file_path: str, block_size: int):
>     assert os.path.isfile(file_path), f"Input file path {file_path} not found"
>     # Here, we do not cache the features, operating under the assumption
>     # that we will soon use fast multithreaded tokenizers from the
>     # `tokenizers` repo everywhere =)
>     #logger.info("Creating features from dataset file at %s", file_path)
>     #with open(file_path, encoding="utf-8") as f:
>     #    lines = [line for line in f.read().splitlines() if (len(line) > 0 and not line.isspace())]
>     #batch_encoding = tokenizer(lines, add_special_tokens=True, truncation=True, max_length=block_size)
> 
> import glob
> files = glob.glob('/home/mtzhang111/fairseq/cs_doc/shards/shard_003*')
> from datasets import load_dataset
> dataset = load_dataset('text', data_files=files)
>     batch_encoding= dataset.map(encode, batched=True)
>     self.examples = batch_encoding["input_ids"]
> 
> 
> def encode(examples):
>     return tokenizer(examples['text'], truncation=True, padding='max_length')
> 
> def __len__(self):
>     return len(self.examples)
> 
> def __getitem__(self, i) -> torch.Tensor:
>     return torch.tensor(self.examples[i], dtype=torch.long)
> ```

I am also struggling with this adaptation. 
I am not sure whether I am right.

I think you don't need to construct `class LazyLineByLineTextDataset(Dataset)` at all. 
torch.utils.data.Dataset is a generator. 

Now, we use `dataset = dataset.map(encode, batched=True)` as a generator. So we just pass dataset to torch.utils.data.DataLoader. 

@chiyuzhang94 Thanks for your reply. After some changes, currently, I managed to make the data loading process running.
I published it in case you might want to take a look. Thanks for your help!
https://github.com/shizhediao/Transformers_TPU

Hi @shizhediao ,

Thanks! It looks great!

But my problem still is the cache directory is a read-only file system. 
[As I mentioned](https://github.com/huggingface/datasets/issues/610#issuecomment-693912285), I tried to change the cache directory but it didn't work. 

Do you have any suggestions?



> I installed datasets at /project/chiyuzh/evn_py36/datasets/src where is a writable directory.
> I also tried change the environment variables to the writable directory:
> `export HF_MODULES_PATH=/project/chiyuzh/evn_py36/datasets/cache_dir/`

I think it is `HF_MODULES_CACHE` and not `HF_MODULES_PATH` @chiyuzhang94 .
Could you try again and let me know if it fixes your issue ?


We should probably add a section in the doc on the caching system with the env variables in particular.

Hi @thomwolf , @lhoestq ,

Thanks for your suggestions. With the latest version of this package, I can load text data without Internet. 

But I found the speed of dataset loading is very slow. 

My scrips like this: 
```
    def token_encode(examples):
        tokenizer_out = tokenizer(examples['text'], truncation=True,  padding="max_length", add_special_tokens=True, max_length=args.block_size)
        return tokenizer_out
    
    path = Path(file_path)
    files = sorted(path.glob('*'))
    dataset = load_dataset('./text.py', data_files=files, cache_dir = args.data_cache_dir, split="train")
    dataset = dataset.map(token_encode, batched=True)

    dataset.set_format(type='torch', columns=['input_ids', 'attention_mask'])
```

I have 1,123,870,657 lines in my input directory. 
I can find the processing speed as following. It is very slow.  
```
| 13/1123871 [00:02<62:37:39,  4.98ba/s]^M  0%|   
| 14/1123871 [00:03<61:27:31,  5.08ba/s]^M  0%|          
| 15/1123871 [00:03<66:34:19,  4.69ba/s]^M  0%|         
| 16/1123871 [00:03<68:25:01,  4.56ba/s]^M  0%|          
| 17/1123871 [00:03<72:00:03,  4.34ba/s]^M  0%|       
```
Do you have any suggestions to accelerate this loading process?

You can use multiprocessing by specifying `num_proc=` in `.map()`

Also it looks like you have `1123871` batches of 1000 elements (default batch size), i.e. 1,123,871,000 lines in total.
Am I right ?

> You can use multiprocessing by specifying `num_proc=` in `.map()`
> 
> Also it looks like you have `1123871` batches of 1000 elements (default batch size), i.e. 1,123,871,000 lines in total.
> Am I right ?

Hi @lhoestq ,

Thanks. I will try it.

You are right. I have 1,123,870,657 lines totally in the path. I split the large file into 440 small files. Each file has 2,560,000 lines.

I have another question. Because I am using a cloud server where only allows running a job up to 7 days. Hence, I need to resume my model every week. If the script needs to load and process the dataset every time. It is very low efficient based on the current processing speed. Is it possible that I process the dataset once and use the process cache to in the future work? 


Hi @lhoestq ,

I tried to use multi-processor, but I got errors as follow: 
Because I am using python distributed training, it seems some conflicts with the distributed job. 

Do you have any suggestions?
```
I0925 10:19:35.603023 140737353971520 filelock.py:318] Lock 140737229443368 released on /tmp/pbs.1120510.pbsha.ib.sockeye/cache/_tmp_pbs.1120510.pbsha.ib.sockeye_cache_text_default-7fb934ed6fac5d01_0.0.0_512f465342e4f4cd07a8791428a629c043bb89d55ad7817cbf7
fcc649178b014.lock
Traceback (most recent call last):
  File "/scratch/chiyuzh/roberta/run_language_modeling.py", line 1024, in <module>
    main()
  File "/scratch/chiyuzh/roberta/run_language_modeling.py", line 967, in main
    train_dataset = load_and_cache_examples(args, tokenizer, evaluate=False)
  File "/scratch/chiyuzh/roberta/run_language_modeling.py", line 180, in load_and_cache_examples
    return HG_Datasets(tokenizer, file_path, args)
  File "/scratch/chiyuzh/roberta/run_language_modeling.py", line 119, in HG_Datasets
    dataset = dataset.map(token_encode, batched=True, batch_size = 10000, num_proc = 16)
  File "/project/chiyuzh/evn_py36/lib/python3.6/site-packages/datasets/arrow_dataset.py", line 1287, in map
    transformed_shards = [r.get() for r in results]
  File "/project/chiyuzh/evn_py36/lib/python3.6/site-packages/datasets/arrow_dataset.py", line 1287, in <listcomp>
    transformed_shards = [r.get() for r in results]
  File "/project/chiyuzh/evn_py36/lib/python3.6/multiprocessing/pool.py", line 644, in get
    raise self._value
  File "/project/chiyuzh/evn_py36/lib/python3.6/multiprocessing/pool.py", line 424, in _handle_tasks
    put(task)
  File "/project/chiyuzh/evn_py36/lib/python3.6/multiprocessing/connection.py", line 206, in send
    self._send_bytes(_ForkingPickler.dumps(obj))
  File "/project/chiyuzh/evn_py36/lib/python3.6/multiprocessing/reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
AttributeError: Can't pickle local object 'HG_Datasets.<locals>.token_encode'
```

For multiprocessing, the function given to `map` must be picklable.
Maybe you could try to define `token_encode` outside `HG_Datasets` ?

Also maybe #656 could make functions defined locally picklable for multiprocessing, once it's merged.

> I have another question. Because I am using a cloud server where only allows running a job up to 7 days. Hence, I need to resume my model every week. If the script needs to load and process the dataset every time. It is very low efficient based on the current processing speed. Is it possible that I process the dataset once and use the process cache to in the future work?

Feel free to save your processed dataset using `dataset.save_to_disk("path/to/save/directory")`.

Then you'll be able to reload it again using
```python
from datasets import load_from_disk

dataset = load_from_disk("path/to/save/directory")
```

Hi @lhoestq ,

Thanks for your suggestion. 
I tried to process the dataset and save it to disk. 
I have 1.12B samples in the raw dataset. I used 16 processors.
I run this process job for 7 days. But it didn't finish. I don't why the processing is such slow. 

The log shows that some processors (\#12, \#14, \#15) are very slow. The different processor has a different speed. These slow processors look like a bottleneck. 

Could you please give me any suggestion to improve the processing speed? 

Thanks. 
Chiyu

Here is my code:
```
def token_encode(examples):
        tokenizer_out = tokenizer(examples['text'], truncation=True,  padding="max_length", add_special_tokens=True, max_length=args.block_size)
        return tokenizer_out

path = Path(file_path)
files = sorted(path.glob('*'))
dataset = load_dataset('./text.py', data_files=files, cache_dir = args.data_cache_dir, split="train")
dataset = dataset.map(token_encode, batched=True, batch_size = 16384, num_proc = 16)
dataset.set_format(type='torch', columns=['input_ids', 'attention_mask'])
dataset.save_to_disk(output_dir)
```
Here is the log. 
```
^M#6:   1%|▏         | 59/4288 [55:10<66:11:58, 56.35s/ba]
^M#1:   8%|▊         | 356/4288 [55:39<10:40:02,  9.77s/ba]
^M#2:   5%|▍         | 210/4288 [55:33<17:47:19, 15.70s/ba]
^M#0:  19%|█▉        | 836/4288 [55:53<4:08:56,  4.33s/ba]
^M#0:  20%|█▉        | 837/4288 [55:57<4:01:52,  4.21s/ba]
^M#1:   8%|▊         | 357/4288 [55:48<10:38:09,  9.74s/ba]
^M#0:  20%|█▉        | 838/4288 [56:01<4:02:56,  4.23s/ba]
^M#3:   4%|▎         | 155/4288 [55:43<24:41:20, 21.51s/ba]
^M#0:  20%|█▉        | 839/4288 [56:05<4:04:48,  4.26s/ba]
^M#12:   1%|          | 29/4288 [54:50<133:20:53, 112.72s/ba]
^M#2:   5%|▍         | 211/4288 [55:48<17:40:33, 15.61s/ba]
^M#14:   0%|          | 2/4288 [04:24<157:17:50, 132.12s/ba]
^M#15:   0%|          | 1/4288 [02:24<172:11:37, 144.60s/ba]
```

Hi !

As far as I can tell, there could be several reasons for your processes to have different speeds:
- some parts of your dataset have short passages while some have longer passages, that take more time to be processed
- OR there are other processes running that prevent some of them to run at full speed
- OR the value of `num_proc` is higher than the number of actual processes that you can run in parallel at full speed.

So I'd suggest you to check that you have nothing else running in parallel to your processing job, and also maybe take a look at the slow parts of the datasets.
When doing multiprocessing, the dataset is sharded in `num_proc` contiguous parts that are processed individually in each process. If you want to take a look at the dataset processed in the 12th shard of 16 for example, you can do:

```python
my_shard = dataset.shard(num_shards=16, index=12, contiguous=True)
```

Hope this helps, let me know if you find what is causing this slow down.

Do you use a fast or a slow tokenizer from the `transformers` library @chiyuzhang94?

> Do you use a fast or a slow tokenizer from the `transformers` library @chiyuzhang94?

Hi @thomwolf ,
 I use this: 
```
from transformers import
AutoTokenizer.from_pretrained(args.model_name_or_path, cache_dir=args.cache_dir)
```

I guess this is a slow one, let me explore the fast tokenizer. 

> Hi !
> 
> As far as I can tell, there could be several reasons for your processes to have different speeds:
> 
> * some parts of your dataset have short passages while some have longer passages, that take more time to be processed
> * OR there are other processes running that prevent some of them to run at full speed
> * OR the value of `num_proc` is higher than the number of actual processes that you can run in parallel at full speed.
> 
> So I'd suggest you to check that you have nothing else running in parallel to your processing job, and also maybe take a look at the slow parts of the datasets.
> When doing multiprocessing, the dataset is sharded in `num_proc` contiguous parts that are processed individually in each process. If you want to take a look at the dataset processed in the 12th shard of 16 for example, you can do:
> 
> ```python
> my_shard = dataset.shard(num_shards=16, index=12, contiguous=True)
> ```
> 
> Hope this helps, let me know if you find what is causing this slow down.

Hi @lhoestq ,

Thanks for your suggestions. 
I don't think my problem is due to any one of these seasons. 

1.  I have 1,123,870,657 lines totally in the path. I split the large file into 440 small files. Each file has 2,560,000 lines. The last file is smaller a little bit. But they are similar. I randomly shuffled all the 1,123,870,657 lines. Hence, the sequences should also be similar across all the files. 

2. I run this script on the entire node. I requested all the resources on the nodes (40 CPUs, 384GB memory). Hence, these were not any other processes. 

 3. As I say, the node has 40 CPUs, but I set num_proc = 16. This should not be a problem.

Hi @thomwolf 
I am using `RobertaTokenizerFast` now. 

But the speed is still imbalanced, some processors are still slow. 
Here is the part of the log. #0 is always much fast than lower rank processors. 

```
#15:   3%|▎         | 115/3513 [3:18:36<98:01:33, 103.85s/ba]
#2:  24%|██▍       | 847/3513 [3:20:43<11:06:49, 15.01s/ba]
#1:  37%|███▋      | 1287/3513 [3:20:52<6:19:02, 10.22s/ba]
#0:  72%|███████▏  | 2546/3513 [3:20:52<1:51:03,  6.89s/ba]
#3:  18%|█▊        | 617/3513 [3:20:36<15:50:30, 19.69s/ba]
#0:  73%|███████▎  | 2547/3513 [3:20:59<1:50:25,  6.86s/ba]
#1:  37%|███▋      | 1288/3513 [3:21:02<6:21:13, 10.28s/ba]
#7:   7%|▋         | 252/3513 [3:20:09<44:09:03, 48.74s/ba]
#12:   4%|▍         | 144/3513 [3:19:19<78:00:54, 83.36s/ba]
#4:  14%|█▍        | 494/3513 [3:20:37<20:46:06, 24.77s/ba]
#0:  73%|███████▎  | 2548/3513 [3:21:06<1:49:26,  6.80s/ba]
#2:  24%|██▍       | 848/3513 [3:20:58<11:06:17, 15.00s/ba]
```
Here is my script related to the datasets processing, 

```
tokenizer = RobertaTokenizerFast.from_pretrained(args.model_name_or_path, cache_dir=args.cache_dir)

def token_encode(examples):
    tokenizer_out = tokenizer(examples['text'], truncation=True,  padding="max_length", add_special_tokens=True, max_length=128)
    return tokenizer_out

def HG_Datasets(tokenizer, file_path, args):
    
    path = Path(file_path)
    files = sorted(path.glob('*'))
    dataset = load_dataset('./text.py', data_files=files, cache_dir = ""./, split="train")
    dataset = dataset.map(token_encode, batched=True, batch_size = 20000, num_proc = 16)

    dataset.set_format(type='torch', columns=['input_ids', 'attention_mask'])
    return dataset

```
I have 1,123,870,657 lines totally in the path. I split the large file into 440 small files. Each file has 2,560,000 lines.

Could you please give any suggestion? Thanks very much!!