Ứng dụng mạng AlexNet vào phân loại hình ảnh
1. Bài toán
Xây dựng một hệ thống nhận diện và phân loại hình ảnh dựa trên mạng neural AlexNet. Hệ thống này sẽ phân tích bức ảnh đầu vào và xác định đối tượng chính xuất hiện trong ảnh.
2. Thực hiện
2.1. Cấu trúc chương trình
Với mục đích dễ quản lý source code, chúng ta có thể đặt chương trình như sau:
root@aicandy:/aicandy/projects/AIcandy_AlexNet_ImageClassification_uddrlyxa# tree
.
├── aicandy_alexnet_convert_onnx_rvecsgnu.py
├── aicandy_alexnet_test_ovpridiv.py
├── aicandy_alexnet_train_sxbavvhx.py
├── aicandy_model_out_uoebddte
└── aicandy_model_src_rimrtnqo
└── aicandy_alexnet_model_dndvgvhk.py
Trong đó:
– File aicandy_alexnet_model_dndvgvhk.py chứa model
– File aicandy_alexnet_train_sxbavvhx.py chứa chương trình train
– File aicandy_alexnet_test_ovpridiv.py chứa chương trình để test.
– File aicandy_alexnet_convert_onnx_rvecsgnu.py chứa chương trình chuyển đổi từ model pytorch sang model onnx phục vụ triển khai model trên nhiều thiết bị khác nhau.
2.2. Dữ liệu
Dữ liệu phục vụ cho việc train gồm các ảnh đã được phân loại trước và được lưu trong các folder theo đối tượng, tên của folder là tên của đối tượng. Ví dụ trong bài này chúng ta có folder ‘dogs’ để chứa tất cả các ảnh có hình ảnh ‘dog’ và folder ‘cats’ để chứa tất cả các hình ảnh có ‘cat’.
Bộ dataset có cấu trúc như sau:
root@aicandy:/aicandy/projects/dataset# ls
cats dogsroot@aicandy:/aicandy/projects/dataset# cd cats
root@aicandy:/aicandy/projects/dataset/cats# tree | head -n 6
.
├── cat.0.jpg
├── cat.1000.jpg
├── cat.1002.jpg
├── cat.1003.jpg
├── cat.1004.jpg
root@aicandy:/aicandy/projects/dataset/cats#
root@aicandy:/aicandy/projects/dataset/cats# cd ../dogs/
root@aicandy:/aicandy/projects/dataset/dogs# tree | head -n 6
├── dog.1000.jpg
├── dog.1002.jpg
├── dog.1003.jpg
├── dog.1004.jpg
├── dog.1005.jpg
root@aicandy:/aicandy/projects/dataset/dogs#
Bộ dữ liệu sử dụng trong bài gồm bộ aicandy_cats_mkemktch và bộ aicandy_dogs_lpmdvpox được download miễn phí tại đây
2.3. Build model
Xây dựng mô hình gồm các thành phần chính:
Lớp Features (Tầng đặc trưng):
- Conv2d(3, 64, kernel_size=11, stride=4, padding=2): Đây là tầng tích chập đầu tiên, nhận đầu vào là một hình ảnh RGB (3 kênh màu) và sử dụng 64 bộ lọc có kích thước 11×11 với bước nhảy (stride) là 4 và thêm viền (padding) 2.
- ReLU(inplace=True): Hàm kích hoạt ReLU (Rectified Linear Unit) được sử dụng sau mỗi tầng tích chập để tăng tính phi tuyến tính cho mô hình.
- MaxPool2d(kernel_size=3, stride=2): Tầng pooling giảm kích thước không gian của đặc trưng sau khi áp dụng tích chập, giữ lại các thông tin quan trọng.
- Các tầng Conv2d, ReLU và MaxPool2d tiếp theo: Mô hình tiếp tục với nhiều tầng tích chập khác nhau để trích xuất đặc trưng từ hình ảnh. Các tham số của từng tầng bao gồm số lượng bộ lọc, kích thước bộ lọc, padding, và stride.
- Các tầng cuối của phần Features:
- Mô hình có thêm các tầng tích chập với kích thước bộ lọc nhỏ hơn (3×3) để trích xuất các đặc trưng chi tiết hơn.
Lớp Classifier (Tầng phân loại):
- Dropout(0.5): Được sử dụng để giảm overfitting, bằng cách ngẫu nhiên “bỏ qua” một số neuron trong quá trình huấn luyện với xác suất 0.5.
- Linear(256 * 6 * 6, 4096): Lớp fully connected, kết nối toàn bộ các neuron của tầng trước với 4096 neuron.
- ReLU(inplace=True): Hàm kích hoạt ReLU tiếp tục được sử dụng sau mỗi tầng fully connected.
- Linear(4096, 4096): Lớp fully connected thứ hai với 4096 neuron.
- Linear(4096, num_classes): Tầng đầu ra cuối cùng, số lượng neuron phụ thuộc vào số lớp (num_classes) bạn định nghĩa cho bài toán phân loại.
Hàm forward(x):
- Hàm forward định nghĩa cách mà dữ liệu di chuyển qua các tầng của mạng.
- Dữ liệu đi qua các tầng trong lớp features trước, sau đó được “flatten” thành vector để đưa qua các lớp fully connected trong classifier.
2.4. Chương trình train
Bước 1: Thư viện
import một số thư viện để xử lý các tác vụ liên quan tới tệp và đường dẫn (os, sys), thư viện xây dựng và tối ưu hóa mô hình (torch, torch.optim, torch.nn), các thư viện xử lý hình ảnh (datasets, transform, train_test_split, Dataloader).
import os
import torch
import torch.optim as optim
import torch.nn as nn
from torchvision import datasets, transforms
from sklearn.model_selection import train_test_split
from torch.utils.data import Subset, DataLoader
from aicandy_model_src_rimrtnqo.aicandy_alexnet_model_dndvgvhk import AlexNet
Bước 2: Nâng cao hiệu suất với GPU
Lựa chọn sử dụng CPU hay GPU để train, chúng ta sử dụng câu lệnh:
device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)
Bước 3: tăng cường dữ liệu bằng sử dụng transforms với:
– transforms.Resize((224, 224)): Thay đổi kích thước hình ảnh thành kích thước cố định (224×224) pixel. Đảm bảo rằng tất cả các hình ảnh đầu vào đều có cùng kích thước, phù hợp với yêu cầu của mạng nơ-ron.
– transforms.RandomHorizontalFlip(): Lật ngẫu nhiên hình ảnh theo chiều ngang. Tăng cường dữ liệu bằng cách tạo ra các phiên bản lật của hình ảnh, giúp mô hình học được các đặc điểm của hình ảnh.
– transforms.RandomRotation(20): Xoay ngẫu nhiên hình ảnh một góc từ -20 đến +20 độ. Giúp mô hình trở nên mạnh mẽ hơn trước các biến thể xoay của đối tượng trong hình ảnh.
– transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2): Điều chỉnh ngẫu nhiên độ sáng, độ tương phản, độ bão hòa và tông màu của hình ảnh. Tăng cường dữ liệu bằng cách tạo ra các biến thể màu sắc khác nhau của hình ảnh, giúp mô hình học được các đặc điểm hình ảnh dưới các điều kiện ánh sáng và màu sắc khác nhau.
– transforms.RandomAffine(degrees=0, translate=(0.1, 0.1)): Áp dụng một phép biến đổi affine ngẫu nhiên với mức dịch chuyển tối đa 10% theo cả chiều ngang và chiều dọc. Tăng cường dữ liệu bằng cách tạo ra các phiên bản hình ảnh bị dịch chuyển một chút, giúp mô hình trở nên linh hoạt hơn với vị trí của đối tượng trong hình ảnh.
– transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]): Chuẩn hóa các giá trị pixel của hình ảnh. Đưa các giá trị pixel về phạm vi có giá trị trung bình là 0 và độ lệch chuẩn là 1 cho từng kênh màu (RGB). Điều này giúp mô hình huấn luyện hiệu quả hơn vì các giá trị đầu vào được chuẩn hóa.
Bước 4: Load data và phân chia thành 2 tập train và val để đánh giá model
dataset = datasets.ImageFolder(root=train_dir, transform=transform)
- datasets.ImageFolder: Đây là một tiện ích của PyTorch để tải ảnh từ một thư mục. Thư mục này cần được tổ chức theo cấu trúc, mỗi thư mục con đại diện cho một lớp (class) khác nhau.
- root=train_dir: train_dir là đường dẫn tới thư mục chứa các ảnh huấn luyện.
- transform=transform: transform là các phép biến đổi (ví dụ: thay đổi kích thước, chuẩn hóa, tăng cường dữ liệu) được áp dụng lên các ảnh khi chúng được tải lên.
train_idx, val_idx = train_test_split(list(range(len(dataset))), test_size=0.2, random_state=42)
- train_test_split: Hàm này từ thư viện sklearn.model_selection chia dữ liệu thành hai phần: huấn luyện và kiểm tra (validation).
- list(range(len(dataset))): Tạo một danh sách các chỉ số tương ứng với tất cả các ảnh trong tập dữ liệu.
- test_size=0.2: 20% dữ liệu được dành cho tập kiểm tra.
- random_state=42: Seed cho bộ sinh số ngẫu nhiên để đảm bảo việc chia dữ liệu có thể tái lập.
train_dataset = Subset(dataset, train_idx)
val_dataset = Subset(dataset, val_idx)
- Subset: Một tiện ích của PyTorch để tạo tập con từ tập dữ liệu gốc dựa trên các chỉ số đã chỉ định.
- train_dataset: Chứa dữ liệu huấn luyện.
- val_dataset: Chứa dữ liệu kiểm tra.
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=4)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, num_workers=4)
- DataLoader: Một tiện ích của PyTorch để tải dữ liệu theo từng batch, cung cấp một iterator (bộ lặp) qua tập dữ liệu.
- train_loader: Dùng để tải dữ liệu huấn luyện theo từng batch.
- batch_size=batch_size: Xác định số lượng mẫu trong mỗi batch.
- shuffle=True: Trộn ngẫu nhiên dữ liệu vào đầu mỗi epoch để ngăn mô hình học theo thứ tự của dữ liệu.
- val_loader: Dùng để tải dữ liệu kiểm tra theo từng batch.
- shuffle=False: Không trộn dữ liệu kiểm tra, giữ nguyên thứ tự của các mẫu.
- num_workers=4: Xác định số lượng luồng con (subprocesses) để tải dữ liệu. Số lượng luồng con cao hơn có thể tăng tốc độ tải dữ liệu.
Bước 5: Lưu thông tin các đối tượng có trong dataset
with open(‘label.txt’, ‘w’) as f:
for idx, class_name in enumerate(dataset.classes):
f.write(f'{idx}: {class_name}\n’)
Chương trình sẽ lưu id và tên của đối tượng vào file label.txt.
Bước 6: Tối ưu và tạo hàm mất mát
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9, weight_decay=1e-4)
- optim.SGD: Đây là một loại trình tối ưu hóa trong PyTorch, gọi là Stochastic Gradient Descent (SGD). SGD là một phương pháp cơ bản và phổ biến để tối ưu hóa các mô hình học sâu.
- model.parameters(): Lấy tất cả các tham số (parameters) của mô hình để SGD có thể cập nhật chúng trong quá trình huấn luyện.
- lr=learning_rate: learning_rate là tốc độ học, một tham số quan trọng quyết định kích thước của bước nhảy khi cập nhật tham số. Giá trị learning_rate thường được định nghĩa trước đó trong quá trình chuẩn bị.
- momentum=0.9: Momentum giúp SGD tránh bị mắc kẹt trong các minima địa phương bằng cách tích lũy động lượng từ các bước trước đó. Giá trị momentum phổ biến là 0.9, giúp tăng tốc quá trình hội tụ.
- weight_decay=1e-4: Weight decay là một hình thức của regularization (chính quy hóa) nhằm tránh overfitting bằng cách thêm một điều khoản phạt vào hàm mất mát, từ đó giảm các giá trị trọng số lớn không cần thiết.
criterion = nn.CrossEntropyLoss()
- nn.CrossEntropyLoss: Đây là một hàm mất mát phổ biến được sử dụng cho các bài toán phân loại nhiều lớp (multi-class classification).
- Hàm này kết hợp giữa Softmax (chuyển đổi đầu ra của mô hình thành xác suất) và Negative Log Likelihood (NLL) để đo lường khoảng cách giữa đầu ra dự đoán của mô hình và nhãn thực tế.
optimizer.zero_grad()
optimizer.zero_grad(): Đặt lại (reset) gradient của tất cả các tham số của mô hình về 0. Trong PyTorch, gradient được cộng dồn sau mỗi lần gọi backward(). Do đó, cần gọi zero_grad() để đảm bảo rằng các gradient của các bước trước không bị cộng dồn vào bước hiện tại.
loss = criterion(outputs, labels)
criterion(outputs, labels): Tính toán hàm mất mát giữa đầu ra dự đoán của mô hình (outputs) và nhãn thực tế (labels). Hàm mất mát được sử dụng ở đây là CrossEntropyLoss, như đã định nghĩa trước đó.
loss.backward()
loss.backward(): Tính toán gradient của hàm mất mát đối với tất cả các tham số của mô hình. Đây là bước quan trọng trong thuật toán lan truyền ngược, giúp mô hình học cách điều chỉnh các tham số để giảm hàm mất mát.
optimizer.step()
optimizer.step(): Cập nhật các tham số của mô hình bằng cách sử dụng các gradient đã được tính toán trong bước backward(). Trình tối ưu hóa (ở đây là SGD) sẽ thực hiện việc này.
running_loss += loss.item()
running_loss += loss.item(): Cộng dồn giá trị mất mát của batch hiện tại vào tổng mất mát (running_loss). loss.item() chuyển đổi giá trị mất mát từ tensor thành một số thực (scalar).
Bước 7: Dự đoán nhãn và tính toán độ chính xác
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
- torch.max(outputs.data, 1): Lấy giá trị lớn nhất (xác suất cao nhất) và chỉ số của nó từ đầu ra dự đoán (outputs). Chỉ số này tương ứng với nhãn dự đoán của mô hình.
- total += labels.size(0): Cộng dồn số lượng mẫu trong batch hiện tại vào tổng số mẫu (total).
- correct += (predicted == labels).sum().item(): Cộng dồn số lượng dự đoán đúng vào tổng số dự đoán đúng (correct).
train_acc = 100 * correct / total
train_loss = running_loss / len(train_loader)
- train_acc = 100 * correct / total: Tính toán độ chính xác của mô hình trên tập huấn luyện, biểu diễn dưới dạng phần trăm (%).
- train_loss = running_loss / len(train_loader): Tính toán giá trị mất mát trung bình trên toàn bộ tập huấn luyện bằng cách chia tổng mất mát (running_loss) cho số lượng batch (len(train_loader)).
Bước 8: Hiện thị thông tin kết quả train và lưu model
val_acc = 100 * val_correct / val_total
val_loss /= len(val_loader)
print(f’Epoch [{epoch+1}/{num_epochs}], Train Loss: {train_loss:.4f}, Train Accuracy: {train_acc:.2f}%, Val Loss: {val_loss:.4f}, Val Accuracy: {val_acc:.2f}%’)
- val_acc: Tính toán và lưu trữ độ chính xác của mô hình trên tập kiểm tra.
- val_loss: Tính toán và lưu trữ mất mát trung bình của mô hình trên tập kiểm tra.
- print(…): Hiển thị kết quả của epoch bao gồm: mất mát và độ chính xác trên cả tập huấn luyện và tập kiểm tra. Điều này giúp bạn theo dõi quá trình huấn luyện và kiểm tra mô hình, xác định xem mô hình có cải thiện hay không qua các epoch.
if val_acc > best_acc:
best_acc = val_acc
torch.save(model.state_dict(), model_path)
print(f’Saved best model with accuracy: {best_acc:.2f}%’)
Sau mỗi epoch train, kiểm tra tính chính xác, nếu độ chính xác tốt lên thì sẽ lưu model với bộ trọng số này.
2.5. Chương trình test
Bước 1: Cần import một số thư viện và cấu trúc model
import torch
from PIL import Image
from torchvision import transforms
from aicandy_model_src_rimrtnqo.aicandy_alexnet_model_dndvgvhk import AlexNet
Bước 2: Xác định tên đối tượng có trong model
with open(label_path, ‘r’) as f:
labels = {int(line.split(“: “)[0]): line.split(“: “)[1].strip() for line in f}
Đoạn trên sẽ trả về cho labels một từ điển với cặp key-value, trong đó:
- key là ID của nhãn (dạng số nguyên).
- value là tên của nhãn (dạng chuỗi).
Bước 3: Load model
model = AlexNet(num_classes=num_classes).to(device)
Tạo một instance của mô hình AlexNet với số lượng lớp đầu ra là num_classes. Chuyển mô hình sang thiết bị cụ thể (device), thường là GPU (torch.device(‘cuda’)) hoặc CPU (torch.device(‘cpu’)). Điều này giúp tăng tốc quá trình tính toán nếu thiết bị đó là GPU.
model.load_state_dict(torch.load(model_path, map_location=device))
- Tải trọng số của mô hình từ tệp model_path. Trọng số này là kết quả của quá trình huấn luyện trước đó.
- map_location=device: Đảm bảo rằng trọng số được tải lên thiết bị (device) cụ thể (CPU hoặc GPU), giúp tránh lỗi khi sử dụng mô hình trên một thiết bị khác so với thiết bị đã huấn luyện.
model.eval()
Chuyển mô hình sang chế độ đánh giá (evaluation mode). Trong chế độ này, các lớp như Dropout và BatchNorm sẽ hoạt động khác so với khi ở chế độ huấn luyện.
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
Đoạn mã này định nghĩa một chuỗi các bước tiền xử lý (preprocessing) được áp dụng cho các hình ảnh trước khi chúng được đưa vào mô hình học sâu. Các bước tiền xử lý này giúp chuẩn hóa dữ liệu đầu vào và chuyển đổi hình ảnh sang định dạng phù hợp cho mô hình. Trong đó:
- Normalize là bước chuẩn hóa từng kênh màu của hình ảnh (R, G, B) bằng cách trừ đi giá trị trung bình (mean) và chia cho độ lệch chuẩn (std).
- [0.485, 0.456, 0.406]: Đây là các giá trị trung bình của các kênh màu (R, G, B) dựa trên bộ dữ liệu ImageNet, một bộ dữ liệu lớn phổ biến được dùng để huấn luyện các mô hình học sâu.
- [0.229, 0.224, 0.225]: Đây là các giá trị độ lệch chuẩn tương ứng của các kênh màu (R, G, B), cũng dựa trên bộ dữ liệu ImageNet.
- Chuẩn hóa này giúp đảm bảo rằng dữ liệu đầu vào có phân phối ổn định, giúp mô hình học tốt hơn và tăng tốc độ hội tụ.
Bước 4: Dự đoán kết quả
with torch.no_grad():
outputs = model(image)
_, predicted = torch.max(outputs, 1)
with torch.no_grad():
- Đây là một ngữ cảnh (context) trong PyTorch, trong đó các phép tính bên trong sẽ không yêu cầu lưu trữ thông tin về gradient.
- Điều này giúp tiết kiệm bộ nhớ và tăng tốc độ tính toán khi thực hiện dự đoán, vì không cần tính toán và lưu trữ gradient như khi huấn luyện mô hình.
- Chế độ này thường được sử dụng trong quá trình dự đoán (inference) hoặc đánh giá mô hình.
torch.max(outputs, 1):
- Hàm torch.max tìm giá trị lớn nhất trong tensor outputs dọc theo chiều thứ nhất (dim=1).
- Trong ngữ cảnh phân loại, mỗi giá trị trong outputs đại diện cho xác suất hoặc độ tin cậy rằng ảnh thuộc về một lớp cụ thể.
- Kết quả trả về là một tuple với hai phần tử:
- Phần tử đầu tiên (_) là giá trị lớn nhất (có thể bỏ qua ở đây).
- Phần tử thứ hai (predicted) là chỉ số (index) của giá trị lớn nhất, tương ứng với lớp mà mô hình dự đoán.
predicted_class = predicted.item()
predicted.item():
- Phương thức item() chuyển đổi một tensor có kích thước 1 (một giá trị duy nhất) thành một giá trị số Python thông thường (integer).
2.6. Chương trình chuyển đổi model
Bước 1: Load model
model = AlexNet(num_classes=num_classes)
AlexNet(num_classes=num_classes): Tạo một instance của mô hình AlexNet với số lượng lớp đầu ra là num_classes.
state_dict = torch.load(model_path, map_location=’cpu’)
model.load_state_dict(state_dict)
- torch.load(model_path, map_location=’cpu’): Tải trọng số từ tệp model_path. Thông thường, trọng số này được lưu sau quá trình huấn luyện.
- map_location=’cpu’: Đảm bảo rằng trọng số được tải lên bộ xử lý trung tâm (CPU), ngay cả khi mô hình ban đầu có thể đã được huấn luyện trên GPU.
Bước 2: Convert model
torch.onnx.export(model, dummy_input, onnx_path, export_params=True, opset_version=11, do_constant_folding=True, input_names=[‘input’], output_names=[‘output’], dynamic_axes={‘input’: {0: ‘batch_size’}, ‘output’: {0: ‘batch_size’}})
- torch.onnx.export(…): Hàm này xuất mô hình PyTorch thành định dạng ONNX.
- model: Mô hình PyTorch đã được huấn luyện.
- dummy_input: Đầu vào giả, mô phỏng dữ liệu đầu vào thực tế.
- onnx_path: Đường dẫn nơi tệp ONNX sẽ được lưu.
- export_params=True: Chỉ định rằng các trọng số đã được huấn luyện của mô hình sẽ được lưu trong tệp ONNX.
- opset_version=11: Phiên bản của ONNX Opset được sử dụng. Opset là tập hợp các toán tử mà ONNX hỗ trợ, và các phiên bản khác nhau có thể có những cải tiến hoặc thay đổi.
- do_constant_folding=True: Tối ưu hóa mô hình bằng cách gộp các hằng số trong biểu đồ tính toán, giúp giảm kích thước mô hình và tăng hiệu suất.
- input_names=[‘input’] và output_names=[‘output’]: Đặt tên cho các tensor đầu vào và đầu ra trong mô hình ONNX. Điều này giúp dễ dàng nhận diện các tensor khi mô hình được sử dụng trong các framework khác.
- dynamic_axes={‘input’: {0: ‘batch_size’}, ‘output’: {0: ‘batch_size’}}: Chỉ định rằng kích thước batch là động, tức là mô hình có thể xử lý các kích thước batch khác nhau trong quá trình suy luận.
3. Kết quả train
Thực hiện train với epoch 100, độ chính xác là 85.11%, đạt được ở epoch 94. Đây là chương trình mẫu, để tăng độ chính xác, chúng ta cũng cần điều chỉnh thêm một số tham số, tăng epoch cũng như tăng số lượng mẫu. Dưới đây là log train ở 50 epoch cuối:
Epoch [50/100], Train Loss: 0.5394, Train Accuracy: 73.25%, Val Loss: 0.5435, Val Accuracy: 73.59%
Saved best model with accuracy: 73.59%
Epoch [51/100], Train Loss: 0.5497, Train Accuracy: 71.84%, Val Loss: 0.5758, Val Accuracy: 71.46%
Epoch [52/100], Train Loss: 0.5280, Train Accuracy: 73.91%, Val Loss: 0.5688, Val Accuracy: 71.34%
Epoch [53/100], Train Loss: 0.5217, Train Accuracy: 74.69%, Val Loss: 0.5207, Val Accuracy: 74.97%
Saved best model with accuracy: 74.97%
Epoch [54/100], Train Loss: 0.5274, Train Accuracy: 73.63%, Val Loss: 0.6374, Val Accuracy: 67.96%
Epoch [55/100], Train Loss: 0.5088, Train Accuracy: 75.54%, Val Loss: 0.5650, Val Accuracy: 72.22%
Epoch [56/100], Train Loss: 0.4925, Train Accuracy: 76.29%, Val Loss: 0.5217, Val Accuracy: 74.97%
Epoch [57/100], Train Loss: 0.4958, Train Accuracy: 76.14%, Val Loss: 0.5264, Val Accuracy: 73.22%
Epoch [58/100], Train Loss: 0.5031, Train Accuracy: 76.17%, Val Loss: 0.5126, Val Accuracy: 75.59%
Saved best model with accuracy: 75.59%
Epoch [59/100], Train Loss: 0.4916, Train Accuracy: 75.82%, Val Loss: 0.4819, Val Accuracy: 76.47%
Saved best model with accuracy: 76.47%
Epoch [60/100], Train Loss: 0.4802, Train Accuracy: 77.36%, Val Loss: 0.5141, Val Accuracy: 74.84%
Epoch [61/100], Train Loss: 0.4673, Train Accuracy: 78.33%, Val Loss: 0.5338, Val Accuracy: 74.72%
Epoch [62/100], Train Loss: 0.4755, Train Accuracy: 77.80%, Val Loss: 0.5468, Val Accuracy: 72.97%
Epoch [63/100], Train Loss: 0.4653, Train Accuracy: 79.11%, Val Loss: 0.5041, Val Accuracy: 75.97%
Epoch [64/100], Train Loss: 0.4538, Train Accuracy: 79.17%, Val Loss: 0.5196, Val Accuracy: 74.47%
Epoch [65/100], Train Loss: 0.4603, Train Accuracy: 78.08%, Val Loss: 0.4904, Val Accuracy: 77.22%
Saved best model with accuracy: 77.22%
Epoch [66/100], Train Loss: 0.4528, Train Accuracy: 78.64%, Val Loss: 0.5268, Val Accuracy: 75.34%
Epoch [67/100], Train Loss: 0.4455, Train Accuracy: 79.52%, Val Loss: 0.5032, Val Accuracy: 77.97%
Saved best model with accuracy: 77.97%
Epoch [68/100], Train Loss: 0.4301, Train Accuracy: 80.39%, Val Loss: 0.4950, Val Accuracy: 77.10%
Epoch [69/100], Train Loss: 0.4401, Train Accuracy: 80.90%, Val Loss: 0.4813, Val Accuracy: 76.47%
Epoch [70/100], Train Loss: 0.4260, Train Accuracy: 80.55%, Val Loss: 0.4705, Val Accuracy: 78.85%
Saved best model with accuracy: 78.85%
Epoch [71/100], Train Loss: 0.4256, Train Accuracy: 80.93%, Val Loss: 0.4573, Val Accuracy: 79.35%
Saved best model with accuracy: 79.35%
Epoch [72/100], Train Loss: 0.4084, Train Accuracy: 81.46%, Val Loss: 0.5348, Val Accuracy: 75.72%
Epoch [73/100], Train Loss: 0.4147, Train Accuracy: 81.11%, Val Loss: 0.4933, Val Accuracy: 78.97%
Epoch [74/100], Train Loss: 0.4141, Train Accuracy: 82.09%, Val Loss: 0.5189, Val Accuracy: 74.97%
Epoch [75/100], Train Loss: 0.4067, Train Accuracy: 81.49%, Val Loss: 0.4314, Val Accuracy: 81.35%
Saved best model with accuracy: 81.35%
Epoch [76/100], Train Loss: 0.3872, Train Accuracy: 83.18%, Val Loss: 0.4513, Val Accuracy: 78.72%
Epoch [77/100], Train Loss: 0.3999, Train Accuracy: 81.74%, Val Loss: 0.4558, Val Accuracy: 79.60%
Epoch [78/100], Train Loss: 0.3915, Train Accuracy: 83.03%, Val Loss: 0.4741, Val Accuracy: 80.48%
Epoch [79/100], Train Loss: 0.3726, Train Accuracy: 83.46%, Val Loss: 0.4635, Val Accuracy: 79.10%
Epoch [80/100], Train Loss: 0.3751, Train Accuracy: 83.65%, Val Loss: 0.4267, Val Accuracy: 80.60%
Epoch [81/100], Train Loss: 0.3721, Train Accuracy: 83.31%, Val Loss: 0.4296, Val Accuracy: 79.72%
Epoch [82/100], Train Loss: 0.3567, Train Accuracy: 83.90%, Val Loss: 0.4173, Val Accuracy: 81.48%
Saved best model with accuracy: 81.48%
Epoch [83/100], Train Loss: 0.3754, Train Accuracy: 82.84%, Val Loss: 0.4178, Val Accuracy: 82.10%
Saved best model with accuracy: 82.10%
Epoch [84/100], Train Loss: 0.3524, Train Accuracy: 84.72%, Val Loss: 0.4504, Val Accuracy: 80.35%
Epoch [85/100], Train Loss: 0.3527, Train Accuracy: 84.62%, Val Loss: 0.4459, Val Accuracy: 80.48%
Epoch [86/100], Train Loss: 0.3370, Train Accuracy: 85.81%, Val Loss: 0.3843, Val Accuracy: 83.48%
Saved best model with accuracy: 83.48%
Epoch [87/100], Train Loss: 0.3488, Train Accuracy: 84.84%, Val Loss: 0.3905, Val Accuracy: 82.60%
Epoch [88/100], Train Loss: 0.3358, Train Accuracy: 85.19%, Val Loss: 0.4411, Val Accuracy: 81.10%
Epoch [89/100], Train Loss: 0.3350, Train Accuracy: 85.31%, Val Loss: 0.4031, Val Accuracy: 82.23%
Epoch [90/100], Train Loss: 0.3141, Train Accuracy: 86.16%, Val Loss: 0.4957, Val Accuracy: 81.10%
Epoch [91/100], Train Loss: 0.3462, Train Accuracy: 84.94%, Val Loss: 0.4845, Val Accuracy: 78.60%
Epoch [92/100], Train Loss: 0.3294, Train Accuracy: 85.19%, Val Loss: 0.4990, Val Accuracy: 77.22%
Epoch [93/100], Train Loss: 0.3298, Train Accuracy: 86.25%, Val Loss: 0.3782, Val Accuracy: 83.48%
Epoch [94/100], Train Loss: 0.2985, Train Accuracy: 86.94%, Val Loss: 0.3775, Val Accuracy: 83.73%
Saved best model with accuracy: 83.73%
Epoch [95/100], Train Loss: 0.3132, Train Accuracy: 86.06%, Val Loss: 0.3679, Val Accuracy: 84.11%
Saved best model with accuracy: 84.11%
Epoch [96/100], Train Loss: 0.3069, Train Accuracy: 86.75%, Val Loss: 0.4030, Val Accuracy: 82.60%
Epoch [97/100], Train Loss: 0.2989, Train Accuracy: 87.19%, Val Loss: 0.3659, Val Accuracy: 85.11%
Saved best model with accuracy: 85.11%
Epoch [98/100], Train Loss: 0.2829, Train Accuracy: 88.07%, Val Loss: 0.3672, Val Accuracy: 84.48%
Epoch [99/100], Train Loss: 0.2875, Train Accuracy: 87.72%, Val Loss: 0.3950, Val Accuracy: 83.60%
Epoch [100/100], Train Loss: 0.2831, Train Accuracy: 88.32%, Val Loss: 0.4030, Val Accuracy: 83.48%
root@aicandy:/aicandy/projects/AIcandy_AlexNet_ImageClassification_uddrlyxa#
Model được lưu tại: aicandy_model_out_uoebddte/aicandy_model_pth_luveqrpt.pth
root@aicandy:/aicandy/projects/AIcandy_AlexNet_ImageClassification_uddrlyxa# ls aicandy_model_out_uoebddte/
aicandy_model_pth_luveqrpt.pth
root@aicandy:/aicandy/projects/AIcandy_AlexNet_ImageClassification_uddrlyxa#
4. Kết quả test
Thử nghiệm test với hình ảnh có ‘dog’, chương trình nhận dạng đúng.
root@aicandy:/aicandy/projects/AIcandy_AlexNet_ImageClassification_uddrlyxa# python aicandy_alexnet_test_ovpridiv.py --image_path ../aicandy_true_dog.jpg --model_path aicandy_model_out_uoebddte/aicandy_model_pth_luveqrpt.pth --label_path label.txt
labels: {0: 'cats', 1: 'dogs'}
Predicted class: dogs
root@aicandy:/aicandy/projects/AIcandy_AlexNet_ImageClassification_uddrlyxa#
5. Source code
Toàn bộ source code được public miễn phí tại đây