地震去噪新探索——无监督卷积神经网络实战
无监督学习极大的发挥了神经网络的学习能力——摆脱人为的帮助,有望通过自动地学习特征,实现智能化的应用。
01 使用全连接神经网络来处理降噪
上一篇文章介绍了一个用全连接神经网络去噪的案例。实现了把这样的含有噪声的图像,如下图。
降噪处理后为这样的效果,如下图。
很显然这样的效果不够好,这其中的原因有很多,比如训练的样本不够,神经网络的参数还不够优化等等。但最重要的原因是还是全连接神经网络本来的局限性——对于细节较多的特征学习能力有限。
现在神经网络发展日新月异,现在对细节学习能力较强的一类的结构就是卷积神经网络。
卷积神经网络仿造生物的视知觉机制构建,可以进行监督学习和非监督学习,其隐含层内的卷积核参数共享和层间连接的稀疏性使得卷积神经网络能够以较小的计算量对复杂的细节特征,例如图像和音频进行学习,具有稳定的效果且对数据没有额外的特征工程要求。
02 实战无监督卷积神经网络去噪
1.训练地震资料
为尽量获取更多形态的训练数据,从5个叠前数据获取了有代表性的区域信号,尺寸为(751,200)其中2个如下图。
2.对地震资料获取训练样本集
和前一篇的组合小块数据类似,不过这次训练样本更多,有10000个,数据块尺寸更小为28*28。训练数据的增加和训练数据的减小,都有助于学习更多特征,减少过拟合风险,并有效地收敛。
3.构造卷积神经网络进行训练
(1)主要的结构是这样的,如下图:
(2)主要的代码包括:
inputs_ = tf.placeholder(tf.float32, (None, 28, 28, 1), name='inputs_')
targets_ = tf.placeholder(tf.float32, (None, 28, 28, 1), name='targets_')
# ## Encoder三层卷积###################
conv1 = tf.layers.conv2d(inputs_, 64, (3,3), padding='same', activation=tf.nn.relu)
conv1 = tf.layers.batch_normalization(conv1, training=True)
conv1 = tf.layers.max_pooling2d(conv1, (2,2), (2,2), padding='same')
conv2 = tf.layers.conv2d(conv1, 64, (3,3), padding='same', activation=tf.nn.relu)
conv2 = tf.layers.batch_normalization(conv2, training=True)
conv2 = tf.layers.max_pooling2d(conv2, (2,2), (2,2), padding='same')
conv3 = tf.layers.conv2d(conv2, 32, (3,3), padding='same', activation=tf.nn.relu)
conv3 = tf.layers.batch_normalization(conv3, training=True)
conv3 = tf.layers.max_pooling2d(conv3, (2,2), (2,2), padding='same')
# ## Decoder
conv4 = tf.image.resize_nearest_neighbor(conv3, (7,7))
conv4 = tf.layers.conv2d(conv4, 32, (3,3), padding='same', activation=tf.nn.relu)
conv4 = tf.layers.batch_normalization(conv4, training=True)
conv5 = tf.image.resize_nearest_neighbor(conv4, (14,14))
conv5 = tf.layers.conv2d(conv5, 64, (3,3), padding='same', activation=tf.nn.relu)
conv5 = tf.layers.batch_normalization(conv5, training=True)
conv6 = tf.image.resize_nearest_neighbor(conv5, (28,28))
conv6 = tf.layers.conv2d(conv6, 64, (3,3), padding='same', activation=tf.nn.relu)
conv6 = tf.layers.batch_normalization(conv6, training=True)
# ## logits and outputs
logits_ = tf.layers.conv2d(conv6, 1, (3,3), padding='same', activation=None)#全连接层
outputs_ = tf.nn.sigmoid(logits_, name='outputs_')
# ## loss and Optimizer
loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=targets_, logits=logits_)
cost = tf.reduce_mean(loss)
learn=0.001
optimizer = tf.train.AdamOptimizer(learn).minimize(cost)
(3)加入50%的随机噪声,训练5个epoch,先看看效果
sess = tf.Session()
epochs = 5
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,...)
fig_loss = np.zeros([epochs])
noise_factor = 0.5
for e in range(epochs):
for i in range(0, len(indices), batch_size):#len(indices)=1000
batch = data[indices[i:i+batch_size]]
imgs = batch#本来数据就已经归一化到了(-1,1)
batch_cost, _ = sess.run([cost, optimizer],
feed_dict={inputs_: imgs,
targets_: imgs})
print("Epoch: {}/{} ".format(e+1, epochs),
"Training loss: {:.4f}".format(batch_cost))
fig_loss[e] = batch_cost
使用纯CPU训练,8.76分钟就出结果了。
但是训练的LOSS图让人有点伤感——没有收敛。
4.进行去噪的处理
虽然训练没有收敛,但也来看看预测效果如何吧。
找了这样一个测试数据:
加上50%的噪声,就变成了这样:
那预测效果如何呢,是这样的:
从这张预测图来看,仅能说CNN学习到了部分特征,离我们预期的清晰效果还是有比较大的距离的。
03 总结和下一步计划
从上面的实验来看,地震数据的去噪处理并没有想象那么简单。
其实上面这个网络用来处理经典的Mnist图片去噪,同样的参数配置,效果是杠杠的,像下图这样:
训练的Loss曲线也是能收敛的,如下图:
这只能说明,地震信号的数据和图片还是有比较大的差别。主要区别有两个:
一是数据分布不均匀。
例如上面训练地震数据的数值范围是(-33147.066,17845.742),但数据直方图是这样的:
上图说明地震数据的偏离度很大,异常值非常多。
而Mnist图片的数值范围是(0,255),数据直方图是这样的:
相对比较均匀,就是集中在0和255。
二是地震数据有负值。由于地震子波有波峰和波谷,所以地震数据的负值不可避免。这直接影响了Loss值的计算,很容易出现负值,导致收敛很难。
面对现在遇到的难题,下一步就要想办法消除地震数据的负值和分布不均匀给训练带来的影响,希望下一次能训练得出更好的去噪效果。