“心中有歌,到處都是舞臺”。
自從投入了自編碼的深度學習研究後,一路走來就是磕磕碰碰。
上一篇將地震信號用在了自編碼卷積神經網絡降噪(見《地震去噪新探索——無監督卷積神經網絡實戰》),結果那叫一個慘。如下面的圖示,上邊是噪聲圖,下邊是去噪圖:
從去噪效果來看,僅能獲取到一些支離破碎的有效信號,這是一張完全拿不出手的效果圖。
01屢敗屢戰的調優之旅
卷積神經網絡不是更能學習到特徵細節,性能更好嗎?為啥我做出來的效果如此之慘?
前期的參數設置包括:使用10000個28*28的訓練小塊,訓練epoch:5,學習率:0.001,優化器:tf.train.AdamOptimizer(learn).minimize(cost),LOSS函數:tf.nn.sigmoid_cross_entropy_with_logits(labels=targets_, logits=logits_),cost = tf.reduce_mean(loss)
網絡結構圖為:
訓練損失曲線:
1.歸一化的優化
慘不忍睹的LOSS訓練結果引起了我的注意。將收斂失敗這個問題拿到網上去尋找答案,有大神說這是歸一化沒做好。
那就先進行2項優化:
一是控制訓練樣本的取值範圍到(-1,1),使用方法是原值除以最大值的方法,就像這樣:
noisy_imgs=noisy_imgs/abs(noisy_imgs).max()
二是在訓練網絡的每個卷積後增加BN,就像這樣:
conv1 = tf.layers.conv2d(inputs_, 64, (3,3), padding='same', activation=tf.nn.relu)
conv1 = tf.layers.batch_normalization(conv1, training=True)
再進行訓練,效果不明顯,還是沒有收斂。
另外,很多歸一化的方法是將取值範圍集中在(0,1),使用這樣的算法:
imgs= (imgs-imgs.min())/(imgs.max()-imgs.min())#歸一化到[0,1]
結果證明對於地震數據完全沒法訓練,曲線是這樣的:
2.學習函數的調整
“一計不成,再生一計”。
我想到了對優化器和LOSS函數進行改動。
在神經網絡學習中,損失函數的作用是度量神經網絡的輸出的預測值,計算與實際值之間的差距,可以說是實現學習的關鍵函數。常見的損失函數包括:最小二乘損失函數、交叉熵損失函數、迴歸中使用的smooth L1損失函數等。
而優化函數的原理是:把損失值從神經網絡的最外層傳遞到最前面,實現反向傳播學習,這是神經網絡實現持續學習達到收斂的關鍵。如最基礎的梯度下降算法包括:隨機梯度下降算法,批量梯度下降算法,帶動量的梯度下降算法,Adagrad,Adadelta,Adam等。
那我就先從優化器函數入手吧。
既然學習率為0.001無法收斂,那試試0.0001呢。結果還真收斂了,如下圖:
那預測效果如何呢?結果是一塌糊塗,連基本特徵都學習不到,如下圖:
這是怎麼回事呢?我的理解是學習率太高,就會讓神經網絡學習到更細粒度的特徵,而失去了我們想要的特徵。就相當於研究一個人的特徵,我們通常是從五官、體型等方面來看,但如果從細胞的角度的去學習,那就無法還原人的外貌特徵了。
另外,設置為0.0005也好不了多少。
那改動LOSS函數能不能起作用呢?
比如改為softmax_cross_entropy_with_logits,像這樣:
loss = tf.nn.softmax_cross_entropy_with_logits(labels=targets_, logits=logits_)
結果是無法學習,如下圖:
3.其它的嘗試
兩板斧過去,還沒有看到變好的跡象。我沒有放棄,我開始思考為啥原程序訓練Mnist效果都如此好,換到地震數據訓練就不行了呢?
我想到了訓練樣本數據是不是有問題。我又進行了以下嘗試:
一是調整訓練樣本數據的尺寸:有128*128,40*40,32*32,28*28等。
二是對樣本數據進行截斷:地震數據不是異常值多,偏離度大嗎。我就篩選數據集中的90%區間,區間外面的進行截斷,再進行歸一化。這樣數據分佈就均勻多了。
三是擴充採樣數據來源,從不同的數據源採樣。是不是數據更豐富,訓練效果就會改觀呢?
……
你可以想象做這些實驗有多麼瑣碎和繁雜,然而現實卻是如此的無情。最後結局都是一個——失敗,根本拿不出一個像樣的效果,連一個較為清晰的結果都沒有。
02 柳暗花明,找到了一個方法
“山窮水復疑無路,柳暗花明又一村”。
在持續N天被現實按在地上摩擦後,我痛定思痛:到底解決的方向在哪裡?
在現有這個無可救藥的神經網絡中,提高學習率可以收斂,但是無法學習到有效特徵。降低學習率可以學習到有效特徵但是無法收斂,也就是說無法持續優化的學習。整個成了一個悖論。
面對這張醜陋的預測結果圖,我意識到可能是網絡結構本身出了問題。很有可能是網絡對圖片數據學習有效,對地震數據學習就是不行。
在翻閱了其它研究者的論文後,我逐步聚焦到了一個結構——解碼。我的程序在這部分是使用卷積核上採樣的結構。像這樣:
conv4 = tf.image.resize_nearest_neighbor(conv3, (8,8))
conv4 = tf.layers.conv2d(conv4, 32, (3,3), padding='same', activation=tf.nn.relu)
而其它地震論文結構卻包含了一個我沒有的結構——反捲積。
如果我也使用反捲積,甚至就只有卷積和反捲積這種最簡單的自編碼結構,效果如何呢?像這樣的結構:
x = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = Conv2DTranspose(32, (3,3), padding='same', activation='relu', kernel_initializer='glorot_normal')(x)#反捲積
x = Conv2DTranspose(32, (3,3), padding='same', activation='relu', kernel_initializer='glorot_normal')(x)
decoded = Conv2DTranspose(1, (1,1), padding='same', activation='tanh', kernel_initializer='glorot_normal')(x)
結果是令人驚豔的。下圖是收斂的效果,很快就能夠收斂:
訓練的效果更好。以下分別是原圖,噪聲圖和去噪效果圖:
可以看到,上面噪聲幾乎淹沒了有效信號。然後通過訓練,僅僅5個迭代,就較好的分離出了有效信號。
03 下一步計劃
“既然選擇了遠方 便只顧風雨兼程”。
看來反捲積是是解決地震學習的一把鑰匙。下一步我將研究反捲積能適應地震處理的原因,然後繼續進行優化和創新,並使用其它算法做對比實驗,爭取做出更好的效果。
如果喜歡請點“贊”,如果小夥伴對程序感興趣,可以聯繫我獲取。