深度分割模型比赛训练技巧( T r i c k s ) 深度分割模型比赛训练技巧(Tricks) 深度分割模型比赛训练技巧(Tricks)
深度分割模型比赛训练技巧示例
在深度模型中进行模型集成:偏向于使用Blend/Average,对多折模型的预测结果进行加权求和。
或者可以使用vote对模型结果进行投票
分割数据集图片中的目标应尽量在完整的出现在图中央,而不是被边缘分割。(OverLap进行要求,一般选输入数据大小的1/10,如果输入图片1024*1024,overlap可以设为124
)
在深度学习模型的训练中,dropout层是模型集成的非常典型的代表。
在训练时使用dropout,在预测时禁用dropout,等于集成了很多模型进行预测。
推荐使用的常用数据扩增
- 翻转
- 旋转或平移
- 亮度改变
- 颜色改变
- 随机形变
- 随机图像缩小
谨慎使用(高阶数据增强方法):
- Mixup
- CutMix
手写数据增强推荐:OpenCV
直接调用库:推荐Albumentations
为什么不用torch或tf等框架自带的数据增强库,其实当然是可以使用的,只不过Albumentations是就打kaggle比赛的一群人写的库,天然会适合一点,而且别人也用习惯了,出现的早一点,提前占领了。
对于少量数据集的学习率调整策略,我建议使用类似于CosineAnnealingLR的策略,其存在学习率由小变大的过程,利于跳出局部最优。
需要调整的参数:
1.选择合适的样本量
2.网络模型
3.优化算法和学习率
4.损失函数
5.激活函数
6.图像预处理
推荐调参的顺序:
一般最后是网络模型
首先确定的是优化算法和学习率
其次是损失函数
之后是图像预处理
…
分割常用问题?
1.模型的精度多少才合适(比赛、论文上找找)
2.为什么这个这么低?是损失函数、还是预处理、还是数据集不均衡
3.分割和分类精度是否正常?如果不正常,如何设计loss,进行调整
实验之后与之前的数据分析是重中之重
如何解决自己分析数据之后的问题
1.莽试
2.找论文
3.找人问
4.找专门的网站
5.找专门的博客
技巧
多任务学习(Multi-Task):有利于解决
存在一个非常烦人的问题,就是比如多任务为分割与分类,这两个任务很有可能是矛盾的,分割好了,分类可能差,这对损失函数的调参需要一定的经验和多次尝试。
网络模型变换
1.增加网络“深度”(low)
2.更好的网络架构(好的网络块)(good)(找目前最新的论文)
输入图像大小调整:
一般原图大小左右就行
但会遇到一些特殊情况
可以考虑从128*128
-->256*256
—>512*512
—>1024*1024
…
loss轮番上:BCE—>Dice loss—>lovasz loss—>…
迁移学习:模型参数迁移起来,加快学习和收敛
常识性基础:
分割任务:Encoder(提取特征)+Decoder(还原分割)
Encoder(提取特征):
需要知道系列:
1.Vgg系列:vgg16、vgg19、se-vgg16…
2.Inception系列:v1、v2、v3
3.Densenet系列:DENSE块
4.SENet系列:SE块
5.ResNet家族系列:resnet系列、resnext系列、se-resnet系列、se-resnext系列....
6.Efficient系列:b0、b1、b2、b3、b4、b5、b6、b7....
Decoder(还原分割):
1.转置卷积
2.上池化
3.线性插值
一 确定合适的调参数据量,以便于快速进行Ideas
的验证
这个具体可以结合时间,大概以一个Epoch在1-5min左右为准,跑10个Epoch,也就是10-50mins
具体图片的量的话,一般的机器,在几百到几千张。
一般建议,训练集在1-2w,验证集在1000-8000左右。这个和时间相矛盾,自己协调吧。
看你设置的合不合理,可以查看你的验证集的loss,是不是在稳定的下降。
二 一些参数值的推荐设置范围
early_stop_round = 5~10
learning_rate = 0.001~0.1(不能太小,也不能太大,感觉是废话)
batch_size = 看你机器了呗
image_size = 理论上是越大越好
学习率可视化
import torch
import torchvision
net = torchvision.models.resnet34(pretrained=False)
net_train_params = filter(lambda p: p.requires_grad, net.parameters())
optimizer = torch.optim.SGD(net_train_params , momentum=0.9, weight_decay=0.0001, lr=0.02)
#scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.3)
#scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[5, 30], gamma=0.1)
scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.99)
for epoch in range(200):
#train
print('lr: %.4f, epoch: %d'%(scheduler.get_lr()[0], epoch))
scheduler.step()
测试你机器显存,是否能撑起这个网络的batch_size和image_size的组合
import sys
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import cv2
import torch
from dataset.dataset_unet import prepare_trainset
from major_model import UNet_puls_plus_plus
%matplotlib inline
sys.path.append('../')
def Test_VRAM(BATCH_SIZE=2, IMG_SIZE=512, device=device):
train_dl, val_dl = prepare_trainset(BATCH_SIZE=BATCH_SIZE,
NUM_WORKERS=8,
SEED=2019,
IMG_SIZE=IMG_SIZE, debug=True)
for i, (images, masks) in enumerate(train_dl):#一次读取一个Bath
images = images.to(device=device, dtype=torch.float)
masks = masks.to(device=device, dtype=torch.float)
if i==0:
break
print(images.size(), masks.size())
##
net = UNet_puls_plus_plus(debug=False)
net = net.to(device=device)
logit = net(images)
print('Pass')
Test_VRAM(BATCH_SIZE=2, IMG_SIZE=512, device='cuda:0')#'cpu'#'cuda:0'
三 Loss的选择
-
Focal Loss
问题:各类别数据不均衡
原理:根据样本概率调节
实现:https://www.kaggle.com/c/tgs-salt-identification-challenge/discussion/65938 -
Dice Loss
-
BCE Loss
-
Weight Loss
-
Boundary Loss
-
Lovasz-Softmax Loss:
问题:IOU和Dice非常容易受到类别影响;
原理︰结合Lovasz hinge和Jaccard loss解决二值图片的分割问题;
实现: https://github.com/bermanmaxim/LovaszSoftmax -
TopK Loss
-
Hausdorff Distance Loss
-
Sensitivity Specificity Loss
-
Distance Penalized CE Loss
-
Colour-Aware Loss
-
OHEM
问题:重点关注错误样本;
原理:增加错误样本的loss,或将错误样本再训练;
实现:
import torch
from torch import nn
import torch.nn.functional as F
__all__ = [
"BCEWithLogitsLossWithOHEM",
"CrossEntropyLossWithOHEM",
"DiceLoss",
"SoftCrossEntropyLossWithOHEM",
]
def _ohem_mask(loss, ohem_ratio):
with torch.no_grad():
values, _ = torch.topk(loss.reshape(-1),
int(loss.nelement() * ohem_ratio))
mask = loss >= values[-1]
return mask.float()
class BCEWithLogitsLossWithOHEM(nn.Module):
def __init__(self, ohem_ratio=1.0, pos_weight=None, eps=1e-7):
super(BCEWithLogitsLossWithOHEM, self).__init__()
self.criterion = nn.BCEWithLogitsLoss(reduction='none',
pos_weight=pos_weight)
self.ohem_ratio = ohem_ratio
self.eps = eps
def forward(self, pred, target):
loss = self.criterion(pred, target)
mask = _ohem_mask(loss, self.ohem_ratio)
loss = loss * mask
return loss.sum() / (mask.sum() + self.eps)
def set_ohem_ratio(self, ohem_ratio):
self.ohem_ratio = ohem_ratio
class CrossEntropyLossWithOHEM(nn.Module):
def __init__(self,
ohem_ratio=1.0,
weight=None,
ignore_index=-100,
eps=1e-7):
super(CrossEntropyLossWithOHEM, self).__init__()
self.criterion = nn.CrossEntropyLoss(weight=weight,
ignore_index=ignore_index,
reduction='none')
self.ohem_ratio = ohem_ratio
self.eps = eps
def forward(self, pred, target):
loss = self.criterion(pred, target)
mask = _ohem_mask(loss, self.ohem_ratio)
loss = loss * mask
return loss.sum() / (mask.sum() + self.eps)
def set_ohem_ratio(self, ohem_ratio):
self.ohem_ratio = ohem_ratio
class DiceLoss(nn.Module):
def __init__(self, eps=1e-7):
super(DiceLoss, self).__init__()
self.eps = eps
def forward(self, pred, target):
pred = torch.sigmoid(pred)
intersection = (pred * target).sum()
loss = 1 - (2. * intersection) / (pred.sum() + target.sum() + self.eps)
return loss
class SoftCrossEntropyLossWithOHEM(nn.Module):
def __init__(self, ohem_ratio=1.0, eps=1e-7):
super(SoftCrossEntropyLossWithOHEM, self).__init__()
self.ohem_ratio = ohem_ratio
self.eps = eps
def forward(self, pred, target):
pred = F.log_softmax(pred, dim=1)
loss = -(pred * target).sum(1)
mask = _ohem_mask(loss, self.ohem_ratio)
loss = loss * mask
return loss.sum() / (mask.sum() + self.eps)
def set_ohem_ratio(self, ohem_ratio):
self.ohem_ratio = ohem_ratio
1.BCE:二分类交叉熵
2.Weighted BCE
3.Focal Loss
4.Dice Loss
5.组合Loss
- BCE+DICE
- 多任务模型,分割loss+分类loss
参考文献
https://lars76.github.io/2018/09/27/loss-functions-for-segmentation.html
https://www.jeremyjordan.me/semantic-segmentation/
https://gombru.github.io/2018/05/23/cross_entropy_loss/
Focal loss paper,Facebook
Lovasz loss,optimize lou
四 优化器选择
啊,这个随便选吧,影响不大。
无论是pytorch还是tensorflow,或者其他,都有API可以调用。用框架提供的就🆗了
选SGD,Adma…,再加一个Momentum动量就差不多了
五 多尺度怎么加
- ASPP
- PPM
- DCM
- DenseASPP
- FPA
- OCVet
- MPM
六 注意力机制怎么加
SE
Non-local
CcNet
GC-Net
Gate
CBAM
Dual Attention
Spatial Attention
Channel Attention
七 卷积块选择
Residual block
Bottle-neck block
Split-Attention block
Depthwise separable convolution
Recurrent convolution
Group convolution
Dilated convolution
Octave convolution
Ghost convolution
八 使用伪标签
当模型精度较高时
当比赛规则允许时
GAN网络的威力,有时候会非常大,在伪标签的使用中
伪标签制作
- 步骤1∶使用训练切图的方法对测试集进行切图(大型图像)
- 步骤2∶对测试集切图进行预测
- 步骤3︰人工修正预测结果&选择模型预测较好的结果
- 步骤4︰将筛选后图片加入训练集切图一起训练
这里提出一个非常搞笑的事情,就是实际在很多实际项目中,数据集的label很可能被标错、标漏、标坏,这种现象非常常见
九 自动化搜索
深度学习自动调参
搜索超参数;
1.网格/随机搜索
2.贝叶斯搜索;
搜索网络结构;
自动化调参工具:
十 基础Net选择
自然、复杂场景下:Mask-RCNN
医学、简单场景下:UNet
如果有类别不均衡的情况,可以先分类再分割;
深度模型的深度最好和感受野相关,就是计算最后的感受野和原图近似等大时的深度会较佳
十一 Test Time Augmentation
在计算资源有限的情况下,不采用多折,使用单折训练
深度学习中单折模型中的模型集成方法: Snapshot Ensemble / Stochastic Weight Averaging
训练过程中保存多个中间权重,进行集成;
十二 池化层选择
Max pooling
Average pooling
Random pooling
Strip Pooling
Mixed Pooling