Goodlenet网络
提升网络的性能最直接的方法就是增加网络的宽度和网络的深度。但是会产生过参数太多,过拟合现象,梯度消失以及产生巨大的计算量。
引入了Inception模块,使用1x1的卷积来进行升降维,在多个尺寸上同时进行卷积再聚合。通过多个卷积核提取图像不同尺度的信息,最后进行融合,可以得到图像更好的特征。将1x1,3x3,5x5的conv和3x3的pooling,堆叠在一起。
原始版本
改进后在卷积前增加1x1的卷积,池化后增加1x1的卷积,减少计算量。
特点:
1.GoogLeNet采用了模块化的结构,有九个Inception Module,方便增添和修改;
2 . 网络最后采用了average pooling来代替全连接层,
3 . 虽然移除了全连接,但是仍然使用了Dropout ;
4 . 为了避免梯度消失,网络在训练时额外增加了2个辅助的softmax用于向前传导梯度,在计算损失时需要按照一定的权重加到最后的总loss中,如下图。
优化Inception结构的规则:
1.要防止出现特征描述的瓶颈,中间某层对特征在空间维度进行较大比例的压缩(比如使用pooling时),导致很多特征丢失。虽然Pooling是CNN结构中必须的功能,但我们可以通过一些优化方法来减少Pooling造成的损失
2.特征的数目越多,收敛的速度越快。
3.可以压缩特征维度数,来减少计算量。
4.网络的深度和宽度要达到平衡。
Inception V2/v3模型
1,引入了Batch Normalize
2,使用vgg网络中的方法,用2个3x3的卷积核代替1个5x5的大卷积核,减少计算量和参数量。
在训练过程中,每一层输入的分布因为前一层参数的变化而不断变化,参数的变化引起激活值分布发生变化。如果网络的某一层输入数据的分布发生变化,那么这一层的网络就需要学习去适应这个新的数据分布,这会产生很大的计算量,耗费时间,准确率也不那么高。
引入Batch Normalize,对输入的信息进行标准化分布,运用在激活函数之前,使收敛速度更快。
3.使用非对称卷积。将nxn的卷积分解成1xn和nx1卷积的串联,例如n=3,分解为3x1和1x3两个卷积,分解后就能节省33%的计算量。非对称卷积用在网络中靠中间的层级才有较好的效果(特别是feature map的大小在12x12~20x20之间时)
4.使用并行结构来优化Pooling。Pooling会造成特征描述的瓶颈,有两种解决办法。方法1:在Pooling前用1x1卷积把特征数加倍,然后再使用池化操作。这种方法有很好的效果,但是1x1卷积会增大计算量。或者先做Pooling减少feature map size,然后再使用1x1 conv对其channels数目放大,但是先使用Pooling的话会造成信息硬性丢失。
方法2:使用两个并行的支路,一路是1x1卷积,由于特征维度没有加倍,计算量相比之前减少了一倍,另一路是Pooling,最后再在特征维度拼合到一起,效果好的同时也没有增加计算量。
方法1:
方法2:
5.使用Label Smoothing来对网络输出进行正则化。
inception v2的网络结构图:
inception v3的网络结构图:
inception v3模型比 inception v2 模型在辅助分类器上多使用了BN。
Incepton v4
Incepton V4把一个先1x1再3x3那步换成了先3x3再1x1。
Incepton V4的结构:
Reduction主要是用来降低feature map的尺寸。Inception v4中基本的Inception module还是使用了Inception v2/v3的结构,只是结构看起来更加简洁,使用更多的Inception module。
Inception-ResNet
引入了residual connection,把Inception和ResNet结合起来,让网络又宽又深,提出了两个版本:
Inception-ResNet v1:Inception加ResNet,计算量和Inception v3相当,较小的模型Inception-ResNet v2:Inception加ResNet,计算量和Inception v4相当,较大的模型准确率也更高。
inception resnet v1中的残差结构:
inception resnet v2中的残差结构:
Inception module每个分支都没有使用pooling,每个Inception module最后都使用了一个1x1的卷积,作用是保证identity部分和Inception部分输出特征维度相同,这样才能保证两部分特征能够相加。
inception resnet v1和inception resnet v2 网络的stem结构不同,其他结构相同如下图。
使用inceptionv3实现猫狗分类
重要代码:
迁移学习
writer = SummaryWriter()
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
transform = transforms.Compose([transforms.CenterCrop(299),
transforms.ToTensor(),
normalize])
train_dataset = ImageFolder(root='./data/train', transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
val_dataset = ImageFolder(root='./data/validation', transform=transform)
val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=64, shuffle=True)
model = models.inception_v3(pretrained=True)
num_aux_ftrs = model.AuxLogits.fc.in_features
num_ftrs = model.fc.in_features
for param in model.parameters():
param.requires_grad = False
model.AuxLogits.fc = nn.Linear(num_aux_ftrs, 2)
model.fc = nn.Linear(num_ftrs, 2)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)
for epoch in range(2):
for i, data in enumerate(train_loader):
sum = 0
total1 = 0
tn = 0
tf = 0
i += 1
total1 = 64
inputs, labels = data
inputs = Variable(inputs)
labels = Variable(labels)
optimizer.zero_grad()
outputs, aux_outputs = model(inputs)
loss1 = criterion(outputs, labels)
loss2 = criterion(aux_outputs, labels)
loss = loss1 + 0.3 * loss2
loss.backward()
optimizer.step()
_, preds = torch.max(outputs, 1)
preds = preds.numpy()
labels = labels.numpy()
print("loss is: ", loss)
writer.add_scalar("loss11", loss, i)
for j in range(64):
if (preds[j] == labels[j]):
sum += 1
if (preds[j] == 0 and labels[j] == 0):
tn += 1
if (preds[j] == 0 and labels[j] == 1):
tf += 1
if i % 4 == 0:
acc1 = sum / total1
TF = tn / (tn + tf)
print('acc is : {:.3f},TF is :{:.3f} '.format(acc1, TF))
writer.add_scalar("acca", acc1, i)
if i == 120:
break
acc = 0
total = 64
sum = 0
for i, data in enumerate(val_loader):
i += 1
inputs, labels = data
inputs = Variable(inputs)
labels = Variable(labels)
optimizer.zero_grad()
outputs, _ = model(inputs)
loss = criterion(outputs, labels)
preds,_ = torch.max(outputs, 1)
preds = preds.numpy()
labels = labels.numpy()
for j in range(24):
if(preds[j] == labels[j]):
sum += 1
if i % 20 == 0:
acc = sum / total
print('ACC is {:.3f}'.format(acc))
writer.add_scalar("acc", acc, i)
writer.close()
运行结果截图:
由tensorboardx图可以看出,Inceptionv3网络对猫狗分类效果较好,经过很短的时间,loss就已经下降到很低,acc在短的时间内就已经达到0.95左右。
补充迁移学习
冻结参数
for para in list(model.parameters())[:-1]😕/除了最后一层的参数,其他 的都冻结。a[1:4:1] a[1:4] a[:-1]