ສ້າງໂມເດວຈຳແນກຮູບພາບ 'ອາຫານລາວ': ແຍກຄວາມແຕກຕ່າງລະຫວ່າງ ລາບ, ຕຳໝາກຫຸ່ງ ແລະ ເຝີ
ສ້າງໂມເດວຈຳແນກຮູບພາບ ‘ອາຫານລາວ’: ແຍກຄວາມແຕກຕ່າງລະຫວ່າງ ລາບ, ຕຳໝາກຫຸ່ງ ແລະ ເຝີ
ລອງຈິນຕະນາການເບິ່ງວ່າ: ຖ້າມີນັກທ່ອງທ່ຽວຍ່າງເຂົ້າໄປໃນຮ້ານອາຫານແຄມຂອງທີ່ນະຄອນຫຼວງວຽງຈັນ, ຖ່າຍຮູບອາຫານທີ່ຢູ່ກົງໜ້າ, ແລ້ວແອັບພລິເຄຊັນໃນມືຖືສາມາດບອກໄດ້ທັນທີວ່າສິ່ງນັ້ນຄື “ຕຳໝາກຫຸ່ງ” ພ້ອມທັງແນະນຳລະດັບຄວາມເຜັດ. ສິ່ງເຫຼົ່ານີ້ບໍ່ແມ່ນເລື່ອງໄກຕົວອີກຕໍ່ໄປ ດ້ວຍເຕັກໂນໂລຊີ 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)
- Transfer Learning ແມ່ນສິ່ງສຳຄັນ: ໃນປະເທດລາວ, ການເກັບກຳຮູບພາບຂໍ້ມູນມະຫາສານຍັງເປັນສິ່ງທ້າທາຍ. ການໃຊ້ໂມເດວປະເພດ Pre-trained ເຊັ່ນ ResNet ຊ່ວຍໃຫ້ເຮົາສ້າງ AI ທີ່ມີປະສິດທິພາບສູງໄດ້ໂດຍໃຊ້ຮູບພາບພຽງຫຼັກຮ້ອຍຮູບ.
- Data Augmentation: ການເພີ່ມຄວາມຫຼາກຫຼາຍໃຫ້ຂໍ້ມູນຮູບພາບ (ເຊັ່ນການໝຸນຮູບ, ການຕັດຮູບ) ຈະຊ່ວຍໃຫ້ໂມເດວເກັ່ງຂຶ້ນ ແລະ ບໍ່ຈື່ຈຳສະເພາະຮູບແບບເກົ່າ (Overfitting).
- ການປະຍຸກໃຊ້ຈິງ: ໂມເດວນີ້ສາມາດພັດທະນາຕໍ່ຍອດເປັນແອັບພລິເຄຊັນຊ່ວຍນັກທ່ອງທ່ຽວ, ລະບົບແນະນຳອາຫານສຳລັບຮ້ານອາຫານທ້ອງຖິ່ນໃນລາວ, ຫຼື ແມ່ນແຕ່ລະບົບຄຳນວນແຄລໍຣີສຳລັບຄົນຮັກສຸຂະພາບ.
ສະຫຼຸບ
ການສ້າງ Image Classifier ເພື່ອຈຳແນກອາຫານລາວ ສະແດງໃຫ້ເຫັນວ່າ ເຕັກໂນໂລຊີ AI ແລະ Computer Vision ບໍ່ແມ່ນສິ່ງທີ່ນຳໃຊ້ໄດ້ສະເພາະແຕ່ກັບບໍລິບົດຂອງຕ່າງປະເທດ. ນັກພັດທະນາລາວສາມາດນຳໃຊ້ເຄື່ອງມືລະດັບໂລກຢ່າງ PyTorch ມາແກ້ໄຂບັນຫາ ແລະ ສ້າງນະວັດຕະກຳໃໝ່ໆທີ່ຕອບໂຈດວັດທະນະທຳການກິນຂອງບ້ານເຮົາໄດ້. ມື້ນີ້ເຮົາແຍກ “ລາບ”, “ຕຳໝາກຫຸ່ງ”, ແລະ “ເຝີ” ອອກຈາກກັນໄດ້ແລ້ວ, ບາດກ້າວຕໍ່ໄປ ອາດຈະແມ່ນການແຍກ “ຕຳປາແດກ” ກັບ “ຕຳໄທ” ກໍເປັນໄດ້!