InversionNet FCNVMB 区别与联系
显著特征
InversionNet
最简单的端到端结构:基于编码器-解码器范式,将原始图像直接输入到深度学习模型,不需要手工设计特征,而是让深度学习模型自动学习图像的特征。
否定空间信息:本文否定了空间信息的重要性,因此在设计网络结构时编码器将图像数据降维成(512,1,1)的格式,丧失了空间信息。
FCNVMB
采用UNet结构:基于编码器-解码器范式,编码过程由卷积操作和池化操作实现,解码过程由卷积操作与反卷积操作组成。同时还添加了skip connection操作。
skip connection:下采样部分会逐渐丢失特征与空间信息,而上采样会逐渐恢复图像尺寸,在上采样操作添加skip connection操作,更充分地融合浅层特征和深层特征,将丢失的空间信息重新插入到特征中,也会更加充分利用空间信息。
迁移学习:迁移学习是一种机器学习的方法,指的是一个预训练的模型被重新用在另一个任务中。
盐数据有两种不同的模拟数据,在训练时先利用数据量较大的模拟速度模型正演得到模拟地震数据,并投入网络得到Pre-trained model。之后使用数据量较小的数据做同样的操作,得到Re-trained model。
网络结构设计与操作详解
InversionNet
卷积操作
由三个基本部分封装成一个卷积操作:
-
卷积层:用于输入数据和特征提取。同时也可以通过设置卷积核、步长与填充的参数值来改变数据的尺寸(一般用于下采样)。
-
批归一化:在网络中的每个隐藏层对输入进行归一化处理,使得每个神经元的输入分布更稳定,从而有助于网络的收敛和训练效果。
-
LeakyReLU:在Leaky ReLU中,当输入为负值时,它会提供一个小的负斜率,从而允许一些负值通过,避免了梯度消失的问题。因此,Leaky ReLU在处理一些具有稀疏数据的任务时表现更好。
代码实现:
class ConvBlock(nn.Module):
def __init__(self, in_fea, out_fea, kernel_size=3, stride=1, padding=1, norm='bn', relu_slop=0.2, dropout=None):
super(ConvBlock,self).__init__()
layers = [nn.Conv2d(in_channels=in_fea, out_channels=out_fea, kernel_size=kernel_size, stride=stride, padding=padding)]
if norm in NORM_LAYERS:
layers.append(NORM_LAYERS[norm](out_fea))
layers.append(nn.LeakyReLU(relu_slop, inplace=True))
if dropout:
layers.append(nn.Dropout2d(0.8))
self.layers = nn.Sequential(*layers)
def forward(self, x):
return self.layers(x)
反卷积操作
类似于卷积操作,由反卷积层、 批归一化和LeakyReLU三部分组成。反卷积可以看作卷积的逆过程,可以用于上采样。
class DeconvBlock(nn.Module):
def __init__(self, in_fea, out_fea, kernel_size=2, stride=2, padding=0, output_padding=0, norm='bn'):
super(DeconvBlock, self).__init__()
layers = [nn.ConvTranspose2d(in_channels=in_fea, out_channels=out_fea, kernel_size=kernel_size, stride=stride, padding=padding, output_padding=output_padding)]
if norm in NORM_LAYERS:
layers.append(NORM_LAYERS[norm](out_fea))
layers.append(nn.LeakyReLU(0.2, inplace=True))
self.layers = nn.Sequential(*layers)
def forward(self, x):
return self.layers(x)
网络结构
上采样
原数据的尺寸是(6,1000,7),首先在时间维度上降维,将图像下采样为方形(128,32,32),接着两个方向同时降维,变成(512,1,1)。
每次下采样,需要两个卷积操作,第一个改变了图像尺寸,第二个没有改变(存疑)。
self.convblock2_1 = ConvBlock(dim1, dim2, kernel_size=(3, 1), stride=(2, 1), padding=(1, 0))
self.convblock2_2 = ConvBlock(dim2, dim2, kernel_size=(3, 1), padding=(1, 0))
下采样
将(512,1,1)的高维向量解码,使用反卷积上采样,两个方向同时升维,最后通过一个Tanh激活函数的卷积操作得到最终的结果。
self.deconv2_1 = DeconvBlock(dim5, dim4, kernel_size=4, stride=2, padding=1)
self.deconv2_2 = ConvBlock(dim4, dim4)
每次上采样,先后需要一个反卷积操作和卷积操作,第一个改变了图像尺寸,第二个没有。
FCNVMB
网络结构
下采样
该网络的下采样由两个部分组成:
- 卷积操作:做两次卷积,尺寸不变。
class unetConv2(nn.Module):
def __init__(self, in_size, out_size, is_batchnorm):
'''
Convolution with two basic operations
:param in_size: Number of channels of input
:param out_size: Number of channels of output
:param is_batchnorm: Whether to use BN
'''
super(unetConv2, self).__init__()
if is_batchnorm:
self.conv1 = nn.Sequential(nn.Conv2d(in_size, out_size, 3, 1, 1),
nn.BatchNorm2d(out_size),
nn.ReLU(inplace=True), )
self.conv2 = nn.Sequential(nn.Conv2d(out_size, out_size, 3, 1, 1),
nn.BatchNorm2d(out_size),
nn.ReLU(inplace=True), )
else:
self.conv1 = nn.Sequential(nn.Conv2d(in_size, out_size, 3, 1, 1),
nn.ReLU(inplace=True), )
self.conv2 = nn.Sequential(nn.Conv2d(out_size, out_size, 3, 1, 1),
nn.ReLU(inplace=True), )
def forward(self, inputs):
'''
:param inputs: Input Image
:return:
'''
outputs = self.conv1(inputs)
outputs = self.conv2(outputs)
return outputs
- 池化操作:卷积层会提取图像特征,产生大量的输出数据,因此在卷积操作之后使用池化操作,可以减少数据量,从而减少计算复杂度,并防止过拟合,提高模型的鲁棒性与泛化能力。这里的池化会将图像缩小一半。
self.down = nn.MaxPool2d(2, 2, ceil_mode=True)
上采样
上采样有input1、input2和output1、output2,最后返回output1、output2连接后并卷积两次的数据
- input1:待skip connection的数据
- input2:上层网络的输出
- output1:将input1填充后的数据,尺寸同output2
- output2:将input2反卷积后的数据
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))
优缺点分析
InversionNet
优点
- 使用了端到端编码器解码器结构,克服了传统fwi的许多问题,比如时间开销大、依赖于初始解等。
- 模型简单易懂。
- 数据体量小,占用内存小。
- 善于处理稀疏数据(LeakyReLU有效解决梯度消失问题)。
缺点
- 否定了空间信息的重要性,将数据编码成(512,1,1)的形式,丧失了空间信息。
- 严格端到端,将设计侧重在网络的设计中,缺乏物理解释,忽视了物理先验知识对模型预测的影响。
FCNVMB
优点
- 一定程度上可以利用空间信息,因为没有编码成(1,1),并且加入了skip connection。
- 引入迁移学习,用最少的数据得到最好的效果。
- 添加池化操作,减少计算复杂度,并防止过拟合,提高模型的鲁棒性与泛化能力。
缺点
- 还是缺乏物理解释,忽视了物理先验知识对模型预测的影响。
- 预测结果对边界轮廓展示不够清晰。
- 模型体量大,占用内存大。