深度学习是人工智能的基石,正飞速的改变着我们的生活,也是现在最热的研究方向之一。深度学习的传统方法是监督学习,需要提供训练的样本标签。但像很多训练很难提供准确的样本标签,比如地震信号的去除噪声标签。这时研究非监督学习就很重要了。
与有监督学习有明确的目标输出不同,无监督学习没有给定目标输出,而是去提取数据本身的静态结构特征。其中一个无监督算法就是自编码。
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 小结
地震信号降噪的原理与图片类似,都是要让模型学习到有规律的特征——有效信号,而去除无效的噪声信号。
但是全连接神经网络结构对于特征学习能力有限,而且训练样本还需要增加,这些都需要在下一次的研究中完善。
喜欢请点赞,或关注公众号“科技爸遇到文艺妈”获取更多干货好文。