ResNet改進綜述

一、ResNet改進版

ResNet(Residual Network)是一種深度神經網路結構,它在ImageNet數據集上取得了巨大的成功。然而,由於殘差網路需要大量的計算資源,同時仍存在著一些問題,因此研究者對殘差網路進行了改進。其中,一種改進版的ResNet是對殘差塊進行了改進。

改進後的ResNet使用了可分離卷積,這種卷積可以將卷積分為兩步:depthwise和pointwise卷積。它們可以減少模型參數和計算量,同時具有更好的表示能力。

以下是改進版的ResNet代碼實現:


import torch
import torch.nn as nn

class SeparableConv2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, bias=False):
        super(SeparableConv2d, self).__init__()
        
        self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size, stride, padding, dilation, groups=in_channels, bias=bias)
        self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, dilation=1, groups=1, bias=bias)

    def forward(self, x):
        x = self.conv1(x)
        x = self.pointwise(x)
        return x

class BasicBlock(nn.Module):
    def __init__(self, in_planes, out_planes, stride=1, downsample=None):
        super(BasicBlock, self).__init__()
        self.stride = stride
        self.downsample = downsample
        
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False),
            nn.BatchNorm2d(out_planes),
            nn.ReLU(inplace=True),
            SeparableConv2d(out_planes, out_planes, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(out_planes),
        )
        self.conv2 = nn.Sequential(
            SeparableConv2d(out_planes, out_planes, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(out_planes),
        )
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        residual = x

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

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

        out += residual
        out = self.relu(out)
        
        return out

class ResNet(nn.Module):
    def __init__(self, block, layers, num_classes):
        super(ResNet, self).__init__()
        
        self.in_planes = 64
        
        self.conv1 = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
        )
        self.layer1 = self._make_layer(block, 64, layers[0], stride=1)
        self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
        self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
        self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(512, num_classes)

    def _make_layer(self, block, planes, blocks, stride=1):
        downsample = None
        if stride != 1 or self.in_planes != planes:
            downsample = nn.Sequential(
                nn.Conv2d(self.in_planes, planes, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(planes),
            )
        
        layers = []
        layers.append(block(self.in_planes, planes, stride, downsample))
        self.in_planes = planes
        
        for i in range(1, blocks):
            layers.append(block(self.in_planes, planes))

        return nn.Sequential(*layers)
    
    def forward(self, x):
        x = self.conv1(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = self.avgpool(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)

        return x

二、ResNet改進CRNN

CRNN(Convolutional Recurrent Neural Network)是一種基於深度神經網路的語音識別模型,其主要結構由卷積神經網路和循環神經網路組成。對於CRNN,研究者們對ResNet的改進主要是引入來自空間和時間領域的特徵結構,提升模型對語音信號的建模能力和特徵表示能力。

具體來說,這種改進是通過將殘差塊中的1×1卷積替換為包含多項式函數的卷積實現的,以增加對空間特徵的提取能力;同時,還引入了一種「多通道門控一維卷積」結構,將時間領域的信息引入模型中。

以下是ResNet改進CRNN的代碼實現:


import torch
import torch.nn as nn

class MultiBranchBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size=(3,1), stride=(1,1), padding=(1,0)):
        super(MultiBranchBlock, self).__init__()

        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding, bias=False)
        self.bn = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU(inplace=True)
        
    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        
        return x

class ChannelGate(nn.Module):
    def __init__(self, gate_channels, reduction_ratio=16, pool_types=['avg', 'max']):
        super(ChannelGate, self).__init__()
        
        self.gate_channels = gate_channels
        self.mlp = nn.Sequential(
            nn.Linear(gate_channels, gate_channels // reduction_ratio),
            nn.ReLU(),
            nn.Linear(gate_channels // reduction_ratio, gate_channels)
        )   
        
        self.pool_types = pool_types
        
    def forward(self, x):
        channel_att_sum = None
        channel_att_max = None
        
        for pool_type in self.pool_types:
            if pool_type == 'avg':
                avg_channel_att = torch.mean(x, dim=(2,3), keepdim=True)
                channel_att = self.mlp(avg_channel_att.view(x.size(0), self.gate_channels))
            elif pool_type == 'max':
                max_channel_att = torch.max(x, dim=(2,3), keepdim=True)[0]
                channel_att = self.mlp(max_channel_att.view(x.size(0), self.gate_channels))
                
            channel_att = torch.sigmoid(channel_att).view(x.size(0), x.size(1), 1, 1)
            if channel_att_sum is None:
                channel_att_sum = channel_att
            else:
                channel_att_sum += channel_att
            if channel_att_max is None:
                channel_att_max = channel_att
            else:
                channel_att_max = torch.max(channel_att_max, channel_att)
        
        return channel_att_sum, channel_att_max

class CRNN(nn.Module):
    def __init__(self, in_channels, num_classes):
        super(CRNN, self).__init__()

        self.cnn = nn.Sequential(
            nn.Conv2d(in_channels, 32, kernel_size=(41,11), stride=(2,2), padding=(20,5), bias=False),
            nn.BatchNorm2d(32),
            nn.Hardtanh(min_val=0, max_val=20, inplace=True),

            nn.Conv2d(32, 32, kernel_size=(21,11), stride=(2,1), padding=(10,5), bias=False),
            nn.BatchNorm2d(32),
            nn.Hardtanh(min_val=0, max_val=20, inplace=True),
            
            nn.Conv2d(32, 32, kernel_size=(21,11), stride=(2,1), padding=(10,5), bias=False),
            nn.BatchNorm2d(32),
            nn.Hardtanh(min_val=0, max_val=20, inplace=True),
        )
        
        self.resblocks = nn.Sequential(
            nn.Sequential(
                ChannelGate(32, reduction_ratio=16),
                nn.Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False),
                nn.BatchNorm2d(32),
                nn.ReLU(inplace=True),
            ),
            nn.Sequential(
                ChannelGate(32, reduction_ratio=16),
                nn.Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False),
                nn.BatchNorm2d(32),
                nn.ReLU(inplace=True),
            ),
            nn.Sequential(
                ChannelGate(32, reduction_ratio=16),
                nn.Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False),
                nn.BatchNorm2d(32),
                nn.ReLU(inplace=True),
            ),
            nn.Sequential(
                ChannelGate(32, reduction_ratio=16),
                nn.Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False),
                nn.BatchNorm2d(32),
                nn.ReLU(inplace=True),
            ),
            nn.Sequential(
                ChannelGate(32, reduction_ratio=16),
                nn.Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False),
                nn.BatchNorm2d(32),
                nn.ReLU(inplace=True),
            ),
        )
        
        self.rnn = nn.LSTM(input_size=32, hidden_size=1024, num_layers=5, dropout=0.2, bidirectional=True)
        self.fc = nn.Linear(2048, num_classes)

    def forward(self, x):
        x = self.cnn(x)
        x = self.resblocks(x)
        x = x.permute(3,0,1,2).contiguous()
        x = x.view(x.size(0), x.size(1), -1).permute(1,0,2).contiguous()
        x, _ = self.rnn(x)
        x = self.fc(x.mean(0))
        return x

三、ResNet改進方法

除了改進結構之外,還有一些其他的方法可以提升ResNet的性能。

其中,一種重要的方法是使用更加廣泛的數據增強,例如Mixup和CutMix。這些方法可以使模型更加健壯,同時減輕過擬合的程度。

此外,還有一種方法是使用自監督學習來預訓練ResNet。自監督學習能夠使用無標註的數據來提取更好的特徵,從而提升模型性能。此外,還可以使用半監督學習來利用有標註和無標註的數據來訓練模型,提升模型性能。

四、ResNet改進太難了

儘管ResNet的改進方法非常多,但是實際上改進ResNet是非常困難的。首先,深度神經網路的結構非常複雜,難以理解;其次,改進ResNet需要大量的計算資源和數據資源,需要進行耗時的實驗。

因此,研究者們需要在理論和實踐方面花費大量的時間和精力來進行改進。同時,他們需要積極探索新的方法和技術,以尋找更加高效和有效的ResNet改進方法。

五、ResNet改進網路

網路的深度和寬度是影響ResNet性能的兩個重要因素。儘管在一定程度上增加深度和寬度可以提升模型性能,但是這也帶來了更多的計算資源和訓練難度。

因此,研究者們提出了一些改進ResNet網路的方法。其中,一種方法是使用ResNeXt網路,這種網路通過在殘差塊中使用多條路徑來增加網路的寬度。

另一種方法是使用DenseNet網路,這種網路結構可以通過連接不同層之

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/257186.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-15 12:44
下一篇 2024-12-15 12:44

相關推薦

  • Resnet參數量詳解

    一、Resnet參數量 Resnet指的是深度殘差網路(Residual Network),是一個使用殘差連接(Residual Connection)的深度神經網路,並在目標分類…

    編程 2025-04-23
  • Inception-Resnet的詳細闡述

    Inception-Resnet是一種深度神經網路結構,是Inception和Resnet的結合。它針對傳統的深度網路結構存在的梯度消失和過擬合問題進行了改進,從而提高了網路模型的…

    編程 2025-04-02
  • ResNet-18的全面解析

    ResNet-18是一種非常著名的深度神經網路,它在ImageNet數據集上表現優異,被廣泛應用於計算機視覺領域。本文將從網路結構、Skip connection、殘差模塊、全局平…

    編程 2024-11-21
  • ResNet論文詳述

    一、ResNet論文作者 ResNet(Residual Neural Network)是由何凱明(Kaiming He)、張弛(Zhang Chi)、孫劍(Sun Jian)所著…

    編程 2024-11-12

發表回復

登錄後才能評論