百度Apollo无人车车道线检测挑战赛(二)

百度Apollo车道线分割比赛二(模型搭建)

百度Apollo车道线分割比赛一(数据处理)
百度Apollo车道线分割比赛三(模型训练)

本实现暂时实现两种常见的分割模型Unet,deeplabv3plus,最后在实现两个模型的融合(百度比赛主要看分割的miou不侧重模型的实时性),其中Unet的backbone采用resnet101,deeplabv3plus采用的backbone为Xcepthon65。backbone可以灵活选择,而且pytorch中有预训练好的权重,可以加载实现快速的训练。

一.Unet
Resnet系列参数如下图,在Unet模型分为 encoder block 和decoder block ,resnet去掉最后的全连接层作为Unet的backbone。另外decoder block上采样采用转置卷积,上采样止原图的1/4大小,最后计算loss时需要将最后输出双线性插值到原图大小再和label做loss。
resnet系列:

Unet结构:
Unet

处理文件为models.Unet_ResNet101.py,代码如下:

#coding:utf-8
#@author: Jiangnan He
#@date:2019.12.10 18:21
'''
resnet101-unet
1.上采样  还是采用 转置卷积
2.进行高低层特征融合时使用了torch.cat() 替换了 FCN 中的 "+"
3.resnet101 下采样1/32 所以进行了 5次下采样 本实现进行了 3次高低层特征融合  最后得到heatmap为原图的1/4
4.与label做loss 时直接将输出 heatmap 上采样到image尺寸

  layer0         input                                                           
                  ↓                                                                 
  layer1     conv3x3  ch=64          (1/2)                                       
                  ↓                                                                 
  layer2     reslayer(maxpool) ch=256  (1/4)   ---------------------------   256+256---conv3 ch=256
                  ↓                                                                 ↑upconv2
  layer3     reslayer   ch=512       (1/8) ------------------------------ 512+512---conv3 ch=512
                  ↓                                                                 ↑upconv2
  layer4     reslayer   ch=1024     (1/16)---------------------------------- 1024+1024--conv3 ch=1024
                  ↓                                                                 ↑upconv2
  layer5     reslaeyr  ch=2048      (1/32)-----------------------------------------
'''
import torch
import torch.nn as nn
from torch.autograd import Variable
from torchsummary import summary
from torch.nn import functional as F

class Block(nn.Module):
    def __init__(self,in_ch,out_ch,ksize=3,stride=1,padding=1):
        super(Block,self).__init__()
        self.conv1=nn.Conv2d(in_ch,out_ch,kernel_size=ksize,stride=stride,padding=padding)
        self.bn=nn.BatchNorm2d(out_ch)
        self.relu=nn.ReLU(inplace=True)
    def forward(self, x):
        return self.relu(self.bn(self.conv1(x)))

def make_layers(in_channels, layer_list):
    layers = []
    for v in layer_list:
        layers += [Block(in_channels, v)]
        in_channels = v
    return nn.Sequential(*layers)

#层
class Layer(nn.Module):
    def __init__(self, in_channels, layer_list):
        super(Layer, self).__init__()
        self.layer = make_layers(in_channels, layer_list)
    def forward(self, x):
        out = self.layer(x)
        return out

#残差块
class ResBlock(nn.Module):
    def __init__(self,ch_list,downsample,Res):# ch_list=[in_ch,ch,out_ch]
        super(ResBlock,self).__init__()

        self.res=Res# 残差块 还是 瓶颈块的标志位
        self.ds = downsample  # 残差块时  是否下采样
        #第一个1x1 卷积
        self.firconv1x1=Block(ch_list[0],ch_list[1],1,1,0)         #第一个1x1卷积   不下采样
        self.firconv1x1d = Block(ch_list[0],ch_list[1], 1,2,0)   #第一个1x1卷积   下采样
        # 3x3卷积
        self.conv3x3=Block(ch_list[1],ch_list[1],3,1,1)
        #第二个1x1卷积
        self.secconv1x1=Block(ch_list[1],ch_list[2],1,1,0)
        #skip 卷积操作
        self.resconv1x1d=Block(ch_list[0],ch_list[2],1,2,0)        #skip下采样的1x1卷积
        self.resconv1x1=Block(ch_list[0],ch_list[2],1,1,0)         #skip下采样的1x1卷积

    def forward(self,x):
        if self.res==True:#此时为残差块
            if self.ds==True:#skip有卷积操作需要下采样
                residual=self.resconv1x1d(x)
                f1=self.firconv1x1d(x)
            else:#skip有卷积操作不需要下采样
                residual = self.resconv1x1(x)
                f1 = self.firconv1x1(x)

        else:# 瓶颈块sikp无卷积操作
            residual=x
            f1 = self.firconv1x1(x)
        f2=self.conv3x3(f1)
        f3=self.secconv1x1(f2)
        f3+=residual
        return f3

#Res层
class ResLayer(nn.Module):
    def __init__(self,ch_list1,ch_list2,downsample,numBotBlock):
        super(ResLayer,self).__init__()
        self.num = numBotBlock
        self.resb=ResBlock(ch_list1,downsample,True)
        self.botb=ResBlock(ch_list2,downsample,False)
        self.BoB=self.make_layers()
    def make_layers(self):
        layers=[]
        for i in range(self.num)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值