В одном из моих предыдущих постов я рассказывал о разных типах автоэнкодеров. В этом посте я уделю больше внимания одному конкретному типу — шумоподавляющим автоэнкодерам.
Удаление шума с изображений является сложной и важной задачей в области обработки изображений и компьютерного зрения. Удаление шума может быть весьма полезным при анализе изображений. Целью, вероятно, является извлечение наиболее важных функций, и если у вас есть способ выбросить всю ненужную информацию, желательно.
Давайте посмотрим на пример, где автоэнкодер смог убрать шум. Из этого:
Сеть была обучена делать это:
Идея состоит в том, чтобы исказить входное изображение, но установить исходное изображение в качестве желаемого результата. Таким образом, наша сеть не просто выучит функцию идентификации, потому что вход и выход разные.
Давайте углубимся в реализацию шумоподавляющего автоэнкодера. Для набора данных я выбрал файл mnist.
Сначала импортируем необходимые библиотеки:
import numpy as np import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers import Dense import PIL import tensorflow as tf from keras.datasets import mnist from tensorflow import keras from keras.models import Sequential from keras.layers import ( Conv2DTranspose,Reshape,BatchNormalization, SeparableConv2D, MaxPooling2D, Activation, Flatten, Dropout, Dense, Conv2D,UpSampling2D,Input ) from PIL import Image as im from keras.models import Model from sklearn.model_selection import train_test_split import cv2
Затем определите функцию для загрузки данных и нормализуйте изображения:
def load_data(): (x_train, y_train), (x_test, y_test) = mnist.load_data() m = x_train.shape[0] n = x_test.shape[0] x_train = np.reshape(x_train, (-1,28,28,1)) x_test = np.reshape(x_test,(-1,28,28,1)) y_train = tf.keras.utils.to_categorical(y_train) y_test = tf.keras.utils.to_categorical(y_test) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 return x_train,y_train,x_test,y_test
И загрузите данные:
x_train,y_train,x_test,y_test = load_data()
Мы хотим добавить к входным данным шум, поэтому определяем функцию Gaussian_noise:
def add_gaussian_noise(X_imgs): gaussian_noise_imgs = [] row, col, ch= X_imgs[0].shape for X_img in X_imgs: gaussian = X_img + 0.3*np.random.normal(loc = 0.0,scale = 1.0,size = (row, col, 1)) gaussian_img = np.clip(gaussian, 0., 1.) gaussian_noise_imgs.append(gaussian_img) gaussian_noise_imgs = np.array(gaussian_noise_imgs, dtype = np.float32) return gaussian_noise_imgs
Добавьте шум к входным изображениям:
x_train_noisy = add_gaussian_noise(x_train) x_test_noisy = add_gaussian_noise(x_test)
Давайте посмотрим, как наши искаженные данные выглядят по сравнению с оригиналом:
Создайте кодировщик для нашего автоэнкодера:
def encoder(input_img): conv1_1 = Conv2D(16, (3, 3), activation='relu', padding='same')(input_img) conv1_2 = BatchNormalization()(conv1_1) conv1_3 = MaxPooling2D((2,2))(conv1_2) conv2_1 = Conv2D(32,kernel_size=3,strides=2,padding='same',activation='relu')(conv1_3) conv2_2 = BatchNormalization()(conv2_1) conv2_3 = MaxPooling2D((2,2))(conv2_2) conv3_1 = Conv2D(64,kernel_size=3,strides=2,padding='same',activation='relu')(conv2_3) conv3_2 = BatchNormalization()(conv3_1) conv4 = Flatten()(conv3_2) conv4 = Dense(576)(conv4) return conv4
И создайте декодер:
def decoder(encode): conv5_1 = Reshape((3,3,64))(encode) conv5_2 = Conv2DTranspose(32, kernel_size = 3, strides = 2,activation='relu', padding='valid')(conv5_1) conv6_1 = Conv2DTranspose(16, kernel_size = 3, strides = 2,activation='relu', padding='same')(conv5_2) conv7_1 = Conv2DTranspose(1, kernel_size=3, strides=2, padding='same', activation="sigmoid")(conv6_1) return conv7_1
Определите нашу модель:
inChannel = 1 x, y = 28, 28 input_img = Input(shape = (x, y,inChannel)) autoencoder = Model(input_img, decoder(encoder(input_img)))
Скомпилируйте нашу модель. Здесь я использовал оптимизатор SGD:
opt = tf.keras.optimizers.SGD(learning_rate=0.5) autoencoder.compile(loss='binary_crossentropy', optimizer = opt)
Разделите тренировочные данные:
train_X,valid_X,train_ground,valid_ground = train_test_split(x_train_noisy,x_train,test_size=0.2,random_state=13)
Обучите модель и сохраните веса:
autoencoder_train = autoencoder.fit(train_X, train_ground, batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(valid_X, valid_ground)) autoencoder.save_weights('autoencoder.h5')
После тренировки посмотрите на результаты:
reconstructs = autoencoder.predict(x_test_noisy) reconstructs = np.reshape(reconstructs,(-1,28,28)) x_test_noisy = np.reshape(x_test_noisy,(-1,28,28)) plt.figure(figsize=(15,12)) for i in range(5): plt.subplot(2,5,1+i) plt.imshow(x_test_noisy[i]) plt.axis('off') plt.subplot(2,5,6+i) plt.imshow(reconstructs[i]) plt.axis('off') plt.show()
Шум успешно удален. Результаты потрясающие, и я действительно советую поиграть с разными архитектурами и наборами данных.
Также попробуйте использовать полученные результаты для какой-нибудь классификации, например. Однако имейте в виду, что шумоподавляющие автоэнкодеры хорошо работают с данными, которые незначительно отличаются от обученных данных. Например, если бы я попробовал эту модель в наборе данных ImageNet, я мог бы также получить большую ошибку реконструкции.
Надеюсь, этот пост был полезен :)