python使用深度卷积神经网络,(采用预训练模型 VGG, GoogLeNet, ResNet, DenseNet 等),对图像数据集 CIFAR-10(https://www.cs.toronto.edu/~kriz/cifar.html) 进行分类,该数据集的训练集包含 50000 张图片,测试集包含 10000 张图片。 要求:准确率尽可能高;需要把训练集划分出 10000 张图片作为验证集,用来进行模型选择,可以使用 Kaggle 的免费 GPU 进行训练。需要在训练集和测试集上画出 accuracy vs. epochs,在验证 集上画出 loss vs. epochs,总共 3 幅图。
时间: 2023-06-11 20:08:13 浏览: 116
各种卷积神经网络(LeNet5、VGGNet、DenseNet、ResNet、GoogleNet),在Mnist等数据集上实现
好的,这是一个非常典型的机器学习任务,我们可以按照以下步骤进行:
1. 下载并预处理数据集
2. 构建深度卷积神经网络模型
3. 训练模型并进行模型选择
4. 绘制准确率和损失的变化曲线
下面我们逐步实现这些步骤。
## 1. 下载并预处理数据集
我们可以使用 `torchvision` 库来下载 CIFAR-10 数据集,该库还提供了一些数据预处理的方法,例如图像的裁剪、旋转、翻转等。我们可以将数据集分为训练集、验证集和测试集,其中训练集包含 40000 张图像,验证集包含 10000 张图像,测试集包含 10000 张图像。
```python
import torch
import torchvision
import torchvision.transforms as transforms
# 定义数据预处理方法
transform_train = transforms.Compose([
transforms.RandomCrop(32, padding=4),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
transform_test = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
# 加载数据集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform_train)
trainset, valset = torch.utils.data.random_split(trainset, [40000, 10000])
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform_test)
# 定义数据加载器
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128,
shuffle=True, num_workers=2)
valloader = torch.utils.data.DataLoader(valset, batch_size=128,
shuffle=False, num_workers=2)
testloader = torch.utils.data.DataLoader(testset, batch_size=128,
shuffle=False, num_workers=2)
```
## 2. 构建深度卷积神经网络模型
我们可以采用预训练模型 VGG、GoogLeNet、ResNet 和 DenseNet 中的任意一种,这些模型已在 ImageNet 数据集上进行了训练,因此可以作为一个很好的特征提取器。我们只需要将最后的全连接层替换为一个输出 10 维的全连接层即可。
这里我们以 ResNet18 为例构建模型。
```python
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision.models import resnet18
# 定义模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.resnet = resnet18(pretrained=True)
self.resnet.fc = nn.Linear(512, 10)
def forward(self, x):
x = self.resnet(x)
return x
net = Net()
```
## 3. 训练模型并进行模型选择
我们可以使用交叉熵损失函数和随机梯度下降优化器来训练模型。在训练过程中我们可以使用验证集来进行模型选择,选择在验证集上性能最好的模型作为最终模型。
```python
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.1, momentum=0.9, weight_decay=1e-4)
# 训练模型
best_acc = 0.0
for epoch in range(50): # 训练 50 轮
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 100 == 99: # 每 100 个 mini-batch 输出一次损失
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 100))
running_loss = 0.0
# 在验证集上测试
correct = 0
total = 0
with torch.no_grad():
for data in valloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# 输出在验证集上的准确率
acc = 100.0 * correct / total
print('Accuracy of the network on the validation set: %d %%' % (acc))
if acc > best_acc: # 选择最好的模型
best_acc = acc
best_model = net.state_dict()
print('Finished Training')
# 加载最好的模型
net.load_state_dict(best_model)
```
## 4. 绘制准确率和损失的变化曲线
在训练过程中我们可以记录每个 epoch 的准确率和损失,然后将其绘制成曲线。
```python
import matplotlib.pyplot as plt
# 记录准确率和损失
train_acc_list, val_acc_list, train_loss_list, val_loss_list = [], [], [], []
for epoch in range(50):
train_correct, train_total, train_loss = 0, 0, 0.0
val_correct, val_total, val_loss = 0, 0, 0.0
for data in trainloader:
images, labels = data
optimizer.zero_grad()
outputs = net(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
_, predicted = torch.max(outputs.data, 1)
train_total += labels.size(0)
train_correct += (predicted == labels).sum().item()
train_loss += loss.item()
train_acc = 100.0 * train_correct / train_total
train_loss /= len(trainloader)
train_acc_list.append(train_acc)
train_loss_list.append(train_loss)
with torch.no_grad():
for data in valloader:
images, labels = data
outputs = net(images)
loss = criterion(outputs, labels)
_, predicted = torch.max(outputs.data, 1)
val_total += labels.size(0)
val_correct += (predicted == labels).sum().item()
val_loss += loss.item()
val_acc = 100.0 * val_correct / val_total
val_loss /= len(valloader)
val_acc_list.append(val_acc)
val_loss_list.append(val_loss)
print('[Epoch %d] Train Loss: %.3f, Train Acc: %.2f%%, Val Loss: %.3f, Val Acc: %.2f%%'
% (epoch + 1, train_loss, train_acc, val_loss, val_acc))
# 绘制准确率和损失的变化曲线
epochs = range(1, 51)
plt.plot(epochs, train_acc_list, label='Training Accuracy')
plt.plot(epochs, val_acc_list, label='Validation Accuracy')
plt.legend()
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.title('Accuracy vs. Epochs')
plt.show()
plt.plot(epochs, train_loss_list, label='Training Loss')
plt.plot(epochs, val_loss_list, label='Validation Loss')
plt.legend()
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Loss vs. Epochs')
plt.show()
# 在测试集上测试
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# 输出在测试集上的准确率
acc = 100.0 * correct / total
print('Accuracy of the network on the test set: %d %%' % (acc))
```
这样我们就完成了 CIFAR-10 数据集的分类任务,并绘制了准确率和损失的变化曲线。
阅读全文