1、Pytorch
原来常用keras搭建网络模型,后来发现keras的训练模型速度和测试速度都较慢,因此转向使用pytorch,其实两者使用难度差不多,都是高层的深度学习框架,适合研究深度学习。
2、U_Net网络介绍
U_Net网络已经提出很早,常被用在图像语义分割领域。模型的主要结构如下图所示,包括下采样和上采样两个过程。为了保证上采样得到的特征图具有较强的语义信息、提高分割的精准度。会在上采样过程中进行通道拼接再卷积。
3、Pytorch代码
3.1、导入包
导入torch,至于为什么导入numpy,显然是因为喜欢。
import torch
from torch import nn
import numpy as np
3.2、下采样模块
下采样模块本文采用了通用卷积进行搭建,当然在语义分割中用的较多的空洞卷积,以及残差结构对网络性能都是有提升效果的。BN层的作用当然是网络节点输出更加稳定,一定程度上能够缓解梯度爆炸和梯度消失问题。激活函数这里使用了Relu6,同样也是考虑到了数据分布,因为通常图片数据在进入网络模型前会进行标准化处理。
class block_down(nn.Module):
def __init__(self,inp_channel,out_channel):
super(block_down,self).__init__()
self.conv1=nn.Conv2d(inp_channel,out_channel,3,padding=1)
self.conv2=nn.Conv2d(out_channel,out_channel,3,padding=1)
self.bn=nn.BatchNorm2d(out_channel)
self.relu=nn.ReLU6(inplace=True)
def forward(self,x):
x=self.conv1(x)
x=self.bn(x)
x=self.relu(x)
x=self.conv2(x)
x=self.bn(x)
x=self.relu(x)
return x
3.3、上采样模块
上采样模块先使用转置卷积进行~~额-->上采样。
常规卷积的输入和输出尺寸关系是:
out_size=(inp_size-f+2p)/stride +1
转置卷积为:
out_size=(inp_size-1)*stride +f
式中f是卷积核(kernel)的尺寸,stride是卷积核滑动步长。
转置卷积的作用显而易见是~~额-->回到过去。
class block_up(nn.Module):
def __init__(self,inp_channel,out_channel,y):
super(block_up,self).__init__()
self.up=nn.ConvTranspose2d(inp_channel,out_channel,2,stride=2)
self.conv1=nn.Conv2d(inp_channel,out_channel,3,padding=1)
self.conv2=nn.Conv2d(out_channel,out_channel,3,padding=1)
self.bn=nn.BatchNorm2d(out_channel)
self.relu=nn.ReLU6(inplace=True)
self.y=y
def forward(self,x):
x=self.up(x)
x=torch.cat([x,self.y],dim=1)
x=self.conv1(x)
x=self.bn(x)
x=self.relu(x)
x=self.conv2(x)
x=self.bn(x)
x=self.relu(x)
return x
3.4、用模块搭建整体网络
至于为什么写block再搭建会显得有点麻烦,原因一是结构清楚,二是超参数更易修改,三是显而易见是我喜欢。
class U_net(nn.Module):
def __init__(self,out_channel):
super(U_net,self).__init__()
self.out=nn.Conv2d(64,out_channel,1)
self.maxpool=nn.MaxPool2d(2)
def forward(self,x):
block1=block_down(3,64)
x1_use=block1(x)
x1=self.maxpool(x1_use)
block2=block_down(64,128)
x2_use=block2(x1)
x2=self.maxpool(x2_use)
block3=block_down(128,256)
x3_use=block3(x2)
x3=self.maxpool(x3_use)
block4=block_down(256,512)
x4_use=block4(x3)
x4=self.maxpool(x4_use)
block5=block_down(512,1024)
x5=block5(x4)
block6=block_up(1024,512,x4_use)
x6=block6(x5)
block7=block_up(512,256,x3_use)
x7=block7(x6)
block8=block_up(256,128,x2_use)
x8=block8(x7)
block9=block_up(128,64,x1_use)
x9=block9(x8)
x10=self.out(x9)
out=nn.Softmax2d()(x10)
return out
4、测试
输入形状和输出相同,完成搭建。
input_size: torch.Size([1, 3, 480, 640]) output_size: torch.Size([1, 3, 480, 640])
if __name__=="__main__":
test_input=torch.rand(1, 3, 480, 640)
print("input_size:",test_input.size())
model=U_net(out_channel=3)
ouput=model(test_input)
print("output_size:",ouput.size())