HybridSN修改
结果为:
经过一周的学习与参考其他同学的代码,我对自己的代码进行了一定的修改。
添加bn层
class HybridSN(nn.Module):
def __init__(self, num_classes=16):
super(HybridSN, self).__init__()
self.conv1 = nn.Sequential(nn.Conv3d(1, 8, (7, 3, 3)), nn.BatchNorm3d(8), nn.ReLU())
self.conv2 = nn.Sequential(nn.Conv3d(8, 16, (5, 3, 3)), nn.BatchNorm3d(16), nn.ReLU())
self.conv3 = nn.Sequential(nn.Conv3d(16, 32, (3, 3, 3)), nn.BatchNorm3d(32), nn.ReLU())
self.conv3_2d = nn.Sequential(nn.Conv2d(576, 64, (3,3)), nn.BatchNorm2d(64), nn.ReLU())
self.dense1 = nn.Linear(18496,256)
self.dense2 = nn.Linear(256,128)
self.out = nn.Linear(128, num_classes)
self.drop = nn.Dropout(p=0.4)
self.soft = nn.LogSoftmax(dim=1)
self.relu = nn.ReLU()
最终结果为:
添加学习率衰减
在参考了解志杰同学的代码后,我发现他使用了一个我没有见过的函数,遂百度之
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min',verbose=True,factor=0.9,min_lr=1e-6)
'''
'''
scheduler.step(loss)
这是一个学习率衰减函数
当网络的评价指标不在提升的时候,可以通过降低网络的学习率来提高网络性能。
class torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10,
verbose=False, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08)
其中:
- optimer指的是网络的优化器
- mode (str) ,可选择‘min’或者‘max’,min表示当监控量停止下降的时候,学习率将减小,max表示当监控量停止上升的时候,学习率将减小。默认值为‘min’
- factor 学习率每次降低多少,new_lr = old_lr * factor
- patience=10,容忍网路的性能不提升的次数,高于这个次数就降低学习率
- verbose(bool) - 如果为True,则为每次更新向stdout输出一条消息。 默认值:False
- threshold(float) - 测量新最佳值的阈值,仅关注重大变化。 默认值:1e-4
- cooldown: 减少lr后恢复正常操作之前要等待的时期数。 默认值:0。
- min_lr,学习率的下限
- eps ,适用于lr的最小衰减。 如果新旧lr之间的差异小于eps,则忽略更新。 默认值:1e-8。
注意:
使用的时候需要选择网络的度量指标,使用如下类的step方法实现,例子如下:
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
scheduler = ReduceLROnPlateau(optimizer, 'min',factor=0.5, patience=4, verbose=True)
.....
scheduler.step(train_loss)
使用后可以发现,学习率确实是在衰减
最终的结果:
采用不同的衰减算法的结果:
scheduler = torch.optim.lr_scheduler.StepLR(optimizer,step_size=5,gamma = 0.8)
scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.98)
train与eval
但是有一个问题始终没有解决,就是每次测试的时候,正确率都在小幅度的变化
为了探究这个问题,我上网查询了相关资料
在pytorch中,网络有train和eval两种模式
在train模式下,dropout和batch normalization会生效
而eval模式下,dropout不生效,bn固定参数。
这就说明了为什么每次的正确率都会浮动而不是一个固定的值,因为如果没有在没有在测试时添加net.eval,则BN和DropOut没有被固定住使用训练好的值,就会导致每次的结果有变化。
SENet网络
万事俱备,只欠东风。
在设计好的HybridSN模块中加入SENet网络试试吧。
class SELayer(nn.Module):
def __init__(self, channel, r=16):
super(SELayer, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d((1,1))
self.fc = nn.Sequential(
nn.Linear(channel, channel // r),
nn.ReLU(),
nn.Linear(channel // r, channel),
nn.Sigmoid()
)
def forward(self, x):
a, b, _, _ = x.size()
y = self.avg_pool(x).view(a, b)
y = self.fc(y).view(a, b, 1, 1)
return x * y.expand_as(x)
class HybridSN(nn.Module):
def __init__(self, num_classes=16):
'''
self.senet = SELayer(64)
'''
def forward(self, x):
'''
out = self.conv3_2d(out)
out = self.senet(out)
'''
最终结果为:
通过表格整理一下(以下结果均为三次测试中的最大值)
方法 | 结果 |
---|---|
HybridSN | 94.99 |
添加bn层 | 98.41 |
添加学习率衰减函数 | 98.93 |
添加SENet | 99.06 |