ОТКЛЮЧЕНИЕ ИЗОБРАЖЕНИЙ С ПОМОЩЬЮ АВТОЭНКОДЕРОВ
Автоэнкодер - это нейронная сеть, используемая для уменьшения размерности; то есть для выбора и извлечения признаков. С точки зрения обработки изображений, мы можем обучить автоэнкодер выполнять за нас автоматическую предварительную обработку изображений. Denoising - одно из классических приложений автоэнкодера при обработке изображений. Процесс шумоподавления удаляет нежелательный шум, который искажает истинный сигнал. Это хорошо известный процесс, и я просто хотел испытать и испытать его на себе в дни COVID-19.
Я использовал набор данных Labeled Faces in the Wild (LFW), который доступен здесь или здесь.
Давайте импортируем то, что мы используем:
import sys import tensorflow as tf import keras, keras.layers as L, keras.backend as K import numpy as np from sklearn.model_selection import train_test_split from lfw_dataset import load_lfw_dataset %matplotlib inline import matplotlib.pyplot as plt import download_utils import keras_utils import numpy as np from keras_utils import reset_tf_session
Python уже имеет встроенный набор функций для загрузки набора данных LFW. Так что загружать данные было легко.
Эти изображения без шума. Для своего эксперимента я добавлю немного шума к изображениям и буду следовать очень распространенному пути, добавляя стандартный нормальный гауссовский шум. Вот наша простая функция:
def apply_gaussian_noise(X,sigma=0.1): noise = np.random.normal(0, sigma, X.shape) return X + noise
Давайте создадим наш автоэнкодер (кодировщик и декодер) с глубокой структурой нейронной сети с прямой связью.
# load images X, attr = load_lfw_dataset(use_raw=True, dimx=32, dimy=32) shape = X.shape[1:] # divided by 255 for normalization and -0.5 is for centralization X = X / 255.0 - 0.5 # Divide our dataset in to train and test parts.I got the ratio as 0.3. X_train, X_test = train_test_split(X, test_size=0.3, random_state=42
Часть кодировщика довольно стандартна, мы складываем сверточные и объединяющие слои и заканчиваем плотным слоем, чтобы получить представление желаемого размера. Самое сложное - определить, на сколько нам нужно нырять. Чтобы найти ответ на этот вопрос, я провел несколько поисков и прочитал несколько статей. Использование функции активации elu также рекомендуется для автоэнкодера шумоподавления. (До этой работы я никогда не слышал об этой функции активации. Я также провел несколько поисков по ней. Я призываю вас сделать то же самое).
Создать декодер не составит труда, если вы уже знаете, что такое кодировщик. Потому что это полная противоположность. (Это должно быть). Операция свертки с шагом приводит к понижению дискретизации. транспонирование свертки противоположно операции свертки. (для детальной информации здесь отличная средняя статья)
def autoencoder(shape, code_size): # encoder part encoder = keras.models.Sequential() encoder.add(L.InputLayer(shape)) #for input #first convolution layer encoder.add(L.Conv2D(32, kernel_size=(3, 3), padding='same', activation='elu')) #first pooling layer. encoder.add(L.MaxPooling2D(pool_size=(2, 2), padding='same')) #second convolution layer encoder.add(L.Conv2D(64, kernel_size=(3, 3), padding='same', activation='elu')) #second pooling layer. encoder.add(L.MaxPooling2D(pool_size=(2, 2), padding='same')) #third convolution layer encoder.add(L.Conv2D(128, kernel_size=(3, 3), padding='same', activation='elu')) encoder.add(L.MaxPooling2D(pool_size=(2, 2), padding='same')) encoder.add(L.Conv2D(256, kernel_size=(3, 3), padding='same', activation='elu')) encoder.add(L.MaxPooling2D(pool_size=(2, 2), padding='same')) encoder.add(L.Flatten()) # to make it one dimensional encoder.add(L.Dense(code_size)) # decoder decoder = keras.models.Sequential() decoder.add(L.InputLayer((code_size,))) decoder.add(L.Dense(2*2*256)) decoder.add(L.Reshape((2,2,256))) decoder.add(L.Conv2DTranspose(filters=128, kernel_size=(3, 3), strides=2, activation='elu', padding='same')) decoder.add(L.Conv2DTranspose(filters=64, kernel_size=(3, 3), strides=2, activation='elu', padding='same')) decoder.add(L.Conv2DTranspose(filters=32, kernel_size=(3, 3), strides=2, activation='elu', padding='same')) decoder.add(L.Conv2DTranspose(filters=3, kernel_size=(3, 3), strides=2, activation=None, padding='same'))
В этой части мне помогли статьи, которые я нашел. После нескольких испытаний я обнаружил, что 25 итераций идеально подходят для достижения оптимального значения потерь. Процесс полностью эмпирический. На каждой итерации я добавлял гауссовский шум к нашим тренировочным и тестовым данным, используя функцию шума, которую мы создали выше. Я использовал среднеквадратичную ошибку (MSE) в качестве типа потерь и оптимизатор Адама в качестве функции потерь. Их, конечно, можно изменить. Можно использовать другую функцию потерь и тип потерь, но эта пара наиболее предпочтительна.
s = reset_tf_session() # reset session ITER=25 # we use bigger code size here for better quality encoder, decoder = build_deep_autoencoder(shape, code_size=512) assert encoder.output_shape[1:]==(512,), "encoder must output a code of required size" inp = L.Input(shape) code = encoder(inp) reconstruction = decoder(code) autoencoder = keras.models.Model(inp, reconstruction) autoencoder.compile('adamax', 'mse') for i in range(ITER): X_train_noise = apply_gaussian_noise(X_train) X_test_noise = apply_gaussian_noise(X_test) autoencoder.fit(x=X_train_noise, y=X_train, epochs=1, validation_data=[X_test_noise, X_test], callbacks=[keras_utils.TqdmProgressCallback()], verbose=0)
В конце концов, добавленного нами шума не было видно в результате. Чтобы визуализировать результаты в сравнении с исходными, мы создаем функцию, как показано ниже:
def visualize(img,encoder,decoder): code = encoder.predict(img[None])[5])# 5 is an arbitrary select denoised= decoder.predict(code[None])[5]) plt.subplot(1,3,1) plt.title("Original Img + Gaussian Noise") show_image(img) plt.subplot(1,3,2) plt.title("Code") plt.imshow(code.reshape([code.shape[-1]//2,-1])) plt.subplot(1,3,3) plt.title("Denoised") show_image(denoised) plt.show() X_test_noise = apply_gaussian_noise(X_test) denoising_mse = autoencoder.evaluate(X_test_noise, X_test, verbose=0) print("Denoising MSE:", denoising_mse) for i in range(5): # print 5 images img = X_test_noise[i] visualize(img,encoder,decoder)
Фактически, это исследование показало нам, что мы можем очистить все данные, которые, как нам известно, содержат шум, с помощью автокодировщика. Более того, тип данных не обязательно должен быть изображением. Может быть, нужно сосредоточиться на том, чтобы получить этот шум. У него уже есть специальное название в среде машинного обучения: Обнаружение аномалий. Итак, давайте поэкспериментируем с этим в другое время.
Буду признателен, если вы поделитесь со мной своими комментариями, отзывами и критикой.
Спасибо.