文章目录
一、视频学习和论文阅读
1.MobileNet V1 & V2
2.MobileNet V3
3.SENet
二、代码学习
1.使用 SENet 对 CIFAR10 数据集进行分类
1.1定义网络结构
1.2训练数据
1.3测试数据
2.HybridSN 高光谱分类
2.1第一次测试得到的分类结果
2.2 第二次测试得到的分类结果
2.3第三次测试得到的分类结果
问题思考
1.3D卷积和2D卷积的区别?
2.为什么每次分类的结果都不一样?
3.想要进一步提升高光谱图像的分类性能,可以如何改进?
网络结构:
作者提出了线性瓶颈层(Linear Bottlenecks)
从上图可以看出,在低维时,Relu 对信号的损失非常大;随着维度增加,损失越来越小;因此,作者认为在输出维度较低是使用 ReLU 函数,很容易造成信息的丢失,故而选择在末层使用线性激活。
bottleneck的结构图
MobileNetV2 的架构包含具有 32 个过滤器的初始全卷积层。我们使用 ReLU6 作为非线性,因为它在与低精度计算一起使用时具有鲁棒性。除了第一层,我们在整个网络中使用恒定的拓展率t=6。
介绍了Mobile netV3的一个变体:Mobile net -Large ,其对应高资源情况;
基本原理:
#创建SENet网络
class SENet(nn.Module):
def __init__(self):
super(SENet, self).__init__()
#最终分类的种类数
self.num_classes = 10
#输入深度为64
self.in_channels = 64
#先使用64*3*3的卷积核
self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(64)
#卷积层的设置,BasicBlock
#2,2,2,2为每个卷积层需要的block块数
self.layer1 = self._make_layer(BasicBlock, 64, 2, stride=1)
self.layer2 = self._make_layer(BasicBlock, 128, 2, stride=2)
self.layer3 = self._make_layer(BasicBlock, 256, 2, stride=2)
self.layer4 = self._make_layer(BasicBlock, 512, 2, stride=2)
#全连接
self.linear = nn.Linear(512, self.num_classes)
#实现每一层卷积
#blocks为大layer中的残差块数
#定义每一个layer有几个残差块,resnet18是2,2,2,2
def _make_layer(self, block, out_channels, blocks, stride):
strides = [stride] + [1]*(blocks-1)
layers = []
for stride in strides:
layers.append(block(self.in_channels, out_channels, stride))
self.in_channels = out_channels
return nn.Sequential(*layers)
#定义网络结构
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = self.layer1(out)
out = self.layer2(out)
out = self.layer3(out)
out = self.layer4(out)
out = F.avg_pool2d(out, 4)
out = out.view(out.size(0), -1)
out = self.linear(out)
return out
#网络放到GPU上
net = SENet().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.001)
for epoch in range(10): # 重复多轮训练
for i, (inputs, labels) in enumerate(trainloader):
inputs = inputs.to(device)
labels = labels.to(device)
# 优化器梯度归零
optimizer.zero_grad()
# 正向传播 + 反向传播 + 优化
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# 输出统计信息
if i % 100 == 0:
print('Epoch: %d Minibatch: %5d loss: %.3f' %(epoch + 1, i + 1, loss.item()))
print('Finished Training')
correct = 0
total = 0
for data in testloader:
images, labels = data
images, labels = images.to(device), labels.to(device)
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
可以明显看出,SENet训练的网络得到的准确率要远高于普通CNN,性能更好。
补充网络部分代码:
class_num = 16
class HybridSN(nn.Module):
def __init__(self):
super(HybridSN, self).__init__()
# 3D卷积层
self.conv1 = nn.Conv3d(1, 8, (7, 3, 3))
self.conv2 = nn.Conv3d(8, 16, (5, 3, 3))
self.conv3 = nn.Conv3d(16, 32, (3, 3, 3))
# 2D卷积层
self.conv4 = nn.Conv2d(576, 64, (3, 3))
# 全连接层
self.liner1 = nn.Linear(18496, 256)
self.liner2 = nn.Linear(256, 128)
self.liner3 = nn.Linear(128, 16)
# Dropout
self.dropout = nn.Dropout(0.4)
# 激活函数
self.relu = nn.LeakyReLU()
self.logsoftmax = nn.LogSoftmax(dim=1)
def forward(self, x):
out = self.conv1(x)
out = self.relu(out)
out = self.conv2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.relu(out)
out = out.view(-1, out.shape[1]*out.shape[2], out.shape[3], out.shape[4])
out = self.conv4(out)
out = self.relu(out)
out = out.view(x.size(0), -1)
out = self.liner1(out)
out = self.relu(out)
out = self.dropout(out)
out = self.liner2(out)
out = self.relu(out)
out = self.dropout(out)
out = self.liner3(out)
out = self.logsoftmax(out)
return out