Home › Forums › Dayu Febri Transformer › Bagian 4: Hasil Pelatihan MLM Bert
- This topic is empty.
-
AuthorPosts
-
March 30, 2024 at 10:14 #10733mulkan syarifKeymaster
Kode sudah saya lampirkan di https://drive.google.com/drive/folders/1wFhoQe9PR5bK1Wk9AamqnDuZHrzYp-Cc?usp=share_link yang telah saya bagikan sebelumnya. Saya bagi menjadi 4 tahapan dan semuanya menggunakan Jupyter karena biar sekalian bisa akses google colab
1. Perayapan Satua Bali.ipynb
Digunakan untuk me scraping isi website, yang pernah saya bahas di https://softscients.com/forums/topic/bagian-13-pembuatan-dataset-kumpulan-daftar-contoh-satua-bali/ hasilnya nanti akan disimpan di satua bali1.csv
import urllib.parse as parse import requests import re from bs4 import BeautifulSoup as BS host = ["https://msatuabali.blogspot.com/", "https://msatuabali.blogspot.com/p/tentang-kami.html", "https://msatuabali.blogspot.com/p/kontak-kami.html", "https://msatuabali.blogspot.com/p/privacy-policy.html", "https://msatuabali.blogspot.com/p/disclaimer.html"] title = [ "Kumpulan Daftar Contoh Satua Bali - Msatua Bali", "Kumpulan Daftar Contoh Satua Bali - Msatua Bali", "Kumpulan Daftar Contoh Cerpen Bahasa Bali - Msatua Bali", "Kumpulan Daftar Contoh Pidato Bahasa Bali - Msatua Bali", "Pengertian Puisi Bali Anyar - Msatua Bali", "Kumpulan Contoh - Contoh Puisi Bali Anyar - Msatua Bali", "Pengertian Puisi Bali Purwa - Msatua Bali", "Kumpulan Contoh - Contoh Puisi Bali Purwa - Msatua Bali", "Kumpulan Contoh - Contoh Sekar Rare - Puisi Bali Purwa - Msatua Bali", "Kumpulan Contoh - Contoh Sekar Alit (Sekar Macapat / Pupuh) - Puisi Bali Purwa - Msatua Bali", "Kumpulan Contoh - Contoh Sekar Madya - Puisi Bali Purwa - Msatua Bali", "Kumpulan Contoh - Contoh Sekar Agung ( Kekawin atau Wirama ) - Puisi Bali Purwa - Msatua Bali", "Sitemap - Msatua Bali" ] req = requests.get("https://msatuabali.blogspot.com/p/satua-bali-i-siap-selem-msatuabali.html") document = BS(req.text,"html.parser") i = 1 final_result = list() for links in document.find_all('a'): link = links.get("href") if (link not in host) and link.find(".html")>0: # print(link) try: req = requests.get(link) document = BS(req.text,"html.parser") if document.title.string not in title: print(document.title.string) try: artikel = document.find_all("div", {"class": "main-content"})[0].text artikel = re.sub(r"\s+", " ", artikel) buffer = artikel.split(". ") # print(len(buffer)) for j, isi in enumerate(buffer): if j!=0 and j<=len(buffer)-11: #baris pertama diabaikan buffer2 = {"content":isi,"title":document.title.string} final_result.append(buffer2) i+=1 except: print("ada error") pass except: pass import pandas as pd pd.DataFrame(final_result).to_csv("satua bali1.csv") print("selesai....")
2. Pembuatan Dataset dan Vocab-Token.ipynb
Berdasarkan satua bali1.csv, kita akan membuat dataset dan dilanjut dengan token/vocab. Kita akan buat function untuk memecah kalimat jika ukurannya cukup besar menjad kalimat-kalimat kecil.
import pandas as pd import os from tokenizers import BertWordPieceTokenizer from pathlib import Path import math from tokenizers.implementations import ByteLevelBPETokenizer, BertWordPieceTokenizer from tokenizers.processors import BertProcessing from transformers import BertTokenizerFast,BertForMaskedLM, pipeline, BertConfig from transformers import LineByLineTextDataset, TextDataset from transformers import DataCollatorForLanguageModeling folder_corpus = 'model1' def pecah_kalimat(kalimat): n = len(kalimat.split(" ")) delta = 60 panjang = math.ceil(n/delta) token = kalimat.split(" ") a = 0 b = a+delta result = [] for i in range(0,panjang): if b>n: b = n # print(a,b) A = a-1 B = b else: # print(a,b) A = a B = b buffer = token[A:B] strs = "" for j in buffer: strs+=j+" " result.append(strs) a = b+1 b = a+delta return result
kita gunakan function diatas untuk membuat file dataset.txt
# buat folder if os.path.exists(folder_corpus)==False: os.mkdir(folder_corpus) # pembuatan dataset persiapan_dataset = True if persiapan_dataset: df = pd.read_csv('satua bali1.csv') artikel = df['content'] with open('dataset.txt', 'w', encoding='utf-8') as fp: for i, kalimat in enumerate(artikel): # cari kalimat yang agak panjang, jangan terlalu sedikit if len(kalimat.split(" "))>=5 and len(kalimat.split(" "))<=60: # print(kalimat) fp.write("\n"+kalimat) else: banyak_kalimat = pecah_kalimat(kalimat) for j in banyak_kalimat: fp.write("\n"+j) if i==10: pass #break print("selesai...")
Selanjutnya berdasarkan dataset.txt akan dibuat token dan vocab
# pembuatan vocab /tokenizer persiapan_dataset = True if persiapan_dataset: tokenizer = BertWordPieceTokenizer() # Bert special_tokens_dict = {'unk_token': '[UNK]', 'sep_token':'[SEP]', 'pad_token':'[PAD]', 'cls_token':'[CLS]', 'mask_token':'[MASK]' } tokenizer.train(files='dataset.txt', vocab_size=32_000, min_frequency=1, special_tokens=[ "[UNK]", "[SEP]", "[PAD]", "[CLS]", "[MASK]"]) if os.path.exists(folder_corpus)==False: os.mkdir(folder_corpus) tokenizer.save_model(folder_corpus) print("selesai disimpan")
hasilnya akan disimpan dalam sebuah folder dengan nama model1/vocab.txt. Kalau dibuka dengan notepad akan terdapat sebanyak 26.380 vocab yang nantinya digunakan sebagai dasar tokenizer.
3. Pelatihan.ipynb
Pada tahap ini yang sangat membutuhkan waktu puluhan jam beroperasi untuk melakukan training. Kita loading dulu beberapa library dan folder yang kita gunakan
import pandas as pd import os from tokenizers import BertWordPieceTokenizer from pathlib import Path import math from tokenizers.implementations import ByteLevelBPETokenizer, BertWordPieceTokenizer from tokenizers.processors import BertProcessing from transformers import BertTokenizerFast,BertForMaskedLM, pipeline, BertConfig,AutoTokenizer,AutoModel from transformers import LineByLineTextDataset, TextDataset from transformers import DataCollatorForLanguageModeling import pandas as pd from torch.utils.data import Dataset, DataLoader import numpy as np folder_corpus = './model1'
kita loading dulu tokenizer dan potong token dengan panjang 256 karakter saja. Karena kalau pakai 512 kehabisan memory
tokenizer = BertTokenizerFast.from_pretrained(folder_corpus, max_len=256)
mari kita coba library token nya apakah bisa digunakan untuk khusus bahasa bali?
idx_token = tokenizer.encode("Dening keto Ida Anake Agung lantas ngambil rabi") print(idx_token) token = tokenizer.decode(idx_token) print(token)
hasilnya sudah sesuai
[3, 514, 163, 144, 237, 386, 140, 1717, 1595, 1] [CLS] dening keto ida anake agung lantas ngambil rabi [SEP]
Loading data menggunakan pandas dengan cara membaca file csv
from datasets import Dataset df = pd.read_csv('satua bali1.csv',usecols=['content']) dataset = Dataset.from_pandas(df.rename(columns={"content":'text'})) print(dataset
kita bisa record nya yaitu 11 ribuan
Dataset({ features: ['text'], num_rows: 11009 })
kita akan memanfaatkan class Dataset dari pytorch untuk menyiapakan datanya dalam bentuk token ID nya
import torch from torch.utils.data import Dataset from accelerate import Accelerator, DistributedType class LineByLineTextDataset(Dataset): def __init__(self, tokenizer, raw_datasets, max_length: int): self.padding = "max_length" self.text_column_name = 'text' self.max_length = max_length self.accelerator = Accelerator(gradient_accumulation_steps=1) self.tokenizer = tokenizer with self.accelerator.main_process_first(): self.tokenized_datasets = raw_datasets.map( self.tokenize_function, batched=True, num_proc=1, remove_columns=[self.text_column_name], desc="Running tokenizer on dataset line_by_line", ) # self.tokenized_datasets.set_format('torch',columns=['input_ids'],dtype=torch.long) def tokenize_function(self,examples): examples[self.text_column_name] = [ line for line in examples[self.text_column_name] if len(line[0]) > 0 and not line[0].isspace() ] return self.tokenizer( examples[self.text_column_name], padding=self.padding, truncation=True, max_length=self.max_length, return_special_tokens_mask=True, ) def __len__(self): return len(self.tokenized_datasets) def __getitem__(self, i): return self.tokenized_datasets[i]
kita panggil saja
tokenized_dataset_train = LineByLineTextDataset( tokenizer= tokenizer, raw_datasets = dataset, max_length=256, )
mari kita panggil tokenizer_dataset_train apakah sudah muncul token ID nya?
# jika ingin melihat dataset nya! for i, batch in enumerate(tokenized_dataset_train): print(batch) break
hasilnya
{'input_ids': [3, 514, 2491, 258, 144, 1116, 2377, 10, 140, 207, 144, 1717, 1595, 207, 2435, 10, 416, 193, 629, 223, 1116, 2377, 12, 449, 497, 3887, 144, 1116, 1595, 10, 629, 193, 199, 174, 223, 1116, 2377, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'special_tokens_mask': [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
ok sudah muncul bisa dilihat input_ids yang berisi token ID nya
kita juga akan membuat data_collator untuk mensetting mask nya
# mlm_probability` denotes # probability with which we mask the input tokens in a sequence. # pengaturan [MASK] sebanyak 0.15% dari kalimat yang ada didalam token akan di masking data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=True, mlm_probability=0.10)
artinya jika ada 1 kalimat dengan jumlah token 100, maka 10% akan di masking
- saya lagi makan donat dan es teh di restoran kota semarang
panjang token diatas yaitu 11, maka akan ada 1 token yg masking secara random
- saya lagi makan donat dan es teh di restoran kota [MASK]
lalu kita atur BERT Config modelnya
config = BertConfig( hidden_size = 384, vocab_size= tokenizer.vocab_size, num_hidden_layers = 6, num_attention_heads = 6, intermediate_size = 1024, max_position_embeddings = 256 ) model = BertForMaskedLM(config=config)
kita atur jumlah epoch, save tensor per berapa kali, dan serta logging nya
from transformers import Trainer, TrainingArguments training_args = TrainingArguments( output_dir=folder_corpus, overwrite_output_dir=True, push_to_hub=False, hub_model_id="bahasa-bali", num_train_epochs=100, per_device_train_batch_size=4, save_steps=5_000, logging_steps = 500, save_total_limit=2, use_mps_device = True, # disable this if you're running non-mac env hub_private_repo = False, # please set true if you want to save model privetly save_safetensors= True, learning_rate = 1e-4, #report_to='wandb' ) trainer = Trainer( model=model, args=training_args, data_collator=data_collator, train_dataset=tokenized_dataset_train )
jika sudah siap, maka lakukan training
trainer.train()
nanti akan muncul informasi
jika sudah selesai, akan dilakukan penyimpanan
trainer.save_model(folder_corpus) print("selsai simpan")
kita bisa juga ploting loss nya tiap iterasi
import pandas as pd from matplotlib import pyplot as plt loss = pd.DataFrame(trainer.state.log_history) plt.figure() plt.plot(loss['loss']) plt.show()
pelatihan diatas butuh waktu sekitar 26 jam beroperasi terus menerus untuk selesaikan training
4. pengujian.ipynb
Model yang telah disimpan, bisa kita gunakan untuk melakukan inference
from transformers import BertForMaskedLM, pipeline,AutoTokenizer import os folder_corpus = './model1' tokenizer = AutoTokenizer.from_pretrained(folder_corpus) model = BertForMaskedLM.from_pretrained(folder_corpus) recognizer = pipeline("fill-mask", model=model, tokenizer=tokenizer)
kita akan lakukan masking dengan contoh berikut
target = "Uli joh koné ia suba ningalin ada sembé di pondokné" teks = "Uli joh koné ia suba [MASK] ada sembé di pondokné" recognizer(teks)
hasilnya
[{'score': 0.2525024712085724, 'token': 197, 'token_str': 'kone', 'sequence': 'uli joh kone ia suba kone ada sembe di pondokne'}, {'score': 0.1863546222448349, 'token': 1203, 'token_str': 'ningalin', 'sequence': 'uli joh kone ia suba ningalin ada sembe di pondokne'}, {'score': 0.0720268115401268, 'token': 515, 'token_str': 'liu', 'sequence': 'uli joh kone ia suba liu ada sembe di pondokne'}, {'score': 0.0452091321349144, 'token': 1344, 'token_str': 'joh', 'sequence': 'uli joh kone ia suba joh ada sembe di pondokne'}, {'score': 0.03558509796857834, 'token': 847, 'token_str': 'taen', 'sequence': 'uli joh kone ia suba taen ada sembe di pondokne'}]
walaupun belum sempurna hasilnya masih salah
Catatan
Setelah saya pelajari lebih lanjut melalui beragam trial and error, dengan dataset yang lebih kecil, diambil dari sebuah puisi dari https://www.brainacademy.id/blog/contoh-puisi
Harus menggunakan setting min_frequency = 1 pada tokenizer
tokenizer = BertWordPieceTokenizer() # Bert special_tokens_dict = {'unk_token': '[UNK]', 'sep_token':'[SEP]', 'pad_token':'[PAD]', 'cls_token':'[CLS]', 'mask_token':'[MASK]' } tokenizer.train(files='dataset.txt', vocab_size=32_000, min_frequency=1, special_tokens=[ "[UNK]", "[SEP]", "[PAD]", "[CLS]", "[MASK]"]) tokenizer.save_model(folder_model)
contoh hasilnya sebagai berikut
belajar filsafat, sastra, teknologi, ilmu kedokteran hasil prediksi: BELAJAR filsafat, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN BELAJAR menyangkut, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN BELAJAR pandangan, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN BELAJAR ada, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN BELAJAR hanya, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN BELAJAR sastra, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN BELAJAR belajar, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN BELAJAR kedokteran, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN BELAJAR ilmu, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN BELAJAR ia, SASTRA, TEKNOLOGI, ILMU KEDOKTERAN
catatan untuk loss function
Untuk loss function diatas masih secara default, belum aku lengkapi dengan referensi berikut: https://discuss.huggingface.co/t/getting-the-mlm-accuracy-for-the-bert-model-i-am-training-from-scratch/6795
https://discuss.huggingface.co/t/how-to-correctly-evaluate-a-masked-language-model/9634/2
ref:
https://mccormickml.com/2019/07/22/BERT-fine-tuning/
-
AuthorPosts
- You must be logged in to reply to this topic.