【深度学习】(5)--搭建卷积神经网络
本篇介绍了如何搭建卷积神经网络,其主要的构造部分为卷积层、激活层以及池化层,可以搭建多层该部分对数据进行多次卷积、池化。注意:同普通的神经网络不同,卷积神经网络在传入图片时不需要将其展开,因为对图片进行卷积就是在原图上进行内积,不能展开。
搭建卷积神经网络
一、数据预处理
1. 下载数据集
在PyTorch中,有许多封装了很多与图像相关的模型、数据集,那么如何获取数据集呢?
导入datasets模块:
from torchvision import datasets #封装了很多与图像相关的模型,数据集
以datasets模块中的MNIST数据集为例,包含70000张手写数字图像:60000张用于训练,10000张用于测试。图像是灰度的,28*28像素,并且居中的,以减少预处理和加快运行。
from torch.utils.data import DataLoader #数据包管理工具,打包数据
from torchvision import datasets #封装了很多与图像相关的模型,数据集
from torchvision.transforms import ToTensor # 数据转换,张量,将其他类型数据转换为tensor张量
"""-----下载训练集数据集-----"""
training_data = datasets.MNIST(
root="data",
train=True,# 取训练集
download=True,
transform=ToTensor(),# 张量,图片是不能直接传入神经网络模型的
) # 对于pytorch库能够识别的数据,一般是tensor张量
"""-----下载测试集数据集-----"""
test_data = datasets.MNIST(
root="data",
train=False,
download=True,
transform=ToTensor(),
)# numpy数组只能在CPU上运行,Tensor可以在GPU上运行,这在深度学习中可以显著提高计算速度
下载完成之后可在project栏查看。
2. 创建DataLoader(数据加载器)
在PyTorch中,创建DataLoader的主要作用是将数据集(Dataset)加载到模型中,以便进行训练或推理。DataLoader通过封装数据集,提供了一个高效、灵活的方式来处理数据。
DataLoader通过batch_size参数将数据集自动划分为多个小批次(batch),每一批次的放入模型训练,减少内存的使用,提高训练速度。
import torch
from torch.utils.data import DataLoader
"""
创建数据DataLoader(数据加载器)
batch_size:将数据集分成多份,每一份为batch_size(指定数值)个数据。
优点:减少内存的使用,提高训练速度
"""
train_dataloder = DataLoader(training_data,batch_size=64)# 64张图片为一个包
test_datalodar = DataLoader(test_data,batch_size=64)
# 查看打包好的数据
for x,y in test_datalodar: #x是表示打包好的每一个数据包
print(f"Shape of x [N, C, H, W]:{x.shape}")
print(f"Shape of y:{y.shape} {y.dtype}")
break
-----------------------
Shape of x [N, C, H, W]:torch.Size([64, 1, 28, 28])
Shape of y:torch.Size([64]) torch.int64
二、搭建神经网络
注意:同普通的神经网络不同,卷积神经网络在传入图片时不需要将其展开,因为对图片进行卷积就是在原图上进行内积,不能展开。
卷积神经网络是由输入层、卷积层、激活层、池化层、全连接层、输出层组成。所以在结构上我们也同这样式的来,但是可以搭建多层卷积哦!
"""---判断当前设备是否支持GPU,其中mps是苹果m系列芯片的GPU"""
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
"""-----定义神经网络-----"""
class CNN(nn.Module):
def __init__(self): # 输入大小(1,28,28)
super(CNN,self).__init__()
self.conv1 = nn.Sequential( # 将多个层组合在一起
nn.Conv2d( # 2d一般用于图像,3d用于视频数据(多一个时间维度),1d一般用于结构化的序列数据
in_channels=1, # 图像通道个数,1表示灰度图(确定卷积核 组中的个数)
out_channels=16, # 要得到多少特征图,卷积核的个数
kernel_size=5, # 卷积核大小
stride=1, # 步长
padding=2 # 边界填充大小
), # 输出的特征图为(16,28,28)-->16个大小28*28的图像
nn.ReLU(), # relu层,不会改变特征图的大小
nn.MaxPool2d(kernel_size=2) # 进行池化操作(2*2区域),输出结果为(16,14,14)
)
self.conv2 = nn.Sequential( # 输入(16,14,14)
nn.Conv2d(16,32,5,1,2), # 输出(32*14*14)
nn.ReLU(),
nn.Conv2d(32,32,5,1,2), # 输出(32*14*14)
nn.ReLU(),
nn.MaxPool2d(2) # 输出(32,7,7)
)
self.conv3 = nn.Sequential( # 输入(32,7,7)
nn.Conv2d(32,64,5,1,2), # 输出(64,7,7)
nn.ReLU()
)
self.out = nn.Linear(64*7*7,10)
def forward(self,x):
x = self.conv1(x)
x = self.conv2(x)
x = self.conv3(x) # 输出(64,7,7)
x = x.view(x.size(0),-1) # flatten 操作,结果为:(batch_size,64*7*7)
output = self.out(x)
return output
model = CNN().to(device)
三、训练数据
- optimizer优化器:
optimizer = torch.optim.Adam(model.parameters(),lr=0.001)
- loss_fn损失函数:
在PyTorch中,**nn.CrossEntropyLoss()**是一个常用的损失函数,它结合了 nn.LogSoftmax() 和 nn.NLLLoss()(负对数似然损失)在一个单独的类中。
loss_fn = nn.CrossEntropyLoss()
- 训练集
from torch import nn #导入神经网络模块
def train(dataloader,model,loss_fn,optimizer):
model.train()# 设置模型为训练模式
batch_size_num =1# 迭代次数
for x,y in dataloader:
x,y = x.to(device),y.to(device) # 将数据和标签发送到指定设备
pred = model.forward(x) # 前向传播
loss = loss_fn(pred,y) # 计算损失
optimizer.zero_grad() # 清除之前的梯度
loss.backward() # 反向传播
optimizer.step() # 更新模型参数
loss_value = loss.item() # 获取损失值
if batch_size_num %200 == 0: # 每200次迭代打印一次损失
print(f"loss:{loss_value:>7f} [number:{batch_size_num}]")
batch_size_num += 1
train(train_dataloder,model,loss_fn,optimizer)
------------------------
loss:0.158841 [number:200]
loss:0.242431 [number:400]
loss:0.173504 [number:600]
loss:0.020542 [number:800]
- 测试集
"""-----测试集-----"""
def test(dataloader,model,loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss,correct = 0,0
with torch.no_grad():
for x,y in dataloader:
x,y = x.to(device),y.to(device)
pred = model.forward(x)
test_loss += loss_fn(pred,y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
a = (pred.argmax(1) == y)
b = (pred.argmax(1) == y).type(torch.float)
test_loss /= num_batches
correct /= size
correct = round(correct, 4)
print(f"Test result: \n Accuracy:{(100*correct)}%,Avg loss:{test_loss}")
test(test_datalodar,model,loss_fn)
--------------------
Test result:
Accuracy:98.11999999999999%,Avg loss:0.05511626677004996
四、优化模型
通过多次迭代,神经网络不断调整其内部参数(如权重和偏置),以最小化预测值与实际值之间的误差。这种优化过程使得神经网络能够更准确地处理输入数据,提高分类、回归等任务的性能。
epochs = 5
for t in range(epochs):
print(f"Epoch {t+1} \n-------------------------")
train(train_dataloder,model,loss_fn,optimizer)
print("Done!")
test(test_datalodar,model,loss_fn)
输出结果:
Epoch 1
-------------------------
loss:0.182339 [number:200]
loss:0.229839 [number:400]
loss:0.210450 [number:600]
loss:0.028532 [number:800]
Epoch 2
-------------------------
loss:0.066216 [number:200]
loss:0.149762 [number:400]
loss:0.084482 [number:600]
loss:0.003749 [number:800]
…………
Done!
Test result:
Accuracy:98.99%,Avg loss:0.03138259953491878
总结
本篇介绍了如何搭建卷积神经网络,其主要的构造部分为卷积层、激活层以及池化层,可以搭建多层该部分对数据进行多次卷积、池化。
注意:同普通的神经网络不同,卷积神经网络在传入图片时不需要将其展开,因为对图片进行卷积就是在原图上进行内积,不能展开。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)