自編碼器的實現與應用


自編碼器是指使用自身的高階特征編碼自己。

自編碼器是一種神經網絡,它的輸出和輸入是一致的,目標是使用稀疏的高階特征重新組合來重構自己。

自動編碼器是一種數據的壓縮算法,其中數據的壓縮和解壓縮函數是數據相關的、有損的、從樣本中自動學習的,在大部分提到自動編碼器的場合,壓縮和解壓縮的函數是通過神經網絡實現的。

 

自編碼器特點:

1.自動編碼是數據相關的,這意味着自動編碼器只能壓縮那些與訓練數據類似的數據。

2.自動編碼器是有損的,與無損壓縮算法不同。

3.自動編碼器是從數據樣本中自動學習的。

 

自編碼器的設計:

1.搭建編碼器,把原圖像編譯成一個向量

2.搭建解碼器,接收一個向量去生成一個圖片

3.設定損失函數,我們希望輸入的圖片和生成的圖片越接近越好,設定一個損失值表示差距。 

 

自編碼器的應用:

1.數據去噪,把一張有噪聲的圖片輸入到神經網絡,讓神經網絡去記住這張圖片的高階特征,在壓縮的時候把高階特征提取出來,再去生成這張圖片本身,實現去噪。

2.降維,把一張圖片降為一張低緯度的向量。

3.圖像生成,給定一個向量去生成一張圖片。

 

變分自編碼器(VAE)

變分自編碼器可以隨機生成隱含變量,提高網絡的泛化能力,比普通的自動編碼器要好,缺點就是生成的圖片會有點模糊

 

實例1.基本自編碼器

編譯環境:tensorflow 2.0、python3.6.12

首先讀取數據集,選用常用的手寫數據集MNIST。

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

(x_train,_),(x_test,_) = tf.keras.datasets.mnist.load_data()

對訓練和測試圖片進行reshape何正規化操作

#自編碼器的數據相似性,我們用來測試的數據仍是手寫數字
print(x_train.shape)    #(60000, 28, 28)
print(x_test.shape)     #(10000, 28, 28)

x_train = x_train.reshape(x_train.shape[0],-1)
x_test = x_test.reshape(x_test.shape[0],-1)

x_train = tf.cast(x_train,tf.float32) /255
x_test = tf.cast(x_test,tf.float32) /255

print(x_train.shape)    #(60000, 784)
print(x_test.shape)     #(10000, 784)

添加輸入層、隱藏層、輸出層的大小

input_size = 784
hidden_size = 32
output_size = 784

編寫自編碼器的模型

#編寫自編碼器模型
input = tf.keras.layers.Input(shape=(input_size,))

#encode 
en = tf.keras.layers.Dense(hidden_size,activation='relu')(input)

#decode
de = tf.keras.layers.Dense(output_size,activation='sigmoid')(en)
model = tf.keras.Model(inputs=input,outputs=de)
model.summary()

#模型編譯
model.compile(optimizer='adam',
              loss='mse')

編譯、訓練和繪出損失圖

#train
history = model.fit(x_train,
          x_train,
          epochs=100,
          batch_size=256,
          shuffle=True,
          validation_data=(x_test,x_test))

print(history.history)

loss = history.history['loss']
val_loss = history.history['val_loss']
plt.plot(history.epoch,loss,'r',label='loss')
plt.plot(history.epoch,val_loss,'b',label='val_loss')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.title('figure')
plt.legend()
plt.show()

訓練完成模型之后,把這個模型用在測試集上看一下效果

encode = tf.keras.Model(inputs=input,outputs=en)
 
input_de = tf.keras.layers.Input(shape=(hidden_size,))
output_de = model.layers[-1](input_de)

decode = tf.keras.Model(inputs=input_de,outputs=output_de)

encode_test = encode(x_test)
print(encode_test.shape)
print(x_test.shape)
decode_test = decode.predict(encode_test)
print(decode_test.shape)

#張量轉化為numpy類型
x_test = x_test.numpy()

最后查看效果,可以發現結果產生的圖片都會有一定程度的損失,也就是模糊:

n = 10

plt.figure(figsize=(25,5))
for i in range(1,n):
    ax = plt.subplot(2,n,i)
    plt.imshow(x_test[i].reshape(28,28))
    ax = plt.subplot(2,n,i + n)
    plt.imshow(decode_test[i].reshape(28,28))

實例2.去噪編碼器

這里和自編碼器不同之處在於給歸一化后的數據添加噪聲來影響原來的圖片。

#添加噪聲
factor = 0.5
#np.random.normal(loc=0.0,scale=1.0,size=None)  對應高斯分布
# loc:float
#     此概率分布的均值(對應着整個分布的中心centre)
# scale:float
#     此概率分布的標准差(對應於分布的寬度,scale越大越矮胖,scale越小,越瘦高)
# size:int or tuple of ints
#     輸出的shape,默認為None,只輸出一個值

#要把最后的結果控制在0到-1之間
x_train_noise = x_train + factor*np.random.normal(size=x_train.shape)
x_test_noise = x_test + factor*np.random.normal(size=x_test.shape)

x_train_noise = np.clip(x_train_noise,0.,1.)
x_test_noise = np.clip(x_test_noise,0.,1.)

查看一下添加噪聲后的訓練圖像

去噪自編碼器模型的搭建和自編碼器一樣不需要改動,在模型訓練需要改變訓練集為添加噪聲后的訓練集,測試集也是如此

#train
history = model.fit(x_train_noise,
          x_train,
          epochs=10,
          batch_size=256,
          shuffle=True,
          validation_data=(x_test_noise,x_test))

之后再改變在去噪自編碼器模型上使用的是添加噪聲的測試集圖片

decode = tf.keras.Model(inputs=input_de,outputs=output_de)
encode_test = encode(x_test_noise)
decode_test = decode.predict(encode_test)

查看一下損失和生成的圖片是否達到去噪的效果

 

 

反卷積和上采樣

下采樣即pooling層,我們實現下采樣一般有三種方法:

  • 全局池化
  • 平均池化
  • 通過卷積改變stride

由於卷積過程中,我們的特征圖像變得很小(比如長寬變為原圖像的1/32),為了得到原圖像大小的稠密像素預測,我們需要進行上采樣。

通過下采樣的方式我們可以反過來使用:

  • 插值法
  • 反池化
  • 反卷積(轉置卷積)

實例3.卷積去噪自編碼器

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

(x_train,_),(x_test,_) = tf.keras.datasets.mnist.load_data()

#自編碼器的數據相似性,我們用來測試的數據仍是手寫數字
print(x_train.shape)    #(60000, 28, 28)
print(x_test.shape)     #(10000, 28, 28)

#擴展維度,卷積網絡常用的輸入形式
x_train = np.expand_dims(x_train,-1)
x_test = np.expand_dims(x_test,-1)
print(x_train.shape)    #(60000, 28, 28, 1)
print(x_test.shape)     #(10000, 28, 28, 1)

#歸一化
x_train = tf.cast(x_train,tf.float32) /255
x_test = tf.cast(x_test,tf.float32) /255

#添加噪聲
factor = 0.5

#要把最后的結果控制在0到-1之間
x_train_noise = x_train + factor*np.random.normal(size=x_train.shape)
x_test_noise = x_test + factor*np.random.normal(size=x_test.shape)

x_train_noise = np.clip(x_train_noise,0.,1.)
x_test_noise = np.clip(x_test_noise,0.,1.)

#卷積去噪自編碼器模型
input = tf.keras.layers.Input(shape=x_train.shape[1:])

#encode 
x = tf.keras.layers.Conv2D(16,(3,3),activation='relu',padding='same')(input)                #28,28,16
x = tf.keras.layers.MaxPooling2D(padding='same')(x)                                         #14,14,16

x = tf.keras.layers.Conv2D(32,(3,3),activation='relu',padding='same')(x)                #14,14,32
x = tf.keras.layers.MaxPooling2D(padding='same')(x)                                         #7,7,32

#decode
x = tf.keras.layers.Conv2DTranspose(16,(3,3),strides=2,activation='relu',padding='same')(x) #14,14,16
x = tf.keras.layers.Conv2DTranspose(1,(3,3),strides=2,activation='sigmoid',padding='same')(x)  #28,28,1

model = tf.keras.Model(inputs=input,outputs=x)
model.summary()

#模型編譯
model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001),
              loss='mse')

#train
history = model.fit(x_train_noise,
          x_train,
          epochs=100,
          batch_size=256,
          shuffle=True,
          validation_data=(x_test_noise,x_test))

print(history.history)

loss = history.history['loss']
val_loss = history.history['val_loss']
plt.plot(history.epoch,loss,'r',label='loss')
plt.plot(history.epoch,val_loss,'b',label='val_loss')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.title('figure')
plt.legend()
plt.show()

pre_test = model.predict(x_train_noise)

n = 10

plt.figure(figsize=(25,5))
for i in range(1,n):
    ax = plt.subplot(2,n,i)
    plt.imshow(x_test_noise[i].reshape(28,28))
    ax = plt.subplot(2,n,i + n)
    plt.imshow(pre_test[i].reshape(28,28))

實驗結果:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM