一、构造 Experiment 类
卷积神经网络训练和测试的代码结构大部分都相同,为了方便今后更加简洁地书写代码,这里先构造一个 Experiment
类,并将其保存在 Experiment.py
文件中。
import torch
import numpy as np
import matplotlib.pyplot as plt
class Experiment:
def __init__(self, train_loader, test_loader, model, num_epochs, lr, optimizer='SGD', quiet=False):
self.train_loader = train_loader
self.test_loader = test_loader
self.model = model.cuda()
self.num_epochs = num_epochs
self.lr = lr
self.loss_fn = torch.nn.CrossEntropyLoss()
self.quiet = quiet
self.train_loss, self.train_acc = [], []
self.test_loss, self.test_acc = [], []
if optimizer == 'SGD':
self.optimizer = torch.optim.SGD(self.model.parameters(), lr=self.lr)
elif optimizer == 'Adam':
self.optimizer = torch.optim.Adam(self.model.parameters(), lr=self.lr)
else:
raise ValueError
def train(self):
correct, avg_loss = 0, 0
for batch_idx, (X, y) in enumerate(self.train_loader):
X, y = X.cuda(), y.cuda()
pred = self.model(X)
loss = self.loss_fn(pred, y)
correct += (pred.argmax(dim=1) == y).sum().item()
avg_loss += loss
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()
avg_loss /= (batch_idx + 1)
correct /= len(self.train_loader.dataset)
self.train_loss.append(avg_loss.item())
self.train_acc.append(correct)
if not self.quiet:
print('Train Avg Loss: {:.6f},'.format(avg_loss), end=' ')
print('Train Accuracy: {:.6f}'.format(correct))
def test(self):
correct, avg_loss = 0, 0
with torch.no_grad():
for batch_idx, (X, y) in enumerate(self.test_loader):
X, y = X.cuda(), y.cuda()
pred = self.model(X)
loss = self.loss_fn(pred, y)
correct += (pred.argmax(dim=1) == y).sum().item()
avg_loss += loss
avg_loss /= (batch_idx + 1)
correct /= len(self.test_loader.dataset)
self.test_loss.append(avg_loss.item())
self.test_acc.append(correct)
if not self.quiet:
print('Test Avg Loss: {:.6f},'.format(avg_loss), end=' ')
print('Test Accuracy: {:.6f}\n'.format(correct))
def main(self):
for epoch in range(self.num_epochs):
if not self.quiet:
print('Epoch {}\n'.format(epoch + 1) + '-' * 50)
self.train()
self.test()
print("Done!")
def show(self):
x = np.arange(1, self.num_epochs + 1)
plt.plot(x, self.train_loss, c='royalblue', label='train loss')
plt.plot(x, self.train_acc, c='seagreen', label='train acc', ls='dashed')
plt.plot(x, self.test_loss, c='darkorchid', label='test loss')
plt.plot(x, self.test_acc, c='firebrick', label='test acc', ls='dashed')
plt.legend(loc='best')
plt.xlabel('epoch')
plt.grid()
plt.show()
具体使用方法:
from Experiment import Experiment as E
net = Net() # 初始化我们的神经网络(无需移动到GPU,因为Experiment会自动将其移动到GPU上)
num_epochs = 20 # 决定有多少个Epoch
lr = 1e-2 # 学习率
e = E(train_loader, test_loader, net, num_epochs, lr)
e.main() # 进行训练和测试
e.show() # 绘制损失曲线和准确率曲线
Experiment
仅支持 SGD 和 Adam 优化器,默认使用 SGD 作为优化器,如需更换优化器,则需要为 optimizer
指定参数:
e = E(train_loader, test_loader, net, num_epochs, lr, optimizer='Adam')
默认情况下,执行 e.main()
会不断输出每一个 Epoch 的结果,如果只想看最后的曲线图而不看这些频繁生成结果,需要指定 quiet
参数的值为 True
e = E(train_loader, test_loader, net, num_epochs, lr, quiet=True)
二、AlexNet 简介
AlexNet 和 LeNet 的设计理念非常相似(可以粗略地认为 AlexNet 是更大更深的 LeNet),但依然存在显著差异。相比 LeNet,AlexNet 采用 ReLU 作为激活函数,平均池化换成了最大池化,全连接层中增加了 Dropout 用作正则,此外对于输入的数据集也进行了图像增强。
文章出处登录后可见!
已经登录?立即刷新