course documentation

ဒေတာများကို စီမံဆောင်ရွက်ခြင်း

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

ဒေတာများကို စီမံဆောင်ရွက်ခြင်း

Ask a Question Open In Colab Open In Studio Lab

ယခင်အခန်း မှ ဥပမာကို ဆက်လက်၍၊ batch တစ်ခုပေါ်တွင် sequence classifier ကို မည်သို့လေ့ကျင့်(Train)ရမည်ကို ဤတွင် ဖော်ပြထားသည်။

import torch
from torch.optim import AdamW
from transformers import AutoTokenizer, AutoModelForSequenceClassification

# အရင်ကအတိုင်း
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
sequences = [
    "I've been waiting for a HuggingFace course my whole life.",
    "This course is amazing!",
]
batch = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")

# ဒါက အသစ်ပါ
batch["labels"] = torch.tensor([1, 1])

optimizer = AdamW(model.parameters())
loss = model(**batch).loss
loss.backward()
optimizer.step()

ဟုတ်ပါတယ်၊ model ကို စာကြောင်းနှစ်ကြောင်းတည်းနဲ့ လေ့ကျင့်တာကတော့ ကောင်းမွန်တဲ့ ရလဒ်တွေရရှိမှာ မဟုတ်ပါဘူး။ ပိုကောင်းတဲ့ရလဒ်တွေ ရဖို့အတွက်၊ ပိုကြီးမားတဲ့ dataset တစ်ခုကို ပြင်ဆင်ဖို့ လိုပါလိမ့်မယ်။

ဒီအပိုင်းမှာတော့ William B. Dolan နဲ့ Chris Brockett တို့ရဲ့ paper မှာ မိတ်ဆက်ခဲ့တဲ့ MRPC (Microsoft Research Paraphrase Corpus) dataset ကို ဥပမာအဖြစ် ကျွန်တော်တို့ အသုံးပြုပါမယ်။ ဒီ dataset မှာ စာကြောင်းအတွဲပေါင်း ၅,၈၀၁ ခု ပါဝင်ပြီး ၎င်းတို့ဟာ paraphrase (ဆိုလိုသည်မှာ စာကြောင်းနှစ်ခုလုံး အဓိပ္ပာယ်တူညီခြင်း) ဟုတ်မဟုတ်ကို ဖော်ပြတဲ့ label တစ်ခု ပါရှိပါတယ်။ ဒီအခန်းအတွက် ရွေးချယ်ရခြင်းကတော့ ဒါဟာ သေးငယ်တဲ့ dataset တစ်ခုဖြစ်ပြီး၊ ဒါကြောင့် လေ့ကျင့်မှုနဲ့ စမ်းသပ်လုပ်ဆောင်ဖို့ လွယ်ကူလို့ပါပဲ။

Hub မှ dataset တစ်ခုကို Loading လုပ်ခြင်း

Hub မှာ model တွေပဲ ပါဝင်တာ မဟုတ်ပါဘူး၊ မတူညီတဲ့ ဘာသာစကားမျိုးစုံနဲ့ dataset များစွာလည်း ရှိပါတယ်။ ဒီနေရာ မှာ dataset တွေကို ကြည့်ရှုနိုင်ပြီး၊ ဒီအပိုင်းကို ပြီးသွားရင် dataset အသစ်တစ်ခုကို loading နဲ့ processing လုပ်ကြည့်ဖို့ ကျွန်တော်တို့ အကြံပြုပါတယ် (ယေဘုယျ documentation ကို ဒီနေရာ မှာ ကြည့်ပါ)။ ဒါပေမယ့် အခုတော့ MRPC dataset ကို အာရုံစိုက်ကြရအောင်။ ဒါက GLUE benchmark ကို ဖွဲ့စည်းထားတဲ့ dataset ၁၀ ခုထဲက တစ်ခုဖြစ်ပါတယ်။ GLUE benchmark ဟာ မတူညီတဲ့ text classification လုပ်ငန်း ၁၀ ခုမှာ ML model တွေရဲ့ စွမ်းဆောင်ရည်ကို တိုင်းတာဖို့ အသုံးပြုတဲ့ academic benchmark တစ်ခု ဖြစ်ပါတယ်။

🤗 Datasets library က Hub ပေါ်က dataset တစ်ခုကို download လုပ်ပြီး cache လုပ်ဖို့ အလွန်ရိုးရှင်းတဲ့ command တစ်ခုကို ပေးစွမ်းပါတယ်။ MRPC dataset ကို ဒီလို download လုပ်နိုင်ပါတယ်။

💡 ထပ်ဆောင်း အရင်းအမြစ်များ: dataset loading နည်းလမ်းတွေနဲ့ ဥပမာတွေ ထပ်မံသိရှိလိုပါက 🤗 Datasets documentation ကို ကြည့်ရှုပါ။

from datasets import load_dataset

raw_datasets = load_dataset("glue", "mrpc")
raw_datasets
DatasetDict({
    train: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 3668
    })
    validation: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 408
    })
    test: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 1725
    })
})

သင်တွေ့ရတဲ့အတိုင်း၊ training set, validation set, နဲ့ test set တွေပါဝင်တဲ့ DatasetDict object တစ်ခုကို ကျွန်တော်တို့ ရရှိပါတယ်။ တစ်ခုချင်းစီမှာ columns များစွာ (sentence1, sentence2, label, နဲ့ idx) နဲ့ မတူညီတဲ့ row အရေအတွက်တွေ ပါဝင်ပါတယ် (ဒါကြောင့် training set မှာ စာကြောင်းအတွဲ ၃,၆၆၈ ခု၊ validation set မှာ ၄၀၈ ခု၊ test set မှာ ၁,၇၂၅ ခု ရှိပါတယ်)။

ဒီ command က dataset ကို download လုပ်ပြီး cache လုပ်ပါတယ်၊ default အားဖြင့် ~/.cache/huggingface/datasets မှာပါ။ Chapter 2 မှာ သင်ယူခဲ့တဲ့အတိုင်း HF_HOME environment variable ကို သတ်မှတ်ခြင်းဖြင့် သင်ရဲ့ cache folder ကို စိတ်ကြိုက်ပြင်ဆင်နိုင်ပါတယ်။

ကျွန်တော်တို့ရဲ့ raw_datasets object ထဲက စာကြောင်းအတွဲတစ်ခုစီကို dictionary နဲ့တူညီစွာ indexing လုပ်ပြီး ဝင်ရောက်ကြည့်ရှုနိုင်ပါတယ်။

raw_train_dataset = raw_datasets["train"]
raw_train_dataset[0]
{'idx': 0,
 'label': 1,
 'sentence1': 'Amrozi accused his brother , whom he called " the witness " , of deliberately distorting his evidence .',
 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'}

label တွေဟာ integer တွေ ဖြစ်နေတာကို ကျွန်တော်တို့ တွေ့ရပါတယ်။ ဒါကြောင့် အဲဒီနေရာမှာ preprocessing လုပ်ဖို့ မလိုအပ်ပါဘူး။ ဘယ် integer က ဘယ် label နဲ့ ကိုက်ညီလဲဆိုတာ သိရှိဖို့အတွက် ကျွန်တော်တို့ရဲ့ raw_train_dataset ရဲ့ features တွေကို စစ်ဆေးနိုင်ပါတယ်။ ဒါက column တစ်ခုစီရဲ့ type ကို ပြောပြပေးပါလိမ့်မယ်။

raw_train_dataset.features
{'sentence1': Value(dtype='string', id=None),
 'sentence2': Value(dtype='string', id=None),
 'label': ClassLabel(num_classes=2, names=['not_equivalent', 'equivalent'], names_file=None, id=None),
 'idx': Value(dtype='int32', id=None)}

နောက်ကွယ်မှာတော့ label ဟာ ClassLabel type ဖြစ်ပြီး၊ integer တွေကနေ label name ကို mapping လုပ်တာက names folder ထဲမှာ သိမ်းဆည်းထားပါတယ်။ 0 က not_equivalent နဲ့ ကိုက်ညီပြီး၊ 1 က equivalent နဲ့ ကိုက်ညီပါတယ်။

✏️ စမ်းသပ်ကြည့်ပါ။ training set ရဲ့ element နံပါတ် ၁၅ နဲ့ validation set ရဲ့ element နံပါတ် ၈၇ ကို ကြည့်ပါ။ ၎င်းတို့ရဲ့ label တွေက ဘာတွေလဲ။

Dataset တစ်ခုကို Preprocessing လုပ်ခြင်း

Dataset ကို preprocessing လုပ်ဖို့အတွက်၊ text တွေကို model နားလည်နိုင်တဲ့ ဂဏန်းတွေအဖြစ် ပြောင်းလဲဖို့ လိုအပ်ပါတယ်။ ယခင်အခန်း မှာ သင်တွေ့ခဲ့တဲ့အတိုင်း၊ ဒါကို tokenizer နဲ့ လုပ်ဆောင်ပါတယ်။ tokenizer ကို sentence တစ်ခု ဒါမှမဟုတ် sentence list တစ်ခု ပေးပို့နိုင်တာကြောင့်၊ pair တစ်ခုစီရဲ့ ပထမ sentence တွေအားလုံးနဲ့ ဒုတိယ sentence တွေအားလုံးကို အခုလို တိုက်ရိုက် tokenize လုပ်နိုင်စေပါတယ်။

from transformers import AutoTokenizer

checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
tokenized_sentences_1 = tokenizer(raw_datasets["train"]["sentence1"])
tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"])

💡 နက်နက်နဲနဲ လေ့လာခြင်း: ပိုမိုအဆင့်မြင့်သော tokenization နည်းလမ်းများနှင့် မတူညီသော tokenizers များ မည်သို့အလုပ်လုပ်သည်ကို နားလည်ရန်အတွက် 🤗 Tokenizers documentation နှင့် cookbook ရှိ tokenization guide ကို လေ့လာပါ။

သို့သော်လည်း၊ model ကို sequences နှစ်ခု ပေးပို့လိုက်ရုံနဲ့ စာကြောင်းနှစ်ခုဟာ paraphrase ဟုတ်မဟုတ်ဆိုတဲ့ prediction ကို ရရှိမှာ မဟုတ်ပါဘူး။ ကျွန်တော်တို့ဟာ sequences နှစ်ခုကို pair အဖြစ် ကိုင်တွယ်ပြီး သင့်လျော်တဲ့ preprocessing ကို အသုံးပြုဖို့ လိုအပ်ပါတယ်။ ကံကောင်းစွာနဲ့ပဲ၊ tokenizer က sequence pair တစ်ခုကိုလည်း ယူပြီး ကျွန်တော်တို့ရဲ့ BERT model မျှော်လင့်ထားတဲ့အတိုင်း ပြင်ဆင်ပေးနိုင်ပါတယ်။

inputs = tokenizer("This is the first sentence.", "This is the second one.")
inputs
{ 
  'input_ids': [101, 2023, 2003, 1996, 2034, 6251, 1012, 102, 2023, 2003, 1996, 2117, 2028, 1012, 102],
  'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
  'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
}

Chapter 2 မှာ input_ids နဲ့ attention_mask keys တွေအကြောင်း ဆွေးနွေးခဲ့ပြီးပါပြီ၊ ဒါပေမယ့် token_type_ids အကြောင်းကိုတော့ နောက်မှ ဆွေးနွေးဖို့ ချန်ထားခဲ့ပါတယ်။ ဒီဥပမာမှာ၊ input ရဲ့ ဘယ်အပိုင်းက ပထမစာကြောင်းဖြစ်ပြီး ဘယ်ဟာက ဒုတိယစာကြောင်းဖြစ်တယ်ဆိုတာကို model ကို ပြောပြတာက ဒါပါပဲ။

✏️ စမ်းသပ်ကြည့်ပါ။ training set ရဲ့ element နံပါတ် ၁၅ ကို ယူပြီး စာကြောင်းနှစ်ကြောင်းကို သီးခြားစီနဲ့ pair အဖြစ် tokenize လုပ်ပါ။ ရလဒ်နှစ်ခုကြား ဘာကွာခြားမှု ရှိပါသလဲ။

input_ids ထဲက IDs တွေကို စကားလုံးတွေအဖြစ် ပြန် decode လုပ်ရင်၊

tokenizer.convert_ids_to_tokens(inputs["input_ids"])

ကျွန်တော်တို့ ရရှိမှာကတော့…

['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]']

ဒါကြောင့် model က input တွေကို [CLS] sentence1 [SEP] sentence2 [SEP] ပုံစံမျိုး မျှော်လင့်ထားတာကို ကျွန်တော်တို့ တွေ့ရပါတယ်။ ဒါကို token_type_ids နဲ့ ချိန်ညှိလိုက်ရင်၊

['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]']
[      0,      0,    0,     0,       0,          0,   0,       0,      1,    1,     1,        1,     1,   1,       1]

သင်တွေ့ရတဲ့အတိုင်း၊ [CLS] sentence1 [SEP] နဲ့ ကိုက်ညီတဲ့ input ရဲ့ အစိတ်အပိုင်းတွေအားလုံးမှာ token type ID 0 ရှိပြီး၊ sentence2 [SEP] နဲ့ ကိုက်ညီတဲ့ အခြားအစိတ်အပိုင်းတွေမှာတော့ token type ID 1 ရှိပါတယ်။

သင်က checkpoint တစ်ခုကို ရွေးချယ်မယ်ဆိုရင်၊ သင်ရဲ့ tokenized inputs တွေထဲမှာ token_type_ids တွေ မပါဝင်နိုင်ဘူး (ဥပမာ DistilBERT model ကို အသုံးပြုရင် ၎င်းတို့ကို ပြန်မပို့ပါဘူး) ဆိုတာ သတိပြုပါ။ ၎င်းတို့ကို model က ၎င်းတို့နဲ့ ဘာလုပ်ရမယ်ဆိုတာ သိတဲ့အခါမှသာ ပြန်ပို့တာဖြစ်ပါတယ်၊ ဘာလို့လဲဆိုတော့ pretraining လုပ်စဉ်က ၎င်းတို့ကို မြင်ဖူးလို့ပါ။

ဒီနေရာမှာ၊ BERT ကို token type IDs တွေနဲ့ pretrain လုပ်ထားပြီး၊ Chapter 1 မှာ ကျွန်တော်တို့ ဆွေးနွေးခဲ့တဲ့ masked language modeling objective အပြင် next sentence prediction လို့ခေါ်တဲ့ အပို objective တစ်ခုလည်း ပါရှိပါတယ်။ ဒီလုပ်ငန်းရဲ့ ရည်ရွယ်ချက်ကတော့ စာကြောင်းအတွဲတွေကြားက ဆက်စပ်မှုကို model လုပ်ဖို့ပါပဲ။

next sentence prediction မှာ၊ model ကို စာကြောင်းအတွဲတွေ (ကျပန်း mask လုပ်ထားတဲ့ tokens တွေနဲ့) ပေးပြီး ဒုတိယစာကြောင်းက ပထမစာကြောင်းနောက်မှာ လိုက်ပါသလားဆိုတာကို ခန့်မှန်းခိုင်းပါတယ်။ ဒီလုပ်ငန်းကို ခက်ခဲစေဖို့အတွက်၊ တစ်ဝက်တစ်ပျက်က စာကြောင်းတွေဟာ ၎င်းတို့ ထုတ်ယူထားတဲ့ မူရင်း document ထဲမှာ အချင်းချင်း လိုက်ပါနေပြီး၊ ကျန်တစ်ဝက်ကတော့ စာကြောင်းနှစ်ခုဟာ မတူညီတဲ့ document နှစ်ခုကနေ လာတာ ဖြစ်ပါတယ်။

ယေဘုယျအားဖြင့်၊ သင်ရဲ့ tokenized inputs တွေထဲမှာ token_type_ids တွေ ပါဝင်သည်ဖြစ်စေ၊ မပါဝင်သည်ဖြစ်စေ သင်စိုးရိမ်ဖို့ မလိုပါဘူး- tokenizer နဲ့ model အတွက် တူညီတဲ့ checkpoint ကို သင်အသုံးပြုနေသရွေ့ အားလုံးအဆင်ပြေမှာပါ၊ ဘာလို့လဲဆိုတော့ tokenizer က သူ့ရဲ့ model ကို ဘာတွေပေးရမယ်ဆိုတာ သိထားလို့ပါ။

အခု ကျွန်တော်တို့ရဲ့ tokenizer က စာကြောင်းအတွဲတစ်ခုကို ဘယ်လိုကိုင်တွယ်နိုင်လဲဆိုတာ သိရှိပြီးတာနဲ့၊ ကျွန်တော်တို့ရဲ့ dataset တစ်ခုလုံးကို tokenize လုပ်ဖို့ အသုံးပြုနိုင်ပါပြီ- ယခင်အခန်း မှာလိုပဲ၊ tokenizer ကို ပထမ sentences list ကို ပေးပြီး၊ နောက်မှ ဒုတိယ sentences list ကို ပေးခြင်းဖြင့် sentences pair list တစ်ခုကို ထည့်သွင်းနိုင်ပါတယ်။ ဒါက Chapter 2 မှာ ကျွန်တော်တို့ တွေ့ခဲ့တဲ့ padding နဲ့ truncation options တွေနဲ့လည်း ကိုက်ညီပါတယ်။ ဒါကြောင့် training dataset ကို preprocessing လုပ်ဖို့ နည်းလမ်းတစ်ခုကတော့…

tokenized_dataset = tokenizer(
    raw_datasets["train"]["sentence1"],
    raw_datasets["train"]["sentence2"],
    padding=True,
    truncation=True,
)

ဒါက ကောင်းကောင်း အလုပ်လုပ်ပါတယ်၊ ဒါပေမယ့် dictionary တစ်ခု (ကျွန်တော်တို့ရဲ့ keys တွေဖြစ်တဲ့ input_ids, attention_mask, နဲ့ token_type_ids တွေနဲ့ list of lists တွေဖြစ်တဲ့ values တွေ) ကို ပြန်ပို့တဲ့ အားနည်းချက် ရှိပါတယ်။ ဒါက tokenization လုပ်စဉ်မှာ သင်ရဲ့ dataset တစ်ခုလုံးကို သိမ်းဆည်းဖို့ RAM လုံလောက်မှသာ အလုပ်လုပ်မှာပါ (🤗 Datasets library က dataset တွေဟာ disk ပေါ်မှာ သိမ်းဆည်းထားတဲ့ Apache Arrow ဖိုင်တွေ ဖြစ်တာကြောင့်၊ သင်တောင်းဆိုထားတဲ့ samples တွေကိုသာ memory ထဲမှာ load လုပ်ထားပါတယ်)။

ဒေတာကို dataset အဖြစ် ဆက်လက်ထားရှိဖို့အတွက်၊ ကျွန်တော်တို့ Dataset.map() method ကို အသုံးပြုပါမယ်။ ဒါက tokenization အပြင် ပိုမို preprocessing လုပ်ဖို့ လိုအပ်ရင် အပိုပြောင်းလွယ်ပြင်လွယ်မှု (flexibility) ကိုလည်း ပေးစွမ်းပါတယ်။ map() method က dataset ရဲ့ element တစ်ခုစီပေါ်မှာ function တစ်ခုကို အသုံးပြုခြင်းဖြင့် အလုပ်လုပ်ပါတယ်၊ ဒါကြောင့် ကျွန်တော်တို့ရဲ့ inputs တွေကို tokenize လုပ်မယ့် function တစ်ခုကို သတ်မှတ်ကြည့်ရအောင်။

def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)

ဒီ function က dictionary တစ်ခု (ကျွန်တော်တို့ရဲ့ dataset ရဲ့ items တွေလိုမျိုး) ကို ယူပြီး input_ids, attention_mask, နဲ့ token_type_ids keys တွေပါတဲ့ dictionary အသစ်တစ်ခုကို ပြန်ပို့ပါတယ်။ example dictionary မှာ samples များစွာ (sentences list တစ်ခုအဖြစ် key တစ်ခုစီ) ပါဝင်နေရင်လည်း အလုပ်လုပ်နိုင်တယ်ဆိုတာ သတိပြုပါ။ ဘာလို့လဲဆိုတော့ tokenizer က အရင်က တွေ့ခဲ့တဲ့အတိုင်း sentences pair list တွေပေါ်မှာ အလုပ်လုပ်လို့ပါပဲ။ ဒါက map() ကို ခေါ်ဆိုတဲ့အခါ batched=True option ကို အသုံးပြုနိုင်စေမှာဖြစ်ပြီး၊ ဒါက tokenization ကို အလွန်မြန်ဆန်စေပါလိမ့်မယ်။ tokenizer ဟာ 🤗 Tokenizers library မှ Rust ဘာသာနဲ့ ရေးထားတဲ့ tokenizer တစ်ခုရဲ့ အထောက်အပံ့နဲ့ အလုပ်လုပ်ပါတယ်။ ဒီ tokenizer က အလွန်မြန်ဆန်နိုင်ပါတယ်၊ ဒါပေမယ့် inputs တွေအများကြီးကို တစ်ပြိုင်နက်တည်း ပေးပို့မှသာ ဖြစ်ပါတယ်။

ကျွန်တော်တို့ရဲ့ tokenization function ထဲမှာ padding argument ကို အခုတော့ ချန်ထားခဲ့တယ်ဆိုတာ သတိပြုပါ။ ဒါက samples အားလုံးကို အများဆုံး အရှည်အထိ padding လုပ်တာက ထိရောက်မှု မရှိလို့ပါပဲ- batch တစ်ခုကို တည်ဆောက်တဲ့အခါ samples တွေကို padding လုပ်တာက ပိုကောင်းပါတယ်။ ဘာလို့လဲဆိုတော့ အဲဒီအခါမှာ batch ထဲက အများဆုံး အရှည်အထိသာ padding လုပ်ဖို့ လိုအပ်ပြီး dataset တစ်ခုလုံးရဲ့ အများဆုံး အရှည်အထိ မဟုတ်ပါဘူး။ ဒါက inputs တွေမှာ အရှည်တွေ အလွန်မတူညီတဲ့အခါ အချိန်နဲ့ processing power အများကြီးကို သက်သာစေနိုင်ပါတယ်!

📚 စွမ်းဆောင်ရည် မြှင့်တင်ရေး အကြံပြုချက်များ: ထိရောက်သော ဒေတာ စီမံဆောင်ရွက်မှု နည်းလမ်းများအကြောင်း ပိုမိုသိရှိလိုပါက 🤗 Datasets performance guide ကို လေ့လာပါ။

ဒီမှာ ကျွန်တော်တို့ရဲ့ datasets အားလုံးပေါ်မှာ tokenization function ကို တစ်ပြိုင်နက်တည်း ဘယ်လို အသုံးပြုရမယ်ဆိုတာကို ပြသထားပါတယ်။ map ကို ခေါ်ဆိုတဲ့အခါ batched=True ကို ကျွန်တော်တို့ အသုံးပြုထားတာကြောင့် function ကို ကျွန်တော်တို့ရဲ့ dataset ရဲ့ element အများအပြားပေါ်မှာ တစ်ပြိုင်နက်တည်း အသုံးပြုတာဖြစ်ပြီး၊ element တစ်ခုစီပေါ်မှာ သီးခြားစီ မဟုတ်ပါဘူး။ ဒါက preprocessing ကို ပိုမိုမြန်ဆန်စေပါတယ်။

tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
tokenized_datasets

🤗 Datasets library က ဒီ processing ကို အသုံးပြုတဲ့ နည်းလမ်းကတော့ preprocessing function က ပြန်ပို့တဲ့ dictionary ထဲက key တစ်ခုစီအတွက် dataset တွေဆီကို fields အသစ်တွေ ထည့်သွင်းပေးတာပါပဲ။

DatasetDict({
    train: Dataset({
        features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'],
        num_rows: 3668
    })
    validation: Dataset({
        features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'],
        num_rows: 408
    })
    test: Dataset({
        features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'],
        num_rows: 1725
    })
})

map() နဲ့ သင်ရဲ့ preprocessing function ကို အသုံးပြုတဲ့အခါ num_proc argument ကို ထည့်သွင်းပေးခြင်းဖြင့် multiprocessing ကိုတောင် အသုံးပြုနိုင်ပါတယ်။ 🤗 Tokenizers library က ကျွန်တော်တို့ရဲ့ samples တွေကို ပိုမိုမြန်ဆန်စွာ tokenize လုပ်ဖို့ threads များစွာကို အသုံးပြုပြီးသား ဖြစ်တာကြောင့် ဒီနေရာမှာ ကျွန်တော်တို့ ဒါကို မလုပ်ခဲ့ပါဘူး။ ဒါပေမယ့် သင် ဒီ library ရဲ့ အထောက်အပံ့မပါတဲ့ fast tokenizer ကို အသုံးမပြုဘူးဆိုရင်တော့ ဒါက သင်ရဲ့ preprocessing ကို အရှိန်မြှင့်ပေးနိုင်ပါတယ်။

ကျွန်တော်တို့ရဲ့ tokenize_function က input_ids, attention_mask, နဲ့ token_type_ids keys တွေပါတဲ့ dictionary တစ်ခုကို ပြန်ပို့တာကြောင့် အဲဒီ fields သုံးခုကို ကျွန်တော်တို့ရဲ့ dataset ရဲ့ splits အားလုံးဆီကို ထည့်သွင်းပါတယ်။ ကျွန်တော်တို့ရဲ့ preprocessing function က map() အသုံးပြုထားတဲ့ dataset ထဲက လက်ရှိ key တစ်ခုအတွက် value အသစ်တစ်ခုကို ပြန်ပို့မယ်ဆိုရင် လက်ရှိ fields တွေကို ပြောင်းလဲနိုင်တယ်ဆိုတာလည်း သတိပြုပါ။

နောက်ဆုံးလုပ်ဆောင်ရမယ့်အရာကတော့ elements တွေကို batch လုပ်တဲ့အခါ samples အားလုံးကို အရှည်ဆုံး element ရဲ့ အရှည်အထိ padding လုပ်ဖို့ပါပဲ - ဒါကို dynamic padding လို့ ကျွန်တော်တို့ ခေါ်ပါတယ်။

Dynamic padding

batch ထဲမှာ samples တွေကို ပေါင်းစည်းပေးတဲ့ function ကို collate function လို့ခေါ်ပါတယ်။ ဒါဟာ DataLoader တစ်ခုကို သင်တည်ဆောက်တဲ့အခါ ထည့်သွင်းနိုင်တဲ့ argument တစ်ခုဖြစ်ပြီး၊ default အားဖြင့်တော့ သင်ရဲ့ samples တွေကို PyTorch tensors တွေအဖြစ် ပြောင်းလဲပြီး (သင်ရဲ့ elements တွေဟာ lists, tuples, ဒါမှမဟုတ် dictionaries တွေဆိုရင်တော့ recursively) တွဲစပ်ပေးမယ့် function တစ်ခုပါပဲ။ ကျွန်တော်တို့ရဲ့ အခြေအနေမှာတော့ ဒါက ဖြစ်နိုင်မှာ မဟုတ်ပါဘူး၊ ဘာလို့လဲဆိုတော့ ကျွန်တော်တို့မှာရှိတဲ့ inputs တွေအားလုံးဟာ size အတူတူ ဖြစ်မှာ မဟုတ်လို့ပါ။ ကျွန်တော်တို့ padding ကို တမင်တကာ နောက်ဆုတ်ထားတာကတော့ batch တစ်ခုစီမှာ လိုအပ်သလောက်သာ အသုံးပြုဖို့နဲ့ padding အများကြီးပါတဲ့ အလွန်ရှည်လျားတဲ့ inputs တွေ မရှိအောင် ရှောင်ရှားဖို့ပါပဲ။ ဒါက training ကို အတော်လေး အရှိန်မြှင့်ပေးပါလိမ့်မယ်၊ ဒါပေမယ့် သင် TPU ပေါ်မှာ လေ့ကျင့်နေတယ်ဆိုရင် ပြဿနာတွေ ဖြစ်စေနိုင်တယ်ဆိုတာ သတိပြုပါ - TPUs တွေက fixed shapes တွေကို ပိုနှစ်သက်ပါတယ်၊ အပို padding လိုအပ်နေရင်တောင်မှပေါ့။

🚀 Optimization လမ်းညွှန်: Training စွမ်းဆောင်ရည်ကို မြှင့်တင်ခြင်းဆိုင်ရာ အသေးစိတ်အချက်အလက်များအတွက်၊ padding strategies များနှင့် TPU ထည့်သွင်းစဉ်းစားမှုများအပါအဝင် 🤗 Transformers performance documentation ကို ကြည့်ရှုပါ။

ဒါကို လက်တွေ့မှာ လုပ်ဆောင်ဖို့အတွက်၊ ကျွန်တော်တို့ batch လုပ်ချင်တဲ့ dataset ရဲ့ items တွေဆီကို မှန်ကန်တဲ့ padding ပမာဏကို အသုံးပြုပေးမယ့် collate function တစ်ခုကို သတ်မှတ်ရပါမယ်။ ကံကောင်းစွာနဲ့ပဲ၊ 🤗 Transformers library က ကျွန်တော်တို့ကို DataCollatorWithPadding ကနေတစ်ဆင့် ဒီလို function တစ်ခု ပေးစွမ်းပါတယ်။ ဒါကို သင် instantiate လုပ်တဲ့အခါ tokenizer တစ်ခုကို ယူပါတယ် (ဘယ် padding token ကို အသုံးပြုရမယ်၊ model က inputs ရဲ့ ဘယ်ဘက် ဒါမှမဟုတ် ညာဘက်မှာ padding ကို မျှော်လင့်ထားသလား သိရှိဖို့) ပြီးတော့ သင်လိုအပ်တဲ့အရာအားလုံးကို လုပ်ဆောင်ပေးပါလိမ့်မယ်-

from transformers import DataCollatorWithPadding

data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

ဒီကိရိယာအသစ်ကို စမ်းသပ်ဖို့အတွက်၊ ကျွန်တော်တို့ရဲ့ training set ကနေ batch လုပ်ချင်တဲ့ samples အနည်းငယ်ကို ယူလိုက်ရအောင်။ ဒီနေရာမှာ ကျွန်တော်တို့ idx, sentence1, နဲ့ sentence2 columns တွေကို ဖယ်ရှားလိုက်ပါတယ်၊ ဘာလို့လဲဆိုတော့ ၎င်းတို့ဟာ မလိုအပ်တော့တဲ့အပြင် strings တွေ ပါဝင်နေလို့ပါ (strings တွေနဲ့ tensors တွေ ဖန်တီးလို့ မရပါဘူး) ပြီးတော့ batch ထဲက entry တစ်ခုစီရဲ့ အရှည်တွေကို ကြည့်ရအောင်-

samples = tokenized_datasets["train"][:8]
samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "sentence2"]}
[len(x) for x in samples["input_ids"]]
[50, 59, 47, 67, 59, 50, 62, 32]

အံ့သြစရာမရှိပါဘူး၊ ၃၂ ကနေ ၆၇ အထိ အရှည်အမျိုးမျိုးရှိတဲ့ samples တွေကို ကျွန်တော်တို့ ရရှိပါတယ်။ Dynamic padding ဆိုတာက ဒီ batch ထဲက samples တွေအားလုံးကို batch ထဲမှာ အများဆုံး အရှည်ဖြစ်တဲ့ ၆၇ အထိ padding လုပ်သင့်တယ်လို့ ဆိုလိုတာပါ။ Dynamic padding မပါရင်၊ samples အားလုံးကို dataset တစ်ခုလုံးရဲ့ အများဆုံး အရှည်အထိ ဒါမှမဟုတ် model က လက်ခံနိုင်တဲ့ အများဆုံး အရှည်အထိ padding လုပ်ရပါလိမ့်မယ်။ ကျွန်တော်တို့ရဲ့ data_collator က batch ကို ကောင်းကောင်း dynamic padding လုပ်နေလားဆိုတာကို ထပ်စစ်ဆေးကြည့်ရအောင်-

batch = data_collator(samples)
{k: v.shape for k, v in batch.items()}
{'attention_mask': torch.Size([8, 67]),
 'input_ids': torch.Size([8, 67]),
 'token_type_ids': torch.Size([8, 67]),
 'labels': torch.Size([8])}

ကောင်းပြီ! အခု ကျွန်တော်တို့ဟာ raw text ကနေ model က ကိုင်တွယ်နိုင်တဲ့ batches တွေအထိ ရောက်ရှိသွားပြီ ဖြစ်တာကြောင့်၊ model ကို fine-tune လုပ်ဖို့ အဆင်သင့်ဖြစ်ပါပြီ။

✏️ စမ်းသပ်ကြည့်ပါ။ GLUE SST-2 dataset ပေါ်မှာ preprocessing ကို ပြန်လုပ်ပါ။ ဒါက single sentences တွေနဲ့ ဖွဲ့စည်းထားတဲ့အတွက် အနည်းငယ် ကွာခြားမှု ရှိပေမယ့်၊ ကျွန်တော်တို့ လုပ်ခဲ့တဲ့ ကျန်တာတွေကတော့ အတူတူပါပဲ။ ပိုမိုခက်ခဲတဲ့ စိန်ခေါ်မှုအတွက်၊ GLUE task တစ်ခုခုပေါ်မှာ အလုပ်လုပ်နိုင်မယ့် preprocessing function တစ်ခု ရေးကြည့်ပါ။

📖 ထပ်ဆောင်းလေ့ကျင့်မှုများ: 🤗 Transformers examples မှ ဤလက်တွေ့ဥပမာများကို ကြည့်ရှုပါ။

ကောင်းပါပြီ။ အခု ကျွန်တော်တို့ရဲ့ ဒေတာကို 🤗 Datasets library မှ နောက်ဆုံးပေါ် အကောင်းဆုံးနည်းလမ်းများဖြင့် preprocessing လုပ်ပြီးသွားပြီ ဖြစ်တာကြောင့်၊ ခေတ်မီ Trainer API ကို အသုံးပြုပြီး ကျွန်တော်တို့ရဲ့ model ကို လေ့ကျင့်ဖို့ အသင့်ဖြစ်ပါပြီ။ နောက်အပိုင်းမှာ Hugging Face ecosystem မှာ ရရှိနိုင်တဲ့ နောက်ဆုံးပေါ် features တွေနဲ့ optimization တွေကို အသုံးပြုပြီး သင်ရဲ့ model ကို ထိရောက်စွာ fine-tune လုပ်နည်းကို ပြသပေးပါလိမ့်မယ်။

အခန်း၏ ဗဟုသုတစစ်ဆေးခြင်း

ဒေတာ စီမံဆောင်ရွက်မှု သဘောတရားများကို သင့်နားလည်မှုကို စမ်းသပ်ပါ-

1. Dataset.map() ကို batched=True နဲ့ အသုံးပြုခြင်းရဲ့ အဓိကအားသာချက်က ဘာလဲ။

2. dataset ထဲက sequences အားလုံးကို အများဆုံးအရှည်အထိ padding လုပ်တာထက် dynamic padding ကို ဘာကြောင့် အသုံးပြုတာလဲ။

3. BERT tokenization မှာ token_type_ids field က ဘာကို ကိုယ်စားပြုလဲ။

4. load_dataset('glue', 'mrpc') နဲ့ dataset တစ်ခုကို loading လုပ်တဲ့အခါ၊ ဒုတိယ argument က ဘာကို သတ်မှတ်သလဲ။

5. Training မလုပ်ခင် ‘sentence1’ နဲ့ ‘sentence2’ လို columns တွေကို ဖယ်ရှားခြင်းရဲ့ ရည်ရွယ်ချက်က ဘာလဲ။

💡 အဓိက အချက်များ:

  • သိသိသာသာ မြန်ဆန်သော preprocessing အတွက် Dataset.map() ကို batched=True ဖြင့် အသုံးပြုပါ။
  • DataCollatorWithPadding ပါသော Dynamic padding သည် fixed-length padding ထက် ပိုမိုထိရောက်သည်။
  • သင်၏ model မျှော်လင့်ထားသည့်အတိုင်း (numerical tensors, မှန်ကန်သော column names) ဒေတာများကို အမြဲ preprocessing လုပ်ပါ။
  • 🤗 Datasets library သည် ဒေတာများကို ပမာဏကြီးမားစွာ ထိရောက်စွာ စီမံဆောင်ရွက်ရန်အတွက် အစွမ်းထက်သော ကိရိယာများကို ပံ့ပိုးပေးသည်။

ဝေါဟာရ ရှင်းလင်းချက် (Glossary)

  • Inference: လေ့ကျင့်ပြီးသား Artificial Intelligence (AI) မော်ဒယ်တစ်ခုကို အသုံးပြုပြီး input data ကနေ ခန့်မှန်းချက်တွေ ဒါမှမဟုတ် output တွေကို ထုတ်လုပ်တဲ့ လုပ်ငန်းစဉ်။
  • Sequence Classifier: စာသား sequence တစ်ခုကို သတ်မှတ်ထားသော အမျိုးအစားများထဲသို့ ခွဲခြားရန် လေ့ကျင့်ထားသော AI မော်ဒယ်။
  • Batch: မတူညီသော input များစွာကို တစ်ပြိုင်နက်တည်း လုပ်ဆောင်နိုင်ရန် အုပ်စုဖွဲ့ခြင်း။
  • torch.optim.AdamW: PyTorch မှာ အသုံးပြုတဲ့ AdamW optimizer။ Model ၏ parameters များကို training လုပ်ရာမှာ အသုံးပြုသည်။
  • torch.tensor: PyTorch framework မှာ data များကို သိမ်းဆည်းရန် အသုံးပြုတဲ့ multi-dimensional array (tensor) တစ်ခုကို ဖန်တီးသော function။
  • model.parameters(): model ၏ လေ့ကျင့်နိုင်သော parameters (weights နှင့် biases) များကို ပြန်ပေးသော method။
  • loss: Model ၏ ခန့်မှန်းချက်များနှင့် အမှန်တကယ် labels များကြား ကွာခြားမှုကို တိုင်းတာသော တန်ဖိုး။
  • loss.backward(): PyTorch မှာ backpropagation ကို လုပ်ဆောင်ပြီး model ၏ parameters တွေအတွက် gradients များကို တွက်ချက်သော method။
  • optimizer.step(): တွက်ချက်ထားသော gradients များကို အသုံးပြုပြီး model ၏ parameters များကို update လုပ်သော optimizer method။
  • MRPC (Microsoft Research Paraphrase Corpus) Dataset: ဝီလျံ ဘီ. ဒိုလန်နှင့် ခရစ် ဘရော့ခ်က်တို့က မိတ်ဆက်ခဲ့သော dataset တစ်ခုဖြစ်ပြီး၊ စာကြောင်းအတွဲများတွင် ၎င်းတို့သည် အဓိပ္ပာယ်တူညီသော paraphrase များ ဟုတ်မဟုတ်ကို ဖော်ပြထားသည်။
  • Paraphrase: အဓိပ္ပာယ်တူညီသော စကားလုံးများ သို့မဟုတ် စာကြောင်းများ။
  • Hugging Face Hub: AI မော်ဒယ်တွေ၊ datasets တွေနဲ့ demo တွေကို အခြားသူတွေနဲ့ မျှဝေဖို့၊ ရှာဖွေဖို့နဲ့ ပြန်လည်အသုံးပြုဖို့အတွက် အွန်လိုင်း platform တစ်ခု ဖြစ်ပါတယ်။
  • GLUE Benchmark: စာသားခွဲခြားသတ်မှတ်ခြင်း လုပ်ငန်း ၁၀ ခုတွင် ML model များ၏ စွမ်းဆောင်ရည်ကို တိုင်းတာရန် အသုံးပြုသည့် academic benchmark တစ်ခု။
  • 🤗 Datasets Library: Hugging Face က ထုတ်လုပ်ထားတဲ့ library တစ်ခုဖြစ်ပြီး AI မော်ဒယ်တွေ လေ့ကျင့်ဖို့အတွက် ဒေတာအစုအဝေး (datasets) တွေကို လွယ်လွယ်ကူကူ ဝင်ရောက်ရယူ၊ စီမံခန့်ခွဲပြီး အသုံးပြုနိုင်စေပါတယ်။
  • load_dataset() Function: Hugging Face Datasets library မှ dataset များကို download လုပ်ပြီး cache လုပ်ရန် အသုံးပြုသော function။
  • DatasetDict Object: Training set, validation set, နှင့် test set ကဲ့သို့သော dataset အများအပြားကို dictionary ပုံစံဖြင့် သိမ်းဆည်းထားသော object။
  • Training Set: Model ကို လေ့ကျင့်ရန်အတွက် အသုံးပြုသော dataset အပိုင်း။
  • Validation Set: Training လုပ်နေစဉ် model ၏ စွမ်းဆောင်ရည်ကို အကဲဖြတ်ရန် အသုံးပြုသော dataset အပိုင်း။
  • Test Set: Model ၏ နောက်ဆုံး စွမ်းဆောင်ရည်ကို တိုင်းတာရန် အသုံးပြုသော dataset အပိုင်း။
  • HF_HOME Environment Variable: Hugging Face library များမှ cache ဖိုင်များကို သိမ်းဆည်းမည့် နေရာကို သတ်မှတ်ရန် အသုံးပြုသော environment variable။
  • raw_datasets["train"]: DatasetDict object မှ training set ကို ဝင်ရောက်ကြည့်ရှုခြင်း။
  • raw_train_dataset.features: Dataset ၏ columns များ၏ အမျိုးအစားများနှင့် အချက်အလက်များကို ပြန်ပေးသော property။
  • ClassLabel: Categorical labels များကို ကိုင်တွယ်ရန် 🤗 Datasets library မှ အသုံးပြုသော feature type။
  • Tokenizer: စာသား (သို့မဟုတ် အခြားဒေတာ) ကို AI မော်ဒယ်များ စီမံဆောင်ရွက်နိုင်ရန် tokens တွေအဖြစ် ပိုင်းခြားပေးသည့် ကိရိယာ သို့မဟုတ် လုပ်ငန်းစဉ်။
  • AutoTokenizer: Hugging Face Transformers library မှာ ပါဝင်တဲ့ class တစ်ခုဖြစ်ပြီး မော်ဒယ်အမည်ကို အသုံးပြုပြီး သက်ဆိုင်ရာ tokenizer ကို အလိုအလျောက် load လုပ်ပေးသည်။
  • Pretrained: Model တစ်ခုကို အကြီးစားဒေတာများဖြင့် အစောပိုင်းကတည်းက လေ့ကျင့်ထားခြင်း။
  • input_ids: Tokenizer မှ ထုတ်ပေးသော tokens တစ်ခုစီ၏ ထူးခြားသော ဂဏန်းဆိုင်ရာ ID များ။
  • attention_mask: မော်ဒယ်ကို အာရုံစိုက်သင့်သည့် tokens များနှင့် လျစ်လျူရှုသင့်သည့် (padding) tokens များကို ခွဲခြားပေးသည့် binary mask။
  • token_type_ids: Sentence pair လုပ်ငန်းများတွင် input sequence တစ်ခုစီမှ token တစ်ခုစီသည် မည်သည့် sentence (ပထမ သို့မဟုတ် ဒုတိယ) နှင့် သက်ဆိုင်သည်ကို ဖော်ပြပေးသော IDs များ။
  • convert_ids_to_tokens() Method: input IDs များကို tokens များအဖြစ် ပြန်ပြောင်းပေးသော tokenizer method။
  • [CLS] Token: BERT model တွင် sequence ၏ အစကို ကိုယ်စားပြုသော special token။
  • [SEP] Token: BERT model တွင် sentence တစ်ခု၏ အဆုံး သို့မဟုတ် sentence နှစ်ခုကြား ပိုင်းခြားရန် အသုံးပြုသော special token။
  • Masked Language Modeling Objective: BERT ကဲ့သို့သော model များကို လေ့ကျင့်ရာတွင် အသုံးပြုသော task တစ်ခုဖြစ်ပြီး၊ စာကြောင်းထဲမှ စကားလုံးအချို့ကို ဝှက်ထားပြီး ၎င်းတို့ကို ခန့်မှန်းစေသည်။
  • Next Sentence Prediction: BERT ကဲ့သို့သော model များကို လေ့ကျင့်ရာတွင် အသုံးပြုသော task တစ်ခုဖြစ်ပြီး၊ စာကြောင်းနှစ်ကြောင်း ပေးပြီး ဒုတိယစာကြောင်းက ပထမစာကြောင်းနောက်မှာ လိုက်ပါသလားဆိုတာကို ခန့်မှန်းစေသည်။
  • Dataset.map() Method: 🤗 Datasets library မှာ ပါဝင်တဲ့ method တစ်ခုဖြစ်ပြီး dataset ရဲ့ element တစ်ခုစီ ဒါမှမဟုတ် batch တစ်ခုစီပေါ်မှာ function တစ်ခုကို အသုံးပြုနိုင်စေသည်။
  • batched=True: map() method မှာ အသုံးပြုသော argument တစ်ခုဖြစ်ပြီး function ကို dataset ရဲ့ element အများအပြားပေါ်မှာ တစ်ပြိုင်နက်တည်း အသုံးပြုစေသည်။
  • Rust: System programming language တစ်ခုဖြစ်ပြီး performance မြင့်မားသော applications များ တည်ဆောက်ရာတွင် အသုံးပြုသည်။
  • 🤗 Tokenizers Library: Rust ဘာသာနဲ့ ရေးသားထားတဲ့ Hugging Face library တစ်ခုဖြစ်ပြီး မြန်ဆန်ထိရောက်တဲ့ tokenization ကို လုပ်ဆောင်ပေးသည်။
  • Dynamic Padding: Batch တစ်ခုအတွင်းရှိ samples များကို အဲဒီ batch ထဲက အရှည်ဆုံး sample ရဲ့ အရှည်အထိသာ padding လုပ်တဲ့ နည်းလမ်း။
  • Collate Function: DataLoader တစ်ခုမှာ အသုံးပြုတဲ့ function တစ်ခုဖြစ်ပြီး batch တစ်ခုအတွင်း samples တွေကို စုစည်းပေးသည်။
  • DataLoader: Dataset ကနေ data တွေကို batch အလိုက် load လုပ်ပေးတဲ့ PyTorch utility class။
  • PyTorch Tensors: PyTorch framework မှာ data တွေကို ကိုယ်စားပြုသော multi-dimensional array များ။
  • Recursively: ကိုယ်တိုင် ပြန်လည်ခေါ်ဆိုသော လုပ်ငန်းစဉ်။
  • TPU (Tensor Processing Unit): Google မှ AI/ML workloads များအတွက် အထူးဒီဇိုင်းထုတ်ထားသော processor တစ်မျိုး။
  • DataCollatorWithPadding: Hugging Face Transformers library မှ ပံ့ပိုးပေးသော class တစ်ခုဖြစ်ပြီး dynamic padding ကို အသုံးပြု၍ batch တစ်ခုအတွင်း samples များကို စုစည်းပေးသည်။
  • num_proc Argument: map() method မှာ အသုံးပြုသော argument တစ်ခုဖြစ်ပြီး multiprocessing ကို အသုံးပြု၍ preprocessing ကို အရှိန်မြှင့်ရန်။
  • GLUE SST-2 Dataset: GLUE benchmark ထဲက sentiment analysis task တစ်ခုဖြစ်ပြီး single sentences တွေ ပါဝင်ပါတယ်။
  • Trainer API: Hugging Face Transformers library မှ model များကို ထိရောက်စွာ လေ့ကျင့်ရန်အတွက် ဒီဇိုင်းထုတ်ထားသော မြင့်မားသောအဆင့် API။
  • Apache Arrow: In-memory data format တစ်ခုဖြစ်ပြီး data analytics applications တွေကြား ဒေတာဖလှယ်မှုကို မြန်ဆန်စေသည်။
Update on GitHub