pytorh学习笔记:根据图示写相应神经网络以及对相应的debug进行修改

 

各位小伙伴大家好,很高兴又能和你见面,,在这篇博客中我将记录我再暑期学习中出现的debug以及修改debug的过程

首先我们先来看看作业要求

 所使用的网络结构:

 由上网络结构我们易知此网路我们需要用到残差结构,所以我们可以参考resnet的写法来写这个网络结构

resnet代码写法可以参考我之前写的Pytorch学习笔记:RNN的原理及其手写复现_后来后来啊的博客-CSDN博客

使用pytorch搭建ResNet并基于迁移学习训练(超详细 |附训练代码)_后来后来啊的博客-CSDN博客

使用pytorch搭建ResNet并基于迁移学习训练(超详细 |附训练代码)_后来后来啊的博客-CSDN博客这篇博客当中,我们定义了一个model函数

所以在此我们也在model.py中定义我们的网络结构

首先我先写了以下代码来实现这个网络结构

import torch
import torch.nn as nn
import torchsummary

class ResidualBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride=1, groups=1):
        super(ResidualBlock, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, padding=0)
        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, groups=groups)
        self.conv3 = nn.Conv2d(out_channels, out_channels, kernel_size=1, stride=1, padding=0)
        self.relu = nn.ReLU(inplace=True)

        if stride != 1 or in_channels != out_channels:
            self.downsample = nn.Sequential(
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, padding=0),
                nn.BatchNorm2d(out_channels)
            )
        else:
            self.downsample = None

    def forward(self, x):
        identity = x

        out = self.conv1(x)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.relu(out)

        out = self.conv3(out)

        if self.downsample is not None:
            identity = self.downsample(x)

        out += identity
        out = self.relu(out)

        return out


class Network(nn.Module):
    def __init__(self):
        super(Network, self).__init__()
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1)
        self.lconv1 = nn.Conv2d(32, 32, kernel_size=3, stride=2, padding=1, groups=32)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=1, stride=1)
        self.conv3 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1, groups=1)
        self.conv4 = nn.Conv2d(128, 128, kernel_size=1, stride=1)
        self.conv5 = nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1, groups=128)
        self.conv6 = nn.Conv2d(256, 256, kernel_size=1, stride=1)
        self.conv7 = nn.Conv2d(256, 512, kernel_size=1, stride=1)
        self.avgpool = nn.AvgPool2d(kernel_size=20)
        self.fc = nn.Linear(2048, 10)  # 修改全连接层的输入维度
        self.softmax = nn.Softmax(dim=1)
        self.relu = nn.ReLU(inplace=True)

        self.residual_block = ResidualBlock(128, 128, stride=2, groups=1)

    def forward(self, x):
        x = self.conv1(x)
        x = self.relu(x)

        x = self.lconv1(x)
        x = self.relu(x)

        x = self.conv2(x)
        x = self.relu(x)

        x = self.conv3(x)
        x = self.relu(x)

        x = self.conv4(x)
        x = self.relu(x)

        x = self.residual_block(x)

        x = self.conv5(x)
        x = self.relu(x)

        x = self.conv6(x)
        x = self.relu(x)

        x = self.conv7(x)
        x = self.relu(x)

        x = self.avgpool(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        x = self.softmax(x)

        return x


model = Network()
model = model.cuda()

# Print the model summary to the console
torchsummary.summary(model, (3, 640, 640))

但是我再跑网络的时候发现该结构运行的准确率只有40%左右,于是我我打印出网络结构层级和输出尺寸等信息

 发现该网络缺少下采样(batchnorm,dropout)等方法的多使用,且总参数 相比较而言偏少

于是我想在每层卷积后都加个下采样会是什么样

import torch
import torch.nn as nn
import torch.nn.functional as F
import torchsummary

class ResidualBlock(nn.Module):#公式:O=(W-F+2P)/S+1
# 构造方法(构造函数中至少需要传入2个参数:进出的通道数。残差块的一个最主要的作用就是改变信号的通道数)
    def __init__(self, in_channels, out_channels, stride=1, groups=1, downsample=None):
        super(ResidualBlock, self).__init__()
        self.conv5 = nn.Sequential(
            nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1, bias=False),
            nn.BatchNorm2d(out_channels))

        self.conv6 = nn.Sequential(nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1, groups=128, bias=False),
        nn.BatchNorm2d(128),
        nn.ReLU)

        self.conv7 = nn.Sequential(nn.Conv2d(in_channels=64, out_channels=128, kernel_size=1, stride=1, bias=False),
        nn.BatchNorm2d(128),
        nn.ReLU())

        self.conv8 = nn.Sequential(nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=2, padding=1, groups=128, bias=False),
        nn.BatchNorm2d(128),
        nn.ReLU())

        self.conv9 = nn.Sequential(nn.Conv2d(in_channels=64, out_channels=128, kernel_size=1, stride=1, bias=False),
        nn.BatchNorm2d(128),
        nn.ReLU())

        self.downsample = downsample

        if stride != 1 or in_channels != out_channels:
            self.downsample = nn.Sequential(
                nn.Conv2d(in_channels=64, out_channels=128, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(256))

    def forward(self, x):
        identity = x
        if self.downsample is not None:
            identity = self.downsample(x)

        out = self.conv5(x)
        out = self.conv6(out)
        out = self.conv7(out)
        out = self.conv8(out)
        out = self.conv9(out)

        out += identity
        out = F.relu(out)
        return out

class Network(nn.Module):
    def __init__(self, num_classes=1000):
        super(Network,self).__init__()
        self.conv1 = nn.Sequential(nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=2, padding=1, bias=True),
                                   nn.BatchNorm2d(32),
                                   nn.ReLU())

        self.conv2 = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, stride=2, padding=1, groups=32, bias=True),
            nn.BatchNorm2d(32),
            nn.ReLU())

        self.conv3 = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=1, stride=1, bias=True),
            nn.BatchNorm2d(64),
            nn.ReLU())

        self.conv4 = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=2, padding=1, groups=64, bias=True),
            nn.BatchNorm2d(64),
            nn.ReLU())

        self.residual_block = ResidualBlock(64, 128, stride=2)

        self.conv10 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1, groups=256),
            nn.BatchNorm2d(256),
            nn.ReLU())

        self.conv11 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=1, stride=1),
            nn.BatchNorm2d(256),
            nn.ReLU())

        self.conv12 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=1, stride=1),
            nn.BatchNorm2d(512),
            nn.ReLU())

        self.Avgpool = nn.AdaptiveAvgPool2d((1,1))#将输入的特征图的大小调整为1x1x512

        self.fc = nn.Linear(512, num_classes)



        def forward(self, x):
            out = self.conv1(x)
            out = self.conv2(x)
            out = self.conv3(x)
            out = self.conv4(x)

            out = self.residual_block(x)

            out = self.conv10(x)
            out = self.conv11(x)
            out = self.conv12(x)

            out = self.Avgpool(x)
            out = torch.flatten(x, 1)
            out = self.fc(x)
            return out

model = Network()
model = model.cuda()
#
# # Print the model summary to the console
torchsummary.summary(model, (3, 640, 640))

这是我重新写的一个网络结构,但是出现了相当多的报错,有小伙伴能在不看的情况下把这些报错都改过来吗,有的话评论区扣1,好了回归正题

首先我们遇到的报错是

根据报错原因说的是这个错误意味着`torch.nn.modules.activation.ReLU`不是`Module`的子类

我们再来自习看代码发现在16行我们使用的是nn.ReLU,但是正确使用方法应该是nn.ReLU()

更改后是第二个报错

 根据报错信息可知是因为输入值不能被groups整除,重新查看网络发现,这是因为我在 定义残差 网络是复制输入那一坨nn.Sequential的时候出现了问题,再看网络时候发现就是输入输出出现了问题

于是改成了

 但是接下来又出现了

 这个报错,思考了我许久,又去看原先定的网络结构,然后 上csdn上 看了这篇博客:NotImplementedError raise NotImplementedError_"s/module.py\", line 201, in _forward_unimplemente_Matthew2333的博客-CSDN博客

该博客说是因为我们forward函数出了错误,再细看网络发现在NetWork中,forward函数中的self没有像正确定义后出现紫色字样,这是因为我们把forward函数定义在了def  __init__中,正确 做法应该是俩个def齐平

如下图

 然后出现了最让我头疼的报错

 最终在改博客中得到解决:解决Given groups=1,weight [128,64,4,4], so expected inputs [32,32,64,64] to have 64 channels类似错误_萨姆西的博客-CSDN博客

根据博主说的是因为我们在输入是打成了x,而不是out,再看看 报错地方正是99行

 我们修改后面的x为out试试,发现变成了

 紧接着报错就变成了

 代码说我们在残差网络中我们输入的是128,但是需要的是256

 由图可以看到我们在定义downsample的时候,输出写成了128才出现了该错误

于是我们改成

虽然此处解决了,但是还可以使用其他方法,这里给大家提供一种思路 

 第1,2点可以用在model的out = self.conv9(out)中,例如

out = self.conv9(out.clone().detach())

最终打印出网络

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1         [-1, 32, 320, 320]             896
       BatchNorm2d-2         [-1, 32, 320, 320]              64
              ReLU-3         [-1, 32, 320, 320]               0
            Conv2d-4         [-1, 32, 160, 160]             320
       BatchNorm2d-5         [-1, 32, 160, 160]              64
              ReLU-6         [-1, 32, 160, 160]               0
            Conv2d-7         [-1, 64, 160, 160]           2,112
       BatchNorm2d-8         [-1, 64, 160, 160]             128
              ReLU-9         [-1, 64, 160, 160]               0
           Conv2d-10           [-1, 64, 80, 80]             640
      BatchNorm2d-11           [-1, 64, 80, 80]             128
             ReLU-12           [-1, 64, 80, 80]               0
           Conv2d-13          [-1, 256, 40, 40]          16,384
      BatchNorm2d-14          [-1, 256, 40, 40]             512
           Conv2d-15          [-1, 128, 80, 80]           8,192
      BatchNorm2d-16          [-1, 128, 80, 80]             256
           Conv2d-17          [-1, 128, 80, 80]           1,152
      BatchNorm2d-18          [-1, 128, 80, 80]             256
             ReLU-19          [-1, 128, 80, 80]               0
           Conv2d-20          [-1, 128, 80, 80]          16,384
      BatchNorm2d-21          [-1, 128, 80, 80]             256
             ReLU-22          [-1, 128, 80, 80]               0
           Conv2d-23          [-1, 128, 40, 40]           1,152
      BatchNorm2d-24          [-1, 128, 40, 40]             256
             ReLU-25          [-1, 128, 40, 40]               0
           Conv2d-26          [-1, 256, 40, 40]          32,768
      BatchNorm2d-27          [-1, 256, 40, 40]             512
             ReLU-28          [-1, 256, 40, 40]               0
    ResidualBlock-29          [-1, 256, 40, 40]               0
           Conv2d-30          [-1, 256, 40, 40]           2,560
      BatchNorm2d-31          [-1, 256, 40, 40]             512
             ReLU-32          [-1, 256, 40, 40]               0
           Conv2d-33          [-1, 256, 40, 40]          65,792
      BatchNorm2d-34          [-1, 256, 40, 40]             512
             ReLU-35          [-1, 256, 40, 40]               0
           Conv2d-36          [-1, 512, 40, 40]         131,584
      BatchNorm2d-37          [-1, 512, 40, 40]           1,024
             ReLU-38          [-1, 512, 40, 40]               0
AdaptiveAvgPool2d-39            [-1, 512, 1, 1]               0
           Linear-40                 [-1, 1000]         513,000
================================================================
Total params: 797,416
Trainable params: 797,416
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 4.69
Forward/backward pass size (MB): 251.57
Params size (MB): 3.04
Estimated Total Size (MB): 259.30
----------------------------------------------------------------

进程已结束,退出代码0

但是在使用该网络的时候又出现了报错

这个报错让我听没有头绪得,因为他说这个错误通常是由于在计算梯度时,某个变量被就地修改(inplace operation)导致的,于是我上csdn查了一下,然后在博客:报错解决:one of the variables needed for gradient computation has been modified by an inplace operation_y4ung的博客-CSDN博客

中说是因为使用了+=,于是返回 model更改为

最终问题解决 ,代码成功跑起

最后附上model.py和train.py

model.py

import torch
import torch.nn as nn
import torch.nn.functional as F
import torchsummary

class ResidualBlock(nn.Module):#公式:O=(W-F+2P)/S+1
# 构造方法(构造函数中至少需要传入2个参数:进出的通道数。残差块的一个最主要的作用就是改变信号的通道数)
    def __init__(self, in_channels, out_channels, stride=1, groups=1, downsample=None):
        super(ResidualBlock, self).__init__()
        self.conv5 = nn.Sequential(
            nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1, bias=False),
            nn.BatchNorm2d(out_channels))

        self.conv6 = nn.Sequential(nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1, groups=128, bias=False),
        nn.BatchNorm2d(128),
        nn.ReLU())

        self.conv7 = nn.Sequential(nn.Conv2d(in_channels=128, out_channels=128, kernel_size=1, stride=1, bias=False),
        nn.BatchNorm2d(128),
        nn.ReLU())

        self.conv8 = nn.Sequential(nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=2, padding=1, groups=128, bias=False),
        nn.BatchNorm2d(128),
        nn.ReLU())

        self.conv9 = nn.Sequential(nn.Conv2d(in_channels=128, out_channels=256, kernel_size=1, stride=1, bias=False),
        nn.BatchNorm2d(256),
        nn.ReLU())

        self.downsample = downsample

        if stride != 1 or in_channels != out_channels:
            self.downsample = nn.Sequential(
                nn.Conv2d(in_channels=64, out_channels=256, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(256))

    def forward(self, x):
        identity = x
        if self.downsample is not None:
            identity = self.downsample(x)

        out = self.conv5(x)
        out = self.conv6(out)
        out = self.conv7(out)
        out = self.conv8(out)
        out = self.conv9(out)

        out = out + identity
        out = F.relu(out)
        return out

class Network(nn.Module):
    def __init__(self, num_classes=1000):
        super(Network,self).__init__()
        self.conv1 = nn.Sequential(nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=2, padding=1, bias=True),
                                   nn.BatchNorm2d(32),
                                   nn.ReLU())

        self.conv2 = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, stride=2, padding=1, groups=32, bias=True),
            nn.BatchNorm2d(32),
            nn.ReLU())

        self.conv3 = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=1, stride=1, bias=True),
            nn.BatchNorm2d(64),
            nn.ReLU())

        self.conv4 = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=2, padding=1, groups=64, bias=True),
            nn.BatchNorm2d(64),
            nn.ReLU())

        self.residual_block = ResidualBlock(64, 128, stride=2)

        self.conv10 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1, groups=256),
            nn.BatchNorm2d(256),
            nn.ReLU())

        self.conv11 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=1, stride=1),
            nn.BatchNorm2d(256),
            nn.ReLU())

        self.conv12 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=1, stride=1),
            nn.BatchNorm2d(512),
            nn.ReLU())

        self.Avgpool = nn.AdaptiveAvgPool2d((1,1))#将输入的特征图的大小调整为1x1x512

        self.fc = nn.Linear(512, num_classes)



    def forward(self, x):
        out = self.conv1(x)
        out = self.conv2(out)
        out = self.conv3(out)
        out = self.conv4(out)

        out = self.residual_block(out)

        out = self.conv10(out)
        out = self.conv11(out)
        out = self.conv12(out)

        out = self.Avgpool(out)
        out = torch.flatten(out, 1)
        out = self.fc(out)
        return out

model = Network()
model = model.cuda()
#
# # Print the model summary to the console
# torchsummary.summary(model, (3, 640, 640))

train.py

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
from torchvision import transforms
from torchvision.models import resnet50, resnet101
from PIL import Image
import os
import model

class LogoDataset(Dataset):
    def __init__(self, root_dir, transform=None):
        self.root_dir = root_dir
        self.transform = transform
        self.image_files = []
        self.labels = []
        self.label_to_int = {}  # 创建一个字典来映射label和整数的关系
        self.int_to_label = {}  # 创建一个字典来映射整数和label的关系
        label_count = 0

        for label in os.listdir(root_dir):
            label_dir = os.path.join(root_dir, label)
            if os.path.isdir(label_dir):
                self.label_to_int[label] = label_count
                self.int_to_label[label_count] = label
                label_count += 1
                for image_file in os.listdir(label_dir):
                    self.image_files.append(os.path.join(label_dir, image_file))
                    self.labels.append(label)

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

    def __getitem__(self, idx):
        image = Image.open(self.image_files[idx]).convert("RGB")
        label = self.labels[idx]
        label = self.label_to_int[label]  # 使用字典将label转换为整数

        if self.transform:
            image = self.transform(image)

        return image, torch.tensor(label)


data_transform = transforms.Compose([
    transforms.Resize((640, 640)),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

train_dataset = LogoDataset("E:/wingstudio/four/logo_data/train", transform=data_transform)
test_dataset = LogoDataset("E:/wingstudio/four/logo_data/test", transform=data_transform)

train_loader = DataLoader(train_dataset, batch_size=4, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=4, shuffle=False)

class LogoClassifier(nn.Module):
    def __init__(self, num_classes):
        super(LogoClassifier, self).__init__()
        self.base_model = model.Network()
        self.fc = nn.Linear(1000, num_classes)

    def forward(self, x):
        x = self.base_model(x)
        x = self.fc(x)
        return x

def train(model, train_loader, criterion, optimizer, device):
    model.train()
    running_loss = 0.0

    for images, labels in train_loader:
        images = images.to(device)
        labels = labels.to(device)

        optimizer.zero_grad()

        outputs = model(images)
        loss = criterion(outputs, labels)

        with torch.autograd.set_detect_anomaly(True):
            loss.backward()

        optimizer.step()

        running_loss += loss.item() * images.size(0)

    epoch_loss = running_loss / len(train_loader.dataset)
    return epoch_loss


def test(model, test_loader, criterion, device):
    model.eval()
    running_loss = 0.0
    correct = 0

    with torch.no_grad():
        for images, labels in test_loader:
            images = images.to(device)
            labels = labels.to(device)

            outputs = model(images)
            loss = criterion(outputs, labels)

            running_loss += loss.item() * images.size(0)
            _, predicted = torch.max(outputs, 1)
            correct += (predicted == labels).sum().item()

    epoch_loss = running_loss / len(test_loader.dataset)
    accuracy = correct / len(test_loader.dataset)
    return epoch_loss, accuracy

def main():
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    model = LogoClassifier(num_classes=5)
    model = model.to(device)

    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(model.parameters(), lr=0.01)

    for epoch in range(40):
        train_loss = train(model, train_loader, criterion, optimizer, device)
        test_loss, test_accuracy = test(model, test_loader, criterion, device)

        print(
            f"Epoch {epoch + 1}/{40}, Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}, Test Accuracy: {test_accuracy:.4f}")



if __name__ == "__main__":
    main()

当然在这个网络结构基础上我有个朋友跑出来的正确率稍微更高一点,同样作者厚着脸皮要来了,这里@下原作者:灼清回梦_-CSDN博客

他的model.py

import torch
import torch.nn as nn
import torchsummary
import matplotlib.pyplot as plt

class ResdualBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride):
        super(ResdualBlock, self).__init__()
        self.conv0 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=1, stride=1, bias=False)
        self.bn0 = nn.BatchNorm2d(128)
        self.relu = nn.ReLU()

        self.conv1 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1, groups=128, bias=False)
        self.bn1 = nn.BatchNorm2d(128)
        self.relu = nn.ReLU()

        self.conv2 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=1, stride=1, bias=False)
        self.bn2 = nn.BatchNorm2d(128)

        self.conv3 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=2, padding=1, groups=128, bias=False)
        self.bn3 = nn.BatchNorm2d(128)

        self.conv4 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=1, stride=1, bias=False)
        self.bn4 = nn.BatchNorm2d(256)

        self.shortcut = nn.Sequential()

        if stride != 1 and in_channels != out_channels:
            self.shortcut = nn.Sequential(nn.Conv2d(in_channels, out_channels=256, stride=2, kernel_size=1, bias=False),
                                          nn.BatchNorm2d(out_channels))

    def forward(self, x):
        identity = x

        out = self.conv0(x)
        out = self.bn0(out)
        out = self.relu(out)

        out = self.conv1(out)
        out = self.bn1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)

        out = self.conv3(out)
        out = self.bn3(out)
        out = self.relu(out)

        out = self.conv4(out)
        out = self.bn4(out)

        out += self.shortcut(identity)
        out = self.relu(out)
        return out


class Network(nn.Module):
    def __init__(self, num_classes=1000):
        super(Network,self).__init__()
        self.conv5 = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(32),
            nn.ReLU(inplace=True)
        )
        #320*320*32

        self.conv6 = nn.Sequential(
            nn.Conv2d(in_channels=32,out_channels=32,kernel_size=3,stride=2,padding=1,groups=32),
            nn.BatchNorm2d(32),
            nn.ReLU(inplace=True)
        )
        # 320*320*32

        self.conv7 = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=1, stride=1),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True)
        )
        #320*320*64

        self.conv8 = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=2,padding=1,groups=64),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True)
        )
        #160*160*64

        self.layer1 = self.make_layer(64,256)

        self.conv9 = nn.Sequential(
            nn.Conv2d(in_channels=256,out_channels=256,kernel_size=3,stride=1,padding=1,groups=256,bias=False),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True)
        )

        self.conv10 = nn.Sequential(
            nn.Conv2d(in_channels=256,out_channels=256,kernel_size=1,stride=1,bias=False),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True)
        )

        self.conv11 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=1, stride=1, bias=False),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True)
        )
        #80*80*512

        self.avgpool = nn.AdaptiveAvgPool2d((1,1))#1*1*512

        self.fc = nn.Linear(512,num_classes)

    def make_layer(self, in_channels, out_channels, stride=2):
        layer = []
        layer.append(ResdualBlock(in_channels,out_channels,stride))
        return nn.Sequential(*layer)

    def forward(self,x):
        out = self.conv5(x)
        out = self.conv6(out)
        out = self.conv7(out)
        out = self.conv8(out)

        out = self.layer1(out)

        out = self.conv9(out)
        out = self.conv10(out)
        out = self.conv11(out)

        out = self.avgpool(out)
        out = torch.flatten(out,1)
        out = self.fc(out)
        return out

model = Network()
model = model.cuda()

# Print the model summary to the console
torchsummary.summary(model, (3, 640, 640))

他的train.py

import torch
from torchvision import datasets, models, transforms
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
import time


import numpy as np
import matplotlib.pyplot as plt
import os
from tqdm import tqdm

image_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(size=256, scale=(0.8, 1.0)),
        transforms.RandomRotation(degrees=15),
        transforms.RandomHorizontalFlip(),
        transforms.CenterCrop(size=224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406],
                             [0.229, 0.224, 0.225])
    ]),
    'test': transforms.Compose([
        transforms.Resize(size=256),
        transforms.CenterCrop(size=224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406],
                             [0.229, 0.224, 0.225])
    ])
}

dataset = 'E:\wingstudio/four\logo_data'
train_directory = os.path.join(dataset, 'train')
valid_directory = os.path.join(dataset, 'test')

batch_size = 32
num_classes = 5
print(train_directory)
data = {
    'train': datasets.ImageFolder(root=train_directory, transform=image_transforms['train']),
    'test': datasets.ImageFolder(root=valid_directory, transform=image_transforms['test'])
}


train_data_size = len(data['train'])
valid_data_size = len(data['test'])

train_data = DataLoader(data['train'], batch_size=batch_size, shuffle=True, num_workers=0)
valid_data = DataLoader(data['test'], batch_size=batch_size, shuffle=True, num_workers=0)

print(train_data_size, valid_data_size)

class ResdualBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride):
        super(ResdualBlock, self).__init__()
        self.conv0 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=1, stride=1, bias=False)
        self.bn0 = nn.BatchNorm2d(128)
        self.relu = nn.ReLU()

        self.conv1 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1, groups=128, bias=False)
        self.bn1 = nn.BatchNorm2d(128)
        self.relu = nn.ReLU()

        self.conv2 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=1, stride=1, bias=False)
        self.bn2 = nn.BatchNorm2d(128)

        self.conv3 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=2, padding=1, groups=128, bias=False)
        self.bn3 = nn.BatchNorm2d(128)

        self.conv4 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=1, stride=1, bias=False)
        self.bn4 = nn.BatchNorm2d(256)

        self.shortcut = nn.Sequential()

        if stride != 1 and in_channels != out_channels:
            self.shortcut = nn.Sequential(nn.Conv2d(in_channels, out_channels=256, stride=2, kernel_size=1, bias=False),
                                          nn.BatchNorm2d(out_channels))

    def forward(self, x):
        identity = x

        out = self.conv0(x)
        out = self.bn0(out)
        out = self.relu(out)

        out = self.conv1(out)
        out = self.bn1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)

        out = self.conv3(out)
        out = self.bn3(out)
        out = self.relu(out)

        out = self.conv4(out)
        out = self.bn4(out)

        out += self.shortcut(identity)
        out = self.relu(out)
        return out

###开始拼接上下部分,要求图片大小先裁剪为640*640
class Network(nn.Module):
    def __init__(self, num_classes=1000):
        super(Network,self).__init__()
        self.conv5 = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(32),
            nn.ReLU(inplace=True)
        )
        #320*320*32

        self.conv6 = nn.Sequential(
            nn.Conv2d(in_channels=32,out_channels=32,kernel_size=3,stride=2,padding=1,groups=32),
            nn.BatchNorm2d(32),
            nn.ReLU(inplace=True)
        )
        # 320*320*32

        self.conv7 = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=1, stride=1),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True)
        )
        #320*320*64

        self.conv8 = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=2,padding=1,groups=64),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True)
        )
        #160*160*64

        self.layer1 = self.make_layer(64,256)

        self.conv9 = nn.Sequential(
            nn.Conv2d(in_channels=256,out_channels=256,kernel_size=3,stride=1,padding=1,groups=256,bias=False),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True)
        )

        self.conv10 = nn.Sequential(
            nn.Conv2d(in_channels=256,out_channels=256,kernel_size=1,stride=1,bias=False),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True)
        )

        self.conv11 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=1, stride=1, bias=False),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True)
        )
        #80*80*512

        self.avgpool = nn.AdaptiveAvgPool2d((1,1))#1*1*512

        self.fc = nn.Linear(512,num_classes)

    def make_layer(self, in_channels, out_channels, stride=2):
        layer = []
        layer.append(ResdualBlock(in_channels,out_channels,stride))
        return nn.Sequential(*layer)

    def forward(self,x):
        out = self.conv5(x)
        out = self.conv6(out)
        out = self.conv7(out)
        out = self.conv8(out)

        out = self.layer1(out)

        out = self.conv9(out)
        out = self.conv10(out)
        out = self.conv11(out)

        out = self.avgpool(out)
        out = torch.flatten(out,1)
        out = self.fc(out)
        return out

resnet_net = Network()
Network.cuda(resnet_net)

loss_func = nn.CrossEntropyLoss()
optimizer = optim.SGD(resnet_net.parameters(),lr=0.01)

def train_and_valid(model, loss_function, optimizer, epochs=50):
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    history = []
    best_acc = 0.0
    best_epoch = 0

    for epoch in range(epochs):
        epoch_start = time.time()
        print("Epoch: {}/{}".format(epoch+1, epochs))

        model.train()

        train_loss = 0.0
        train_acc = 0.0
        valid_loss = 0.0
        valid_acc = 0.0

        for i, (inputs, labels) in enumerate(tqdm(train_data)):
            inputs = inputs.to(device)
            labels = labels.to(device)
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = loss_function(outputs, labels)
            loss.backward()
            optimizer.step()
            train_loss += loss.item() * inputs.size(0)
            ret, predictions = torch.max(outputs.data, 1)
            correct_counts = predictions.eq(labels.data.view_as(predictions))
            acc = torch.mean(correct_counts.type(torch.FloatTensor))
            train_acc += acc.item() * inputs.size(0)

        with torch.no_grad():
            model.eval()

            for j, (inputs, labels) in enumerate(tqdm(valid_data)):
                inputs = inputs.to(device)
                labels = labels.to(device)
                outputs = model(inputs)
                loss = loss_function(outputs, labels)
                valid_loss += loss.item() * inputs.size(0)
                ret, predictions = torch.max(outputs.data, 1)
                correct_counts = predictions.eq(labels.data.view_as(predictions))
                acc = torch.mean(correct_counts.type(torch.FloatTensor))
                valid_acc += acc.item() * inputs.size(0)

        avg_train_loss = train_loss/train_data_size
        avg_train_acc = train_acc/train_data_size

        avg_valid_loss = valid_loss/valid_data_size
        avg_valid_acc = valid_acc/valid_data_size

        history.append([avg_train_loss, avg_valid_loss, avg_train_acc, avg_valid_acc])

        if best_acc < avg_valid_acc:
            best_acc = avg_valid_acc
            best_epoch = epoch + 1

        epoch_end = time.time()

        print("Epoch: {:03d}, Training: Loss: {:.4f}, Accuracy: {:.4f}%, \n\t\tValidation: Loss: {:.4f}, Accuracy: {:.4f}%, Time: {:.4f}s".format(
            epoch+1, avg_valid_loss, avg_train_acc*100, avg_valid_loss, avg_valid_acc*100, epoch_end-epoch_start
        ))
        print("Best Accuracy for validation : {:.4f} at epoch {:03d}".format(best_acc, best_epoch))

        torch.save(model,dataset + '_model_' + str(epoch + 1) + '.pt')
    return model, history

num_epochs = 40
trained_model, history = train_and_valid(resnet_net, loss_func, optimizer, num_epochs)
torch.save(history,dataset+'_history.pt')

history = np.array(history)
plt.plot(history[:, 0:2])
plt.legend(['Tr Loss', 'Val Loss'])
plt.xlabel('Epoch Number')
plt.ylabel('Loss')
plt.ylim(0, 2)
plt.show()

plt.plot(history[:, 2:4])
plt.legend(['Tr Accuracy', 'Val Accuracy'])
plt.xlabel('Epoch Number')
plt.ylabel('Accuracy')
plt.ylim(0, 1)
plt.show()

# 六、使用模型进行预测
# 加载训练好的模型
model = torch.load(dataset+'_model_'+str(num_epochs)+'.pt')
model.eval()

# 定义预测函数
def predict_image(image_path):
    image = image_transforms['test'](Image.open(image_path))
    image_tensor = image.unsqueeze_(0)
    input = image_tensor.to("cuda:0")
    output = model(input)
    index = output.data.cpu().numpy().argmax()
    return index

# 预测新的图像是个啥
from PIL import Image
image_path = r'E:\wingstudio\four\logo_data\test\burger king\ankamall_image_106.jpg'
print("这张图片标签索引是:",predict_image(image_path))

def predict(model, image_path):
    # 加载图像并进行预处理
    image = Image.open(image_path)
    image_tensor = image_transforms['test'](image).float()
    image_tensor = image_tensor.unsqueeze_(0)
    input = input = image_tensor

    # 将输入传递给模型并获取输出
    output = model(input.cuda())

    # 获取预测结果并转换为类别标签
    _, predicted = torch.max(output.data, 1)
    class_index = predicted.cpu().numpy()[0]
    return data['train'].classes[class_index]


# 预测again
image_path = r'E:\wingstudio\four\logo_data\test\burger king\ankamall_image_106.jpg'
print("这张图片是:", predict(trained_model, image_path))

以上就是全部内容了,我还会继续向更加优秀的博主和up主学习,看到这个应该也是真爱粉了,大家一起共勉吧