J6:ResNeXt-50实战解析

本文介绍了ResNeXt50模型,由何凯明团队提出的用于解决深度学习网络深度和宽度增加带来的挑战。文章详细解释了分组卷积原理,并展示了如何用ResNeXt-50算法进行猴痘病识别,最终达到89.28%的最高准确率。
摘要由CSDN通过智能技术生成

📌 本周任务:
●阅读ResNeXt论文,了解作者的构建思路
●对比我们之前介绍的ResNet50V2、DenseNet算法
●使用ResNeXt-50算法完成猴痘病识别

前言

ResNeXt是由何凯明团队在2017年CVPR会议上提出来的新型图像分类网络。在论文《Aggregated Residual Transformations for Deep Neural Networks》作者提出了当时普遍存在的问题:如何提高模型的准确率?

常用的方法是提高网络的深度或宽度,但单纯的提高网络的深度或宽度,加大了设计的难度,也加大了计算的开销。由此何团队设计了cardinality的概念。将卷积通道分组,再对分组进行卷积。
在这里插入图片描述

分组卷积

分组卷机简单来说就是将特征图分为不同的组,再对每组特征图分别进行卷积,这个操作可以有效的降低计算量。在分组卷积中,每个卷积核只处理部分通道,每个卷积核生成一张特征图。
在这里插入图片描述
在这里插入图片描述

class Bottleneck(nn.Module):  
    expansion = 4  
 
    def __init__(self, in_channel, out_channel, stride=1, downsample=None, groups=1, base_width=64):  # 初始化方法
        super(Bottleneck, self).__init__() 
        width = int(in_channel * (base_width / 64.0)) * groups 
        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=width, kernel_size=1, stride=1,
                               bias=False)  
        self.bn1 = nn.BatchNorm2d(num_features=width) 
        self.conv2 = nn.Conv2d(in_channels=width, out_channels=width, groups=groups, kernel_size=3, stride=stride,
                               padding=1, bias=False)  
        self.bn2 = nn.BatchNorm2d(num_features=width) 
        self.conv3 = nn.Conv2d(in_channels=width, out_channels=out_channel * self.expansion, kernel_size=1, stride=1,
                               bias=False) 
        self.bn3 = nn.BatchNorm2d(num_features=out_channel * self.expansion)
 
        self.relu = nn.ReLU(inplace=True) 
        self.downsample = downsample 
 
    def forward(self, x):  
        identity = x  
        if self.downsample: 
            identity = self.downsample(x)  
 
        x = self.conv1(x) 
        x = self.bn1(x)  
        x = self.relu(x) 
 
        x = self.conv2(x) 
        x = self.bn2(x) 
        x = self.relu(x) 
 
        x = self.conv3(x)  
        x = self.bn3(x) 
 
        x += identity  
        x = self.relu(x) 
 
        return x

ResNeXt50_Model模型

class ResNeXt50_Model(nn.Module):
    def __init__(self, in_channel=3, N_classes=1000):
        super(ResNeXt50_Model, self).__init__()
        self.in_channels = in_channel
        self.layers = [2, 3, 5, 2]

        self.zeropadding2d = nn.ZeroPad2d(3)
        self.cov0 = nn.Conv2d(self.in_channels, out_channels=64, kernel_size=7, stride=2, padding=3)
        self.bn0 = nn.BatchNorm2d(num_features=64)
        self.relu0 = nn.ReLU(inplace=False)
        self.maxpool0 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        
        self.channel = 64
        self.groups = 1
        self.base_width = 64
        
        self.layer1 = self._make_layer(Bottleneck, 64, self.layers[0]) 
        self.layer2 = self._make_layer(Bottleneck, 128, self.layers[1], stride=2) 
        self.layer3 = self._make_layer(Bottleneck, 256, self.layers[2], stride=2)  
        self.layer4 = self._make_layer(Bottleneck, 512, self.layers[3], stride=2) 
        self.avgpool = nn.AvgPool2d((7, 7))

        self.fc = nn.Sequential(nn.Linear(2048, N_classes),
                                nn.Softmax(dim=1))
 
        for m in self.modules(): 
            if isinstance(m, nn.Conv2d):  
                nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity="relu") 
 
    def basic_layer1(self, x):

        x = self.zeropadding2d(x)
        x = self.cov0(x)
        x = self.bn0(x)
        x = self.relu0(x)
        x = self.maxpool0(x)
        
        return x
    
    def _make_layer(self, block, channel, blocks, stride=1): 
        downsample = None 
 
        if stride != 1 or self.channel != channel * block.expansion: 
            downsample = nn.Sequential(
                nn.Conv2d(in_channels=self.channel, out_channels=channel * block.expansion, kernel_size=1, 
                          stride=stride, bias=False),
                nn.BatchNorm2d(num_features=channel * block.expansion)  
            )
        layers = [] 
 
        layers.append(block(self.channel, channel, downsample=downsample, stride=stride, groups=self.groups,
                            base_width=self.base_width))
        self.channel = channel * block.expansion  
        for _ in range(1, blocks):
            layers.append(block(self.channel, channel, groups=self.groups, base_width=self.base_width)) 
        return nn.Sequential(*layers) 
 
    def forward(self, x):
        
        x = self.basic_layer1(x)
        
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.fc(x)
 
        return x

测试模型

def train_and_test(model, loss_fn, optimizer,Epoch):
    train_loss = []
    train_acc = []
    test_loss = []
    test_acc = []
    
    best_acc = 0.0
    best_epoch = 0
    for epoch in range(1,Epoch+1):
        time_start = time.time()
        model.train()
        running_loss = 0.0
        running_corrects = 0
        for inputs, labels in train_loader:
            inputs = inputs.to(device)
            labels = labels.to(device)
            outputs = model(inputs)
            loss = loss_fn(outputs, labels)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            _, preds = torch.max(outputs, 1)
            running_loss += loss.item() * inputs.size(0)
            running_corrects += torch.sum(preds == labels.data)
        epoch_loss = running_loss / train_data_size
        epoch_acc = running_corrects.double() / train_data_size
        train_loss.append(epoch_loss)
        train_acc.append(epoch_acc)
        time_train = time.time() - time_start
        print('Epoch: {} Train Loss: {:.4f} Train Acc: {:.4f} Training Time : {:.4f}'.format(epoch, epoch_loss, epoch_acc,time_train))
        
        model.eval()
        running_loss = 0.0
        running_corrects = 0
        with torch.no_grad():
            time_test = time.time()
            for inputs, labels in test_loader:
                inputs = inputs.to(device)
                labels = labels.to(device)
                outputs = model(inputs)
                loss = loss_fn(outputs, labels)
                _, preds = torch.max(outputs, 1)
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)
            epoch_loss = running_loss / test_data_size
            epoch_acc = running_corrects.double() / test_data_size
            test_loss.append(epoch_loss)
            test_acc.append(epoch_acc)
            time_test = time.time() - time_test
            print('Epoch: {} Test Loss: {:.4f} Test Acc: {:.4f} Testing Time : {:.4f}'.format(epoch, epoch_loss, epoch_acc,time_test))
            if epoch_acc > best_acc:
                best_acc = epoch_acc
                best_epoch = epoch
    return model , train_loss, train_acc, test_loss, test_acc

在这里插入图片描述
在这里插入图片描述
最佳Accuracy为89.28%

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值