1️⃣ Unet介绍
语义分割的目的是判断每个像素点的类别,进行精确的分割,在自动驾驶,医疗影像等领域具有广泛应用。
上图为自动驾驶中的分割任务的分割结果,可以从一张图片中有效的识别出汽车(深蓝色),行人(红色),红绿灯(黄色),道路(浅紫色)等
Unet是最常用、最简单的一种分割模型,在2015
年被提出。
2️⃣ 原理分析
Unet之所以叫Unet是因为其网络结构类似一个U的形状,该结构由编码器和解码器两部分组成。
- 编码器中的卷积逐步提取特征(深度增加),maxpool降低空间分辨率(高宽减少)
- 解码器通过上采样(反卷积)高宽加倍,深度减半;通过卷积降低拼接特征的深度
UNet的关键创新是在解码器中引入了跳跃连接(Skip Connection)
,即将编码器
中的特征图与解码器
中对应的特征图进行连接。这种跳跃连接可以帮助解码器更好地利用不同层次的特征信息,从而提高图像分割的准确性和细节保留能力
3️⃣网络结构
首先介绍一下图片中的几个箭头:
-
conv3×3,ReLU:图片中所有的操作都是,3×3卷积,stride=1,padding=0,但卷积核个数动态变化
-
copy and crop:对编码器的特征进行裁剪,方便和解码器中上采样后的特征进行拼接
-
max pool 2×2:下采样,2×2,stride=2,padding=0。通道数不变,高宽减半
-
up-conv 2×2:上采样,即反卷积,2×2反卷积,stride=2,padding=0。通道数减半,高宽加倍
反卷积公式: 反卷积后的尺寸 = ( 输入图像尺寸 − 1 ) × 步长 + 反卷积核大小 − 2 × P a d d i n g 反卷积后的尺寸=(输入图像尺寸-1)×步长+反卷积核大小-2×Padding 反卷积后的尺寸=(输入图像尺寸−1)×步长+反卷积核大小−2×Padding 反卷积后的通道数 = 反卷积核数量 反卷积后的通道数=反卷积核数量 反卷积后的通道数=反卷积核数量代码:nn.ConvTranspose2d(in_channels=xx, out_channels=xx, kernel_size=2, stride=2, padding=0)
-
conv1×1:最终输出的时候采用1×1的卷积,stride=1,padding=0,用于改变通道数
接下来详细介绍网络的结构:编码器由图中红色的1→5组成,解码器由图中绿色的1→4组成
- 编码器1:
# 输入572×572×1 # 经过conv1_1,由572×572×1变成了570×570×64 self.conv1_1=nn.Conv2d(in_channels=1, out_channels=64, kernel_size=3, stride=1, padding=0) self.relu1_1 = nn.ReLU() # 经过conv1_2,由570×570×64变成568×568×64 self.conv1_2 = nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=0) self.relu1_2 = nn.ReLU() # 维度变化:572×572×1→570×570×64→568×568×64
- 最大池化层1:
# 经过 maxpool_1,由568×568×64变成284×284×64 self.maxpool_1 = nn.MaxPool2d(kernel_size=2, stride=2,padding=0) # 维度变化:568×568×64→284×284×64
- 编码器2:
# 经过conv2_1,由284×284×64变成282×282×128 self.conv2_1 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=0) self.relu2_1 = nn.ReLU() # 经过conv2_2,由282×282×128变成280×280×128 self.conv2_2 = nn.Conv2d(128, 128, kernel_size=3, stride=1