卷积自编码去噪(基于pytorch)

数据集

链接:https://pan.baidu.com/s/10hZI4a-8I9cNJWw_baCD1Q
提取码:yker

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from skimage.util import random_noise
from skimage.metrics import peak_signal_noise_ratio
import scipy.io as scio
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.data as Data
import torch.optim as optim
from torchvision import transforms
from torchvision.datasets import STL10

def read_image(data_path):
    with open(data_path, 'rb') as f:
        data1 = np.fromfile(f,dtype=np.uint8)
        image = np.reshape(data1, (-1,3,96,96))
        images = np.transpose(image,(0,3,2,1))
    return images/255.0


def gaussian_noise(images, sigma):
    sigma2 = sigma**2 / (255**2) #噪声方差
    images_noisy = np.zeros_like(images)
    for ii in range(images.shape[0]):
        image = images[ii]
        noise_im = random_noise(image,mode='gaussian',var=sigma2,clip=True)
        images_noisy[ii] = noise_im
    return images_noisy


data_path = r'G:\data\STL10\stl10_binary\train_X.bin'
images = read_image(data_path)
#print('image.shape', images.shape)  #(5000,96,96,3)
images_noise = gaussian_noise(images, 30)


#显示原图
plt.figure(figsize=(6,6))
for ii in np.arange(36):
    plt.subplot(6,6,ii+1)
    plt.imshow(images[ii,...])
    plt.axis('off')
plt.show()


#显示带噪声的
plt.figure(figsize=(6,6))
for ii in np.arange(36):
    plt.subplot(6,6,ii+1)
    plt.imshow(images_noise[ii,...])
    plt.axis('off')
plt.show()

原图:
在这里插入图片描述
添加噪声:
在这里插入图片描述

训练保存模型

data_Y = np.transpose(images, (0, 3, 2, 1))  # 输出不带噪声
data_X = np.transpose(images_noise, (0, 3, 2, 1))  # 输入带噪声

X_train, X_val, y_train, y_val = train_test_split(data_X, data_Y,test_size=0.2,random_state=123)

#图像转为tensor
X_train = torch.tensor(X_train, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32)
X_val = torch.tensor(X_val, dtype=torch.float32)
y_val = torch.tensor(y_val, dtype=torch.float32)

train_data = Data.TensorDataset(X_train, y_train)
val_data = Data.TensorDataset(X_val, y_val)
print('X_train.shape:', X_train.shape)
print('y_train.shape:', y_train.shape)
print('X_val.shape:', X_val.shape)
print('y_val.shape:', y_val.shape)

train_loader = Data.DataLoader(
    dataset=train_data,
    batch_size=32,
    shuffle=True,
    num_workers=4
)

val_loader = Data.DataLoader(
    dataset=val_data,
    batch_size=32,
    shuffle=True,
    num_workers=4
)

class DenoiseAutoEncoder(nn.Module):
    def __init__(self):
        super(DenoiseAutoEncoder, self).__init__()

        #Encoder
        self.Encoder = nn.Sequential(
            nn.Conv2d(3, 64, 3, 1, 1),
            nn.ReLU(),

            nn.BatchNorm2d(64),
            nn.Conv2d(64, 64, 3, 1, 1),
            nn.ReLU(),

            nn.MaxPool2d(2, 2),
            nn.BatchNorm2d(64),
            nn.Conv2d(64, 128, 3, 1, 1),
            nn.ReLU(),

            nn.BatchNorm2d(128),
            nn.Conv2d(128, 128, 3, 1, 1),
            nn.ReLU(),

            nn.BatchNorm2d(128),
            nn.Conv2d(128, 256, 3, 1, 1),
            nn.ReLU(),

            nn.MaxPool2d(2, 2),
            nn.BatchNorm2d(256),
        )

        #Decoder
        self.Decoder = nn.Sequential(
            nn.ConvTranspose2d(256, 128,3, 1, 1),
            nn.ReLU(),

            nn.BatchNorm2d(128),
            nn.ConvTranspose2d(128, 128, 3, 2, 1, 1),
            nn.ReLU(),

            nn.BatchNorm2d(128),
            nn.ConvTranspose2d(128, 64, 3, 1, 1),
            nn.ReLU(),

            nn.BatchNorm2d(64),
            nn.ConvTranspose2d(64, 32, 3, 1, 1),
            nn.ReLU(),

            nn.BatchNorm2d(32),
            nn.ConvTranspose2d(32, 32, 3, 1, 1),
            nn.ConvTranspose2d(32, 16, 3,2, 1, 1),
            nn.ReLU(),

            nn.BatchNorm2d(16),
            nn.ConvTranspose2d(16, 3, 3, 1, 1),
            nn.Sigmoid(),
        )
    def forward(self, x):
        encoder = self.Encoder(x)
        decoder = self.Decoder(encoder)
        return encoder,decoder


 # train and save
DAEmodel = DenoiseAutoEncoder()
print(DAEmodel)



optimizer = optim.Adam(DAEmodel.parameters(),lr=0.0003)
loss_func = nn.MSELoss()

train_loss = []
val_loss = []
for epoch in range(10):
    train_loss_epoch = 0
    val_loss_epoch = 0
    for step,(b_x,b_y) in enumerate(train_loader):
        DAEmodel.train()
        _, output = DAEmodel(b_x)  # 加密,解密
        loss = loss_func(output, b_y)  # b_y 为不加噪声原图像

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        train_loss_epoch +=loss.item() * b_x.size(0)
    train_loss.append(train_loss_epoch / len(train_data))

    for step, (b_x,b_y) in enumerate(val_loader):
        DAEmodel.eval()
        _, output = DAEmodel(b_x)  # 加密,解密
        loss = loss_func(output, b_y)
        val_loss_epoch += loss.item() * b_x.size(0)
    val_loss.append(val_loss_epoch / len(val_data))

    print('*************************************************','finished:',epoch+1)
    print('train_loss:',train_loss)
    print('val_loss:',val_loss)


torch.save(DAEmodel, 'DAEmodel.pth',_use_new_zipfile_serialization=False)
scio.savemat('train_loss.mat',{'train_loss': train_loss})

scio.savemat('val_loss.mat',{'val_loss': val_loss})

在该模型中,我们依然对比了Adam和SDG算法:
Adam:
在这里插入图片描述
SGD:
在这里插入图片描述
笔者认为在该模型中Adam优于SDG算法。因此选用了Adam算法的模型。

加载模型

DAEmodel = torch.load('DAEmodel.pth')

#带噪图
im = X_val[1, ...].unsqueeze(0)
imnose = np.transpose(im.data.numpy(), (0,3,2,1))[0,...]

#去噪
DAEmodel.eval()
_, output = DAEmodel(im)
imde = np.transpose(output.data.numpy(), (0,3,2,1))[0,...]

#原图
im = y_val[1, ...].unsqueeze(0)
imor = np.transpose(im.data.numpy(), (0,3,2,1))[0,...]

#计算PNSR
print('加噪后的PNSR:', peak_signal_noise_ratio(imor, imnose), 'dB')
print('去噪后的:', peak_signal_noise_ratio(imor, imde), 'dB')


plt.figure(figsize=(12, 4))
plt.subplot(1,3,1)
plt.imshow(imor)
plt.axis('off')
plt.title('Origin image')
plt.subplot(1,3,2)
plt.imshow(imnose)
plt.axis('off')
plt.title('noise image sigma=30')
plt.subplot(1,3,3)
plt.imshow(imde)
plt.axis('off')
plt.title('Denoise image')
plt.show()

图像如下:
在这里插入图片描述
在评价图像去噪效果时,我们使用PSNR(peak signal noise ration)峰值信噪比来评价,该值越大说明两个图像之间越相似。

峰值信噪比的计算

python中有自带库来计算两个图像的峰值信噪比。

from skimage.metrics import peak_signal_noise_ratio

假设两个图像(图像I与图像K)的长,宽均为 m, n,K(i,j)表示K图第i行第j列个像素,可算得其均方误差为:
均方误差(MSE)
在这里插入图片描述
求得均方误差后,其峰值信噪比为:
MAXI是表示图像点颜色的最大数值
在这里插入图片描述

计算PSNR提升量的均值

# 计算平均PNSR的提升
psnr_val = []
DAEmodel.eval()
for ii in range(X_val.shape[0]):
    im = X_val[ii,...].unsqueeze(0)  #X_val 带噪
    imnose = np.transpose(im.data.numpy(), (0, 3, 2, 1))[0, ...]

    #去噪
    _, output = DAEmodel(im)
    imde = np.transpose(output.data.numpy(), (0, 3, 2, 1))[0,...]

    #输出
    im = y_val[ii, ...]
    imor = im.unsqueeze(0)
    imor = np.transpose(imor.data.numpy(), (0, 3, 2, 1))
    imor = imor[0,...]
    psnr_val.append(peak_signal_noise_ratio(imor,imde) - peak_signal_noise_ratio(imor, imnose))

print('PSNR提升:',np.mean(psnr_val))

在这里插入图片描述
经过我们的卷积自编码去噪,平均每张图片的峰值信噪比提升了5.32dB

  • 4
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
以下是使用PyTorch实现稀疏卷积去噪自编码器的示例代码: ```python import torch import torch.nn as nn import torch.nn.functional as F class SparseConvAutoencoder(nn.Module): def __init__(self): super(SparseConvAutoencoder, self).__init__() # Encoder self.conv1 = nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1) self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=2, padding=1) self.conv3 = nn.Conv2d(32, 64, kernel_size=3, stride=2, padding=1) # Decoder self.deconv1 = nn.ConvTranspose2d(64, 32, kernel_size=3, stride=2, padding=1, output_padding=1) self.deconv2 = nn.ConvTranspose2d(32, 16, kernel_size=3, stride=2, padding=1, output_padding=1) self.deconv3 = nn.ConvTranspose2d(16, 1, kernel_size=3, stride=2, padding=1, output_padding=1) # Sparse Convolution self.sparseconv1 = nn.Conv2d(16, 16, kernel_size=3, stride=1, padding=1, bias=False, groups=16) self.sparseconv2 = nn.Conv2d(32, 32, kernel_size=3, stride=1, padding=1, bias=False, groups=32) self.sparseconv3 = nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1, bias=False, groups=64) def forward(self, x): # Encoder x = F.relu(self.conv1(x)) x = F.relu(self.sparseconv1(x)) x = F.relu(self.conv2(x)) x = F.relu(self.sparseconv2(x)) x = F.relu(self.conv3(x)) x = F.relu(self.sparseconv3(x)) # Decoder x = F.relu(self.deconv1(x)) x = F.relu(self.deconv2(x)) x = torch.sigmoid(self.deconv3(x)) return x ``` 在这个模型中,我们使用了三个卷积层作为编码器,以及三个反卷积层作为解码器。为了实现稀疏卷积,我们还添加了三个稀疏卷积层,它们的groups参数设置为输出通道数,这样每个输出通道只与输入的一个子集通道进行卷积,从而实现了稀疏卷积。 在前向传播中,我们先对输入进行编码,然后对编码结果进行解码,并使用sigmoid激活函数将输出限制在[0,1]范围内。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JiYH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值