使用Python代码实现ResNet神经网络模型进行猫的十二分类,并生成CSV文件和可视化结果
本指南介绍了使用Python代码构建一个ResNet神经网络模型来对猫图像进行十二分类,并生成CSV文件存储预测结果以及可视化训练和验证过程。
由于本人是AI语言模型,无法直接访问Kaggle数据集,因此无法提供完整的代码。但我可以提供一个基本的框架,您可以根据该框架进行编写。
1. 数据集
/kaggle/input/cat111/cat_12_train/cat_12_train(下一目录为照片,共2115张)/kaggle/input/cat111/cat_12_test/cat_12_test(下一目录为照片,共240张)/kaggle/input/cat111/train_list.txt(训练集图片的路径文本文件)
2. 训练集和验证集
- 训练集:80%
- 验证集:20%
3. 模型定义(ResNet)和训练
4. 结果可视化和预测可视化
代码框架
首先,我们需要导入必要的库:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import torchvision.transforms as transforms
from PIL import Image
import os
import pandas as pd
import matplotlib.pyplot as plt
接下来,我们需要定义一个自定义数据集类,继承自torch.utils.data.Dataset类。该类将用于加载和预处理数据集中的图像。
class CatDataset(Dataset):
def __init__(self, root_dir, file_list, transform=None):
self.root_dir = root_dir
self.file_list = file_list
self.transform = transform
def __len__(self):
return len(self.file_list)
def __getitem__(self, idx):
img_path = os.path.join(self.root_dir, self.file_list[idx])
img = Image.open(img_path).convert('RGB')
label = int(self.file_list[idx].split('_')[0])
if self.transform:
img = self.transform(img)
return img, label
接下来,我们需要定义一个ResNet模型。我们可以使用PyTorch提供的torchvision.models.resnet模块,但需要自己调整输出层的大小以适应我们的分类任务。
class ResNet(nn.Module):
def __init__(self, num_classes):
super(ResNet, self).__init__()
self.resnet = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1),
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1, bias=False),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1, bias=False),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, 512, kernel_size=3, stride=2, padding=1, bias=False),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.AvgPool2d(kernel_size=4, stride=1),
)
self.fc = nn.Linear(512, num_classes)
def forward(self, x):
x = self.resnet(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
接下来,我们需要对数据集进行预处理,包括缩放、剪裁、标准化等。这里我们使用了torchvision.transforms模块提供的一些转换函数。
train_transform = transforms.Compose([
transforms.Resize(256),
transforms.RandomCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
test_transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
接下来,我们需要加载数据集和标签,并将其分成训练集和验证集。
root_dir = '/kaggle/input/cat111'
train_list_path = os.path.join(root_dir, 'train_list.txt')
test_list_path = os.path.join(root_dir, 'test_list.txt')
train_list = pd.read_csv(train_list_path, header=None, sep=' ')[0].tolist()
test_list = pd.read_csv(test_list_path, header=None, sep=' ')[0].tolist()
train_size = int(len(train_list) * 0.8)
valid_size = len(train_list) - train_size
train_set = CatDataset(root_dir=os.path.join(root_dir, 'cat_12_train'),
file_list=train_list[:train_size],
transform=train_transform)
valid_set = CatDataset(root_dir=os.path.join(root_dir, 'cat_12_train'),
file_list=train_list[train_size:],
transform=test_transform)
test_set = CatDataset(root_dir=os.path.join(root_dir, 'cat_12_test'),
file_list=test_list,
transform=test_transform)
train_loader = DataLoader(train_set, batch_size=32, shuffle=True)
valid_loader = DataLoader(valid_set, batch_size=32, shuffle=False)
test_loader = DataLoader(test_set, batch_size=32, shuffle=False)
接下来,我们需要定义损失函数和优化器。
model = ResNet(num_classes=12)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=1e-4)
scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[30, 60, 90], gamma=0.1)
接下来,我们需要定义训练和验证函数。
def train(model, dataloader, criterion, optimizer, device):
model.train()
running_loss = 0.0
running_corrects = 0
for inputs, labels in dataloader:
inputs = inputs.to(device)
labels = labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / len(dataloader.dataset)
epoch_acc = running_corrects.double() / len(dataloader.dataset)
return epoch_loss, epoch_acc
def validate(model, dataloader, criterion, device):
model.eval()
running_loss = 0.0
running_corrects = 0
with torch.no_grad():
for inputs, labels in dataloader:
inputs = inputs.to(device)
labels = labels.to(device)
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / len(dataloader.dataset)
epoch_acc = running_corrects.double() / len(dataloader.dataset)
return epoch_loss, epoch_acc
最后,我们可以开始训练模型:
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
model.to(device)
num_epochs = 100
train_loss_history = []
train_acc_history = []
valid_loss_history = []
valid_acc_history = []
best_acc = 0.0
for epoch in range(num_epochs):
train_loss, train_acc = train(model, train_loader, criterion, optimizer, device)
valid_loss, valid_acc = validate(model, valid_loader, criterion, device)
train_loss_history.append(train_loss)
train_acc_history.append(train_acc)
valid_loss_history.append(valid_loss)
valid_acc_history.append(valid_acc)
if valid_acc > best_acc:
best_acc = valid_acc
torch.save(model.state_dict(), 'best_model.pth')
print('Epoch [{}/{}], Train Loss: {:.4f}, Train Acc: {:.4f}, Valid Loss: {:.4f}, Valid Acc: {:.4f}'
.format(epoch + 1, num_epochs, train_loss, train_acc, valid_loss, valid_acc))
scheduler.step()
model.load_state_dict(torch.load('best_model.pth'))
test_loss, test_acc = validate(model, test_loader, criterion, device)
print('Test Loss: {:.4f}, Test Acc: {:.4f}'.format(test_loss, test_acc))
完成训练后,我们可以使用训练和验证的历史记录绘制损失和准确度曲线:
plt.figure(figsize=(10, 5))
plt.plot(train_loss_history, label='Train Loss')
plt.plot(valid_loss_history, label='Valid Loss')
plt.legend()
plt.show()
plt.figure(figsize=(10, 5))
plt.plot(train_acc_history, label='Train Acc')
plt.plot(valid_acc_history, label='Valid Acc')
plt.legend()
plt.show()
最后,我们可以使用模型进行预测,并将结果保存到CSV文件中。
model.eval()
preds = []
for inputs, labels in test_loader:
inputs = inputs.to(device)
outputs = model(inputs)
_, batch_preds = torch.max(outputs, 1)
preds += batch_preds.tolist()
result = pd.DataFrame({'id': test_list, 'label': preds})
result.to_csv('result.csv', index=False)
原文地址: https://www.cveoy.top/t/topic/oEJc 著作权归作者所有。请勿转载和采集!