ResNet18深度学习记录——代码复现

神经网络/深度学习

第三章 Python机器学习入门之ResNet18的使用



前言

本文主要是复现resnet18网络代码,训练自己的二分类模型,学习记录下来。
在这里插入图片描述


一、ResNet是什么?

深度残差网络(Deep residual network, ResNet)的提出是CNN图像史上的一件里程碑事件,具体多牛,大家自己某度咯。ResNet的作者何恺明也因此摘得CVPR2016最佳论文奖,当然何博士的成就远不止于此,感兴趣的也可以去搜一下他后来的辉煌战绩。下面简单讲述ResNet的理论及实现。具体的解释可以去这位大佬的博文看看。

原文链接:https://blog.csdn.net/weixin_39524208/article/details/124894216

二、使用步骤

1.制作excel表格

图片
我们已第一列为例,0代表扁平,1代表拟物。一次代码只能实行一个二分类的训练,例如途中有四列,那么就要训练四次。下面会说

2.引入库

import torch
from torch.utils.data import DataLoader
from torchvision import transforms
from PIL import Image
from torch.utils.data import Dataset
import pandas as pd
from sklearn.model_selection import train_test_split
import torchvision.models as models
import torch.nn as nn

torch, torchvision, PIL, pandas, sklearn等库用于深度学习、图像处理和数据处理。

3.定义自定义数据集类CustomDataset:

class CustomDataset(Dataset):
    def __init__(self, image_paths, labels, transform=None):
        self.image_paths = image_paths
        self.labels = labels
        self.transform = transform

    def __len__(self):
        return len(self.image_paths)

    def __getitem__(self, idx):
        try:
            image = Image.open(self.image_paths[idx]).convert('RGB')
            if self.transform:
                image = self.transform(image)
            label = self.labels[idx]
            return image, torch.tensor(label, dtype=torch.float32)
        except Exception as e:
            print(f"Error loading image {self.image_paths[idx]}: {e}")
            return None

该类继承自 torch.utils.data.Dataset,用于加载图像数据和相应的标签。它包括三个主要方法:
init:初始化图像路径、标签和图像变换。
len:返回数据集的大小。
getitem:获取指定索引的图像和标签,并进行预处理。

4.数据加载预处理和模型训练

def main():
    df = pd.read_excel('excel/训练基础标签.xlsx', sheet_name='Sheet1')#这里是读取excel的位置。excel的内容上面已经写了
    image_paths = [f"train/基础标签/{path}" for path in
                   df.iloc[:, 0].astype(str)]#这里是图片训练集所在的位置,也就是excel表中第一列的那些图片
    labels = df.iloc[:, 1].tolist()
    
    #image_paths:从第一列获取图像文件名,并将其拼接成完整的路径。
    #labels:从第二列(也就是简约复杂)获取标签,并将其转换为列表形式。如果是第三列就可以改成[:, 2]

    transform = transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.ToTensor(),
    ])

    train_images, test_images, train_labels, test_labels = train_test_split(
        image_paths, labels, test_size=0.2, random_state=42)

    train_dataset = CustomDataset(train_images, train_labels, transform)
    test_dataset = CustomDataset(test_images, test_labels, transform)
    train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True, num_workers=16)
    test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=16)

    model = models.resnet18(pretrained=True)  # 使用预训练的 ResNet18 模型
	num_ftrs = model.fc.in_features  # 获取最后一层全连接层的输入特征数
	model.fc = nn.Linear(num_ftrs, 1)  # 修改最后一层以适应二分类任务,输出一个神经元
	model.to('cuda')  # 将模型加载到 GPU 上

    criterion = nn.BCEWithLogitsLoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=0.0001)

    for epoch in range(10):
        model.train()
        for images, labels in train_loader:
            if images is None:
                continue
            images, labels = images.to('cuda'), labels.to('cuda')
            optimizer.zero_grad()
            outputs = model(images).squeeze()
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
        print(f'Epoch {epoch + 1} complete.')

    # Model evaluation
    model.eval()
    total = 0
    correct = 0
    with torch.no_grad():
        for images, labels in test_loader:
            if images is None:
                continue
            images, labels = images.to('cuda'), labels.to('cuda')
            outputs = model(images).squeeze()
            predicted = (torch.sigmoid(outputs) > 0.5).float()
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

    print(f'Accuracy: {100 * correct / total:.2f}%')

    # Save the model
    torch.save(model.state_dict(),'models/resnet_multilabel_jichu01.pth')#模型存放的位置
    print("Model saved successfully.")


if __name__ == '__main__':
    main()

总结来说,在读取文件和标签的时候,确实只读取了Excel文件的前两列,其中第一列包含图像文件名,第二列包含对应的标签(如果训练其他的标签只需要对列数进行修改)。还有一定要注意修改最后一层全连接层的输入特征数,以适应二分类任务,输出一个神经元。


总结

以上就是今天代码所复现的内容,本文仅仅简单复现了ResNet18的代码并训练,如有不足还望批评指正。

  • 31
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ResNet18的主要原理是通过添加残差连接(skip connection)来构建深层神经网络。残差连接是将输入直接加到网络的输出中,从而使得网络可以学习到输入与输出的差异,从而更好地拟合数据。 在代码实现方面,可以使用PyTorch框架来实现ResNet18。以下是ResNet18的简单代码实现: ```python import torch.nn as nn import torch.nn.functional as F class BasicBlock(nn.Module): expansion = 1 def __init__(self, in_channels, out_channels, stride=1): super(BasicBlock, self).__init__() self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(out_channels) self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(out_channels) self.shortcut = nn.Sequential() if stride != 1 or in_channels != self.expansion * out_channels: self.shortcut = nn.Sequential( nn.Conv2d(in_channels, self.expansion * out_channels, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(self.expansion * out_channels) ) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) out += self.shortcut(x) out = F.relu(out) return out class ResNet(nn.Module): def __init__(self, block, num_blocks, num_classes=10): super(ResNet, self).__init__() self.in_channels = 64 self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(64) self.layer1 = self.make_layer(block, 64, num_blocks[0], stride=1) self.layer2 = self.make_layer(block, 128, num_blocks[1], stride=2) self.layer3 = self.make_layer(block, 256, num_blocks[2], stride=2) self.layer4 = self.make_layer(block, 512, num_blocks[3], stride=2) self.avg_pool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(512 * block.expansion, num_classes) def make_layer(self, block, out_channels, num_blocks, stride): strides = [stride] + [1] * (num_blocks - 1) layers = [] for stride in strides: layers.append(block(self.in_channels, out_channels, stride)) self.in_channels = out_channels * block.expansion return nn.Sequential(*layers) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = self.layer1(out) out = self.layer2(out) out = self.layer3(out) out = self.layer4(out) out = self.avg_pool(out) out = out.view(out.size(0), -1) out = self.fc(out) return out def ResNet18(): return ResNet(BasicBlock, [2, 2, 2, 2]) ``` 上述代码中,首先定义了一个BasicBlock类,用于构建ResNet18中的基本块。然后定义了一个ResNet类,该类包含了多个BasicBlock块,并且包括了一个全连接层用于分类。最后,定义了一个ResNet18函数,用于构建一个ResNet18模型。 要复现ResNet18模型,可以使用以上代码,并对数据集进行适当的预处理和训练。具体实现可以参考PyTorch官方文档和相关教程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值