Pytorch TensorFlow

Pipeline နောက်ကွယ်မှ အကြောင်းအရာများ

Ask a Question Open In Colab Open In Studio Lab

Chapter 1 မှာ အောက်ပါ code ကို run တဲ့အခါ ဘာတွေဖြစ်ပျက်သွားလဲဆိုတာကို ကြည့်ခြင်းဖြင့် ဥပမာတစ်ခုနဲ့ စလိုက်ရအောင်…။

from transformers import pipeline

classifier = pipeline("sentiment-analysis")
classifier(
    [
        "I've been waiting for a HuggingFace course my whole life.",
        "I hate this so much!",
    ]
)

အောက်ပါရလဒ်ကို ရရှိခဲ့ပါတယ်။

[{'label': 'POSITIVE', 'score': 0.9598047137260437},
 {'label': 'NEGATIVE', 'score': 0.9994558095932007}]

Chapter 1 မှာ ကျွန်တော်တို့ တွေ့ခဲ့ရသလို၊ ဒီ pipeline ဟာ အဆင့်သုံးဆင့်ကို ပေါင်းစပ်ထားပါတယ်၊ preprocessing လုပ်ခြင်း၊ model ကနေတဆင့် inputs တွေကို ပေးပို့ခြင်း၊ နဲ့ postprocessing လုပ်ခြင်းတို့ ဖြစ်ပါတယ်။

The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head.

ဒါတွေကို အမြန်ဆုံး တစ်ခုချင်းစီ လေ့လာကြည့်ရအောင်။

Tokenizer ဖြင့် Preprocessing ပြုလုပ်ခြင်း

အခြား neural network များကဲ့သို့ Transformer မော်ဒယ်များသည် raw text များကို တိုက်ရိုက်လုပ်ဆောင်၍ မရပါ။ ထို့ကြောင့် ကျွန်တော်တို့ pipeline ၏ ပထမအဆင့်မှာ text inputs များကို မော်ဒယ်နားလည်နိုင်သော ဂဏန်းများအဖြစ် ပြောင်းလဲခြင်းဖြစ်သည်။ ၎င်းကို ပြုလုပ်ရန် ကျွန်တော်တို့သည် tokenizer ကို အသုံးပြုပါသည်။ ၎င်းသည် အောက်ပါတို့ကို လုပ်ဆောင်ရန် တာဝန်ရှိသည်-

ဒီ preprocessing အားလုံးကို မော်ဒယ်ကို pre-trained လုပ်ခဲ့စဉ်က အတိအကျလုပ်ခဲ့တဲ့ နည်းလမ်းအတိုင်း ပြုလုပ်ဖို့ လိုအပ်ပါတယ်။ ဒါကြောင့် ကျွန်တော်တို့ အရင်ဆုံး Model Hub ကနေ အဲဒီအချက်အလက်တွေကို download လုပ်ဖို့ လိုပါတယ်။ ဒါကို လုပ်ဖို့အတွက် AutoTokenizer class နဲ့ သူ့ရဲ့ from_pretrained() method ကို ကျွန်တော်တို့ အသုံးပြုပါတယ်။ ကျွန်တော်တို့ model ရဲ့ checkpoint name ကို အသုံးပြုပြီး၊ ၎င်းသည် model ရဲ့ tokenizer နဲ့ ဆက်စပ်နေတဲ့ ဒေတာတွေကို အလိုအလျောက် ရယူပြီး cache လုပ်ပါလိမ့်မယ် (ဒါကြောင့် အောက်က code ကို ပထမဆုံးအကြိမ် run မှသာ download လုပ်ပါလိမ့်မယ်)။

sentiment-analysis pipeline ရဲ့ default checkpoint က distilbert-base-uncased-finetuned-sst-2-english ဖြစ်တာကြောင့် (၎င်းရဲ့ model card ကို ဒီနေရာမှာ ကြည့်နိုင်ပါတယ်)၊ အောက်ပါ code ကို ကျွန်တော်တို့ run ပြုလုပ်ပေးပါတယ်။

from transformers import AutoTokenizer

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

tokenizer ကို ရရှိပြီဆိုတာနဲ့၊ ကျွန်တော်တို့ရဲ့ စာကြောင်းတွေကို တိုက်ရိုက် ပေးပို့နိုင်ပြီး model ကို ထည့်သွင်းဖို့ အဆင်သင့်ဖြစ်နေတဲ့ dictionary တစ်ခု ပြန်ရပါလိမ့်မယ်။ လုပ်ဆောင်ဖို့ ကျန်ရှိတာကတော့ input IDs တွေရဲ့ list ကို tensors တွေအဖြစ် ပြောင်းလဲဖို့ပါပဲ။

သင်ဟာ backend မှာ ဘယ် ML framework ကို အသုံးပြုလဲဆိုတာ စိုးရိမ်စရာမလိုဘဲ 🤗 Transformers ကို အသုံးပြုနိုင်ပါတယ်။ အချို့မော်ဒယ်တွေအတွက် PyTorch ဒါမှမဟုတ် Flax ဖြစ်နိုင်ပါတယ်။ သို့သော် Transformer မော်ဒယ်တွေက tensors တွေကိုပဲ input အဖြစ် လက်ခံပါတယ်။ tensors တွေအကြောင်းကို အခုမှ စကြားဖူးတာဆိုရင်၊ ၎င်းတို့ကို NumPy arrays တွေအဖြစ် တွေးကြည့်နိုင်ပါတယ်။ NumPy array တစ်ခုက scalar (0D)၊ vector (1D)၊ matrix (2D) သို့မဟုတ် dimension များစွာရှိနိုင်ပါတယ်။ ဒါက တကယ်တော့ tensor တစ်ခုပါပဲ။ အခြား ML frameworks တွေရဲ့ tensors တွေလည်း အလားတူပဲ အလုပ်လုပ်ပြီး၊ NumPy arrays တွေလိုပဲ လွယ်ကူစွာ instantiate လုပ်နိုင်ပါတယ်။

ကျွန်တော်တို့ ပြန်လိုချင်တဲ့ tensors (PyTorch သို့မဟုတ် plain NumPy) အမျိုးအစားကို သတ်မှတ်ဖို့အတွက် return_tensors argument ကို အသုံးပြုနိုင်ပါတယ်။

raw_inputs = [
    "I've been waiting for a HuggingFace course my whole life.",
    "I hate this so much!",
]
inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt")
print(inputs)

padding နဲ့ truncation အကြောင်းကို အခုထိ စိတ်ပူမနေပါနဲ့၊ ဒါတွေကို နောက်မှ ရှင်းပြပါမယ်။ ဒီနေရာမှာ မှတ်ထားရမယ့် အဓိကအချက်တွေကတော့ သင်ဟာ စာကြောင်းတစ်ကြောင်း ဒါမှမဟုတ် စာကြောင်းများစွာပါတဲ့ list ကို ပေးပို့နိုင်သလို၊ သင်ပြန်လိုချင်တဲ့ tensors အမျိုးအစားကိုလည်း သတ်မှတ်နိုင်ပါတယ် (မည်သည့် type ကိုမျှ မပေးပို့ရင် list of lists အဖြစ် ရလဒ်ရပါလိမ့်မယ်)။

PyTorch tensors အဖြစ် ရလဒ်တွေက အောက်ပါအတိုင်း ဖြစ်ပါတယ်။

{
    'input_ids': tensor([
        [  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172, 2607,  2026,  2878,  2166,  1012,   102],
        [  101,  1045,  5223,  2023,  2061,  2172,   999,   102,     0,     0,     0,     0,     0,     0,     0,     0]
    ]), 
    'attention_mask': tensor([
        [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]
    ])
}

output ကိုယ်တိုင်က input_ids နဲ့ attention_mask ဆိုတဲ့ key နှစ်ခုပါဝင်တဲ့ dictionary တစ်ခု ဖြစ်ပါတယ်။ input_ids မှာ integer row နှစ်ခု (စာကြောင်းတစ်ကြောင်းစီအတွက် တစ်ခု) ပါဝင်ပြီး ၎င်းတို့ဟာ စာကြောင်းတစ်ကြောင်းစီရှိ tokens တွေရဲ့ ထူးခြားတဲ့ identifiers တွေ ဖြစ်ပါတယ်။ attention_mask ဆိုတာ ဘာလဲဆိုတာကို ဒီအခန်းရဲ့ နောက်ပိုင်းမှာ ကျွန်တော်တို့ ရှင်းပြပါမယ်။

Model ကို ဖြတ်သန်းခြင်း

ကျွန်တော်တို့ tokenizer ကို လုပ်ခဲ့သလိုပဲ pre-trained model ကို download လုပ်နိုင်ပါတယ်။ 🤗 Transformers က from_pretrained() method ပါဝင်တဲ့ AutoModel class ကို ပံ့ပိုးပေးပါတယ်။

from transformers import AutoModel

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModel.from_pretrained(checkpoint)

ဒီ code snippet မှာ ကျွန်တော်တို့ဟာ ယခင်က pipeline မှာ အသုံးပြုခဲ့တဲ့ checkpoint အတူတူကို download လုပ်ပြီး model တစ်ခုကို instantiate လုပ်ခဲ့ပါတယ်။ (ဒါကို အမှန်တကယ်တော့ cache လုပ်ထားပြီးသား ဖြစ်သင့်ပါတယ်)။

ဒီ architecture မှာ base Transformer module သာ ပါဝင်ပါတယ်- inputs အချို့ကို ပေးလိုက်တဲ့အခါ ၎င်းသည် hidden states ဟုခေါ်သော အရာများကို ထုတ်ပေးပါတယ်။ ၎င်းတို့ကို features ဟုလည်း ခေါ်ပါတယ်။ model input တစ်ခုစီအတွက် Transformer model က အဲဒီ input ကို အကြောင်းအရာအရ နားလည်ထားမှုကို ကိုယ်စားပြုတဲ့ high-dimensional vector တစ်ခုကို ကျွန်တော်တို့ ပြန်ရပါလိမ့်မယ်။

ဒါကို နားမလည်ရင် စိတ်မပူပါနဲ့။ ဒါတွေကို နောက်မှ အားလုံးရှင်းပြပါမယ်။

ဒီ hidden states တွေက သူ့ဘာသာသူ အသုံးဝင်နိုင်ပေမယ့်၊ ၎င်းတို့ဟာ များသောအားဖြင့် head လို့ခေါ်တဲ့ model ရဲ့ နောက်ထပ်အစိတ်အပိုင်းတစ်ခုရဲ့ inputs တွေ ဖြစ်ပါတယ်။ Chapter 1 မှာ မတူညီတဲ့ လုပ်ငန်းတာဝန်တွေကို architecture တူတူနဲ့ လုပ်ဆောင်နိုင်ခဲ့ပေမယ့်၊ ဒီလုပ်ငန်းတာဝန်တစ်ခုစီမှာ ၎င်းနဲ့ ဆက်စပ်နေတဲ့ head တစ်ခုစီ ရှိပါတယ်။

High-dimensional vector တစ်ခုလား။

Transformer module ကနေ ထုတ်ပေးတဲ့ vector ဟာ များသောအားဖြင့် ကြီးမားပါတယ်။ ဒါက အများအားဖြင့် dimensions သုံးခု ရှိပါတယ်-

နောက်ဆုံးတန်ဖိုးကြောင့် “high dimensional” လို့ ခေါ်တာ ဖြစ်ပါတယ်။ hidden size က အလွန်ကြီးမားနိုင်ပါတယ် (768 က ပိုသေးငယ်တဲ့ မော်ဒယ်တွေအတွက် အများအားဖြင့်ဖြစ်ပြီး၊ ပိုကြီးတဲ့ မော်ဒယ်တွေမှာ ဒါက 3072 ဒါမှမဟုတ် ပိုများနိုင်ပါတယ်)။

ကျွန်တော်တို့ preprocessing လုပ်ထားတဲ့ inputs တွေကို model ကို ပေးပို့ကြည့်ရင် ဒါကို တွေ့နိုင်ပါတယ်။

outputs = model(**inputs)
print(outputs.last_hidden_state.shape)
torch.Size([2, 16, 768])

🤗 Transformers မော်ဒယ်တွေရဲ့ outputs တွေဟာ namedtuple တွေ ဒါမှမဟုတ် dictionaries တွေလို အလုပ်လုပ်တယ်ဆိုတာကို သတိပြုပါ။ attribute တွေ (ကျွန်တော်တို့ လုပ်ခဲ့သလို) ဒါမှမဟုတ် key ( outputs["last_hidden_state"] ) နဲ့ ဒါမှမဟုတ် သင်ရှာနေတဲ့အရာ ဘယ်နေရာမှာရှိတယ်ဆိုတာ အတိအကျသိရင် index ( outputs[0] ) နဲ့ပါ ဝင်ရောက်ကြည့်ရှုနိုင်ပါတယ်။

Model heads: ဂဏန်းတွေကနေ အဓိပ္ပာယ်ထုတ်ယူခြင်း

Model heads တွေက hidden states တွေရဲ့ high-dimensional vector ကို input အဖြစ် ယူပြီး ၎င်းတို့ကို မတူညီတဲ့ dimension တစ်ခုပေါ်သို့ project လုပ်ပါတယ်။ ၎င်းတို့ဟာ များသောအားဖြင့် linear layers တစ်ခု ဒါမှမဟုတ် အနည်းငယ်နဲ့ ဖွဲ့စည်းထားပါတယ်-

A Transformer network alongside its head.

Transformer model ရဲ့ output ကို model head ကို တိုက်ရိုက်ပို့ပြီး လုပ်ဆောင်ပါတယ်။

ဒီပုံမှာ မော်ဒယ်ကို embeddings layer နဲ့ နောက်ဆက်တွဲ layers တွေနဲ့ ကိုယ်စားပြုထားပါတယ်။ embeddings layer က tokenized input ထဲက input ID တစ်ခုစီကို ၎င်းနဲ့ ဆက်စပ်နေတဲ့ token ကို ကိုယ်စားပြုတဲ့ vector တစ်ခုအဖြစ် ပြောင်းလဲပေးပါတယ်။ နောက်ဆက်တွဲ layers တွေက attention mechanism ကို အသုံးပြုပြီး အဲဒီ vectors တွေကို စီမံခန့်ခွဲကာ စာကြောင်းတွေရဲ့ နောက်ဆုံးကိုယ်စားပြုမှုကို ထုတ်ပေးပါတယ်။

🤗 Transformers မှာ မတူညီတဲ့ architecture များစွာ ရရှိနိုင်ပြီး၊ တစ်ခုချင်းစီကို သီးခြားလုပ်ငန်းတစ်ခုကို ဖြေရှင်းဖို့ ဒီဇိုင်းထုတ်ထားပါတယ်။ အောက်ပါတို့ကတော့ မပြည့်စုံသေးသော စာရင်းတစ်ခု ဖြစ်ပါတယ်-

ကျွန်တော်တို့ရဲ့ ဥပမာအတွက်၊ sequence classification head ပါဝင်တဲ့ မော်ဒယ်တစ်ခု လိုအပ်ပါလိမ့်မယ် (စာကြောင်းတွေကို positive သို့မဟုတ် negative အဖြစ် ခွဲခြားသတ်မှတ်နိုင်ဖို့)။ ဒါကြောင့် ကျွန်တော်တို့ဟာ AutoModel class ကို အမှန်တကယ် အသုံးပြုမှာ မဟုတ်ဘဲ AutoModelForSequenceClassification ကို အသုံးပြုပါမယ်။

from transformers import AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(**inputs)

အခု outputs တွေရဲ့ shape ကို ကြည့်လိုက်ရင်၊ dimensionality က အများကြီး နိမ့်သွားပါလိမ့်မယ်၊ model head က ယခင်က ကျွန်တော်တို့ တွေ့ခဲ့တဲ့ high-dimensional vectors တွေကို input အဖြစ် ယူပြီး၊ တန်ဖိုးနှစ်ခု (label တစ်ခုစီအတွက် တစ်ခု) ပါဝင်တဲ့ vectors တွေကို ထုတ်ပေးပါတယ်။

print(outputs.logits.shape)
torch.Size([2, 2])

ကျွန်တော်တို့မှာ စာကြောင်းနှစ်ကြောင်းနဲ့ label နှစ်ခုပဲ ရှိတာကြောင့်၊ ကျွန်တော်တို့ model ကနေ ရရှိတဲ့ ရလဒ်ဟာ 2 x 2 shape ဖြစ်ပါတယ်။

Output ကို Postprocessing ပြုလုပ်ခြင်း

ကျွန်တော်တို့ model ကနေ output အဖြစ် ရရှိတဲ့ တန်ဖိုးတွေက သူ့ဘာသာသူ အဓိပ္ပာယ်ရှိတာ မဟုတ်ပါဘူး။ ကြည့်ကြည့်ရအောင်။

print(outputs.logits)
tensor([[-1.5607,  1.6123],
        [ 4.1692, -3.3464]], grad_fn=<AddmmBackward>)

ကျွန်တော်တို့ရဲ့ model က ပထမစာကြောင်းအတွက် [-1.5607, 1.6123] ကို ခန့်မှန်းခဲ့ပြီး၊ ဒုတိယစာကြောင်းအတွက် [ 4.1692, -3.3464] ကို ခန့်မှန်းခဲ့ပါတယ်။ ဒါတွေက ဖြစ်နိုင်ခြေတွေ မဟုတ်ဘဲ logits တွေ ဖြစ်ပါတယ်။ ၎င်းတို့က model ရဲ့ နောက်ဆုံး layer ကနေ ထုတ်ပေးတဲ့ raw, unnormalized scores တွေပါ။ ဖြစ်နိုင်ခြေတွေအဖြစ် ပြောင်းလဲဖို့အတွက် SoftMax layer ကို ဖြတ်သန်းဖို့ လိုအပ်ပါတယ် (🤗 Transformers model အားလုံးက logits တွေကို ထုတ်ပေးပါတယ်၊ ဘာလို့လဲဆိုတော့ training အတွက် loss function က SoftMax လိုမျိုး နောက်ဆုံး activation function နဲ့ cross entropy လိုမျိုး loss function အမှန်တကယ်ကို ပေါင်းစပ်ထားတာ ဖြစ်လေ့ရှိပါတယ်)။

import torch

predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
print(predictions)
tensor([[4.0195e-02, 9.5980e-01],
        [9.9946e-01, 5.4418e-04]], grad_fn=<SoftmaxBackward>)

အခု ကျွန်တော်တို့ model က ပထမစာကြောင်းအတွက် [0.0402, 0.9598] ကို ခန့်မှန်းခဲ့ပြီး၊ ဒုတိယစာကြောင်းအတွက် [0.9995, 0.0005] ကို ခန့်မှန်းခဲ့တယ်ဆိုတာ တွေ့ရပါပြီ။ ဒါတွေက အသိအမှတ်ပြုနိုင်တဲ့ ဖြစ်နိုင်ခြေ scores တွေ ဖြစ်ပါတယ်။

position တစ်ခုစီနဲ့ ကိုက်ညီတဲ့ labels တွေကို ရယူဖို့အတွက် model config ရဲ့ id2label attribute ကို စစ်ဆေးနိုင်ပါတယ် (ဒီအကြောင်းကို နောက်အပိုင်းမှာ ပိုမိုသိရှိရပါလိမ့်မယ်)။

model.config.id2label
{0: 'NEGATIVE', 1: 'POSITIVE'}

Nအခု ကျွန်တော်တို့ model က အောက်ပါအတိုင်း ခန့်မှန်းခဲ့တယ်လို့ ကောက်ချက်ချနိုင်ပါပြီ-

ကျွန်တော်တို့ pipeline ရဲ့ အဆင့်သုံးဆင့်လုံးကို အောင်မြင်စွာ ပြန်လည်ဖန်တီးနိုင်ခဲ့ပါပြီ- tokenizers တွေနဲ့ preprocessing လုပ်ခြင်း၊ model ကနေတဆင့် inputs တွေကို ပေးပို့ခြင်း၊ နဲ့ postprocessing လုပ်ခြင်းတို့ ဖြစ်ပါတယ်။ အခုတော့ ဒီအဆင့်တစ်ခုချင်းစီကို ပိုပြီး နက်နက်နဲနဲ လေ့လာကြည့်ရအောင်။

✏️ စမ်းသပ်ကြည့်ပါ။ သင်ကိုယ်တိုင် စာသား (၂) ခု (သို့မဟုတ် ပိုမိုများပြား) ရွေးချယ်ပြီး sentiment-analysis pipeline ကနေတဆင့် run ပါ။ ထို့နောက် ဒီနေရာမှာ သင်တွေ့ခဲ့ရတဲ့ အဆင့်တွေကို ကိုယ်တိုင်ပြန်လုပ်ပြီး တူညီတဲ့ ရလဒ်တွေ ရရှိမရရှိ စစ်ဆေးပါ။

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

Update on GitHub