Удаление шума с изображения с использованием ядерного PCA#

Этот пример показывает, как использовать KernelPCA для шумоподавления изображений. Короче говоря, мы используем преимущество аппроксимационной функции, изученной во время fit для восстановления исходного изображения.

Мы сравним результаты с точной реконструкцией, используя PCA.

Мы будем использовать набор данных цифр USPS для воспроизведения, представленного в разделе 4 [1].

Ссылки

# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause

Загрузить набор данных через OpenML#

Набор данных цифр USPS доступен в OpenML. Мы используем fetch_openml чтобы получить этот набор данных. Кроме того, мы нормализуем набор данных так, чтобы все значения пикселей находились в диапазоне (0, 1).

import numpy as np

from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

X, y = fetch_openml(data_id=41082, as_frame=False, return_X_y=True)
X = MinMaxScaler().fit_transform(X)

Идея заключается в изучении базиса PCA (с ядром и без) на зашумленных изображениях и последующем использовании этих моделей для восстановления и удаления шума с этих изображений.

Таким образом, мы разделяем наш набор данных на обучающую и тестовую выборки, состоящие из 1000 образцов для обучения и 100 образцов для тестирования. Эти изображения не содержат шума, и мы будем использовать их для оценки эффективности подходов к удалению шума. Кроме того, мы создаем копию исходного набора данных и добавляем гауссовский шум.

Идея этого приложения — показать, что мы можем удалить шум с искажённых изображений, изучая базис PCA на некоторых неискажённых изображениях. Мы будем использовать как PCA, так и PCA на основе ядра для решения этой задачи.

X_train, X_test, y_train, y_test = train_test_split(
    X, y, stratify=y, random_state=0, train_size=1_000, test_size=100
)

rng = np.random.RandomState(0)
noise = rng.normal(scale=0.25, size=X_test.shape)
X_test_noisy = X_test + noise

noise = rng.normal(scale=0.25, size=X_train.shape)
X_train_noisy = X_train + noise

Кроме того, мы создадим вспомогательную функцию для качественной оценки реконструкции изображения путем построения тестовых изображений.

import matplotlib.pyplot as plt


def plot_digits(X, title):
    """Small helper function to plot 100 digits."""
    fig, axs = plt.subplots(nrows=10, ncols=10, figsize=(8, 8))
    for img, ax in zip(X, axs.ravel()):
        ax.imshow(img.reshape((16, 16)), cmap="Greys")
        ax.axis("off")
    fig.suptitle(title, fontsize=24)

Кроме того, мы будем использовать среднеквадратичную ошибку (MSE) для количественной оценки восстановления изображения.

Давайте сначала посмотрим, чтобы увидеть разницу между изображениями без шума и с шумом. Мы проверим тестовый набор в этом отношении.

plot_digits(X_test, "Uncorrupted test images")
plot_digits(
    X_test_noisy, f"Noisy test images\nMSE: {np.mean((X_test - X_test_noisy) ** 2):.2f}"
)
  • Uncorrupted test images
  • Noisy test images MSE: 0.06

Обучить PCA базис#

Теперь мы можем обучить наш базис PCA, используя как линейный PCA, так и ядерный PCA, который использует ядро радиальной базисной функции (RBF).

from sklearn.decomposition import PCA, KernelPCA

pca = PCA(n_components=32, random_state=42)
kernel_pca = KernelPCA(
    n_components=400,
    kernel="rbf",
    gamma=1e-3,
    fit_inverse_transform=True,
    alpha=5e-3,
    random_state=42,
)

pca.fit(X_train_noisy)
_ = kernel_pca.fit(X_train_noisy)

Восстановите и очистите тестовые изображения от шума#

Теперь мы можем преобразовать и восстановить зашумленный тестовый набор. Поскольку мы использовали меньше компонентов, чем количество исходных признаков, мы получим приближение исходного набора. Действительно, отбрасывая компоненты, объясняющие наименьшую дисперсию в PCA, мы надеемся удалить шум. Аналогичное мышление применяется в ядерном PCA; однако мы ожидаем лучшую реконструкцию, потому что используем нелинейное ядро для изучения базиса PCA и ядерный гребень для изучения функции отображения.

X_reconstructed_kernel_pca = kernel_pca.inverse_transform(
    kernel_pca.transform(X_test_noisy)
)
X_reconstructed_pca = pca.inverse_transform(pca.transform(X_test_noisy))
plot_digits(X_test, "Uncorrupted test images")
plot_digits(
    X_reconstructed_pca,
    f"PCA reconstruction\nMSE: {np.mean((X_test - X_reconstructed_pca) ** 2):.2f}",
)
plot_digits(
    X_reconstructed_kernel_pca,
    (
        "Kernel PCA reconstruction\n"
        f"MSE: {np.mean((X_test - X_reconstructed_kernel_pca) ** 2):.2f}"
    ),
)
  • Uncorrupted test images
  • PCA reconstruction MSE: 0.01
  • Kernel PCA reconstruction MSE: 0.03

PCA имеет меньшую MSE, чем kernel PCA. Однако качественный анализ может не отдавать предпочтение PCA вместо kernel PCA. Мы наблюдаем, что kernel PCA способен удалять фоновый шум и обеспечивать более гладкое изображение.

Однако следует отметить, что результаты шумоподавления с помощью ядерного PCA будут зависеть от параметров n_components, gamma, и alpha.

Общее время выполнения скрипта: (0 минут 7.614 секунд)

Связанные примеры

Агломерация признаков

Агломерация признаков

Ядерный PCA

Ядерный PCA

Распознавание рукописных цифр

Распознавание рукописных цифр

Онлайн-обучение словаря частей лиц

Онлайн-обучение словаря частей лиц

Галерея, созданная Sphinx-Gallery