眼科医院网站优化服务商,海口建网站,怎么开通个人网站,网站建设哪个好卷积神经网络——pytorch与paddle实现卷积神经网络
本文将深入探讨卷积神经网络的理论基础#xff0c;并通过PyTorch和PaddlePaddle两个深度学习框架来展示如何实现卷积神经网络模型。我们将首先介绍卷积神经网络、图像处理的基本概念#xff0c;这些理论基础是理解和实现卷…卷积神经网络——pytorch与paddle实现卷积神经网络
本文将深入探讨卷积神经网络的理论基础并通过PyTorch和PaddlePaddle两个深度学习框架来展示如何实现卷积神经网络模型。我们将首先介绍卷积神经网络、图像处理的基本概念这些理论基础是理解和实现卷积神经网络的基础。通过PyTorch和PaddlePaddle的代码示例我们将展示如何设计、训练和评估一个卷积神经网络模型从而让读者能够直观地理解并掌握这两种框架在计算机视觉问题中的应用。
本文部分为torch框架以及部分理论分析paddle框架对应代码可见卷积神经网络paddle
import torch
print(pytorch version:,torch.__version__)pytorch version: 2.0.1cu118图像卷积的基本原理
图像卷积运算实际上是在进行图像空间域的滤波。卷积层是CNN的核心组件通过卷积运算提取特征。卷积运算是指从图像的左上角开始开一个与模板也称为卷积核或滤波器同样大小的活动窗口窗口图像与模板像元对应起来相乘再相加并用计算结果代替窗口中心的像元亮度值。然后活动窗口向右移动一列或一行并作同样的运算。以此类推从左到右、从上到下即可得到一幅新图像。
二维离散卷积公式用于描述两个二维信号在图像处理中通常是一个图像和一个滤波器或卷积核之间的卷积运算。给定一个二维图像信号 f [ i , j ] f[i, j] f[i,j] 和一个二维滤波器 h [ k , l ] h[k, l] h[k,l]二维离散卷积的结果 g [ x , y ] g[x, y] g[x,y] 可以通过以下公式计算 g [ x , y ] ∑ k − ∞ ∞ ∑ l − ∞ ∞ f [ i , j ] ⋅ h [ x − i , y − j ] g[x, y] \sum_{k-\infty}^{\infty} \sum_{l-\infty}^{\infty} f[i, j] \cdot h[x-i, y-j] g[x,y]k−∞∑∞l−∞∑∞f[i,j]⋅h[x−i,y−j]
其中 i i i 和 j j j 表示图像中像素的坐标而 x x x 和 y y y 表示卷积结果中像素的坐标。实际上在离散环境中图像的尺寸是有限的所以卷积核 h [ k , l ] h[k, l] h[k,l] 只在有限的区域内非零因此上述求和实际上也只在有限的范围内进行。
更具体地如果我们有一个 M × N M \times N M×N 的图像和一个 m × n m \times n m×n 的滤波器那么对于输出图像中的每个位置 ( x , y ) (x, y) (x,y)卷积操作可以定义为 g [ x , y ] ∑ k 0 m − 1 ∑ l 0 n − 1 f [ x k − m / 2 , y l − n / 2 ] ⋅ h [ k , l ] g[x, y] \sum_{k0}^{m-1} \sum_{l0}^{n-1} f[xk-m/2, yl-n/2] \cdot h[k, l] g[x,y]k0∑m−1l0∑n−1f[xk−m/2,yl−n/2]⋅h[k,l]
在实际应用中我们还需要处理边界条件例如通过填充如零填充或裁剪图像边缘。下方动图过程来源于CoolGPU’s Blog展示了卷积运算的过程。
该过程展示了一张 1 × 5 × 5 1 \times 5 \times 5 1×5×5的图像以及一个 3 × 3 3 \times 3 3×3的卷积核。在卷积运算中我们首先将卷积核在图像上滑动每次滑动一个像素的距离。在每次滑动中我们计算卷积核与图像对应位置像素的乘积并将这些乘积相加得到一个值作为卷积运算的结果。最后我们将这些结果拼接在一起得到一个新的 1 × 3 × 3 1 \times 3 \times 3 1×3×3的图像。
该过程展示了一张 3 × 5 × 5 3 \times 5 \times 5 3×5×5的图像即该图像有三个通道以及一个 3 × 3 × 3 3 \times 3 \times 3 3×3×3的卷积核。卷积核与图像进行卷积运算。最后将这些结果对应值加在一起算上偏置项得到一个新的 1 × 3 × 3 1 \times 3 \times 3 1×3×3的图像。
该过程与上方过程类似但此时我们给图像外边填充了一圈0同时卷积核每次移动步长变为2这样我们最终也得到了一个 1 × 3 × 3 1 \times 3 \times 3 1×3×3的图像。
卷积层设计及其梯度反向传播
首先我们导入一张图片然后利用卷积层对其进行滤波提取特征。
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline# 展示图像
image cv2.imread(img/cells.png)
plt.imshow(image)可以看到该图片为 1133 × 1700 × 3 1133 \times 1700 \times 3 1133×1700×3的形状我们将其转化为 1 × 3 × 1133 × 1700 1 \times 3 \times 1133 \times 1700 1×3×1133×1700的形式
# 将 ndarray 转换为 torch tensor
tensor torch.from_numpy(image)
tensor tensor.to(torch.float32) # 将数据类型转化为float# 调整 tensor 的维度使其变为 (1, 3, 1133, 1700)
tensor tensor.permute(2, 0, 1).unsqueeze(0) 接下来我们设计一个卷积层实现图像的卷积操作。
import torch.nn as nn
import torch.nn.functional as Fclass ConvLayer(nn.Module):卷积层设计def __init__(self, in_channels, out_channels, kernel_size, stride1, padding0):super(ConvLayer, self).__init__()# 构建卷积核self.kernel nn.Parameter(torch.randn(out_channels, in_channels, kernel_size, kernel_size))# 构建偏置项self.bias nn.Parameter(torch.randn(out_channels))self.stride strideself.padding paddingdef forward(self, x):# 卷积操作out F.conv2d(x, self.kernel, self.bias, strideself.stride, paddingself.padding)return out接下来我们利用该卷积层实现对图像在空间域的均值滤波让我们来试试吧
conv ConvLayer(in_channels1, out_channels1, kernel_size3, stride1, padding1)# 构建均值滤波卷积核
conv.kernel nn.Parameter(torch.ones_like(conv.kernel))
conv.bias nn.Parameter(torch.zeros_like(conv.bias))out_1 conv(tensor[0, 0, :, :].reshape(1, 1, 1133, 1700))
out_2 conv(tensor[0, 1, :, :].reshape(1, 1, 1133, 1700))
out_3 conv(tensor[0, 2, :, :].reshape(1, 1, 1133, 1700))
# 分析可知每一个像素由9个值相加得到我们对每一个像素除以9并将其合并为图像
out_1, out_2, out_3 out_1/9, out_2/9, out_3/9out torch.cat((out_1, out_2, out_3), dim0) # 合并
# 将out转化为ndarry并将形状调整为1133*1700*3的整形数组
out out.squeeze().detach().numpy().transpose(1, 2, 0) # 从tensor中取出数据调整形状转置
out out.astype(np.uint8) # 转化为整形数组
plt.imshow(out)这样我们就利用卷积神经网络实现了图像的均值滤波过程。
卷积神经网络解决分类问题的简单实现
从上述过程可以看到卷积实际上是对图像进行某种滤波提取图像特征的过程。下方我们将利用卷积神经网络实现对图像的分类任务。首先我们导入数据集并构建卷积神经网络。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms # 构建数据集
train_dataset datasets.MNIST(root./data, trainTrue, transformtransforms.ToTensor(), downloadTrue)
test_dataset datasets.MNIST(root./data, trainFalse, transformtransforms.ToTensor(), downloadTrue) # 构建数据加载器
train_loader DataLoader(datasettrain_dataset, batch_size64, shuffleTrue)
test_loader DataLoader(datasettest_dataset, batch_size64, shuffleFalse) # 构建卷积神经网络
class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()# 构建卷积层self.conv1 nn.Conv2d(in_channels1, out_channels16, kernel_size3, stride1, padding1)self.conv2 nn.Conv2d(in_channels16, out_channels32, kernel_size3, stride1, padding1)# 构建全连接层self.fc1 nn.Linear(32 * 7 * 7, 128)self.fc2 nn.Linear(128, 10)def forward(self, x):# 卷积操作x F.relu(self.conv1(x))x F.max_pool2d(x, 2)x F.relu(self.conv2(x))x F.max_pool2d(x, 2)# 展平操作x x.view(x.size(0), -1)# 全连接操作x F.relu(self.fc1(x))x self.fc2(x)return x# 构建模型实例
device cuda if torch.cuda.is_available else cpu
model CNN().to(device)
# 定义损失函数和优化器
criterion nn.CrossEntropyLoss()
optimizer optim.Adam(model.parameters(), lr0.001)# 训练模型
model.train()
for epoch in range(5):for data in train_loader:imgs, labels dataoutputs model(imgs.to(device))loss criterion(outputs, labels.to(device))optimizer.zero_grad()loss.backward()optimizer.step()# 测试模型
model.eval()
total 0
correct 0
for data in test_loader:imgs, labels dataoutputs model(imgs.to(device))_, predicted torch.max(outputs.data, 1)total labels.size(0)correct (predicted labels.to(device)).sum()print(Accuracy: %.2f %% % (100 * correct / total))Accuracy: 98.80 %可以看到该模型具有较高的精度我们不妨将图像进行的每一次操作呈现出来看看卷积层到底提取了什么样的特征。
首先我们将模型参数保存下来。
# 保存模型参数
torch.save(model, data/model_CNN_parameters.pt)接下来我们就可以在任意时间点加载这次训练好的模型了。
# 加载模型
model torch.load(data/model_CNN_parameters.pt)让我们看看每一次操作时图像的特征变换
# 加载某个图片
img imgs[3, :].reshape(1, 28, 28)
img img.detach().numpy().transpose(1, 2, 0) # 从tensor中取出数据调整形状转置
# 将图像放缩到0~255
img 255 * img
img img.astype(np.uint8) # 转化为整形数组
plt.imshow(img)人类可以较明显的识别出该数字是几让我们将图像送入网络看看网络的识别结果。
model model.to(device)
test_out model(imgs[3, :].reshape(1, 1, 28, 28).to(device))
_, prediction torch.max(test_out.data, 1)
predictiontensor([4], devicecuda:0)可以看到网络的识别结果也是准确的。让我们将网络每一步图像处理进行的操作展示出来。
x_out1 F.relu(model.conv1(imgs[3, :].reshape(1, 1, 28, 28).to(device)))
x_out2 F.max_pool2d(x_out1, 2)
x_out3 F.relu(model.conv2(x_out2))
x_out4 F.max_pool2d(x_out3, 2)import math
def transform_imag(img):# 将tensor格式转换为合适的图片_, channels, cols, rows img.shapeimg img.reshape(channels, cols, rows).to(cpu)img img.detach().numpy().transpose(1, 2, 0) # 从tensor中取出数据调整形状转置# 将图像放缩到0~255img 255 * imgimg img.astype(np.uint8) # 转化为整形数组return imgdef show_Features(img):# 展示img中包含的特征c, r, channels img.shapecols round(math.sqrt(channels))for i in range(channels):plt.subplot(cols, math.ceil(channels / cols), i1)plt.imshow(img[:, :, i].reshape(c, r, 1))plt.show()img1 transform_imag(x_out1)
show_Features(img1)img2 transform_imag(x_out2)
show_Features(img2)img3 transform_imag(x_out3)
show_Features(img3)img4 transform_imag(x_out4)
show_Features(img4)可以看到网络图像越到后边层各图像内容越简单且越抽象。
卷积神经网络CNN提取高阶特征的过程是一个层次性的数据处理与抽象过程CNN通过卷积层利用卷积核在输入图像上滑动执行卷积操作以捕捉图像的局部特征如边缘、纹理等随着网络层次的加深这些简单特征被逐层抽象与组合形成更复杂的特征表示例如形状、物体的部分等。在此过程中多个卷积核被用于每一层以提取不同的特征而池化层则通过下采样操作降低特征图的维度同时保留重要信息增强特征的鲁棒性。最终通过全连接层整合前面提取的特征形成针对特定任务如分类或回归的高度抽象的特征表示从而实现高阶特征的提取与利用。这一过程体现了CNN从底层到高层的特征学习和表示能力是其在图像识别等任务中取得优异表现的关键。