pytorch的波传播模块。
deepwave的Python项目详细描述
深波
DeepWave为Pythorch提供了波传播模块(目前仅适用于恒密度声波/标量波方程)。它主要用于地震成像/反演。其中一个有趣的优点是,它允许您将操作链接在一起。例如,您可以使用deepwave使用自定义成本函数(只要pytorch能够自动区分它)执行fwi,或者在波传播前后添加一些其他操作,pytorch将反向传播所有这些操作。
DeepWave运行在CPU和NVIDIA GPU上。它应该在安装过程中自动检测兼容的GPU,如果发现任何GPU代码,则编译GPU代码。要在GPU上运行,必须以标准pytorch方式(使用.cuda()
或.to(设备)
)将模型、源振幅、源和接收器位置张量传输到GPU。
安装
deepwave需要numpy,因此强烈建议首先安装anaconda。它还需要在安装deepwave之前安装pytorch(使用类似conda install pytorch cpu-c pytorch的方法)。然后,您可以使用
pip安装deepwave
或使用
pip安装git+https://github.com/ar4/deepwave.git
用法
deepwave可以做两件事:正向建模和反向传播。
正向建模
我们首先需要创建一个波传播模块。如果您熟悉训练神经网络,这与定义您的网络(或其中的一部分)并初始化权重是一样的。
prop=deepwave.scalar.Propagator({'vp':model},dx)
两个必需的参数是波速模型(model
)和模型中使用的单元格大小(dx
)。该模型应以pytorch浮子张量的形式提供,[nz,(ny,(nx))]
。1d、2d和3d传播器可用,模型形状用于在它们之间进行选择。例如,如果希望一维波传播,则模型形状将为[nz]
。单元格大小还应作为单个浮点(如果在每个维度中都相同)或包含每个空间维度中单元格大小的浮点张量提供;3d中为[dz,dy,dx]
,1d中为[dz]
。
现在我们可以呼叫我们的传播者。
receiver_amplitudes=prop(source_amplitudes,x_s,x_r,dt)
所需参数是源振幅、源坐标(xus
)、接收器坐标(xur
)和源样本之间的时间间隔(dt
)。接收器振幅返回。源振幅s应该是一个形状为[nt,num_shots,num_sources_per_shot]
的浮点张量,其中nt
是时间采样数。请注意,每次放炮可以有多个震源,但在活动震源地震实验中通常只有一个震源。源坐标数组是形状为[num-shots,num-sources-per-shot,num-dimensions]
的浮点张量,其中num-dimensions
对应于模型中的维数。类似地,接收器坐标数组是形状为[num-shots,num-receivers-per-shot,num-dimensions]
的浮点张量。坐标以与dx
相同的单位指定,并且与模型的原点有关。时间步长dt
应为常规浮点。返回的形状为[nt,num_shots,num_receivers_per_shot]的浮点张量包含接收器振幅。
可以使用不同的输入多次运行正向传播,例如,对数据集中的每个快照进行正向建模。您可能已经注意到,传播器还被设计为同时转发多个单独的快照(输入中的num_shots
维度)。这样做可能比单独传播每个快照提供更好的性能,但也可能会耗尽内存。
下面是一个完整的示例:
importmathimporttorchimportdeepwavedx=5.0# 5m in each dimensiondt=0.004# 4msnz=20ny=40nt=int(1/dt)# 1speak_freq=4peak_source_time=1/peak_freq# constant 1500m/s modelmodel=torch.ones(nz,ny)*1500# one source and receiver at the same locationx_s=torch.Tensor([[[0,20*dx]]])x_r=x_s.clone()source_amplitudes=deepwave.wavelets.ricker(peak_freq,nt,dt,peak_source_time).reshape(-1,1,1)prop=deepwave.scalar.Propagator({'vp':model},dx)receiver_amplitudes=prop(source_amplitudes,x_s,x_r,dt)
反向传播/反转(fwi)
fwi试图通过修改模型来匹配预测的和真实的接收器振幅。这类似于在训练期间修改神经网络中的权重。为了实现这一点,我们首先指定我们需要计算与我们的模型有关的梯度。
model.requires_grad=True
我们还需要指定要使用的优化算法和损失/成本/目标函数。
optimizer=torch.optim.Adam([model],lr=10)criterion=torch.nn.MSELoss()
我选择使用学习率为10的ADAM优化器,并使用均方误差(MSE)作为成本函数。mse cost函数是pytorch提供给我们的,但我也可以自己编写cost函数并使用它(只要pytorch可以自动区分它)。
当我们的传播器初始化为上面的正向建模部分时,我们可以迭代优化模型。
foriterinrange(num_iter):optimizer.zero_grad()receiver_amplitudes_pred=prop(source_amplitudes,x_s,x_r,dt)loss=criterion(receiver_amplitudes_pred,receiver_amplitudes_true)loss.backward()optimizer.step()
在每次迭代中,我们将梯度归零,从当前模型计算预测的接收器振幅,使用我们的成本函数将其与真实数据进行比较,反向传播计算相对于模型的损耗梯度,然后更新模型。
Pythorch的灵活性意味着很容易修改它以满足您自己的需要。
有关使用deepwave for fwi的完整示例,请参见本笔记本
利用深波进行震源反演也是可能的。只需在源振幅张量上将设置为
真,就需要_grad
。
born正演模拟(用于分层和lsrtm)
要执行born正向建模,请使用bornpropagator
。除了背景波速模型外,还需要散射模型("图像")。例如,将以下行添加到上面的常规正向建模示例中:
scatter=torch.zeros_like(model)scatter[10,20]=100
这将创建一个散射模型,其点散射体的振幅为100 m/s。然后,将创建传播器的线替换为使用born传播器的线:
prop=deepwave.scalar.BornPropagator({'vp':model,'scatter':scatter},dx)
结果数据应仅包含来自散射波场的记录,因此不会有任何直接到达。
要执行lsrtm,请优化变量scatter
。Born传播子目前不支持优化源振幅或波速模型。
有关使用DeepWave进行LSRTM的示例,请参见本笔记本
注释
- 深波只是测试使用Python 3.6。
- 对于无反射曲面,将曲面处的PML宽度设置为零。例如,在3d中,当另一侧的pml宽度为10个单元格时,如果自由曲面位于第一个维度的开头,则在创建传播器时提供参数
pml_width=[0,10,10,10,10]
。格式为[z1,z2,y1,y2,x1,x2],其中z1,y1和x1是z,y和x维度开始处的pml宽度,z2,y2和x2是这些维度结束处的pml宽度。 - 要将波浪模拟限制在测量覆盖的区域(源和接收器),请在创建传播器时提供
测量键盘
关键字参数。例如,要使用整个Z维度,但距离Y和X维度中的第一个和最后一个源/接收器最多100米,请使用survey_pad=[none,none,100,100,100,100]
,其中none
表示继续到模型的边缘,格式与用于pml_宽度
。每个条目的默认值都是none
。 - @lukasmosser发现GCC 4.9或更高版本是必需的(;18)。
- 支持镜头上的分布式并行化,但不支持镜头内的分布式并行化;每个镜头必须在一个节点内运行。
- 目前,前向源波场保存在存储器中,以便在反向传播期间使用。这意味着真实的三维测量可能需要比可用内存更多的内存。这将在以后的版本中修复。
贡献
我们非常感谢您对改善深海波浪的帮助。如果您在使用deepwave时遇到任何困难,请将其作为github问题报告,以便修复。如果您有让deepwave更好的功能建议或其他想法,请将其作为github问题报告。如果你想帮助编码,那将是特别美妙的。github问题包含一个需要工作的列表。如果您看到要尝试的,请要求将其分配给您。