Doctor AI

Dr. Savath Saypadith

240 ບົດຄວາມ

ການສ້າງຕົວຕັດຄໍາພາສາລາວແບບກໍານົດເອງ (Custom Lao Tokenizer) ໂດຍໃຊ້ກົດເກນຂອງພະຍາງ

ໂພສເມື່ອ # Natural Language Processing # Machine Learning # Rule-based Systems # Deep Learning

ການສ້າງສູດຕັດຄໍາພາສາລາວ (Custom Lao Tokenizer) ໂດຍອີງໃສ່ກົດເກນຂອງພະຍາງ

ການປະມວນຜົນພາສາທຳມະຊາດ (Natural Language Processing ຫຼື NLP) ສຳລັບພາສາລາວ ມີສິ່ງທ້າທາຍທີ່ເປັນເອກະລັກສະເພາະຕົວ: ພາສາລາວເປັນພາສາທີ່ບໍ່ມີການຍະຫວ່າງລະຫວ່າງຄຳສັບ (Scriptio Continua). ເມື່ອເຮົາຕ້ອງການສອນໃຫ້ AI ເຂົ້າໃຈຂໍ້ມູນທ້ອງຖິ່ນ ບໍ່ວ່າຈະເປັນການວິເຄາະຄວາມຄິດເຫັນກ່ຽວກັບສະພາບການຈະລາຈອນນະຄອນຫຼວງວຽງຈັນ, ການພະຍາກອນລະດັບນໍ້າຂອງ, ຫຼື ການສ້າງ Chatbot ໃຫ້ກັບທຸລະກິດ SMEs ພາຍໃນປະເທດ, ຂັ້ນຕອນທໍາອິດແລະເປັນຂັ້ນຕອນທີ່ສໍາຄັນທີ່ສຸດແມ່ນ ການຕັດຄຳ (Tokenization).

ໃນລະດັບ Advanced, ການເພິ່ງພາພຽງແຕ່ Dictionary-based Tokenizer (ການຕັດຄຳຕາມວັດຈະນານຸກົມ) ສາມາດເຮັດໃຫ້ເກີດບັນຫາ Out-of-Vocabulary (OOV) ເມື່ອພົບຄໍາສັບໃໝ່ໆ. ວິທີທີ່ຊົງພະລັງກວ່າໃນການກຽມຂໍ້ມູນກ່ອນນຳໄປຝຶກໃນໂມເດວ LLMs (ເຊັ່ນ: ການເຮັດ BPE ຫຼື WordPiece) ແມ່ນການສ້າງຕັດຄຳໃນລະດັບ ພະຍາງ (Syllable-level Tokenizer) ໂດຍໃຊ້ Regular Expressions (RegEx) ບວກກັບ ກົດເກນທາງພາສາສາດຂອງລາວ.

ບົດຄວາມນີ້ຈະພາທ່ານລົງເລິກເຖິງວິທີການກຳນົດໂຄງສ້າງພະຍາງພາສາລາວ ແລະ ການຂຽນ Python ຈຳລອງ Tokenizer ແບບກຳນົດເອງ (Custom) ເພື່ອນຳໄປໃຊ້ໃນ Pipeline ຂອງ Machine Learning.

ວິເຄາະໂຄງສ້າງຂອງພະຍາງພາສາລາວ (Lao Syllable Morphology)

ເພື່ອທີ່ຈະຂຽນຄວາມໝາຍຂອງ RegEx ໃຫ້ຖືກຕ້ອງ, ເຮົາຕ້ອງເຂົ້າໃຈໂຄງສ້າງທາງພາສາສາດຂອງພະຍາງລາວກ່ອນ. ພະຍາງລາວໜຶ່ງໆ ໂດຍທົ່ວໄປຈະປະກອບດ້ວຍອົງປະກອບດັ່ງນີ້:

[ສະຫຼະໜ້າ]? + [ພະຍັນຊະນະເຄົ້າ] + [ພະຍັນຊະນະຄວບ]? + [ສະຫຼະເທິງ/ລຸ່ມ/ຫຼັງ]? + [ວັນນະຍຸດ]? + [ຕົວສະກົດ]? + [ສະຫຼະພິເສດ/ກາລັນ]?

ການກຳນົດ Unicode Blocks ແລະ Regular Expressions

ພາສາລາວໃນລະບົບ Unicode ຈັດຢູ່ໃນຊ່ວງ \u0E80 ຫາ \u0EFF. ເຮົາສາມາດແບ່ງກຸ່ມ (Capture Groups) ເພື່ອສ້າງ Regular Expression ດັ່ງນີ້:

import re

# 1. ໝວດພະຍັນຊະນະ (Consonants)
cons = r'[\u0E81-\u0EAE\u0EDC-\u0EDD]' # ກ-ຮ, ໜ, ໝ

# 2. ໝວດສະຫຼະໜ້າ (Front Vowels)
front_vowels = r'[\u0EC0-\u0EC4]'     # ເ, ແ, ໂ, ໃ, ໄ

# 3. ໝວດສະຫຼະເທິງ-ລຸ່ມ-ຫຼັງ (Top/Bottom/Back Vowels) 
dependent_vowels = r'[\u0EB0-\u0EB9\u0EBB-\u0EBD]' 

# 4. ໝວດວັນນະຍຸດ (Tone Marks)
tones = r'[\u0EC8-\u0ECB]'            # ່, ້, ໊, ໋

# 5. ໝວດເຄື່ອງໝາຍພິເສດ ແລະ ກາລັນ (Special Marks & Cancellation)
cancellation = r'[\u0ECC]'            # ໌ (ໄມ້ກາລັນ)
nikkahit = r'[\u0ECD]'                # ໍ (ນິກຄະຫິດ)

# ປະກອບເຂົ້າກັນເປັນ Syllable Rule ສໍາລັບພາສາລາວ
# Pattern ຫຼັກ: (ສະຫຼະໜ້າ)? (ພະຍັນຊະນະ) (ພະຍັນຊະນະຄວບ)? (ສະຫຼະ)? (ວັນນະຍຸດ)? (ກາລັນ)? (ຕົວສະກົດ)?
lao_syllable_pattern = re.compile(
    f"({front_vowels}?"
    f"{cons}{{1,2}}"
    f"{dependent_vowels}*"
    f"{nikkahit}?"
    f"{tones}?"
    f"{cancellation}?"
    f"{cons}?)"
)

ຂໍ້ຄວນລະວັງ (Edge Cases): ພາສາລາວມີຄວາມຊັບຊ້ອນໃນຄໍາທີ່ມີສະຫຼະປະສົມ ຫຼື ຄໍາທີ່ມີສະຫຼະເຊື່ອງຮູບ ເຊັ່ນ: “ຂົນສົ່ງ” (ຂ-ົ-ນ-ສ-ົ-່-ງ). ກົດເກນ RegEx ຂ້າງເທິງອາດຈະກວມເອົາບາງກໍລະນີບໍ່ຄົບຮ້ອຍເປີເຊັນ, ແຕ່ມັນເຮັດວຽກໄດ້ດີຫຼາຍສໍາລັບການແຍກ Sub-word.

ການພັດທະນາ Syllable Tokenizer Class ດ້ວຍ Python

ລອງມາເບິ່ງການນຳໃຊ້ຕົວຈິງ ໃນການສ້າງ Class ສຳລັບ Tokenizer ທີ່ສາມາດແຍກທັງພາສາລາວ, ໂຕເລກ ແລະ ຄຳສັບພາສາອັງກິດ (ເຊັ່ນ: AI, SMEs) ທີ່ມັກຈະປົນກັນມາໃນຂໍ້ມູນຕົວຈິງຈາກ Social Media.

import re

class LaoSyllableTokenizer:
    def __init__(self):
        # ກໍານົດ Regular Expressions ເພື່ອຈັບຄູ່ Pattern
        self.lao_regex = re.compile(
            r'([\u0EC0-\u0EC4]?[\u0E81-\u0EAE\u0EDC-\u0EDD]{1,2}'
            r'[\u0EB0-\u0EB9\u0EBB-\u0EBD]*[\u0ECD]?[\u0EC8-\u0ECB]?[\u0ECC]?[\u0E81-\u0EAE\u0EDC-\u0EDD]?)'
        )
        # ຮອງຮັບຕົວເລກ, ພາສາອັງກິດ ແລະ ເຄື່ອງໝາຍຕ່າງໆ
        self.alnum_regex = re.compile(r'([a-zA-Z0-9]+)')
        self.punct_regex = re.compile(r'([^\w\s\u0E80-\u0EFF])')

    def tokenize(self, text):
        # ຂັ້ນຕອນທີ 1: ແຍກຂໍ້ຄວາມຍ່ອຍດ້ວຍ Whitespace ກ່ອນ
        raw_tokens = text.split()
        final_tokens = []

        for token in raw_tokens:
            # ຂັ້ນຕອນທີ 2: ໃຊ້ Findall ເພື່ອແຍກພະຍາງ ແລະ ອັກຂະລະອື່ນໆ
            # ເຮົາຈະໃຊ້ regex match ແບບ greedy
            parts = re.finditer(
                f'{self.alnum_regex.pattern}|{self.lao_regex.pattern}|{self.punct_regex.pattern}', 
                token
            )
            
            for match in parts:
                extracted = match.group(0).strip()
                if extracted:
                    final_tokens.append(extracted)
                    
        return final_tokens

# --- ການທົດສອບ (Testing the Tokenizer) ---
tokenizer = LaoSyllableTokenizer()

sample_text = "ການຈະລາຈອນຢູ່ທີ່ນະຄອນຫຼວງວຽງຈັນມີຄວາມແອອັດຫຼາຍ, ໂດຍສະເພາະ AI startup ແລະ SMEs."
tokens = tokenizer.tokenize(sample_text)

print(tokens)

ຜົນຮັບທີ່ໄດ້ (Output):

['ກາ', 'ນ', 'ຈະ', 'ລາ', 'ຈອ', 'ນ', 'ຢູ່', 'ທີ່', 'ນະ', 'ຄອ', 'ນ', 'ຫຼວ', 'ງ', 'ວຽ', 'ງ', 'ຈັ', 'ນ', 'ມີ', 'ຄວາ', 'ມ', 'ແອ', 'ອັ', 'ດ', 'ຫຼາ', 'ຍ', ',', 'ໂດ້', 'ຍ', 'ສະ', 'ເພາະ', 'AI', 'startup', 'ແລ', 'ະ', 'SMEs', '.']

(ໝາຍເຫດ: ຜົນຮັບອາດເບິ່ງຄືວ່າແຍກຍ່ອຍເກີນໄປ (Over-fragmented) ເຊັ່ນ “ກາ”, “ນ” ຍ້ອນຂໍ້ຈຳກັດຂອງ RegEx ທີ່ບໍ່ມີ Dictionary ກວດສອບ, ແຕ່ນີ້ຄືຈຸດປະສົງຫຼັກຂອງ Pre-tokenization ເພື່ອນຳໄປສ້າງ BPE!)

ການນຳໄປໃຊ້ປະສົມປະສານ (Integration with BPE)

ສຳລັບນັກພັດທະນາທີ່ເຮັດວຽກກັບ Deep Learning ແລະ LLMs (ເຊັ່ນໂຄງສ້າງ Transformer, LLaMA, ຫລື BERT) ທ່ານບໍ່ຄວນປ້ອນພະຍາງເຫຼົ່ານີ້ເຂົ້າໄປໃນໂມເດວໂດຍກົງ. ແທນທີ່ຈະເຮັດແບບນັ້ນ, ທ່ານຄວນໃຊ້ Syllable Tokenizer ນີ້ເປັນ Pre-tokenizer.

  1. Pre-tokenization: ໃຊ້ Code ທີ່ຂຽນຂ້າງເທິງເພື່ອແບ່ງຂໍ້ຄວາມ (Corpus) ຈໍານວນເປັນຮ້ອຍໆ Gigabytes ໃຫ້ກາຍເປັນຕ່ອນພະຍາງນ້ອຍໆ (Syllables).
  2. Train BPE Tokenizer: ເອົາຜົນຮັບທີ່ໄດ້ໄປຝຶກດ້ວຍ Hugging Face tokenizers (Byte-Pair Encoding).
  3. ຜົນປະໂຫຍດ: ວິທີການນີ້ຈະຊ່ວຍໃຫ້ BPE ຮຽນຮູ້ການລວມພະຍາງທີ່ມັກຢູ່ຊ້ອນກັນໃຫ້ກາຍເປັນ “ຄຳ” (Word-level) ໄດ້ຢ່າງສະຫຼາດ ເຊັ່ນ ມັນຈະຮຽນຮູ້ທີ່ຈະລວມ ນະ + ຄອ + ໃຫ້ກາຍເປັນ Token ດຽວຄື ນະຄອນ ໂດຍທີ່ບໍ່ໄປດຶງເອົາພະຍັນຊະນະຈາກຄຳອື່ນມາປົນກັນມົ້ວ.

ສະຫຼຸບ (Key Takeaways)

ຫວັງວ່າບົດຄວາມການລົງເລິກທາງເຕັກນິກນີ້ ຈະເປັນປະໂຫຍດແກ່ນັກຄົ້ນຄວ້າ, ນັກສຶກສາ ແລະ ວິສະວະກອນ AI ຊາວລາວທຸກທ່ານ ໃນການພັດທະນາໂຄງສ້າງພື້ນຖານ NLP ສໍາລັບປະເທດຂອງເຮົາ.


ບົດຄວາມໂດຍ: Dr. Savath Saypadith ຊີຣີຍ໌ບົດຄວາມ: ສ້າງເຕັກໂນໂລຊີ AI ເພື່ອພາສາລາວ.