深度学习去噪新思路——教你用自编码实现非监督地震降噪

深度学习是人工智能的基石,正飞速的改变着我们的生活,也是现在最热的研究方向之一。深度学习的传统方法是监督学习,需要提供训练的样本标签。但像很多训练很难提供准确的样本标签,比如地震信号的去除噪声标签。这时研究非监督学习就很重要了。

与有监督学习有明确的目标输出不同,无监督学习没有给定目标输出,而是去提取数据本身的静态结构特征。其中一个无监督算法就是自编码。

01 什么是自编码

自编码是区别于人工编码的过程,人工编码是通过人的经验将数据进行编码。而自编码过程是不需要人工的。那么,自编码一定需要有办法知道自己的编码方法是否合理。这个方法就是解码器,用解码器来看解码之后的复原情况。如果我能通过解码器将你编码器压缩的数据恢复得差不多,那么你的编码就是合理的。如下图:

同样的原理,如果自编码从噪声数据中学习到了有效信号的特征,那么通过编码和解码,就可以从噪声中还原有用的信号。如下图:

02 一个地震信号通过非监督学习去除噪声的全过程

1.训练地震资料

这里使用一个仿真近地表的地震资料,如下图:

这是一个不含有随机噪声的地震资料(终止时间3000毫秒),尺寸为661到*661采样点。

2.对地震资料获取训练样本集

(1)读取地震信号

使用segyio读取地震信号

with segyio.open(file_list[i],'r',ignore_geometry=True) as f

(2)从地震信号中获取小块训练样本

获取1000个,128*128的地震小块样本,在获取过程中还设计了90、180、270等不同角度的翻转,使得训练样本形态更丰富。

另外,为了处理和可视化展示高效,数据都归一化到了(-1,1)区间。主要代码:

data_test = data_test/data_test.max()#归一化到-1,1之间

(3)将训练样本保存为二级制文件

为了方便后续调用训练数据集方便,将训练集保存为二进制文件。

np.save('seismic_patches.npy', train_data)

3.对训练样本集使用全连接网络进行训练

(1)读取二进制的训练集

train_data='seismic_patches.npy'

data = np.load(train_data)#(1000,128,128,1)

data = data.astype(np.float64)

(2)构建全连接神经网络模型

这是一个隐藏层为32层的全连接神经网络。主要代码如下:

# 构建模型

hidden_units = 32

image_size =data.shape[1]#128

# 输入层

inputs_ = tf.placeholder(tf.float32, [None, image_size,image_size,1], name='inputs_')

targets_ = tf.placeholder(tf.float32, [None, image_size,image_size,1], name='targets_')

## 隐层

hidden_layer = tf.layers.dense(inputs_, hidden_units, activation=tf.nn.relu)

## 输出层

#logits_ = tf.layers.dense(hidden_layer,image_size, activation=None)

logits_ = tf.layers.dense(hidden_layer,1, activation=None)

outputs_ = tf.sigmoid(logits_, name='outputs_')

# 损失函数

loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=targets_, logits=logits_)

cost = tf.reduce_mean(loss)

# 优化函数

optimizer = tf.train.AdamOptimizer(0.001).minimize(loss)

(3)训练样本

采用20个周期训练,每个批次为50,在每个批次训练过程中加噪声。这里训练的样本和标签都是噪声数据。主要代码如下:

sess = tf.Session()

epochs = 20#改为20

noise_factor = 25

batch_size = 50

sess.run(tf.global_variables_initializer())

indices = list(range(data.shape[0]))#1000,一个序列(0,1,2...999)

np.random.shuffle(indices) # shuffle简单随机排列,打乱顺序(624,2942,2149,...)

for e in range(epochs):

for i in range(0, len(indices), batch_size):#len(indices)=1000

batch = data[indices[i:i+batch_size]]

noise = np.random.normal(0, noise_factor/255.0, batch.shape)

batch_noise = batch + noise

batch_noise = np.clip(batch_noise, 0.0, 1.0)

batch_cost, _ = sess.run([cost, optimizer],

feed_dict={inputs_:batch_noise, targets_: batch_noise})

print("Epoch: {}/{}...".format(e+1, epochs),"Training loss: {:.4f}".format(batch_cost))

4.测试训练效果

(1)选取测试数据

还是从训练地震信号中选取一块256*256的数据块,并进行归一化处理。

(2)将地震数据增加噪声。

(3)将地震噪声信号拆分为小的地震块并带入程序进行预测

noisy_imgs = myimtocol(inputs, patch_rows, patch_rows, n2, n1*n3, tslide,xslide,1);#拆分为(81,128,128)的地震块

reconstructed = sess.run(outputs_, feed_dict={inputs_: noisy_imgs})#(81,128,128,1)预测清晰信号

(4)重新组合小地震块并显示最终的效果

reconstructed = myimtocol(reconstructed, patch_rows, patch_rows, n2, n1*n3, tslide,xslide,0);#将地震块组合为完整地震数据(256,256)

im_Denoise = axs[0].imshow(reconstructed, cmap=plt.cm.seismic, vmin=vmin, vmax=vmax)#显示最终去噪效果

这个效果确实不太让人满意,主要是全连接神经网络本来的性能有限。在参数设置方面,使用20个epoch,使用81张图块进行训练,这些训练量都太小了。

在网上有个爱好者使用自编码对Minist图片训练集降噪,找了10000个小图块进行降噪训练,效果如下图,确实也不太理想。

03 小结

地震信号降噪的原理与图片类似,都是要让模型学习到有规律的特征——有效信号,而去除无效的噪声信号。

但是全连接神经网络结构对于特征学习能力有限,而且训练样本还需要增加,这些都需要在下一次的研究中完善。

喜欢请点赞,或关注公众号“科技爸遇到文艺妈”获取更多干货好文。

你可能感兴趣的:(深度学习去噪新思路——教你用自编码实现非监督地震降噪)