import numpy as npimport torch# 调入pytorch内置的mnist数据from torchvision.datasets import mnist# 导入预处理模块import torchvision.transforms as transformsfrom torch.utils.data import DataLoader# 导入nn以及优化器import torch.nn.functional as Fimport torch.optim as optimfrom torch import nnimport matplotlib.pyplot as plt# 当前程序为残差的手写数字识别# 定义一些超参数train_batch_size = 32test_batch_size = 64learning_rate = 0.01num_epoches = 10lr = 0.01momentum = 0.5# 下载数据并且进行数据预处理# 定义预处理函数,这些函数依次放在Compose函数中# 其中transforms.Compose用来把他们组合在一起,Normalize([0.5], [0.5])用来进行归一化# 因图像是灰色的,只有一个通道,所以只有一个数字,如果是三个通道,就需要三个数字transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize([0.5], [0.5])])# 下载数据,并对数据进行预处理train_dataset = mnist.MNIST('./data', train=True, transform=transform, download=False)test_dataset = mnist.MNIST('./data', train=False, transform=transform)# dataloader是一个可迭代对象,可以使用迭代器一样使用。train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)# 可视化数据源examples = enumerate(test_loader)batch_idx, (example_data, example_targets) = next(examples)fig = plt.figure()# 用来展示图片# for i in range(6):# plt.subplot(2, 3, i + 1)# plt.tight_layout()# plt.imshow(example_data[i][0], cmap='gray', interpolation='none')# plt.title("Ground Truth: {}".format(example_targets[i]))# plt.xticks([])# plt.yticks([])# plt.show()class ResidualBlock(nn.Module): def __init__(self, channels): super(ResidualBlock, self).__init__() self.channels = channels self.conv1 = torch.nn.Conv2d(channels, channels, kernel_size=3, padding=1) self.conv2 = torch.nn.Conv2d(channels, channels, kernel_size=3, padding=1) def forward(self, x): y = F.relu(self.conv1(x)) y = self.conv2(y) return F.relu(x + y)class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 10, 5) self.mp = nn.MaxPool2d(2) self.rblock1 = ResidualBlock(10) self.conv2 = nn.Conv2d(10, 20, 3) self.rblock2 = ResidualBlock(20) self.flatten1 = nn.Flatten() self.linear1 = nn.Linear(500, 10) def forward(self, x): x = F.relu(self.mp(self.conv1(x))) x = self.rblock1(x) x = F.relu(self.mp(self.conv2(x))) x = self.rblock2(x) x = self.flatten1(x) x = self.linear1(x) x = F.log_softmax(x, dim=1) return xdevice = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# 实例化网络model = Net()model.to(device)# 定义损失函数和优化器criterion = nn.CrossEntropyLoss();optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)# 训练模型losses = []acces = []eval_losses = []eval_acces = []for epoch in range(num_epoches): train_loss = 0 train_acc = 0 model.train() # 动态修改学习率 if epoch % 5 == 0: optimizer.param_groups[0]['lr'] *= 0.1 for batch_idx, (img, label) in enumerate(train_loader): # print(img.shape) # torch.Size([64, 1, 28, 28]) img = img.to(device) label = label.to(device) # 这里把图像压成了一维的 # img = img.view(img.size(0), -1) # 前向传播 out = model(img) loss = criterion(out, label) # 反向传播 optimizer.zero_grad() loss.backward() optimizer.step() # 记录误差 train_loss += loss.item() # 计算分类的准确率 _, pred = out.max(1) num_correct = (pred == label).sum().item() acc = num_correct / img.shape[0] train_acc += acc losses.append(train_loss / len(train_loader)) acces.append(train_acc / len(train_loader)) # 在测试集上检验效果 eval_loss = 0 eval_acc = 0 # 将模型改为预测模式 model.eval() for img, label in test_loader: img = img.to(device) label = label.to(device) out = model(img) loss = criterion(out, label) # 记录误差 eval_loss += loss.item() # 记录准确率 _, pred = out.max(1) num_correct = (pred == label).sum().item() acc = num_correct / img.shape[0] eval_acc += acc eval_losses.append(eval_loss / len(test_loader)) eval_acces.append(eval_acc / len(test_loader)) print('epoch: {}, Train Loss: {:.4f}, Train Acc: {:.4f}, Test Loss: {:.4f}, Test Acc: {:.4f}' .format(epoch, train_loss / len(train_loader), train_acc / len(train_loader), eval_loss / len(test_loader), eval_acc / len(test_loader)))plt.title('train loss')plt.plot(np.arange(len(losses)), losses)plt.legend(['Train Loss'], loc='upper right')plt.show()