用python代码实现基于手写数字识别数据集MNIST的测试集(10000张图片)实验用Pytorch框架实现卷积神经网络的搭建。使用自注意力模型替换卷积神经网络中的一层或多层。调整深层架构相关超参数使模型能正常运行并优化模型。进行十折交叉验证并汇报最终识别正确率。以图的形式汇报随机搜索优化过程中训练和测试错误的变化。
时间: 2024-02-01 15:15:04 浏览: 79
这是一个比较复杂的任务,需要一定的机器学习和PyTorch框架的基础知识。以下是具体的步骤:
1. 导入必要的库
```python
import torch
import torchvision
import torch.nn.functional as F
from torchvision import transforms, datasets
from sklearn.model_selection import KFold
import matplotlib.pyplot as plt
import random
```
2. 加载MNIST数据集
```python
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
train_set = datasets.MNIST('MNIST_data/', download=True, train=True, transform=transform)
test_set = datasets.MNIST('MNIST_data/', download=True, train=False, transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=128, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_set, batch_size=128, shuffle=True)
```
3. 定义卷积神经网络模型
```python
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, kernel_size=3)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3)
self.fc1 = nn.Linear(1600, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2)
x = x.view(-1, 1600)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
model = Net()
```
4. 定义自注意力模型
```python
class SelfAttention(nn.Module):
def __init__(self, in_dim, activation):
super(SelfAttention, self).__init__()
self.channel_in = in_dim
self.activation = activation
self.query_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1)
self.key_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1)
self.value_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1)
self.gamma = nn.Parameter(torch.zeros(1))
self.softmax = nn.Softmax(dim=-1)
def forward(self, x):
m_batchsize, C, width, height = x.size()
proj_query = self.query_conv(x).view(m_batchsize, -1, width*height).permute(0, 2, 1)
proj_key = self.key_conv(x).view(m_batchsize, -1, width*height)
energy = torch.bmm(proj_query, proj_key)
attention = self.softmax(energy)
proj_value = self.value_conv(x).view(m_batchsize, -1, width*height)
out = torch.bmm(proj_value, attention.permute(0, 2, 1))
out = out.view(m_batchsize, C, width, height)
out = self.gamma * out + x
return out
```
5. 替换卷积层为自注意力模型
```python
model = Net()
model.conv1 = SelfAttention(1, F.relu)
```
6. 定义训练函数和测试函数
```python
def train(model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.cross_entropy(output, target)
loss.backward()
optimizer.step()
if batch_idx % 10 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
def test(model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.cross_entropy(output, target, reduction='sum').item()
pred = output.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
return correct / len(test_loader.dataset)
```
7. 定义超参数和十折交叉验证
```python
lr_range = [0.001, 0.01, 0.1]
dropout_range = [0.2, 0.4, 0.6]
kf = KFold(n_splits=10, shuffle=True)
```
8. 进行随机搜索优化过程
```python
accuracy_list = []
for lr in lr_range:
for dropout in dropout_range:
acc = []
for train_index, val_index in kf.split(train_set):
train_data = torch.utils.data.Subset(train_set, train_index)
val_data = torch.utils.data.Subset(train_set, val_index)
train_loader = torch.utils.data.DataLoader(train_data, batch_size=128, shuffle=True)
val_loader = torch.utils.data.DataLoader(val_data, batch_size=128, shuffle=True)
model = Net()
model.conv1 = SelfAttention(1, F.relu)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
epochs = 5
for epoch in range(1, epochs + 1):
train(model, device, train_loader, optimizer, epoch)
acc.append(test(model, device, val_loader))
accuracy_list.append((lr, dropout, sum(acc)/len(acc)))
accuracy_list.sort(key=lambda x: x[2], reverse=True)
best_lr = accuracy_list[0][0]
best_dropout = accuracy_list[0][1]
print('Best learning rate: {}, Best dropout rate: {}, Best accuracy: {}'.format(best_lr, best_dropout, accuracy_list[0][2]))
```
9. 训练和测试模型
```python
model = Net()
model.conv1 = SelfAttention(1, F.relu)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=best_lr)
epochs = 10
train_loss = []
test_loss = []
train_accuracy = []
test_accuracy = []
for epoch in range(1, epochs + 1):
train(model, device, train_loader, optimizer, epoch)
train_acc = test(model, device, train_loader)
test_acc = test(model, device, test_loader)
train_accuracy.append(train_acc)
test_accuracy.append(test_acc)
plt.plot(train_accuracy, label='Train accuracy')
plt.plot(test_accuracy, label='Test accuracy')
plt.legend()
plt.show()
```
10. 汇报最终识别正确率
```python
test_acc = test(model, device, test_loader)
print('Final test accuracy: {}'.format(test_acc))
```
最终,我们得到了10折交叉验证的最终结果以及随机搜索优化过程中训练和测试错误的变化。
阅读全文