I'm trying to finetune with old german texts (using bert-base-german-case model), running the script in Kubernetes in Docker image. I have some questions:
Preprocessing Dataset /data/german_old_texts/processed/lm/train.txt: 2%|1 | 7/451 [02:39<2:48:40, 22.79s/ Dicts]
Traceback (most recent call last):
File "finetune_lm.py", line 61, in <module>
max_processes=20
File "/home/user/farm/data_handler/data_silo.py", line 105, in __init__
self._load_data()
File "/home/user/farm/data_handler/data_silo.py", line 205, in _load_data
self.data["train"], self.tensor_names = self._get_dataset(train_file)
File "/home/user/farm/data_handler/data_silo.py", line 176, in _get_dataset
for dataset, tensor_names in results:
File "/usr/lib/python3.6/multiprocessing/pool.py", line 735, in next
raise value
multiprocessing.pool.MaybeEncodingError: Error sending result: '(<torch.utils.data.dataset.TensorDataset object at 0x7f3341f74f98>, ['input_ids', 'padding_mask', 'segment_ids', 'lm_label_ids', 'nextsentence_label_ids'])'. Reason: 'RuntimeError('unable to write to file </torch_70_633414359>',)'
However, this error doesn't occur everytime. What can I do to avoid this error?
nextsentence_label_ids: [0]
_____________________________________________________
(This happened whether I run just one version of script at a time, or both running parallel)
Is it still processing or is it freezing? What cause this problem?
Setting in YAML file:
resources:
limits:
nvidia.com/gpu: "2"
cpu: "20"
memory: "32Gi"
But when using the big training file, 20 parallel workers were assigned to process the dataset. Why doesn't it assign more than 1 worker when processing the small training file?
Additional Info:
When I tried to add this to the code:
from multiprocessing import set_start_method
set_start_method("spawn")
after showing the second sample and after the same line as in previous question, what happened is this:
```
nextsentence_label_ids: [0] _____________________________________________________ 07/13/2020 22:11:28 - INFO - transformers.file_utils - PyTorch version 1.5.0 available. 07/13/2020 22:11:28 - INFO - farm.utils - device: cuda n_gpu: 2, distributed training: False, automatic mixed precision training: None
07/13/2020 22:12:12 - INFO - transformers.file_utils - PyTorch version 1.5.0 available. 07/13/2020 22:12:12 - INFO - farm.utils - device: cuda n_gpu: 2, distributed training: False, automatic mixed precision training: None
```
And then it freezes again.
We added this code in the hope to solve the first problem (with the multiprocessing error). I don't know if this information will be useful, but I just add it here.
Please help. I've been trying to do this finetuning in kubernetes since weeks already without success (I first tested the script for finetuning on Google Colab with a really small training data and it has worked without error). I don't know what I should do anymore to make it work. Please let me know if I should add any information. Thanks in advance.
Hey @lingsond good that you contacted us, I can relate to the confusion and difficulties you went through when working on large datafiles.
I think there are two very quick solutions to your issues:
n_batches=len(stream_data_silo.get_data_loader("train"))Explanations to the solutions
When not using streaming approach all data will be loaded into memory, which is quite a lot. You "just" assigned 32GB to your machine, in some of our use cases more than 200GB is needed. Your particular error though possibly comes from very large multiprocessing chunks. So your data is split into chunks (determined by max_multiprocessing_chunksize parameter). If these chunks are very large (possibly due to your train.txt file contains large documents) an error like "'RuntimeError('unable to write to file ',)'" occurs.
Hope that can help you. We will be able to assist if further problems occur.
Maybe post your small train file for a quick check if you can?
Hi @Timoeller , thanks for your reply.
# from multiprocessing import set_start_method
import logging
import os
import json
import math
from pathlib import Path
from tqdm import tqdm, trange
from farm.modeling.tokenization import Tokenizer
from farm.data_handler.data_silo import DataSilo, StreamingDataSilo
from farm.data_handler.processor import BertStyleLMProcessor
from farm.data_handler.utils import split_file
from farm.modeling.adaptive_model import AdaptiveModel
from farm.modeling.language_model import LanguageModel
from farm.modeling.optimization import initialize_optimizer
from farm.modeling.prediction_head import BertLMHead, NextSentenceHead
from farm.train import Trainer, EarlyStopping
from farm.utils import set_all_seeds, initialize_device_settings
import torch
And this is the error I'm getting:
Traceback (most recent call last):
File "finetune_lm_split_sleep.py", line 13, in <module>
from farm.data_handler.utils import split_file
ImportError: cannot import name 'split_file'
Did I miss anything?
Thanks for the help.
Never mind the import error. It turns out that I was still using version 0.4.3 where the split_file hasn't been implemented.
I've change the code accordingly like the example. but I still got an error:
Traceback (most recent call last):
File "finetune_lm_split_sleep.py", line 223, in <module>
main()
File "finetune_lm_split_sleep.py", line 218, in main
train_batch()
File "finetune_lm_split_sleep.py", line 170, in train_batch
n_batches=len(data_silo.get_data_loader["train"]),
TypeError: 'method' object is not subscriptable
That line is the one in the initialize_optimizer:
# 5. Create an optimizer
warmup_proportion = 0.05
grad_acc = 1
model, optimizer, lr_schedule = initialize_optimizer(
model=model,
learning_rate=2e-5,
schedule_opts={"name": "LinearWarmup", "warmup_proportion": warmup_proportion},
grad_acc_steps=grad_acc,
device=device,
n_batches=len(data_silo.get_data_loader["train"]),
n_epochs=n_epochs,
)
But it's a great progress since I never get so far before :)
What cause this error and how can I fix it?
Nice self service about the import error : ) The next error is about method vs data index. As I have written you should use: n_batches=len(stream_data_silo.get_data_loader("train")). there get_data_loader is a function that takes an argument. In the normal datasilo case it is a dictionary that takes keys.
About your dataset, I think you do not need to send it via pm, I think your explanations agree with our hypothesis. If you do not have many docs in your txt file only one (or a few) processes are used. This is because each process needs to select random documents for the next sentence prediction task of Bert finetuning. If you only have 20 docs all of them will be assigned to one process.
I didn't change the variable data_silo to stream_data_silo but i still use the StreamingDataSilo.
data_loader_workers = 10
data_silo = StreamingDataSilo(processor=processor, batch_size=batch_size, dataloader_workers=data_loader_workers)
Just to complete the information, here's the processor:
processor = BertStyleLMProcessor(
data_dir=Path('/data/german_old_texts/processed/lm_batch'),
tokenizer=tokenizer,
max_seq_len=512,
max_docs=None,
next_sent_pred_style=next_sent_pred_style,
train_filename=file_name,
dev_filename=None,
test_filename=None,
dev_split=0.1
)
next_sent_pred_style is 'bert-style', and for tokenizer I used 'bert-base-german-cased' as languange model.
I didn't change the variable data_silo to stream_data_silo but i still use the StreamingDataSilo.
that is why you have to change how n_batches is computed. One is a method call with ("train") the other one a dictionary access with ["train"]. I agree this handling is confusing and we should unify the usage.
Does it work with the StreamingDataSilo then?
Hi @Timoeller , it seems that you have misunderstood me. What I mean is, I didn't change the variable name because I only use one data silo in the script. But I did change the code to use StreamingDataSilo as you can see in the code I posted above. Besides, if using the normal DataSilo, it uses data_silo.loaders instead of get_data_loader.
However, from your explanation I've realized my mistake. In my code, I changed the data_silo.loaders to data_silo.get_data_loader, but I didn't notice the bracket's difference, so I didn't change the them from [ ] to ( ). After changing the brackets, everything work as perfectly. It is currently doing the training, but everything looks good for now. And the speed is even faster than I expected. Wunderbar!
Vielen Dank. I've been struggling with this problem for a long time already.
Btw, I didn't use the split_file yet because it caused this error:
Splitting file ...: 5%|5 | 127877/2407713 [00:00<00:02, 869200.61it/s]
Traceback (most recent call last):
File "finetune_lm.py", line 43, in <module>
split_file(data_dir / "train.txt", output_dir=Path('/data/german_old_texts/processed/lm/split_files'), docs_per_file=20)
File "/home/user/farm/data_handler/utils.py", line 785, in split_file
write_file.writelines(lines_to_write)
UnicodeEncodeError: 'ascii' codec can't encode character '\xe4' in position 62: ordinal not in range(128)
From the source, the default should be using utf-8 for the encoding.
If I'm not mistaken, in the source code of the split_file method, when it open read the file, it uses the encoding, but during the writing process, the encoding was omitted. Perhaps that caused the error?
Nice, always happy to help.
About the split_file encoding issue. This might be a bug and your proposed solution seems reasonable.
Would you like to create a separate issue with this bug and maybe a minimal example showing the error? If you want you could even contribute a PR adding the encoding to the writing?
Ok, I'll create a separate issue for the split_file. However, I'm still not too familiar with git so I don't know how to contribute a PR.
Since the original issue with the multiprocessing problem is solved, should I close this issue?
I will close this one for you.
About creating a PR: here is a nice tutorial, starting from step 2: https://medium.com/@jenweber/your-first-open-source-contribution-a-step-by-step-technical-guide-d3aca55cc5a6