这里主要是通过记录一些笔记来阅读这篇 Paper,它的产生跟 ImageNet LSVRC-2010 竞赛有关,通过训练一个大的、深的卷积网络来将 1.2 million 的 HR 图像分成 1000 类 ,这个网络实现了 top-1 37.5% 和 top-5 17.0% 的错误率,相较于之前先进的方法实现了很大的改进。
在LeNet的基础上提出了CNN ,打破了传统的方法的局限;
Link:https://dl.acm.org/doi/pdf/10.1145/3065386
全称是 Large Scale Visual Recognition Challenge 2010,中文意为大规模视觉识别挑战赛2010
LSVRC是一个针对计算机视觉领域的竞赛,旨在推动图像分类和目标识别等任务的研究和发展。该竞赛由ImageNet项目发起,是计算机视觉领域最具影响力和知名度的竞赛之一。
在LSVRC-2010中,参赛者需要使用给定的数据集(即ImageNet提供的数据集),在图像分类和目标识别任务上进行算法和模型的评估。该竞赛的数据集包含来自多个类别的数百万张图像,并且参赛者需要开发出能够准确识别和分类这些图像的算法和模型。
ImageNet数据集的产生源于斯坦福大学的一个研究项目,旨在解决计算机对图像的理解和识别能力的挑战。2006年,斯坦福大学的计算机科学教授Fei-Fei Li等人启动了一个名为"ImageNet项目"的研究计划,旨在构建一个大规模的图像数据库,涵盖丰富的物体类别和场景。他们认识到,要想使计算机能够真正理解图像,需要一个庞大而多样的数据集,能够覆盖人类生活中的各种物体和概念。
这个网络的成绩(省略) & 网络的主要结构
The neural network,which has 60 million parameters and 650,000 neurons, consists of five convolutional layers, some of which are followed by max-pooling layers, and three fully connected layers with a final 1000-way softmax.
网络有 60 million 参数,650000 神经元,组成了 5 层卷积,后 +最大池化层+ 3个有着softmax的全连接层。
To make training faster, we used nonsaturating neurons and a very efficient GPU implementation of the convolution operation. To reduce overfitting in the fully connected layers we employed a recently developed regularization method called “dropout” that proved to be very effective. We also entered a variant of this model in the ILSVRC-2012 competition and achieved a winning top-5 test error rate of 15.3%, compared to 26.2% achieved by the second-best entry.
非饱和的神经元:即非线性的神经元,引入网络非线性元素,例如ReLu...
使用高效的 GPU使得训练的速度加快 ; 使用dropout正则化方式来减少过拟合;
CNN的一些前期发展困难和反向传播的使用等等...
说明了目前数据集不够大所带来的模型不够好的问题并已被认证,想尝试通过保留标签的转换来尝试获得更多的数据集。使得能够在不过拟合的情况下,充分训练一个模型。还介绍了本论文的一些贡献:本文的具体贡献如下:(1)训练了一个大规模的CNN网络并且取得了不错的成绩。(2)编写了一个高度优化的GPU实现的2D卷积和训练cnn中固有的所有其他操作。我们的网络包含了一些新的和不寻常的特性,提高了性能,减少了训练时间。(3)我们的网络的规模使过拟合成为一个重大的问题,即使有120万个标记的训练例子,所以我们使用了几种有效的技术来防止过拟合。我们最终的网络包含5个卷积层和3个完全连接的层,这个深度似乎很重要:我们发现去除任何卷积层(每个层包含不超过1%的模型参数)会导致较差的性能。
饱和非线性激活函数(如Sigmoid和Tanh)在某些输入范围内导数接近于零,容易导致梯度消失的问题。而非饱和非线性激活函数(如ReLU、Leaky ReLU和ELU)的导数在整个输入范围内保持较大的值,有助于缓解梯度消失问题,并提供更强的非线性表达能力。选择适合的激活函数取决于具体的任务和网络结构,需要综合考虑梯度传播、非线性表示能力和计算效率等因素。
如上图,我们可以看到一个四层的卷积神经网络使用ReLU比tanh训练达到同一错误率的速度快;
主要是在两个GPU上进行训练,使用DPL并行训练,提升训练网络的速度;
6.3 Local response normalization
局部响应归一化,能够对网络有很好的泛化效果;
6.4 Overlapping pooling
具有池化重叠相较于不重叠的反而效果是更好的;
6.5 Overall architecture
以 AlexNet网络为例子,来回忆一下卷积的流程,包括卷积层和全连接层一共有八层;
0.输入层:AlexNet 接受输入为227x227大小的图像
输入维度为:227X227X3(有一些争议,但是基本上以代码为主)
1.卷积层-ReLu-池化层(最大池化):
(1)卷积:包含96个大小为11x11的卷积核K,步幅S为4,没有填充。
输入维度为:227X227X3
输出维度为:55x55x96
H_out = (H_in + 2P - K) / S + 1 = (227 + 2x0 - 11) / 4 + 1 = 55
W_out = (W_in + 2P - K) / S + 1 = (227 + 2x0 - 11) / 4 + 1 = 55(2)激活函数:ReLU非线性激活函数;
(3)池化:池化核大小3 × 3,不扩充边缘padding = 0,步长stride = 2,因此输出大小为(55-3+0×2)/2+1=27
输入维度为:55x55x96
输出维度为:27x27x96(如果是两个GPU,那就是48)
2.卷积层-ReLu-池化层(最大池化):
(1)卷积:输入27×27×96,256个5×5×96的卷积核,扩充边缘padding = 2, 步长stride = 1,因此输出结果为(27-5+2×2)/1+1 = 27,即27×27×256;
(2)激活函数:ReLU;
(3)池化:池化核大小3 × 3,不扩充边缘padding = 0,步长stride = 2,输出大小为(27-3+0)/2+1=13;输入维度为:27x27x256
输出维度为:13x13x256
3.卷积层-ReLu:
(1)卷积:输入13×13×256,384个3×3×256的卷积核, 扩充边缘padding = 1,步长stride = 1,因此其FeatureMap大小为(13-3+1×2)/1+1 = 13,即13×13×384;
输入维度为:13x13x256
输出维度为:13x13x384
(2)激活函数:ReLu
4. 卷积层-ReLu:
(1)卷积:输入13×13×384,384个3×3×384的卷积核, 扩充边缘padding = 1,步长stride = 1,因此其FeatureMap大小为(13-3+1×2)/1+1 = 13,即13×13×384;
输入维度为:13x13x384;
输出维度为:13x13x384
(2)激活函数:ReLU;
5.卷积层-ReLu-池化层(最大池化)
(1)卷积:输入13×13×384,256个3×3×384的卷积核,扩充边缘padding = 1,步长stride = 1,因此其FeatureMap大小为(13-3+1×2)/1+1 = 13,即13×13×256;
(2)激活函数:ReLU;
(3)池化:池化核大小3 × 3, 扩充边缘padding = 0,步长stride = 2,因此其FeatureMap输出大小为(13-3+0×2)/2+1=6;
输入维度为:13x13x384;
输出维度为:6x6x256;
6.全连接层-ReLu-Droupt:包含4096个神经元,应用ReLU激活函数。
(1)全连接实际上是通过卷积进行的,输入6×6×256,4096个6×6×256的卷积核,扩充边缘padding = 0, 步长stride = 1
输入维度为:6x6x256;
输出维度为:1x1x4096;
(2)激活函数:ReLU;
(3)Dropout:全连接层中去掉了一些神经节点,达到防止过拟合,输出为1×1×4096;
7.全连接层-ReLu-droupout:
(1)全连接:此层的全连接,输入1×1×4096;
(2)激活函数:ReLU;
(3)Dropout:全连接层中去掉了一些神经节点,达到防止过拟合,输出为1×1×4096;
8.全连接层-sofmax
(1)全连接:此层的全连接,输入1×1×4096;
(2)softmax:softmax为1000,输出为1×1×1000;
当网络没有过拟合时,它意味着模型在训练数据上的性能良好,可以很好地拟合训练数据的特征和标签。然而,这并不意味着网络能够学习到更多的参数或更复杂的模式。
一个网络的容量(capacity)是指其可以学习的模型的复杂程度或灵活性。容量较低的网络可能无法学习到复杂的模式和关系,导致欠拟合;而容量较高的网络可以更好地适应训练数据,但也容易发生过拟合。
(1)保留标签的变换;
(2)改变训练图像RGB通道的强度;
主要是用在前两个全连接网络中,来防止网络的过拟合;
我们使用随机梯度下降(stochastic gradient descent),bs = 128,momentum =0.9,weight decay = 0.0005;
import time
import torch
from torch import nn, optim
import torchvision
import sys
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 网络的定义
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding
nn.ReLU(),
nn.MaxPool2d(3, 2), # kernel_size, stride
# 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
nn.Conv2d(96, 256, 5, 1, 2),
nn.ReLU(),
nn.MaxPool2d(3, 2),
# 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
nn.Conv2d(256, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 256, 3, 1, 1),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
self.fc = nn.Sequential(
nn.Linear(256*6*6, 4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096, 10),
)
def forward(self, img):
feature = self.conv(img)
output = self.fc(feature.view(img.shape[0], -1))
return output
# 读取数据并且对其进行处理
resize = 227
trans = []
num_workers = 8
trans.append(torchvision.transforms.Resize(size=resize))
trans.append(torchvision.transforms.ToTensor())
transform = torchvision.transforms.Compose(trans)
root = '/home/tangb_lab/cse30011373/data/'
batch_size = 128
num_epochs = 10
mnist_train = torchvision.datasets.FashionMNIST(root=root, train=True, download=False, transform=transform)
mnist_test = torchvision.datasets.FashionMNIST(root=root, train=False, download=False, transform=transform)
train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)
def evaluate_accuracy(data_iter, net, device=None):
if device is None and isinstance(net, torch.nn.Module):
# 如果没指定device就使用net的device
device = list(net.parameters())[0].device
acc_sum, n = 0.0, 0
with torch.no_grad():
for X, y in data_iter:
net.eval() # 评估模式, 这会关闭dropout
acc_sum += (net(X.to(device)).argmax(dim=1) == y.to(device)).float().sum().cpu().item()
net.train() # 改回训练模式
n += y.shape[0]
return acc_sum / n
# 开始训练
net = AlexNet()
net = net.to(device)
print("training on ", device)
lr = 0.001
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
loss = torch.nn.CrossEntropyLoss()
for epoch in range(num_epochs):
train_l_sum, train_acc_sum, n, batch_count, start = 0.0, 0.0, 0, 0, time.time()
for X, y in train_iter:
X = X.to(device)
y = y.to(device)
y_hat = net(X)
l = loss(y_hat, y)
optimizer.zero_grad()
l.backward()
optimizer.step()
train_l_sum += l.cpu().item()
train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()
n += y.shape[0]
batch_count += 1
test_acc = evaluate_accuracy(test_iter, net)
print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, time %.1f sec'
% (epoch + 1, train_l_sum / batch_count, train_acc_sum / n, test_acc, time.time() - start))