残差神经网络101层(Resnt101)实现(食物分类)

本文介绍了残差神经网络(ResNet)的工作原理,如何通过残差块和跳跃连接解决深度学习中的梯度问题。随后详细展示了如何在PyTorch中实现ResNet-101模型,包括数据预处理、模型构建、参数选择、损失函数和优化器设定,以及训练和测试过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、简单介绍残差神经网络

二、代码实现

1、导入库

2、创建ResNet-101模型,并修改全连接层:

3、确定需要更新的参数

4、数据转换定义

6、加载图像数据和对应的标签,并为训练和测试数据集创建了数据加载器

7、检查配置,并导入模型

8、训练集和测试集

9、设置损失函数和优化器

10、训练并测试

三、实现结果


一、简单介绍残差神经网络

残差神经网络(Residual Neural Network,通常缩写为ResNet)是一种深度学习神经网络架构,用于解决深度神经网络训练中的梯度消失梯度爆炸等问题。

ResNet引入了残差块(Residual Block),这是网络的基本构建单元。每个残差块包含两个主要部分:恒等映射(Identity Mapping)和残差映射(Residual Mapping)。

在一个传统的神经网络中,每个层都会通过权重和激活函数来变换输入。在ResNet中,每个残差块尝试学习的是将输入映射到期望的输出,而不是直接学习最终的映射。这是通过在残差块中引入跳跃连接(skip connection)来实现的。

跳跃连接允许网络直接将输入添加到层的输出,从而使残差块能够学习残差的变化。这意味着即使网络增加了更多的层,也不会导致梯度消失或梯度爆炸问题,因为梯度可以通过跳跃连接轻松地传播。这使得能够构建非常深的神经网络,如数百层或更多,而不会出现训练问题。

ResNet在图像分类、目标检测、语义分割等计算机视觉任务中取得了巨大成功,成为了深度学习领域的重要突破之一。这个网络架构的核心思想通过残差连接来让网络更深,从而提高了模型性能

二、代码实现

1、导入库

from torch.utils.data import Dataset, DataLoader
#用于创建自定义数据集和数据加载器。
import torch
from torch import nn
#PyTorch核心库,用于深度学习模型的构建和训练。
import numpy as np
#用于处理数据的数值计算库。
from torchvision import transforms
#PyTorch中用于数据增强和预处理的工具。
from PIL import Image
#Python Imaging Library,用于图像处理。
import torchvision.models as models
#包含了许多预训练的深度学习模型,包括ResNet。

2、创建ResNet-101模型,并修改全连接层:

resnet_model = models.resnet101(weights=models.ResNet101_Weights.DEFAULT)
#创建一个ResNet-101模型,并使用默认的预训练权重。
in_features = resnet_model.fc.in_features
#获取ResNet-101最后一个全连接层的输入特征数。
resnet_model.fc = nn.Linear(in_features,20)
#将ResNet-101的全连接层替换为一个新的线性层,输出维度为20。

3、确定需要更新的参数

params_to_update = []
for param in resnet_model.parameters():
    if param.requires_grad == True:
        params_to_update.append(param)
#使用一个for循环,遍历ResNet-101模型的所有参数,并将 requires_grad 属性为True的参数添加到 params_to_update 列表中。

4、数据转换定义

data_transforms = {
#data_transforms是一个字典,包含了两种数据变换('train' 和 'valid'),分别用于训练和验证数据集。
    'train':
        transforms.Compose([
            transforms.Resize([300, 300]),
            transforms.RandomRotation(45),
            transforms.CenterCrop(256),
            transforms.RandomHorizontalFlip(p=0.5),
            transforms.RandomVerticalFlip(p=0.5),
            transforms.ColorJitter(brightness=0.2,contrast=0.1,saturation=0.1,hue=0.1),
            transforms.RandomGrayscale(p=0.1),
            transforms.ToTensor(),
            transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225]),
        ]),
        #这些数据转换包括对图像的操作,如调整大小、随机旋转、中心裁剪、随机水平翻转、随机垂直翻转、颜色调整、随机灰度化等。
    'valid':
        transforms.Compose([
            transforms.Resize([256, 256]),
            transforms.ToTensor(),
            transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225]),
        ]),
        #transforms.ToTensor() 和 transforms.Normalize() 用于将图像数据转换为张量并进行标准化。
}

6、加载图像数据和对应的标签,并为训练和测试数据集创建了数据加载器

class food_dataset(Dataset):
    def __init__(self, file_path, transform=None):
        #接受两参数,file_path 和 transform,file_path 是包含图像文件路径和标签的文本文件路径,transform 是数据预处理的转换。
        self.file_path = file_path
        self.imgs = []
        self.labels = []
        self.transform = transform
        #初始化了数据集的实例变量 self.file_path,self.imgs,self.labels 和 self.transform。
        with open(self.file_path) as f:
            samples = [x.strip().split(' ') for x in f.readlines()]
            #打开指定的文本文件 file_path,并逐行读取文件内容。每行应包含图像路径和对应标签,以空格分隔。
            for img_path, label in samples:
                self.imgs.append(img_path)
                self.labels.append(label)
            #将图像路径和标签分别添加到 self.imgs 和 self.labels 列表中,以准备后续使用。
    def __len__(self):
        return len(self.imgs)
        #该方法返回数据集的长度,即数据集中图像的数量。
    def __getitem__(self, item):
        #接受一个整数 item,表示数据集中的一个样本索引。
        image = Image.open(self.imgs[item])
        #打开图像文件 self.imgs[item] 使用PIL库,并将其存储在变量 image 中。
        if self.transform:
            image = self.transform(image)
            #如果定义了数据预处理转换 self.transform,则将图像应用这些转换,以便在模型训练过程中使用。
        label = self.labels[item]
        #从 self.labels 中获取相应索引的标签,并将其存储在变量 label 中。
        label = torch.from_numpy(np.array(label, dtype=np.int64))
        #转换标签为PyTorch的Tensor对象,使用torch.from_numpy(np.array(label, dtype=np.int64))。
        return image, label
training_data = food_dataset(file_path='./train.txt', transform=data_transforms['train'])
testing_data = food_dataset(file_path='./test.txt', transform=data_transforms['valid'])
#training_data 和 testing_data 分别是 food_dataset 类的实例,用于训练和测试数据集。
#它们通过传递不同的文件路径和数据预处理转换 data_transforms 来创建。
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
test_dataloader = DataLoader(testing_data, batch_size=64, shuffle=True)
#使用 DataLoader 类创建训练数据加载器 train_dataloader 和测试数据加载器 test_dataloader。
#这些数据加载器用于批量加载数据,每个批次的大小是64,并且可以随机洗牌数据。

7、检查配置,并导入模型

device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else 'cpu'
print(f"Using {device} device")
#此行根据支持 CUDA 的 GPU 和 MPS 的可用性设置变量。
# 它使用 检查启用了 CUDA 的 GPU 是否可用。如果为 true,则设置为“cuda”。
# 否则,它将使用 检查 MPS 是否可用。如果为 true,则设置为“mps”。如果两个条件都为 false,则设置为“cpu”。

model=resnet_model.to(device)
#一个CNN类的实例被创建并赋值给model变量。.to(device)调用将模型参数移到指定的设备(例如,GPU上的“cuda”或CPU上的“cpu”)进行计算。
print(model)

8、训练集和测试集

def train(dataloader,model,loss_fn,optimizer):
    model.train()
    #通过这个方法将神经网络模型设置为训练模式,以确保在训练期间所需的操作(如批量归一化和丢弃)生效。
    batch_size_num = 1
    #初始化一个变量 batch_size_num,用于跟踪处理的批次数目。
    for X,y in dataloader:#开始遍历训练数据加载器中的每个批次,每个批次包括输入数据 X 和相应的标签 y。
        X , y = X.to(device),y.to(device)
        #将输入数据 X 和标签 y 移动到指定的设备(可能是GPU或CPU),以便与模型的设备匹配。
        pred = model.forward(X)
        #使用神经网络模型进行前向传播,得到预测结果 pred。
        loss = loss_fn(pred,y)
        #使用指定的损失函数 loss_fn 计算模型的预测结果 pred 与真实标签 y 之间的损失。
        optimizer.zero_grad()
        #使用优化器zero_grad()方法将模型的梯度清零,以准备进行反向传播。
        loss.backward()
        #使用反向传播计算模型参数的梯度,以便优化器可以更新模型权重以最小化损失。
        optimizer.step()
        #使用优化器的 step() 方法来执行一步优化,即更新模型的权重。

        loss_value = loss.item()#将损失值从 PyTorch 张量中提取出来,并存储在 loss_value 变量中。
        # print(f'loss:{loss_value:>7f} [number:{batch_size_num}]')
        batch_size_num+=1
        #增加 batch_size_num 的值,以跟踪处理的批次数目。

best_acc=0
def test(dataloader,model,loss_fn):
    global best_acc

    size= len (dataloader.dataset)
    #计算测试数据集的总样本数。
    num_batches = len(dataloader)
    #计算测试数据集的总样本数。
    model.eval()
    #通过这个方法将神经网络模型设置为评估模式,以关闭一些在训练时启用的操作,例如丢弃。
    test_loss,correct=0,0
    #初始化两个变量 test_loss 和 correct,分别用于累积测试损失和正确分类的样本数量。
    with torch.no_grad():
        #使用 torch.no_grad() 上下文管理器,将其包裹的代码块中的梯度计算禁用,以减少内存使用和加速计算。
        for X,y in dataloader:
            #开始遍历测试数据加载器中的每个批次,每个批次包括输入数据 X 和相应的标签 y。
            X,y=X.to(device),y.to(device)
            #将测试数据移动到指定的设备,以确保与模型的设备匹配。
            pred=model.forward(X)
            #使用神经网络模型进行前向传播,得到预测结果 pred。
            test_loss += loss_fn(pred,y).item()
            #计算并累积测试损失,通过使用损失函数 loss_fn 计算模型的预测结果 pred 与真实标签 y 之间的损失。
            correct += (pred.argmax(1)==y).type(torch.float).sum().item()
            #计算并累积正确分类的样本数量。这里使用了 argmax 函数来找到预测结果中的最大值对应的类别,然后检查是否与真实标签匹配,并将匹配的结果转换为浮点数。
            a = (pred.argmax(1) == y)  # dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号
            b = (pred.argmax(1) == y).type(torch.float)
    test_loss /=num_batches
    #计算测试的平均损失,将累积的损失值除以批次数目。
    correct /= size
    #计算准确率,将正确分类的样本数量除以总样本数,然后将其乘以 100 得到百分比形式。
    print(f'Test result:\n Accuracy:{(100*correct)}%,Avg loss: {test_loss}')
    #打印测试结果,包括准确率和平均损失。
    acc_s.append(correct)
    loss_s.append(test_loss)

    if correct>best_acc:
        best_acc=correct
        # print(model.state_dict().keys())
        # torch.save(model.state_dict(),'model_parameter.pt')#.pt/pth .t7
        #保存权重(w,b)
        torch.save(model,'best.pt')#保存模型

9、设置损失函数和优化器

loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(params_to_update,lr=0.001)
#使用交叉熵损失函数和Adam优化器来训练模型,并在测试集上评估模型的性能。

10、训练并测试

epoch=30
acc_s=[]
loss_s=[]
for i in range(epoch):
    print(f'Epoch{i+1}----------------')
    train(train_dataloader, model, loss_fn, optimizer)
    test(test_dataloader, model, loss_fn)
print('Done')

三、实现结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值