I want to fine tune a BERT MLM model from Hugging Face. I have only a small amount of data (train.csv) like this:
text
בראשית ברא אלהים את השמים ואת הארץ
והארץ היתה תהו ובהו וחשך על פני תהום ורוח אלהים מרחפת על פני המים
ויאמר אלהים יהי אור ויהי אור
וירא אלהים את האור כי טוב ויבדל אלהים בין האור ובין החשך
ויקרא אלהים לאור יום ולחשך קרא לילה ויהי ערב ויהי בקר יום אחד
ויאמר אלהים יהי רקיע בתוך המים ויהי מבדיל בין מים למים
ויעש אלהים את הרקיע ויבדל בין המים אשר מתחת לרקיע ובין המים אשר מעל לרקיע ויהי כן
ויקרא אלהים לרקיע שמים ויהי ערב ויהי בקר יום שני
ויאמר אלהים יקוו המים מתחת השמים אל מקום אחד ותראה היבשה ויהי כן
ויקרא אלהים ליבשה ארץ ולמקוה המים קרא ימים וירא אלהים כי טוב
Below is my script in doing the fine-tuning:
from huggingface_hub import login
from transformers import AutoModelForMaskedLM
from transformers import AutoTokenizer
import torch
from datasets import load_dataset
from transformers import DataCollatorForLanguageModeling
import collections
import numpy as np
from transformers import default_data_collator
from transformers import TrainingArguments
from transformers import Trainer
import math
from transformers import EarlyStoppingCallback, IntervalStrategy
access_token_write = "hf_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
login(token = access_token_write)
model_checkpoint = "dicta-il/BEREL_2.0"
model = AutoModelForMaskedLM.from_pretrained(model_checkpoint)
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
sam_dataset = load_dataset("johnlockejrr/samv2")
def tokenize_function(examples):
result = tokenizer(examples["text"])
if tokenizer.is_fast:
result["word_ids"] = [result.word_ids(i) for i in range(len(result["input_ids"]))]
return result
tokenized_datasets = sam_dataset.map(
tokenize_function, batched=True, remove_columns=["text"]
)
chunk_size = 128
tokenized_samples = tokenized_datasets["train"][:3]
concatenated_examples = {
k: sum(tokenized_samples[k], []) for k in tokenized_samples.keys()
}
def group_texts(examples):
# Concatenate all texts
concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
# Compute length of concatenated texts
total_length = len(concatenated_examples[list(examples.keys())[0]])
# We drop the last chunk if it's smaller than chunk_size
total_length = (total_length // chunk_size) * chunk_size
# Split by chunks of max_len
result = {
k: [t[i : i + chunk_size] for i in range(0, total_length, chunk_size)]
for k, t in concatenated_examples.items()
}
# Create a new labels column
result["text"] = result["input_ids"].copy()
return result
lm_datasets = tokenized_datasets.map(group_texts, batched=True)
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)
samples = [lm_datasets["train"][i] for i in range(2)]
train_size = 1_000
test_size = int(0.1 * train_size)
downsampled_dataset = lm_datasets["train"].train_test_split(
train_size=train_size, test_size=test_size, seed=42
)
batch_size = 64
logging_steps = len(downsampled_dataset["train"]) // batch_size
model_name = model_checkpoint.split("/")[-1]
training_args = TrainingArguments(
output_dir=f"{model_name}-finetuned-sam-v1",
overwrite_output_dir=True,
evaluation_strategy=IntervalStrategy.STEPS, # "steps"
eval_steps = 50, # Evaluation and Save happens every 50 steps
save_total_limit = 5, # Only last 5 models are saved. Older ones are deleted.
learning_rate=2e-5,
weight_decay=0.01,
per_device_train_batch_size=batch_size,
per_device_eval_batch_size=batch_size,
num_train_epochs=5,
push_to_hub=True,
fp16=True,
logging_steps=logging_steps,
metric_for_best_model = 'f1',
load_best_model_at_end=True
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=downsampled_dataset["train"],
eval_dataset=downsampled_dataset["test"],
data_collator=data_collator,
tokenizer=tokenizer,
)
trainer.train()
eval_results = trainer.evaluate()
print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
trainer.push_to_hub()
All went well, model trained, pushed to Hugging Face. Problems:
Loss: 6.2156
Model work for
Fill-Mask
but with my new data seems something happened in the process and some words are masked as tokens and not full words: Here is a script as an example ofFill-Mask
and the output:from transformers import pipeline
mask_filler = pipeline( "fill-mask", model="johnlockejrr/BEREL_2.0-finetuned-sam-v1" )
text = "ואלין שמהת בני [MASK] דעלו למצרים עם יעקב גבר וביתה עלו" preds = mask_filler(text)
for pred in preds: print(f">>> {pred['sequence']}")
Output:
>>> ואלין שמה ##ת בני יעקב דעלו למצרים עם יעקב גבר ובית ##ה עלו
>>> ואלין שמה ##ת בני ישראל דעלו למצרים עם יעקב גבר ובית ##ה עלו
>>> ואלין שמה ##ת בני לאה דעלו למצרים עם יעקב גבר ובית ##ה עלו
>>> ואלין שמה ##ת בני ראובן דעלו למצרים עם יעקב גבר ובית ##ה עלו
>>> ואלין שמה ##ת בני דן דעלו למצרים עם יעקב גבר ובית ##ה עלו
I was expecting this output:
>>> ואלין שמהת בני יעקב דעלו למצרים עם יעקב גבר וביתה עלו
>>> ואלין שמהת בני ישראל דעלו למצרים עם יעקב גבר וביתה עלו
>>> ואלין שמהת בני לאה דעלו למצרים עם יעקב גבר וביתה עלו
>>> ואלין שמהת בני ראובן דעלו למצרים עם יעקב גבר וביתה עלו
>>> ואלין שמהת בני דן דעלו למצרים עם יעקב גבר וביתה עלו
What am I doing wrong?