Фантастический автоэнкодер! Шумоподавление изображения, уменьшение размерности данных, реконструкция изображения...

глубокое обучение

Структура автоэнкодера

Auto Encoder — это модель нейронной сети. Он состоит из двух частей: кодера (Ecoder) и декодера (Decoder).

КодерОн используется для кодирования входных данных (входных данных), чтобы отобразить входные данные в скрытое пространство (скрытое пространство) с меньшим размером и получить закодированные данные (кодированные данные).

декодерИспользуется для восстановления (декодирования) данных, закодированных в скрытом пространстве, в «входные данные». Причина кавычек здесь в том, что восстановленные «входные данные» будут иметь некоторые потери по сравнению с исходными входными данными, поэтому это не настоящие входные данные.

На следующем рисунке показана структура автоэнкодера.

Приложения автоэнкодеров

Уменьшение размерности данных/извлечение признаков

Такое использование автоэнкодера легко представить по его структуре. На этапе обучения,XXПосле отображения кодировщика низкоразмерныйzz,zzВосстановлено декодером иXXПостоянные размеры, похожий контентX'X', обновите веса сети обратным распространением, чтобы свести к минимуму вводXXи выводX'X'потери между ними.

один из нихzzэто данные после уменьшения размерности, потому что если вы можете передатьzzвосстановить вводXX, то можно сказать, чтоzzуже выучилXXбольшинство характеристик.

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

Шумоподавление изображения

Шумоподавление изображения заключается в удалении шума из изображения. Например, левая половина изображения ниже — это изображение без шума, а правая половина — с шумом. Наша цель состоит в том, чтобы обучить автоэнкодер, ввод которого представляет собой зашумленное изображение, а вывод — изображение с шумоподавлением, таким образом достигая цели устранения шума.

Метод обучения также очень прост. Подготовьте несколько изображений без шумаXX, а затем вручную добавить шум к этим изображениям, чтобы получить соответствующие изображения с шумомXnoiseX_{noise}. будетXXВход в кодировщик, а затем в декодер, чтобы получить выводX'X', обновите веса с помощью обратного распространения, чтобы свести к минимумуX'X'иXXпотери между ними. Таким образом, выводX'X'будет почти бесшумнымXX, который достигает цели снижения шума.

В приложении просто введите зашумленное изображение в обученный автоэнкодер, чтобы получить выходное изображение без шумов.

Изображение "сгенерировано"

Фактически, введение изображения «генерация» было включено во введение двух предыдущих приложений. Удалите энкодер из обученного автоэнкодера, а остаток можно рассматривать как «генератор». Низкоразмерное представление входного скрытого пространстваzz, сгенерированное изображение может быть получено через декодер.

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

Поэтому "поколение" здесь не совсем поколение, а точнее должно быть "перестроение".

Вариационные автоэнкодеры могут исправить этот недостаток, о котором мы поговорим в следующей статье.

Написать автоэнкодер в Pytorch

Теперь обучите автоэнкодер, используя набор данных рукописных цифр.

Набор данных рукописных цифр изначально состоял из нескольких1*28*281*28*28, здесь мы обучаем полносвязную нейронную сеть, поэтому используем сглаженный1*28*28=7841*28*28=784размерные характеристики. То есть, если естьNNкартинка, то наши данныеshapeэтоNNРяд784784Список.

Сначала импортируйте необходимые библиотеки:

import torch
import torch.nn as nn
import torch.optim as optim 
import torchvision
import matplotlib.pyplot as plt
import numpy as np

Затем подготовьте набор данных рукописных цифр:

transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])

train_dataset = torchvision.datasets.MNIST(
    root="torch_datasets", train=True, transform=transform, download=True
)

test_dataset = torchvision.datasets.MNIST(
    root="torch_datasets", train=False, transform=transform, download=True
)

train_loader = torch.utils.data.DataLoader(
    train_dataset, batch_size=128, shuffle=True, num_workers=4, pin_memory=True
)

test_loader = torch.utils.data.DataLoader(
    test_dataset, batch_size=32, shuffle=False, num_workers=4
)

Приведенный выше код автоматически загрузит набор данных из сети в указанныйrootпод дорожкой.

Затем создайте сеть автоэнкодера:

class AE(nn.Module):
    def __init__(self, **kwargs):
        super().__init__()
        #编码器
        self.encoder_hidden_layer = nn.Linear(
            in_features=kwargs["input_shape"], out_features=128)
        self.encoder_output_layer = nn.Linear(
            in_features=128, out_features=128)
        #解码器
        self.decoder_hidden_layer = nn.Linear(
            in_features=128, out_features=128)
        self.decoder_output_layer = nn.Linear(
            in_features=128, out_features=kwargs["input_shape"])

    def forward(self, features):
        #编码器
        activation = torch.relu(self.encoder_hidden_layer(features))
        code = torch.relu(self.encoder_output_layer(activation))
        #解码器
        activation = torch.relu(self.decoder_hidden_layer(code))
        reconstructed = torch.relu(self.decoder_output_layer(activation))
        #返回重建的图像
        return reconstructed

Задайте еще несколько параметров:

#设定随机种子,让每次的结果都一样
#原因:Pytorch的某些操作具有随机性
seed = 42
torch.manual_seed(seed)
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.deterministic = True
#设置 迭代轮数,学习率
epochs = 20
learning_rate = 1e-3

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = AE(input_shape=784).to(device)
#使用Adam优化器
optimizer = optim.Adam(model.parameters(), lr=1e-3)
#使用均方误差作为损失函数
criterion = nn.MSELoss()

Начать обучение:


for epoch in range(epochs):
    loss = 0
    for batch_features, _ in train_loader:
        #将N张*28*28的图片打平成N张784维的特征向量
        batch_features = batch_features.view(-1, 784).to(device)

        optimizer.zero_grad()
        
        # 前向传播
        outputs = model(batch_features)
        
        # 计算损失
        train_loss = criterion(outputs, batch_features)
        
        # 反向传播计算梯度
        train_loss.backward()
        
        # 更新网络权重
        optimizer.step()
        
        # 损失累加
        loss += train_loss.item()
    
    # 计算本轮损失
    loss = loss / len(train_loader)
    
    # 进度条
    print("epoch : {}/{}, loss = {:.6f}".format(epoch + 1, epochs, loss))

Видно, что потери постепенно уменьшаются.

После завершения обучения используйте первую партию тестового набора для тестирования:


#取第一个batch进行测试
with torch.no_grad():
    for batch_features in test_loader:
        # 只取图片,不取标签
        batch_features = batch_features[0]
        # 打平
        test_examples = batch_features.view(-1, 784).to(device)
        # 前向推理
        reconstruction = model(test_examples)
        break

reconstructionСодержит 32 реконструированных изображения, каждое из которых представлено 784-мерными признаками. Теперь давайте визуализируем и сравним изображения до и после реконструкции.Обратите внимание, что для восстановленного изображения нам нужно изменить его форму обратно к1*28*281*28*28.

with torch.no_grad():
    number = 10
    plt.figure(figsize=(20, 4))
    for index in range(number):
        # 可视化原始图片
        ax = plt.subplot(2, number, index + 1)
        plt.imshow(test_examples[index].cpu().numpy().reshape(28, 28))
        plt.gray()
        #不显示坐标轴
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)

        # 可视化重建后的图片
        ax = plt.subplot(2, number, index + 1 + number)
        plt.imshow(reconstruction[index].cpu().numpy().reshape(28, 28))# on gpu
        plt.gray()
        #不显示坐标轴
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
    plt.show()

Выходное изображение получается следующим образом:

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

Эта статья была впервые опубликована в публичном аккаунте WeChat:Я найду тебя в Антарктиде, публичная учетная запись, которая отправляет только галантерею, нижняя панель меню полна галантерейных товаров, обратите внимание!

Ссылаться на:

[1][medium.com/py факел/имп…]

[2][woohoo.comp three.com/blog/auto ru…]

[3][Ууху, боюсь пиара Grady.net/music-com…]

[4][в сторону зашумления данных science.com/ahhh…]