赞
踩
AlexNet模型来源于论文-ImageNet Classification with Deep Convolutional Neural Networks,作者Alex Krizhevsky,Ilya Sutskever,Geoffrey E.Hinton.
AlexNet在ImageNet LSVRC-2012比赛中,达到最低的15.3%的Top-5错误率,比第二名低10.8个百分点。
AlexNet包含八层,前五层是卷积层,最后三层是全连接层。它使用了ReLU激活函数,显示出比tabh和sigmoid更好的训练性能。
论文中的图比较抽象,不便于分析结构,下面提供一个更直观的结构图。
参考链接:Netscope
本次实验中使用的垃圾分类数据集一共2307张图片,分为六个分类, cardboard(370), glass(457), metal(380), paper(540), plastic(445), trash(115)。数据集中的图片是经过处理的512x384的三通道图片。
由于该数据集较小,因此需要通过数据增强扩充数据集。在本次试验中通过对图片进行随机翻转,裁剪227x227大小的子图扩充数据集,为了提高模型的准确率,在输入模型前,还需要对图片进行归一化处理,将每个像素的值映射到(0,1)之间。
定义一个torch.utils.data.Dataset
类的子类,用于从硬盘中加载数据集,因为存在随机裁剪,在GarbageDataset
类中将数据集大小扩大10倍。
class GarbageDataset(Dataset): classifications = ["cardboard", "glass", "metal", "paper", "plastic", "trash"] def __init__(self, root_dir, transform = None): super(GarbageDataset, self).__init__() self.root_dir = root_dir self.transform = transform self.imgs = [] self.read() def __len__(self): return 10 * len(self.imgs) def __getitem__(self, item): img, label = self.imgs[item % len(self.imgs)] if self.transform: img = self.transform(img) return img, label def read(self): img_dir = os.path.join(self.root_dir, "garbage") for i, c in enumerate(GarbageDataset.classifications, 0): dir = os.path.join(img_dir, c) for img_name in os.listdir(dir): img = Image.open(os.path.join(dir, img_name)) self.imgs.append((img, i))
定义transforms
, 实例化GarbageDataset
加载数据集, 并按照6:2:2的比例划分训练集,验证集和测试集。
dataset = GarbageDataset("data", transform=transforms.Compose([
transforms.Resize(227),
transforms.RandomHorizontalFlip(),
transforms.RandomCrop(227),
transforms.RandomRotation(90),
transforms.ToTensor(),
transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
]))
dataset_size = len(dataset)
validset_size = int(dataset_size / 5)
testset_size = validset_size
trainset_size = dataset_size - validset_size - testset_size
trainset, validset, testset = torch.utils.data.random_split(dataset, [trainset_size, validset_size, testset_size])
对训练集,验证集,测试集分别实例化一个DataLoader
。
# 训练集需要打乱顺序
trainloader = DataLoader(dataset=trainset, batch_size=128, shuffle=True)
# 验证集和测试集可以不用打乱数据顺序
validloader = DataLoader(dataset=validset, batch_size=128, shuffle=False)
testloader = DataLoader(dataset=testset, batch_size=128, shuffle=False)
class GarbageNet(nn.Module): def __init__(self): super(GarbageNet, self).__init__() self.conv1 = nn.Conv2d(3, 96, 11, 4) self.conv2 = nn.Conv2d(96, 256, 5, 1, padding=2, groups=2) self.conv3 = nn.Conv2d(256, 384, 3, 1, padding=1) self.conv4 = nn.Conv2d(384, 384, 3, 1, padding=1) self.conv5 = nn.Conv2d(384, 256, 3, 1, padding=1) self.fc1 = nn.Linear(256 * 6 * 6, 4096) self.fc2 = nn.Linear(4096, 4096) self.fc3 = nn.Linear(4096, 6) def forward(self, x): x = self.conv1(x) x = F.relu(x) x = F.max_pool2d(x, kernel_size=3, stride=2) # x = F.max_pool2d(F.relu(self.conv1(x)), kernel_size=3, stride=2) x = F.max_pool2d(F.relu(self.conv2(x)), kernel_size=3, stride=2) x = F.relu(self.conv3(x)) x = F.relu(self.conv4(x)) x = F.max_pool2d(self.conv5(x), kernel_size=3, stride=2) x = x.view(-1, 256 * 6 * 6) x = F.dropout(F.relu(self.fc1(x))) x = F.dropout(F.relu(self.fc2(x))) x = self.fc3(x) return x
在本次垃圾分类任务中,最终将图片分为六类,因此与原始AlexNet不同,最后一层全连接层的输出size为6。
根据AlexNet论文中的参数,优化器使用SGD, 并将其学习率设置为0.01, 动量衰减参数设置为0.9,权重衰减参数为0.0005。
损失函数使用CrossEntropyLoss
。
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=0.0005)
criterion = nn.CrossEntropyLoss()
def train(dataloader): epoch_loss = 0.0 iter_num = 0 correct = 0 total = 0 for i, data in enumerate(dataloader, 0): inputs, labels = data if use_gpu: inputs = inputs.to(GPU) labels = labels.to(GPU) if torch.is_grad_enabled(): optimizer.zero_grad() outputs = net(inputs) loss = criterion(outputs, labels) if torch.is_grad_enabled(): loss.backward() optimizer.step() epoch_loss += loss.item() iter_num += 1 _, predicted = torch.max(outputs, 1) c = (predicted == labels).squeeze() for i, lb in enumerate(labels): correct += c[i].item() total += 1 return epoch_loss / iter_num, correct / total
for epoch in range(0, EPOCH_NUMBER):
t_l, t_a = train(trainloader)
train_loss.append(t_l)
train_accuracy.append(t_a)
with torch.no_grad():
v_l, v_a = train(validloader)
print("Epoch %03d train loss: %.6f" % (epoch + 1, t_l))
print(" val accuracy: %.2f%%" % (100 * v_a))
val_loss.append(v_l)
val_accuracy.append(v_a)
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.plot(range(EPOCH_NUMBER), train_accuracy, label="train")
plt.plot(range(EPOCH_NUMBER), val_accuracy, label='val')
plt.title("Accuracy", size=15)
plt.legend()
plt.grid(True)
plt.subplot(122)
plt.plot(range(EPOCH_NUMBER), train_loss, label="train")
plt.plot(range(EPOCH_NUMBER), val_loss, label="val")
plt.title("Loss", size=15)
plt.legend()
plt.grid(True)
plt.show()
从图中可以看出, 随着迭代次数的增加,准确率逐渐增加,当迭代次数超过75次之后,趋向于稳定。 在验证集上的精度可以到95%以上,与训练集差别很小,说明分类效果良好,模型泛化能力不错。
欢迎关注我们的微信公众号:MomodelAI
同时,欢迎使用 「Mo AI编程」 微信小程序
以及登录官网,了解更多信息:Mo 平台
Mo,发现意外,创造可能
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。