Doctor AI

Dr. Savath Saypadith

240 ບົດຄວາມ

ສ້າງໂມເດວຈຳແນກຮູບພາບ 'ອາຫານລາວ': ແຍກຄວາມແຕກຕ່າງລະຫວ່າງ ລາບ, ຕຳໝາກຫຸ່ງ ແລະ ເຝີ

ໂພສເມື່ອ # Computer Vision # Machine Learning # PyTorch

ສ້າງໂມເດວຈຳແນກຮູບພາບ ‘ອາຫານລາວ’: ແຍກຄວາມແຕກຕ່າງລະຫວ່າງ ລາບ, ຕຳໝາກຫຸ່ງ ແລະ ເຝີ

ລອງຈິນຕະນາການເບິ່ງວ່າ: ຖ້າມີນັກທ່ອງທ່ຽວຍ່າງເຂົ້າໄປໃນຮ້ານອາຫານແຄມຂອງທີ່ນະຄອນຫຼວງວຽງຈັນ, ຖ່າຍຮູບອາຫານທີ່ຢູ່ກົງໜ້າ, ແລ້ວແອັບພລິເຄຊັນໃນມືຖືສາມາດບອກໄດ້ທັນທີວ່າສິ່ງນັ້ນຄື “ຕຳໝາກຫຸ່ງ” ພ້ອມທັງແນະນຳລະດັບຄວາມເຜັດ. ສິ່ງເຫຼົ່ານີ້ບໍ່ແມ່ນເລື່ອງໄກຕົວອີກຕໍ່ໄປ ດ້ວຍເຕັກໂນໂລຊີ Computer Vision (CV).

ໃນບົດຄວາມນີ້, ເຮົາຈະມາລົງເລິກວິທີການສ້າງ Image Classifier ສຳລັບ “ອາຫານລາວ” ໂດຍສະເພາະ. ເຮົາຈະໃຊ້ເຕັກນິກທີ່ເອີ້ນວ່າ Transfer Learning ເພື່ອຝຶກສອນໂມເດວໃຫ້ສາມາດແຍກແຍະລະຫວ່າງອາຫານ 3 ປະເພດຫຼັກຄື: ລາບ, ຕຳໝາກຫຸ່ງ (Papaya Salad) ແລະ ເຝີ (Pho). ບົດຄວາມນີ້ເໝາະສຳລັບຜູ້ທີ່ມີພື້ນຖານການຂຽນໂປຣແກຣມ Python ແລະ ເຂົ້າໃຈຫຼັກການເຮັດວຽກເບື້ອງຕົ້ນຂອງ Machine Learning ມາແລ້ວ.

1. ຄວາມທ້າທາຍຂອງຂໍ້ມູນ (The Data Challenge)

ການຈຳແນກອາຫານລາວມີຄວາມທ້າທາຍສະເພາະຕົວ. ຕົວຢ່າງ: “ລາບ” ແລະ “ຕຳໝາກຫຸ່ງ” ອາດມີການໃຊ້ພືດຜັກສີຂຽວທີ່ຄ້າຍຄືກັນ (ເຊັ່ນ: ໝາກຖົ່ວ, ຫອມລາບ), ສ່ວນ “ເຝີ” ກໍມີຈຸດເດັ່ນຄືນ້ຳຊຸບ ແລະ ເສັ້ນ. ເພື່ອໃຫ້ໂມເດວຮຽນຮູ້ໄດ້ດີ, ເຮົາຈຳເປັນຕ້ອງຈັດຕຽມຊຸດຂໍ້ມູນ (Dataset) ໃຫ້ເປັນລະບຽບ.

ໂຄງສ້າງ Folder ສຳລັບ Dataset ຄວນເປັນແບບນີ້:

dataset/
├── train/
│   ├── laap/ (ຮູບລາບ ປະມານ 200-300 ຮູບ)
│   ├── papaya_salad/ (ຮູບຕຳໝາກຫຸ່ງ)
│   └── pho/ (ຮູບເຝີ)
└── val/
    ├── laap/ (ຮູບສຳລັບທົດສອບ ປະມານ 50 ຮູບ)
    ├── papaya_salad/
    └── pho/

2. ສ້າງໂມເດວດ້ວຍ PyTorch ແລະ Transfer Learning

ເນື່ອງຈາກເຮົາບໍ່ມີຮູບພາບອາຫານລາວເປັນຫຼາຍລ້ານຮູບ ເຮົາຈຶ່ງຈະໃຊ້ Transfer Learning. ເຕັກນິກນີ້ຄືການນຳເອົາໂມເດວທີ່ເຄີຍຝຶກສອນກັບຮູບພາບຈຳນວນມະຫາສານມາແລ້ວ (ເຊັ່ນ ResNet) ມາປັບແຕ່ງ (Fine-tune) ໃຫ້ຮູ້ຈັກອາຫານລາວຂອງເຮົາ.

ມາເລີ່ມຕົ້ນຂຽນໂຄດກັນເລີຍ!

ການນຳເຂົ້າ Libraries ທີ່ຈຳເປັນ

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, models, transforms
from torch.utils.data import DataLoader
import os

# ກຳນົດໃຫ້ໃຊ້ GPU ຖ້າມີ
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

ການກຽມຂໍ້ມູນ (Data Preprocessing)

ເຮົາຕ້ອງຫຍໍ້ຮູບພາບທຸກຮູບໃຫ້ມີຂະໜາດ 224x224 ພິກເຊວ ຊຶ່ງເປັນຂະໜາດມາດຕະຖານສຳລັບໂມເດວ ResNet ແລະ ເຮັດ Data Augmentation ເພື່ອເພີ່ມຄວາມຫຼາກຫຼາຍໃຫ້ຂໍ້ມູນ.

data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(), # ປີ້ນຮູບຊ້າຍຂວາ ເພື່ອຈຳລອງມຸມມອງໃໝ່
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

data_dir = 'dataset'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) 
                  for x in ['train', 'val']}

dataloaders = {x: DataLoader(image_datasets[x], batch_size=32, shuffle=True, num_workers=2) 
               for x in ['train', 'val']}

class_names = image_datasets['train'].classes
print(f"Categories: {class_names}") # ຈະສະແດງ ['laap', 'papaya_salad', 'pho']

ການໂຫຼດໂມເດວ ResNet18 ແລະ ປັບແຕ່ງຊັ້ນສຸດທ້າຍ (Classifier Layer)

# ໂຫຼດໂມເດວ ResNet18 ທີ່ຖືກ pre-trained ມາແລ້ວ
model_ft = models.resnet18(pretrained=True)

# ດຶງເອົາຈຳນວນ features ຈາກຊັ້ນສຸດທ້າຍຂອງໂມເດວ
num_ftrs = model_ft.fc.in_features

# ປ່ຽນຊັ້ນ Output ໃຫ້ມີພຽງ 3 Classes (ລາບ, ຕຳໝາກຫຸ່ງ, ເຝີ)
model_ft.fc = nn.Linear(num_ftrs, len(class_names))
model_ft = model_ft.to(device)

criterion = nn.CrossEntropyLoss()
optimizer_ft = optim.Adam(model_ft.parameters(), lr=0.001)

3. ການຝຶກສອນໂມເດວ (Training Loop)

ຕອນນີ້ ເຮົາພ້ອມແລ້ວທີ່ຈະນຳຮູບອາຫານລາວຂອງເຮົາເຂົ້າໄປຝຶກສອນ (Train) ໃນໂມເດວ. ການຝຶກສອນຈະແບ່ງເປັນຮອບ ເຊິ່ງເອີ້ນວ່າ Epochs.

num_epochs = 10

for epoch in range(num_epochs):
    print(f'Epoch {epoch+1}/{num_epochs}')
    print('-' * 10)

    for phase in ['train', 'val']:
        if phase == 'train':
            model_ft.train()
        else:
            model_ft.eval()

        running_loss = 0.0
        running_corrects = 0

        for inputs, labels in dataloaders[phase]:
            inputs = inputs.to(device)
            labels = labels.to(device)

            optimizer_ft.zero_grad()

            with torch.set_grad_enabled(phase == 'train'):
                outputs = model_ft(inputs)
                _, preds = torch.max(outputs, 1)
                loss = criterion(outputs, labels)

                if phase == 'train':
                    loss.backward()
                    optimizer_ft.step()

            running_loss += loss.item() * inputs.size(0)
            running_corrects += torch.sum(preds == labels.data)

        epoch_loss = running_loss / len(image_datasets[phase])
        epoch_acc = running_corrects.double() / len(image_datasets[phase])

        print(f'{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')

ຫຼັງຈາກການຝຶກສອນສຳເລັດ, ໂມເດວຈະສາມາດຈຳແນກໄດ້ວ່າ ຮູບທີ່ຮັບເຂົ້າມານັ້ນແມ່ນ ລາບຊິ້ນງົວ, ຕຳໝາກຫຸ່ງປາກຊ່ອງ ຫຼື ເຝີແຊບບ້ານເຮົາ. ເນື່ອງຈາກເຮົານຳໃຊ້ Transfer Learning, ໂມເດວຈະສາມາດຮຽນຮູ້ຈຸດເດັ່ນເຊັ່ນ: ສີແດງຂອງໝາກເລັ່ນໃນຕຳໝາກຫຸ່ງ, ເສັ້ນສີຂາວຂອງເຝີ ຫຼື ສີນ້ຳຕານຂອງຊີ້ນໃນລາບໄດ້ຢ່າງແນ່ນອນ ແລະ ວ່ອງໄວ.

ຂໍ້ຄວນຈື່ (Key Takeaways)

ສະຫຼຸບ

ການສ້າງ Image Classifier ເພື່ອຈຳແນກອາຫານລາວ ສະແດງໃຫ້ເຫັນວ່າ ເຕັກໂນໂລຊີ AI ແລະ Computer Vision ບໍ່ແມ່ນສິ່ງທີ່ນຳໃຊ້ໄດ້ສະເພາະແຕ່ກັບບໍລິບົດຂອງຕ່າງປະເທດ. ນັກພັດທະນາລາວສາມາດນຳໃຊ້ເຄື່ອງມືລະດັບໂລກຢ່າງ PyTorch ມາແກ້ໄຂບັນຫາ ແລະ ສ້າງນະວັດຕະກຳໃໝ່ໆທີ່ຕອບໂຈດວັດທະນະທຳການກິນຂອງບ້ານເຮົາໄດ້. ມື້ນີ້ເຮົາແຍກ “ລາບ”, “ຕຳໝາກຫຸ່ງ”, ແລະ “ເຝີ” ອອກຈາກກັນໄດ້ແລ້ວ, ບາດກ້າວຕໍ່ໄປ ອາດຈະແມ່ນການແຍກ “ຕຳປາແດກ” ກັບ “ຕຳໄທ” ກໍເປັນໄດ້!