用深度卷積自編碼器在10分鐘內下降圖像噪聲

做者|Orhan Gazi Yalçınv
編譯|VK
來源|Towards Datas Sciencepython

你可能對不一樣的神經網絡結構有點熟悉。你可能據說過前饋神經網絡,CNNs,RNNs,這些神經網絡對於解決諸如迴歸和分類之類的監督學習任務很是有用。編程

可是,在無監督學習領域,咱們面臨着大量的問題,如降維、特徵提取、異常檢測、數據生成、加強以及噪聲抑制等。對於這些任務,咱們須要特殊的神經網絡的幫助,這些神經網絡是專門爲無監督學習任務而開發的。數組

所以,他們必須可以在不須要監督的狀況下訓練出來。其中一種特殊的神經網絡結構是自編碼器。網絡

自編碼器

什麼是自編碼器?

自編碼器是一種神經網絡結構,它由兩個子網絡組成,即編碼和解碼網絡,它們之間經過一個潛在空間相互鏈接。dom

自編碼器最先由傑弗裏·辛頓(Geoffrey Hinton)和PDP小組在20世紀80年代開發。Hinton和PDP小組的目標是解決「沒有教師的反向傳播」問題,即無監督學習,將輸入做爲教師。換句話說,他們只是簡單地將特徵數據用做特徵數據和標籤數據。讓咱們仔細看看自編碼器是如何工做的!機器學習

自編碼器體系結構

自編碼器由一個編碼器網絡組成,該網絡接收特徵數據並對其進行編碼以適應潛在空間。解碼器使用該編碼數據(即代碼)將其轉換回特徵數據。在編碼器中,模型學習的是如何有效地編碼數據,以便解碼器可以將其轉換回原始數據。所以,自編碼器訓練的關鍵是生成一個優化的潛在空間。ide

如今,要知道在大多數狀況下,潛在空間中的神經元數量要比輸入層和輸出層小得多,但不必定要這樣。有不一樣類型的自編碼器,如欠完備、過完備、稀疏、去噪、壓縮和變分自編碼器。在本教程中,咱們只關注用於去噪的欠完備自編碼器。函數

自編碼器中的層

構建自編碼器時的標準作法是設計一個編碼器並建立該網絡的反向版本做爲該自編碼器的解碼器。所以,只要編碼器和解碼器網絡之間存在反向關係,你就能夠自由地向這些子網絡添加任何層。例如,若是你處理的是圖像數據,你確定須要卷積和池層。另外一方面,若是要處理序列數據,則可能須要LSTM、GRU或RNN單元。這裏重要的一點是,你能夠自由地構建任何你想要的東西。學習

如今,你已經有了能夠構建圖像降噪的自編碼器的想法,咱們能夠繼續學習教程,開始爲圖像降噪模型編寫代碼。在本教程中,咱們選擇使用TensorFlow的官方教程之一《Autoencoders簡介》[1],咱們將使用AI社區成員中很是流行的數據集:Fashion MNIST。測試

下載Fashion MNIST數據集

Fashion MNIST由德國柏林的歐洲電子商務公司Zalando設計和維護。Fashion MNIST由60000個圖像的訓練集和10000個圖像的測試集組成。每一個例子是一個28×28的灰度圖像,與來自10個類的標籤相關聯。

Fashion MNIST包含服裝的圖像(如圖所示),被設計爲MNIST數據集的替代數據集,MNIST數據集包含手寫數字。咱們選擇Fashion MNIST僅僅是由於MNIST在許多教程中已經被過分使用。

下面的行導入TensorFlow和load Fashion MNIST:

import tensorflow as tf
from tensorflow.keras.datasets import fashion_mnist
# 咱們不須要y_train和y_test
(x_train, _), (x_test, _) = fashion_mnist.load_data()
print('Max value in the x_train is', x_train[0].max())
print('Min value in the x_train is', x_train[0].min())

如今,讓咱們使用數據集中的示例生成一個網格,其中包含如下行:

import matplotlib.pyplot as plt

fig, axs = plt.subplots(5, 10) 
fig.tight_layout(pad=-1)
plt.gray()
a = 0 
for i in range(5): 
  for j in range(10): 
    axs[i, j].imshow(tf.squeeze(x_test[a])) 
    axs[i, j].xaxis.set_visible(False) 
    axs[i, j].yaxis.set_visible(False) 
    a = a + 1

咱們的輸出顯示了測試數據集的前50個樣本:

處理Fashion MNIST數據

爲了提升計算效率和模型可靠性,咱們必須對圖像數據應用Minmax規範化,將值範圍限制在0到1之間。因爲咱們的數據是RGB格式的,因此最小值爲0,最大值爲255,咱們可使用如下代碼進行最小最大規格化操做:

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.

咱們還必須改變NumPy數組維度,由於數據集的當前形狀是(60000,28,28)和(10000,28,28)。咱們只須要添加一個單一值的第四個維度(例如,從(60000,28,28)到(60000,28,28,1))。

第四維幾乎能夠證實咱們的數據是灰度格式的。若是咱們有彩色圖像,那麼咱們須要在第四維中有三個值。可是咱們只須要一個包含單一值的第四維度,由於咱們使用灰度圖像。如下幾行代碼能夠作到這一點:

x_train = x_train[…, tf.newaxis]
x_test = x_test[…, tf.newaxis]

讓咱們經過如下幾行來看看NumPy數組的形狀:

print(x_train.shape)
print(x_test.shape)

輸出:(60000,28,1)和(10000,28,28,1)

給圖像添加噪聲

記住咱們的目標是創建一個模型,它可以對圖像進行降噪處理。爲了作到這一點,咱們將使用現有的圖像數據並將它們添加到隨機噪聲中。

而後,咱們將原始圖像做爲輸入,噪聲圖像做爲輸出。咱們的自編碼器將學習乾淨的圖像和有噪聲的圖像之間的關係,以及如何清除有噪聲的圖像。

所以,讓咱們建立一個有噪聲的版本。

對於這個任務,咱們使用tf.random.normal方法。而後,咱們用一個噪聲係數乘以隨機值,你能夠隨意使用它。如下代碼爲圖像添加噪聲:

noise_factor = 0.4
x_train_noisy = x_train + noise_factor * tf.random.normal(shape=x_train.shape) 
x_test_noisy = x_test + noise_factor * tf.random.normal(shape=x_test.shape)

咱們還須要確保數組項的值在0到1的範圍內。爲此,咱們可使用 tf.clip_by_value方法。clip_by_value是一種TensorFlow方法,它將「最小值-最大值」範圍以外的值剪裁併替換爲指定的「最小值」或「最大值」。如下代碼剪輯超出範圍的值:

x_train_noisy = tf.clip_by_value(x_train_noisy, clip_value_min=0., clip_value_max=1.) 
x_test_noisy = tf.clip_by_value(x_test_noisy, clip_value_min=0., clip_value_max=1.)

如今,咱們已經建立了數據集的規則化和噪聲版本,咱們能夠查看它的外觀:

n = 5
plt.figure(figsize=(20, 8))
plt.gray()
for i in range(n):
  ax = plt.subplot(2, n, i + 1) 
  plt.title("original", size=20) 
  plt.imshow(tf.squeeze(x_test[i])) 
  plt.gray() 
  bx = plt.subplot(2, n, n+ i + 1) 
  plt.title("original + noise", size=20) 
  plt.imshow(tf.squeeze(x_test_noisy[i])) 
plt.show()

正如你所見,在嘈雜的圖像中幾乎不可能理解咱們所看到的。然而,咱們的自編碼器將神奇地學會清潔它。

創建咱們的模型

在TensorFlow中,除了順序API和函數API以外,還有第三種方法來構建模型:模型子類化。在模型子類化中,咱們能夠自由地從零開始實現一切。

模型子類化是徹底可定製的,使咱們可以實現本身的定製模型。這是一個很是強大的方法,由於咱們能夠創建任何類型的模型。可是,它須要基本的面向對象編程知識。咱們的自定義類是tf.keras.Model對象。它還須要聲明幾個變量和函數。

另外請注意,因爲咱們處理的是圖像數據,所以構建一個卷積式自編碼器更爲有效,以下所示:

要構建模型,咱們只需完成如下任務:

  • 建立一個擴展keras.Model的對象
  • 建立一個函數來聲明兩個用順序API構建的獨立模型。在它們中,咱們須要聲明相互顛倒的層。一個Conv2D層用於編碼器模型,而一個Conv2DTranspose層用於解碼器模型。
  • 使用__init__ 方法建立一個call函數,告訴模型如何使用初始化的變量來處理輸入
  • 咱們須要調用以圖像爲輸入的初始化編碼器模型
  • 咱們還須要調用以編碼器模型(encoded)的輸出做爲輸入的初始化解碼器模型
  • 返回解碼器的輸出

咱們能夠經過如下代碼實現全部這些目標:

from tensorflow.keras.layers import Conv2DTranspose, Conv2D, Input

class NoiseReducer(tf.keras.Model): 
  def __init__(self):

    super(NoiseReducer, self).__init__() 

    self.encoder = tf.keras.Sequential([ 
      Input(shape=(28, 28, 1)), 
      Conv2D(16, (3,3), activation='relu', padding='same', strides=2), 
      Conv2D(8, (3,3), activation='relu', padding='same', strides=2)]) 
    
    self.decoder = tf.keras.Sequential([ 
      Conv2DTranspose(8, kernel_size=3, strides=2, activation='relu', padding='same'), 
      Conv2DTranspose(16, kernel_size=3, strides=2, activation='relu', padding='same'), 
      Conv2D(1, kernel_size=(3,3), activation='sigmoid', padding='same')]) 
  
  def call(self, x): 
    encoded = self.encoder(x) 
    decoded = self.decoder(encoded) 
    return decoded

讓咱們用一個對象調用來建立模型:

autoencoder = NoiseReducer()

配置咱們的模型

對於這個任務,咱們將使用Adam優化器和模型的均方偏差。咱們能夠很容易地使用compile函數來配置咱們的自編碼器,以下所示:

autoencoder.compile(optimizer='adam', loss='mse')

最後,咱們能夠在10個epoch下經過輸入噪聲和乾淨的圖像運行咱們的模型,這將須要大約1分鐘的訓練。咱們還使用測試數據集進行驗證。如下代碼用於訓練模型:

autoencoder.fit(x_train_noisy, 
                x_train, 
                epochs=10, 
                shuffle=True, 
                validation_data=(x_test_noisy, x_test))

用咱們訓練過的自編碼器下降圖像噪聲

咱們如今就能夠開始清理噪音圖像了。注意,咱們能夠訪問編碼器和解碼器網絡,由於咱們在NoiseReducer對象下定義了它們。

因此,首先,咱們將使用一個編碼器來編碼咱們的噪聲測試數據集(x_test_noise)。而後,咱們將編碼後的輸出輸入到解碼器,以得到乾淨的圖像。如下代碼完成這些任務:

encoded_imgs=autoencoder.encoder(x_test_noisy).numpy()
decoded_imgs=autoencoder.decoder(encoded_imgs)

讓咱們繪製前10個樣本,進行並排比較:

n = 10 
plt.figure(figsize=(20, 7))
plt.gray()
for i in range(n): 
  # 顯示原始+噪聲
  bx = plt.subplot(3, n, i + 1) 
  plt.title("original + noise") 
  plt.imshow(tf.squeeze(x_test_noisy[i])) 
  ax.get_xaxis().set_visible(False) 
  ax.get_yaxis().set_visible(False) 
  
  # 顯示重建
  cx = plt.subplot(3, n, i + n + 1) 
  plt.title("reconstructed") 
  plt.imshow(tf.squeeze(decoded_imgs[i])) 
  bx.get_xaxis().set_visible(False) 
  bx.get_yaxis().set_visible(False) 
  
  # 顯示原始
  ax = plt.subplot(3, n, i + 2*n + 1) 
  plt.title("original") 
  plt.imshow(tf.squeeze(x_test[i])) 
  ax.get_xaxis().set_visible(False) 
  ax.get_yaxis().set_visible(False) 

plt.show()

第一行用於噪聲圖像,第二行用於清理(重建)圖像,最後,第三行用於原始圖像。查看清理後的圖像與原始圖像的類似性:

結尾

你已經構建了一個自編碼器模型,它能夠成功地清除很是嘈雜的圖像,這是它之前從未見過的(咱們使用測試數據集)。

顯然有一些未恢復的變形,例如右起第二張圖片中缺乏拖鞋的底部。然而,若是考慮到噪聲圖像的變形程度,咱們能夠說咱們的模型在恢復失真圖像方面是至關成功的。

在個人腦子裏,你能夠好比說——考慮擴展這個自編碼器,並將其嵌入照片加強應用程序中,這樣能夠提升照片的清晰度和清晰度。

參考

[1] Intro to Autoencoders, TensorFlow, available on https://www.tensorflow.org/tu...

原文連接:https://towardsdatascience.co...

歡迎關注磐創AI博客站:
http://panchuang.net/

sklearn機器學習中文官方文檔:
http://sklearn123.com/

歡迎關注磐創博客資源彙總站:
http://docs.panchuang.net/

相關文章
相關標籤/搜索