基于Pytorch框架构建LeNet-5模型

一、训练模型

1.导入必要的库

torch.nn.functional as F: 导入 PyTorch 的不带参数的函数模块,包含各种函数,如激活函数、池化层等。
torch.optim as optim: 导入 PyTorch 的优化器模块,用于定义优化器。
torch.cuda.is_available(): 导入 PyTorch 的 CUDA 模块,用于检查是否有可用的 CUDA GPU。
torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’): 导入 PyTorch 的设备模块,用于定义计算设备。如果 CUDA GPU 可用,则定义为 ‘cuda’;否则定义为 ‘cpu’。

# 导入库
import torch.nn.functional as F
import torch.optim as optim
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.optim
import torch.utils.data
import torch.utils.data.distributed
import torchvision.transforms as transforms
import torchvision.datasets as datasets

2.设置超参数

定义超参数,这些参数将用于控制模型的训练过程。

以下是超参数的详细说明:
CH_SIZE: 定义了每个训练批次的样本数量。较大的批大小可以提高计算效率,但可能会增加内存需求。在这个例子中,批大小被设置为 20。
EPOCHS: 定义了训练过程中迭代的轮数。每个 epoch 表示数据集被完整地遍历了一次。在这个例子中,训练过程被设置为进行 10 个 epoch。
DEVICE: 定义了计算设备。如果环境中存在可用的 GPU,它会定义为 ‘cuda’;如果环境中没有可用的 GPU,它会定义为 ‘cpu’。

# 设置超参数
#每次的个数
BATCH_SIZE = 20
#迭代次数
EPOCHS = 10
#采用cpu还是gpu进行计算
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

3.数据预处理

定义数据预处理步骤,这些步骤将被应用于每个图像上,以增强数据的多样性并标准化数据格式。
以下是预处理步骤的详细说明:
1)Resize(100): 将图片大小调整为 100x100 像素。
2)RandomVerticalFlip(): 随机垂直翻转图片。
3)RandomCrop(50): 从原始图片中随机裁剪一个大小为 50x50 的区域。
4)RandomResizedCrop(150): 从原始图片中随机裁剪一个大小为 150x150 的区域,并随机调整裁剪区域的缩放比例。
5)ColorJitter(brightness=0.5, contrast=0.5, hue=0.5): 随机调整图片的亮度、对比度和色调。
6)ToTensor(): 将 PIL 图像转换为 PyTorch 张量。
7)Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]): 对图像进行归一化处理,将每个通道的均值和标准差调整为 0.5。

# 定义数据预处理
transform = transforms.Compose([
    transforms.Resize(100),
    transforms.RandomVerticalFlip(),
    transforms.RandomCrop(50),
    transforms.RandomResizedCrop(150),
    transforms.ColorJitter(brightness=0.5, contrast=0.5, hue=0.5),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])

4.读取数据

使用 PyTorch 的数据加载和处理功能来读取数据集,并为训练和测试阶段准备数据加载器。

以下是代码的详细步骤:
1)dataset_train = datasets.ImageFolder(‘E:\xm\dataset\train’, transform): 创建一个ImageFolder数据集,用于加载和分类E:\xm\dataset\train目录中的图像。这个目录应该包含多个子目录,每个子目录代表一个类别,子目录中的图像将归属于该类别。transform变量包含了应用于每个图像的预处理操作。
2)print(dataset_train.imgs): 打印数据集中所有图像的文件路径和对应的类别索引。imgs是一个列表,每个元素是一个包含图像文件路径和类别索引的元组。
3)print(dataset_train.class_to_idx): 打印类别到索引的映射。class_to_idx是一个字典,键是类别名称,值是相应的索引。
4)dataset_test = datasets.ImageFolder(‘E:\xm\dataset\val’, transform): 创建一个ImageFolder数据集,用于加载和分类E:\xm\dataset\val目录中的验证图像。
5)print(dataset_test.class_to_idx): 这行代码打印验证数据集中类别到索引的映射。
6)train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True): 创建一个训练数据加载器。DataLoader类接受一个数据集和一个批处理大小batch_size,以及一个shuffle标志,表示是否在每次遍历数据集时随机打乱数据的顺序。
7)test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=True): 创建一个测试数据加载器。与训练数据加载器类似,但它也用于加载验证数据集。

# 读取数据
dataset_train = datasets.ImageFolder('E:\\xm\dataset\\train', transform)
print(dataset_train.imgs)
 
# 对应文件夹的label
print(dataset_train.class_to_idx)
dataset_test = datasets.ImageFolder('E:\\xm\dataset\\val', transform)
 
# 对应文件夹的label
print(dataset_test.class_to_idx)
 
# 导入数据
train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=True)

运行结果:
在这里插入图片描述

二、定义卷积神经网络

1.定义卷积神经网络

定义名为 ConvNet 的卷积神经网络类,它继承自 torch.nn.Module。这个类实现了一个简单的卷积神经网络结构,用于图像分类任务。

以下是网络结构的详细说明:
1)init(self): 构造函数中,定义了以下层:

  • 6 个卷积层(conv1 到 conv6),每个卷积层后面都跟着一个 ReLU 激活函数和 一个最大池化层(max_pool1 到max_pool4)。
  • 每个卷积层的输出通道数逐渐增加,从 32 到 128。
  • 两个全连接层(fc1 和 fc2),其中 fc1 具有512 个神经元,fc2 具有 1 个神经元(对应于二分类问题)。
  • 最后一个全连接层后面跟着一个 Sigmoid 激活函数。

2)forward(self, x): 前向传播函数接收输入 x,并依次通过以下层:

  • 6 个卷积和池化层的组合,用于提取图像特征。
  • 将最后一个池化层的输出特征图展平为一维向量。
  • 通过全连接层 fc1 和 fc2。
  • 通过 Sigmoid 激活函数生成最终输出。
class ConvNet(nn.Module):
    def __init__(self):
        super(ConvNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 32, 3)
        self.max_pool1 = nn.MaxPool2d(2)
        self.conv2 = nn.Conv2d(32, 64, 3) 
        self.max_pool2 = nn.MaxPool2d(2) 
        self.conv3 = nn.Conv2d(64, 64, 3) 
        self.conv4 = nn.Conv2d(64, 64, 3) 
        self.max_pool3 = nn.MaxPool2d(2) 
        self.conv5 = nn.Conv2d(64, 128, 3) 
        self.conv6 = nn.Conv2d(128, 128, 3) 
        self.max_pool4 = nn.MaxPool2d(2) 
        self.fc1 = nn.Linear(4608, 512) 
        self.fc2 = nn.Linear(512, 1)
  
    def forward(self, x): 
        in_size = x.size(0) 
        x = self.conv1(x) 
        x = F.relu(x) 
        x = self.max_pool1(x) 
        x = self.conv2(x) 
        x = F.relu(x) 
        x = self.max_pool2(x) 
        x = self.conv3(x) 
        x = F.relu(x) 
        x = self.conv4(x) 
        x = F.relu(x) 
        x = self.max_pool3(x) 
        x = self.conv5(x) 
        x = F.relu(x) 
        x = self.conv6(x) 
        x = F.relu(x)
        x = self.max_pool4(x) 
        # 展开
        x = x.view(in_size, -1)
        x = self.fc1(x)
        x = F.relu(x) 
        x = self.fc2(x) 
        x = torch.sigmoid(x) 
        return x

2.定义学习率

定义模型的学习率为 0.0001。

modellr = 1e-4

3.实例化模型并且移动到GPU

创建 ConvNet 模型实例,并使用 to(DEVICE) 方法将其移动到指定的计算设备上。如果 DEVICE 是 ‘cuda’,则模型将被移动到 GPU;如果 DEVICE 是 ‘cpu’,则模型将被移动到 CPU。

# 实例化模型并且移动到GPU
model = ConvNet().to(DEVICE)

4.选择优化器

创建 Adam 优化器,其中 model.parameters() 表示模型的所有参数,lr=modellr 表示学习率为 0.0001。

# 选择简单暴力的Adam优化器,学习率调低
optimizer = optim.Adam(model.parameters(), lr=modellr)

三、定义调整学习率的函数

1.定义调整学习率的函数

这个函数实现一个简单的学习率衰减策略,它能够根据当前的 epoch 调整学习率。

1)定义学习率衰减规则:

  • modellrnew = modellr * (0.1 ** (epoch // 5)) :定义了一个学习率衰减规则,其中 modellr
    是初始学习率,0.1 ** (epoch // 5) 表示每 5 个 epoch 学习率减少 10 倍。

2)打印新学习率:

  • print(“lr:”,modellrnew):打印出新的学习率。

3)调整优化器的学习率:

  • for param_group in optimizer.param_groups:
    遍历优化器中的每个参数组,并将每个参数组的学习率设置为新学习率。
def adjust_learning_rate(optimizer, epoch):
 
    """Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""
    modellrnew = modellr * (0.1 ** (epoch // 5)) 
    print("lr:",modellrnew) 
    for param_group in optimizer.param_groups: 
        param_group['lr'] = modellrnew

四、训练模型

1.设置模型为训练模式

将模型设置为训练模式,这样模型在计算梯度时会使用 Dropout 和 BatchNorm 层。

# 定义训练过程
def train(model, device, train_loader, optimizer, epoch):
    model.train() 

2.遍历训练数据加载器

遍历 train_loader 中的每个批次,并将数据和标签移动到指定的设备上。然后,它执行前向传播、计算损失、反向传播和更新模型参数。

for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device).float().unsqueeze(1)
optimizer.zero_grad()
output = model(data)

# print(output)
loss = F.binary_cross_entropy(output, target)
loss.backward()
optimizer.step()

3.打印进度

在每 10 个批次后打印当前的轮次、批次数、损失值和进度百分比,以便监控训练进度。

if (batch_idx + 1) % 10 == 0:
    print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
        epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),
            100. * (batch_idx + 1) / len(train_loader), loss.item()))

五、验证模型

1.设置模型为验证模式

将模型设置为验证模式,这样模型在计算梯度时不会使用 Dropout 和 BatchNorm 层。

# 定义测试过程
def val(model, device, test_loader):
    model.eval()

2.初始化计数器

用于在每次迭代时累积损失、正确预测的数量和总样本数。

test_loss = 0
correct = 0
total = 0

3.遍历测试数据加载器

遍历 test_loader 中的每个批次,并将数据和标签移动到指定的设备上。然后,它执行前向传播并计算损失。由于模型处于验证模式,它不会计算梯度。同时,它累积损失、样本数和正确预测的数量。

  with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device).float().unsqueeze(1)
            output = model(data)
            test_loss += F.binary_cross_entropy(output, target, reduction='mean').item()
            pred = torch.tensor([[1] if num[0] >= 0.5 else [0] for num in output]).to(device)
            correct += pred.eq(target.long()).sum().item()
            total += target.size(0)  # 计算总数

4.计算准确率

accuracy = 100. * correct / total

5.打印验证结果

在验证过程结束时打印平均损失和准确率。

print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.2f}%)\n'.format(

test_loss, correct, total, 100 * correct / total))

说明:这个函数实现了一个基本的验证循环,它能够验证模型在测试数据集上的性能。在实际使用中,您可能需要根据您的具体任务调整超参数,并确保数据加载器的设置与模型的需求相匹配。

五、定义训练循环

1.调整学习率
在每个 epoch 开始时调整学习率。

# 训练
for epoch in range(1, EPOCHS + 1):
 
    adjust_learning_rate(optimizer, epoch)

2.执行训练和验证

在每个 epoch 中执行训练和验证过程。

   train(model, DEVICE, train_loader, optimizer, epoch) 
    val(model, DEVICE, test_loader)

3.保存模型

在训练结束后保存模型的状态字典。

torch.save(model.state_dict(), 'ConvNet.pth')

运行结果:
在这里插入图片描述
在这里插入图片描述

# 二、测试模型




import torch
from PIL import Image
import torchvision.transforms as transforms
from torchvision import models
from torch.autograd import Variable


# 定义数据预处理
transform_test = transforms.Compose([
    transforms.Resize(100),
    transforms.RandomVerticalFlip(),
    transforms.RandomCrop(50),
    transforms.RandomResizedCrop(150),
    transforms.ColorJitter(brightness=0.5, contrast=0.5, hue=0.5),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])

# 定义类别
classes = ['cat', 'dog']  # 替换为您的实际类别名称

# 检查是否有可用的 GPU
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 定义自定义的 VGG-19 模型
# 定义网络
class ConvNet(nn.Module):
    def __init__(self):
        super(ConvNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 32, 3)
        self.max_pool1 = nn.MaxPool2d(2)
        self.conv2 = nn.Conv2d(32, 64, 3)
        self.max_pool2 = nn.MaxPool2d(2)
        self.conv3 = nn.Conv2d(64, 64, 3)
        self.conv4 = nn.Conv2d(64, 64, 3)
        self.max_pool3 = nn.MaxPool2d(2)
        self.conv5 = nn.Conv2d(64, 128, 3)
        self.conv6 = nn.Conv2d(128, 128, 3)
        self.max_pool4 = nn.MaxPool2d(2)
        self.fc1 = nn.Linear(4608, 512)
        self.fc2 = nn.Linear(512, 1)
 
    def forward(self, x):
        in_size = x.size(0)
        x = self.conv1(x)
        x = F.relu(x)
        x = self.max_pool1(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = self.max_pool2(x)
        x = self.conv3(x)
        x = F.relu(x)
        x = self.conv4(x)
        x = F.relu(x)
        x = self.max_pool3(x)
        x = self.conv5(x)
        x = F.relu(x)
        x = self.conv6(x)
        x = F.relu(x)
        x = self.max_pool4(x)
        # 展开
        x = x.view(in_size, -1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = torch.sigmoid(x)
        return x


# 实例化 Resnet50 类

# 加载权重
model.load_state_dict(torch.load("ConvNet.pth"))
model.to(DEVICE)
model.eval()

# 定义预测函数
def predict_image(image_path):
    # 打开图片
    image = Image.open(image_path)
    # 应用预处理
    image = transform(image).unsqueeze(0)  # 添加batch维度
    # 转换为Variable(如果模型需要)
    image = Variable(image).to(DEVICE)
    # 获取模型预测
    output = model(image)
    _, prediction = torch.max(output.data, 1)
    return classes[prediction.item()]

# 上传的图片路径
uploaded_image_path = '44.jpg'
# 进行预测
predicted_class = predict_image(uploaded_image_path)

print(f"The uploaded image is predicted as: {predicted_class}")

运行结果:
在这里插入图片描述

  • 32
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个关于深度学习的问题,需要一些代码实现和数据分析。我会尽力回答,但是由于文字表述的局限性,可能无法完全准确地解答问题。若有不懂的地方,可以随时问我。 首先,我们需要了解一下Lenet-5模型的结构。它是一个经典的卷积神经网络,用于手写数字识别。它的结构如下所示: ``` Input -> Convolution -> ReLU -> Pooling -> Convolution -> ReLU -> Pooling -> Fully Connected -> ReLU -> Fully Connected ``` 其中,Convolution层使用了6个5x5的卷积核,Pooling层使用了2x2的最大池化,Fully Connected层使用了两个隐藏层。 我们可以使用PyTorch框架来实现Lenet-5模型。代码如下: ```python import torch import torch.nn as nn import torch.nn.functional as F class LeNet5(nn.Module): def __init__(self): super(LeNet5, self).__init__() self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5) self.conv2 = nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5) self.fc1 = nn.Linear(in_features=16*4*4, out_features=120) self.fc2 = nn.Linear(in_features=120, out_features=84) self.fc3 = nn.Linear(in_features=84, out_features=10) def forward(self, x): x = F.relu(self.conv1(x)) x = F.max_pool2d(x, kernel_size=2) x = F.relu(self.conv2(x)) x = F.max_pool2d(x, kernel_size=2) x = x.view(-1, 16*4*4) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x ``` 接下来,我们需要加载MNIST数据集,并训练模型。代码如下: ```python import torchvision.datasets as dsets import torchvision.transforms as transforms train_dataset = dsets.MNIST(root='./data', train=True, transform=transforms.ToTensor(), download=True) test_dataset = dsets.MNIST(root='./data', train=False, transform=transforms.ToTensor(), download=True) train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=100, shuffle=True) test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=100, shuffle=False) model = LeNet5() criterion = nn.CrossEntropyLoss() optimizer = torch.optim.SGD(model.parameters(), lr=0.01) for epoch in range(10): for i, (images, labels) in enumerate(train_loader): optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() if (i+1) % 100 == 0: print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'.format(epoch+1, 10, i+1, len(train_loader), loss.item())) # 测试模型 model.eval() with torch.no_grad(): correct = 0 total = 0 for images, labels in test_loader: outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Test Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total)) ``` 接下来,我们需要构建自己的卷积神经网络模型,并与Lenet-5模型进行比较。可以尝试增加卷积层数、卷积核大小、全连接层数等,以提高分类精度。代码如下: ```python class MyConvNet(nn.Module): def __init__(self): super(MyConvNet, self).__init__() self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3) self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3) self.conv3 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3) self.fc1 = nn.Linear(in_features=128*2*2, out_features=256) self.fc2 = nn.Linear(in_features=256, out_features=10) def forward(self, x): x = F.relu(self.conv1(x)) x = F.max_pool2d(x, kernel_size=2) x = F.relu(self.conv2(x)) x = F.max_pool2d(x, kernel_size=2) x = F.relu(self.conv3(x)) x = x.view(-1, 128*2*2) x = F.relu(self.fc1(x)) x = self.fc2(x) return x ``` 训练代码与Lenet-5模型相同,这里不再重复。训练完成后,我们可以使用混淆矩阵来分析两个模型的分类精度。混淆矩阵可以展示模型对于每个类别的分类情况,常用于评估多分类问题的性能。代码如下: ```python from sklearn.metrics import confusion_matrix import matplotlib.pyplot as plt import seaborn as sns # 测试模型 model.eval() with torch.no_grad(): correct = 0 total = 0 predicted_labels = [] true_labels = [] for images, labels in test_loader: outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() predicted_labels.extend(predicted.tolist()) true_labels.extend(labels.tolist()) print('Test Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total)) # 绘制混淆矩阵 cm = confusion_matrix(true_labels, predicted_labels) plt.figure(figsize=(10,8)) sns.heatmap(cm, annot=True, cmap='Blues', fmt='g', xticklabels=[str(i) for i in range(10)], yticklabels=[str(i) for i in range(10)]) plt.xlabel('Predicted labels') plt.ylabel('True labels') plt.show() ``` 通过混淆矩阵,我们可以看到每个类别的分类情况,以及哪些类别容易被混淆。根据混淆矩阵,我们可以针对性地改进模型,提高分类精度。 以上是关于如何基于pytorch平台,利用MNIST数据集,实现经典的Lenet-5模型,同时加以改变构建自己的卷积模型,以分类的准确度和混淆矩阵为衡量指标,分析两个模型的分类精度的回答。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值