卷积神经网络(离焦图像去模糊)
卷积网络介绍
卷积过程
对于计算卷积之后的大小,需要考虑图像的尺寸n,卷积核的大小f,图像的填充p,步长s。
池化
主要目的:是减小特征图的空间维度,同时保留重要的特征信息。具体来分析具有以下功能:
特征降维:池化操作可以减小特征图的空间尺寸,从而降低整个网络的参数量和计算量。加快网络的训练和推理速度。
位置不变性:池化操作具有一定的平移不变性,无论特征在图像中的位置如何变化,池化操作都能够保留其相对位置信息。
过拟合控制:池化操作可以通过减少特征图的维度和参数数量来控制模型的复杂性,从而降低过拟合的风险。池化操作的降维作用可以减少参数的数量,有助于提高模型的泛化能力。
经典神经网络结构介绍
LeNet-5
网络结构的概要:
输入层:图像通常被标准化为32x32像素的灰度图像作为网络的输入。
卷积层1:第一层卷积层有6个卷积核(滤波器),每个卷积核大小为5x5,步长为1,通过滑窗操作对输入图像进行特征提取,输出特征图尺寸会因为有效感受野而减小至28x28。
每个卷积核后面都会接一个sigmoid激活函数,增加网络的非线性表达能力。
池化层1:使用平均池化(pooling)操作,窗口大小为2x2,步长也为2,进行下采样,输出特征图尺寸进一步减小至14x14。
卷积层2:第二个卷积层有16个卷积核,每个卷积核大小仍为5x5,同样使用sigmoid激活函数。
这一步之后输出的特征图尺寸变为10x10。
池化层2:再次进行池化操作,窗口大小和步长同上,输出尺寸为5x5。
全连接层1:将前一层池化层的结果展平成一维向量,然后连接到一个全连接层,该层有120个神经元,并且每个神经元后都跟随sigmoid激活函数。
全连接层2:又一个全连接层,拥有84个神经元,同样使用sigmoid激活函数。
输出层:最后一层是全连接层,对应于最终分类任务,对于MNIST数据集,该层会有10个神经元(对应0-9十个数字类别),并通常使用softmax函数生成概率分布,表示每个类别的预测可能性。
AlexNet
输入层:AlexNet 的输入是固定大小的图像,通常为 227x227 像素的 RGB 图像。
卷积层1:第一个卷积层有 96 个卷积核(过滤器),大小为 11x11,步幅为 4,使用 ReLU 激活函数。这个卷积层负责提取图像的低级特征。
池化层1:一个 3x3 大小的最大池化层,步幅为 2。这个池化层的作用是减小特征图的尺寸。
卷积层2:第二个卷积层有 256 个卷积核,大小为 5x5,使用 ReLU 激活函数。这个卷积层进一步提取图像的中级特征。
池化层2:一个 3x3 大小的最大池化层,步幅为 2。
卷积层3-4:两个连续的卷积层,每个卷积层有 384 个卷积核,大小为 3x3,使用 ReLU 激活函数。这些卷积层继续提取图像的高级特征。
卷积层5:第五个卷积层有 256 个卷积核,大小为 3x3,使用 ReLU 激活函数。这个卷积层进一步提取图像的高级特征。
池化层3:一个 3x3 大小的最大池化层,步幅为 2。
全连接层1:一个具有 4096 个神经元的全连接层,使用 ReLU 激活函数。
全连接层2:一个具有 4096 个神经元的全连接层,使用 ReLU 激活函数。
全连接层3:一个具有 1000 个神经元的全连接层,对应于 ImageNet 数据集中的 1000 个类别。这个全连接层的输出通过 Softmax 函数进行分类预测。
vgg16
输入层:VGG16 模型的输入是固定大小的图像,通常为 224x224 像素的 RGB 图像。
卷积层1-2:两个连续的卷积层,每个卷积层都有 64 个卷积核(过滤器)大小为 3x3,使用 ReLU 激活函数。这两个卷积层的作用是提取图像的低级特征。
池化层1:一个 2x2 大小的最大池化层,其步幅为 2。这个池化层的作用是减小特征图的尺寸并保留重要的特征。
卷积层3-4:两个连续的卷积层,每个卷积层都有 128 个卷积核(过滤器)大小为 3x3,使用 ReLU 激活函数。这两个卷积层进一步提取图像的中级特征。
池化层2:一个 2x2 大小的最大池化层,其步幅为 2。
卷积层5-7:三个连续的卷积层,每个卷积层都有 256 个卷积核(过滤器)大小为 3x3,使用 ReLU 激活函数。这些卷积层继续提取图像的中级特征。
池化层3:一个 2x2 大小的最大池化层,其步幅为 2。
卷积层8-9:两个连续的卷积层,每个卷积层都有 512 个卷积核(过滤器)大小为 3x3,使用 ReLU 激活函数。这些卷积层进一步提取图像的高级特征。
池化层4:一个 2x2 大小的最大池化层,其步幅为 2。
卷积层10-11:两个连续的卷积层,每个卷积层都有 512 个卷积核(过滤器)大小为 3x3,使用 ReLU 激活函数。这些卷积层继续提取图像的高级特征。
池化层5:一个 2x2 大小的最大池化层,其步幅为 2。
全连接层1-2:两个全连接层,每个全连接层有 4096 个神经元,使用 ReLU 激活函数。这些全连接层将卷积层输出的特征映射转换为固定长度的特征向量。
全连接层3:一个全连接层,有 1000 个神经元,对应于 ImageNet 数据集中的 1000 个类别。这个全连接层的输出通过 Softmax 函数进行分类预测。
残差神经网络
问题:梯度消失,梯度爆炸
残差网络:
经典残差网络:Deep Residual Learning for Image Recognition Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
[https://arxiv.org/abs/1512.03385]
使用卷积神经网络实现模糊图像去模糊
数据集介绍
使用圆盘点扩散函数(psf)对原始进行模糊,得到需要复原的图像,以模糊图像和原始图像为训练数据,实现模糊图像到原始图像的端到端映射。
训练数据加载
class ImagePairDataset(Dataset):
def __init__(self, root_dir, transform=None):
self.root_dir = root_dir
self.transform = transform
self.file_list = os.listdir(os.path.join(root_dir, "images"))#获取images下的所有图片名称
def __len__(self):
return len(self.file_list)
def __getitem__(self, index):
filename = self.file_list[index]
image_path = os.path.join(self.root_dir, "images", filename)#获取图片地址
image = self.load_image(image_path)
label_path = os.path.join(self.root_dir, "labels", filename)
label = self.load_image(label_path)
if self.transform:
image = self.transform(image)
label = self.transform(label)
return image, label
def load_image(self, image_path):
image = cv2.imread(image_path,0)
image = cv2.resize(image,(256,256))
return image
网络结构模型
class VGG16(nn.Module):
def __init__(self,channels):
super(VGG16, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(channels, 64, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(64, 128, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(128, 128, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.ConvTranspose2d(128,128,kernel_size=3,padding=1, stride=2, output_padding=1),
nn.ConvTranspose2d(128, 128, kernel_size=3, padding=1),
nn.ConvTranspose2d(128, 64, kernel_size=3, padding=1),
nn.ConvTranspose2d(64, 64, kernel_size=3, padding=1, stride=2, output_padding=1),
nn.ConvTranspose2d(64, 64, kernel_size=3, padding=1),
nn.ConvTranspose2d(64, channels, kernel_size=3, padding=1),
)
def forward(self, x):
x = self.features(x)
return x
通过端到端的网络结构模型进行图像的去模糊,特征提取部分借鉴了VGG16网络的前两个block,图像重建的网络层使用对称的反卷积层。
训练循环
def train(model, train_loader, criterion, optimizer, num_epochs):
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
min_loss = float('inf')
for epoch in range(num_epochs):
running_loss = 0.0
for images, labels in train_loader:
images = images.to(device)
labels = labels.to(device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
scheduler.step() # 在每个epoch结束时更新学习率
if running_loss < min_loss:
# 更新最小损失值
min_loss = running_loss
# 保存模型
torch.save(model.state_dict(), 'best_model.pt')
print(f"Epoch {epoch+1}/{num_epochs}, Loss: {running_loss/len(train_loader)}")
torch.save(model.state_dict(), 'last_model.pt')
print("Training completed.")
评估测试
def _test(model, test_loader):
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.eval() # 将模型设置为评估模式
model.to(device)
total_loss = 0
with torch.no_grad():
for images, _ in test_loader:
images = images.to(device)
outputs = model(images) # 前向传播
original_image = images.squeeze().cpu()
restored_image = outputs.squeeze().cpu()
fig, axs = plt.subplots(1, 2)
axs[0].imshow(original_image, cmap='gray')
axs[0].set_title('Originaldasd Image')
axs[0].axis('off')
axs[1].imshow(restored_image, cmap='gray')
axs[1].set_title('Restored Image')
axs[1].axis('off')
plt.show()
avg_loss = total_loss / len(test_loader)
return avg_loss
训练参数设置
# 加载训练数据
train_data = ImagePairDataset("train", transform=transforms.ToTensor())
train_loader = DataLoader(train_data, batch_size=4, shuffle=True)
channels = 1
model = VGG16(channels)
for m in model.features:
if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)):
init.xavier_uniform_(m.weight)
if m.bias is not None:
init.zeros_(m.bias)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=1e-4)
# 设置余弦衰减调度器
T_max = 20 # 设置周期的一半,即余弦函数半个周期的epochs数
eta_min = 0 # 学习率衰减时的最小值,默认为0
scheduler = CosineAnnealingLR(optimizer, T_max=T_max, eta_min=eta_min)
# Step 6: 开始训练
num_epochs = 3000
train(model, train_loader, criterion, optimizer, num_epochs)
model = VGG16(channels)
checkpoint = torch.load('best_model.pt')
optimizer = optim.Adam(model.parameters(), lr=1e-4)
# 设置余弦衰减调度器
T_max = 20 # 设置周期的一半,即余弦函数半个周期的epochs数
eta_min = 0 # 学习率衰减时的最小值,默认为0
scheduler = CosineAnnealingLR(optimizer, T_max=T_max, eta_min=eta_min)
# 如果需要,还可以加载学习率调度器的状态
# scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
# scheduler.load_state_dict(checkpoint['scheduler_state_dict'])
# 设置模型为训练模式
model.train()
train(model, train_loader, criterion, optimizer, num_epochs)
模糊图像复原效果