CNN网络主要得过程:输入层-卷积层(ReLU)-池化层-全连接层-输出层 如下图所示:
从传统的CNN网络架构中,我们可以看出CNN网络的最后加入一些全连接层,经过softmax后就可以获得类别概率信息,这个概率信息是一维的,即只能标识整个图片的类别,不能标识每个像素点的类别。
全连接层:
在 CNN 结构中,经多个卷积层和池化层后,连接着1个或1个以上的全连接层,全连接层中的每个神经元与其前一层的所有神经元进行全连接.全连接层可以整合卷积层或者池化层中具有类别区分性的局部信息。最后全连接层输出进行分类。

其中一共有13个卷积层;5个池化层和3个全连接层。其中
从结构图可以看出,VCG有很明显的优缺点;其中
优点:
缺点
如下是一个代码的主要过程思路:
def __init__(self):
super(vgg16, self).__init__()
self.model = models.Sequential([ # 假设输入图像尺寸为224*224*3
#64个通道;3x3的卷积核,步长为1,padding=same填充,卷积两次,再经ReLU激活,输出的尺寸大小为224x224x64
Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation='relu'),
Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation='relu'),
BatchNormalization(),
#最大池化层采用2*2 步长为2 输出的尺寸大小为 112x112x64
MaxPooling2D(),
#128个通道 3x3的卷积核,步长为1,padding=same填充,卷积两次,再经ReLU激活,输出的尺寸大小为112x112x128
Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation='relu'),
Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation='relu'),
BatchNormalization(),
# 最大池化层采用2*2 步长为2 输出的尺寸大小为 56x56x128
MaxPooling2D(),
# 256个通道 3x3的卷积核,步长为1,padding=same填充,卷积三次,再经ReLU激活,输出的尺寸大小为56x56x256
Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu'),
Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu'),
Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu'),
BatchNormalization(),
# 最大池化层采用2*2 步长为2 输出的尺寸大小为 28x28x256
MaxPooling2D(),
# 512个通道 3x3的卷积核,步长为1,padding=same填充,卷积三次,再经ReLU激活,输出的尺寸大小为28x28x512
Conv2D(filters=512, kernel_size=(3, 3), padding='same', activation='relu'),
Conv2D(filters=512, kernel_size=(3, 3), padding='same', activation='relu'),
Conv2D(filters=512, kernel_size=(3, 3), padding='same', activation='relu'),
BatchNormalization(),
# 最大池化层采用2*2 步长为2 输出的尺寸大小为 14x14x512
MaxPooling2D(),
# 512个通道 3x3的卷积核,步长为1,padding=same填充,卷积三次,再经ReLU激活,输出的尺寸大小为14x14x512
Conv2D(filters=512, kernel_size=(3, 3), padding='same', activation='relu'),
Conv2D(filters=512, kernel_size=(3, 3), padding='same', activation='relu'),
Conv2D(filters=512, kernel_size=(3, 3), padding='same', activation='relu'),
BatchNormalization(),
# 最大池化层采用2*2 步长为2 输出的尺寸大小为 7x7x512
MaxPooling2D(),
#将数据拉平成向量,变成一维51277=25088
Flatten(),
# 经过两层1x1x4096,一层1x1x1000的全连接层(共三层),经ReLU激活
Dense(4096, activation='relu'),
Dense(4096, activation='relu'),
# 通过softmax输出1000个预测结果
Dense(10, activation='softmax')
])
FCN论文链接:Fully Convolutional Networks for Semantic Segmentation
对比传统的CNN网络,只进行了图像层面上的分类,而FCN的提出,对输入的图像进行了像素级分类的全卷积网络(这是开创性的),从而解决了语义级别的图像分割问题。(语义分割:图像中的每个像素分配给其所属的语义类别,即为图像中的每个像素标记一个类别标签;旨在理解图像中的物体和场景的整体语义信息,而不仅仅是对不同物体的像素进行分割)
例如下图:


下面主要分享的是FCN在CNN基础上的主要改进:



(2)FCN16S:第二阶段:使用跳跃连接将conv7+pool4进行特征融合提升精确性

(3)FCN8S:使用跳跃连接将conv7+pool4+pool3进行特征融合提升精确性


从FCN网络训练结果看出,他得到的结果不够精细,采样结果还是比较模糊和平滑,对一些细节的处理还不是很好。但是在这篇论文中提供的思路是值得我们去学习和扩展的。
U-Net论文地址:Convolutional Networks for Biomedical Image Segmentation
U-Net提出的初衷和fcn一样,也是为了解决医学图像分割的问题,他主要得特点是:
在U-Net网络结构中:如下是FCNVMB网络结构图:
数据集层级关系:
FCNVMB是基于U-Net网络架构,结合上面的U-Net网络结构,FCNVMB也是一个对称的编码器-解码器结构;中间也采用了卷积,池化,反卷积和skip-connection; 但在U-Net下有创新之处如下:


监督网络:用大量的有标签的数据训练来训练模型,模型最终学习到输入和输出标签之间的相关性。监督学习主要是学习一种映射关系;
无监督网络:不依赖任何标签值(用无标签的数据训练),通过对数据内在特征的挖掘,找到样本间的关联。比如聚类算法;
class FCNVMB(nn.Module):
def __init__(self, n_classes, in_channels, is_deconv, is_batchnorm):
'''
Network architecture of FCNVMB
:param n_classes: Number of channels of output (any single decoder) 输出通道数
:param in_channels: Number of channels of network input 输入通道树
:param is_deconv: Whether to use deconvolution 是否使用反卷积
:param is_batchnorm: Whether to use BN 是否使用BN
'''
super(FCNVMB, self).__init__()
self.is_deconv = is_deconv
self.in_channels = in_channels
self.is_batchnorm = is_batchnorm
self.n_classes = n_classes
filters = [64, 128, 256, 512, 1024] #表示网络的通道数,这些整数用于定义U-Net模型的不同层级的通道数
self.down1 = unetDown(self.in_channels, filters[0], self.is_batchnorm)
self.down2 = unetDown(filters[0], filters[1], self.is_batchnorm)
self.down3 = unetDown(filters[1], filters[2], self.is_batchnorm)
self.down4 = unetDown(filters[2], filters[3], self.is_batchnorm)
self.center = unetConv2(filters[3], filters[4], self.is_batchnorm)
self.up4 = unetUp(filters[4], filters[3], self.is_deconv)
self.up3 = unetUp(filters[3], filters[2], self.is_deconv)
self.up2 = unetUp(filters[2], filters[1], self.is_deconv)
self.up1 = unetUp(filters[1], filters[0], self.is_deconv)
self.final = nn.Conv2d(filters[0], self.n_classes, 1)
def forward(self, inputs, label_dsp_dim):
'''
:param inputs: Input Image
:param label_dsp_dim: Size of the network output image (velocity model size)
:return:
'''
down1 = self.down1(inputs)
down2 = self.down2(down1)
down3 = self.down3(down2)
down4 = self.down4(down3)
center = self.center(down4)
up4 = self.up4(down4, center)
up3 = self.up3(down3, up4)
up2 = self.up2(down2, up3)
up1 = self.up1(down1, up2)
up1 = up1[:, :, 1:1 + label_dsp_dim[0], 1:1 + label_dsp_dim[1]].contiguous()
return self.final(up1)
(1) 其中unetDown函数包含上采样过程:经过卷积和池化。
class unetDown(nn.Module):
def __init__(self, in_size, out_size, is_batchnorm):
'''
Downsampling Unit
[Affiliated with FCNVMB]
:param in_size: Number of channels of input
:param out_size: Number of channels of output
:param is_batchnorm: Whether to use BN
'''
super(unetDown, self).__init__()
self.conv = unetConv2(in_size, out_size, is_batchnorm)
self.down = nn.MaxPool2d(2, 2, ceil_mode=True)
def forward(self, inputs):
'''
:param inputs: Input Image
:return:
'''
outputs = self.conv(inputs)
outputs = self.down(outputs)
return outputs
(2) 其中UnetCenter部分
主要是增加了通道数,图像分辨率不变
(3) 其中unetUp函数:提供了两种方式的上采样,ConvTranspose2d:创建反卷积层进行上采样(U-Net使用的则是这一种);UpsamplingBilinear2d:传统的双线性插值上采样(FCN使用的是这一种); 另一个是skip-connection:是采用U-Net网络结构中的叠操作(copy+crop),并且是填充大小。
class unetUp(nn.Module):
def __init__(self, in_size, out_size, is_deconv):
'''
Upsampling Unit
[Affiliated with FCNVMB]
:param in_size: Number of channels of input
:param out_size: Number of channels of output
:param is_deconv: Whether to use deconvolution
'''
super(unetUp, self).__init__()
self.conv = unetConv2(in_size, out_size, True)
# Transposed convolution
if is_deconv:
self.up = nn.ConvTranspose2d(in_size, out_size, kernel_size=2, stride=2)
else:
self.up = nn.UpsamplingBilinear2d(scale_factor=2)
def forward(self, inputs1, inputs2):
'''
:param inputs1: Layer of the selected coding area via skip connection
:param inputs2: Current network layer based on network flows
:return:
'''
outputs2 = self.up(inputs2)
offset1 = (outputs2.size()[2] - inputs1.size()[2])
offset2 = (outputs2.size()[3] - inputs1.size()[3])
padding = [offset2 // 2, (offset2 + 1) // 2, offset1 // 2, (offset1 + 1) // 2]
# Skip and concatenate
outputs1 = F.pad(inputs1, padding)
return self.conv(torch.cat([outputs1, outputs2], 1))
(1)VMB的局限1:训练数据集的选择;FCNVMB网络结构很依赖选择的数据集,直接使用经过训练的网络来测试复杂(例如SEG盐模型)或真实模型会很困难。如实验中对数据进行不加盐的预测(使用 10 个不含盐的训练样本进行训练),用现有的FCNVMB和FWI去预测,其预测结果如下,VMB的性能结构并没有FWI好

结合这个问题,一方面我们可以增强数据,增加数据的多样性(对现有数据进行变换、旋转、缩放),另一方面是引入迁移学习,迁移学习主要思想:将在一个任务上学到的知识或模型应用于解决另一个相关任务(尤其是新任务的数据集相对较小或缺乏标注时),则可以使用预训练网络作为初始化网络,目的是更有效地显示输入和输出之间的非线性映射,而不仅仅是让机器记住数据集的特征。
(2) 低频信息的重要性。
低频信息的在论文中提到当低频信息被移除时(利用技术滤除低频信息进行实验),速度模型的结构边界变得不太清晰,背景速度层次略显模糊。这表明低频信息对于提高速度模型预测的精度和清晰度非常重要。VMB的局限2:但是如何获取低频信息是一个难点。(为什么低频信息回很重要呢,多少hz才算低频?)
(3)作者在最后提出了另一个思想即利用生成对抗网络(GAN): 生成对抗网络包含一个生成模型和一个判别模型(一种基于有限开放数据集的半监督学习网络)其中
(4)作者论文提到以后可能得一个研究方向是去揭示传统反演方法与特定网络之间的潜在关系。我觉得挺有趣的,就像本论文的VMB,他其实就是在传统经典的网络架构上进行了改进,将他巧妙的应用到地震反演中并修改了输入输出。