分类模型--ResNet系列--ResNet50

ResNet是什么?解决了?

Residual net(残差网络):将靠前若干层的某一层数据输出直接跳过多层引入到后面的数据层的输入部分;表明了后面的特征层的内容会有一部分由前面的某一层线性贡献。结构如下:

ResNet网络解决深度网络退化问题。采用ResNet网络结构的网络层数越深,性能越佳;如下图一显示,56层的深度网络的训练误差和测试误差反而比20层网络更大,这就是深度网络退化;而图二展示了使用ResNet结构前后,34层网络与18层网络的训练结果对比;

 ResNet原理及结构

假设我们想要网络块学习到的映射为H(x),而直接学习H(x)是很难学习到的。若我们学习另一个残差函数F(x) = H(x) - x可以很容易学习,因为此时网络块的训练目标是将F(x)逼近于0,而不是某一特定映射。因此,最后的映射H(x)就是将F(x)和x相加,H(x) = F(x) + x,如图所示。

 因此,这个网络块的输出y

y=F(x,{W_{i}})+x.

 为了相加,必须保证加号左右侧维度相同,因此可写成通式如下,Ws用于匹配维度;

y=F(x,W_{i})+W_{s} \: x.

文中提到两种维度匹配的方式:(A)用zero-paddiing增加维度;(B)用1*1卷积增加维度;

在ResNet网络中,有两种基础块,分别是BasicBlock和BotteNeck;前者用于ResNet34以下的网络,后者用于ResNet50及以上的网络;

ResNet50

其包含两个基本块,分别叫做 Conv Block Identity Block,其中Conv块输入和输出维度是不一样的,所以不能连续串联,其用于改变网络的维度;Identity块输入维度和输出维度相同,可以串联,用于加深网络;

Conv Block

在这里插入图片描述

 Identity Block

在这里插入图片描述

 整体结构如下:

在这里插入图片描述

代码

resnet50.py

import torch
import torch.nn as nn
from torch.nn import functional as F


class ResNet50BasicBlock(nn.Module):
    def __init__(self, in_channel, outs, kernerl_size, stride, padding):
        super(ResNet50BasicBlock, self).__init__()
        self.conv1 = nn.Conv2d(in_channel, outs[0], kernel_size=kernerl_size[0], stride=stride[0], padding=padding[0])
        self.bn1 = nn.BatchNorm2d(outs[0])
        self.conv2 = nn.Conv2d(outs[0], outs[1], kernel_size=kernerl_size[1], stride=stride[0], padding=padding[1])
        self.bn2 = nn.BatchNorm2d(outs[1])
        self.conv3 = nn.Conv2d(outs[1], outs[2], kernel_size=kernerl_size[2], stride=stride[0], padding=padding[2])
        self.bn3 = nn.BatchNorm2d(outs[2])

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

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

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

        return F.relu(out + x)


class ResNet50DownBlock(nn.Module):
    def __init__(self, in_channel, outs, kernel_size, stride, padding):
        super(ResNet50DownBlock, self).__init__()
        # out1, out2, out3 = outs
        # print(outs)
        self.conv1 = nn.Conv2d(in_channel, outs[0], kernel_size=kernel_size[0], stride=stride[0], padding=padding[0])
        self.bn1 = nn.BatchNorm2d(outs[0])
        self.conv2 = nn.Conv2d(outs[0], outs[1], kernel_size=kernel_size[1], stride=stride[1], padding=padding[1])
        self.bn2 = nn.BatchNorm2d(outs[1])
        self.conv3 = nn.Conv2d(outs[1], outs[2], kernel_size=kernel_size[2], stride=stride[2], padding=padding[2])
        self.bn3 = nn.BatchNorm2d(outs[2])

        self.extra = nn.Sequential(
            nn.Conv2d(in_channel, outs[2], kernel_size=1, stride=stride[3], padding=0),
            nn.BatchNorm2d(outs[2])
        )

    def forward(self, x):
        x_shortcut = self.extra(x)
        out = self.conv1(x)
        out = self.bn1(out)
        out = F.relu(out)

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

        out = self.conv3(out)
        out = self.bn3(out)
        return F.relu(x_shortcut + out)


class ResNet50(nn.Module):
    def __init__(self):
        super(ResNet50, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

        self.layer1 = nn.Sequential(
            ResNet50DownBlock(64, outs=[64, 64, 256], kernel_size=[1, 3, 1], stride=[1, 1, 1, 1], padding=[0, 1, 0]),
            ResNet50BasicBlock(256, outs=[64, 64, 256], kernerl_size=[1, 3, 1], stride=[1, 1, 1, 1], padding=[0, 1, 0]),
            ResNet50BasicBlock(256, outs=[64, 64, 256], kernerl_size=[1, 3, 1], stride=[1, 1, 1, 1], padding=[0, 1, 0]),
        )

        self.layer2 = nn.Sequential(
            ResNet50DownBlock(256, outs=[128, 128, 512], kernel_size=[1, 3, 1], stride=[1, 2, 1, 2], padding=[0, 1, 0]),
            ResNet50BasicBlock(512, outs=[128, 128, 512], kernerl_size=[1, 3, 1], stride=[1, 1, 1, 1], padding=[0, 1, 0]),
            ResNet50BasicBlock(512, outs=[128, 128, 512], kernerl_size=[1, 3, 1], stride=[1, 1, 1, 1], padding=[0, 1, 0]),
            ResNet50DownBlock(512, outs=[128, 128, 512], kernel_size=[1, 3, 1], stride=[1, 1, 1, 1], padding=[0, 1, 0])
        )

        self.layer3 = nn.Sequential(
            ResNet50DownBlock(512, outs=[256, 256, 1024], kernel_size=[1, 3, 1], stride=[1, 2, 1, 2], padding=[0, 1, 0]),
            ResNet50BasicBlock(1024, outs=[256, 256, 1024], kernerl_size=[1, 3, 1], stride=[1, 1, 1, 1],
                               padding=[0, 1, 0]),
            ResNet50BasicBlock(1024, outs=[256, 256, 1024], kernerl_size=[1, 3, 1], stride=[1, 1, 1, 1],
                               padding=[0, 1, 0]),
            ResNet50DownBlock(1024, outs=[256, 256, 1024], kernel_size=[1, 3, 1], stride=[1, 1, 1, 1],
                              padding=[0, 1, 0]),
            ResNet50DownBlock(1024, outs=[256, 256, 1024], kernel_size=[1, 3, 1], stride=[1, 1, 1, 1],
                              padding=[0, 1, 0]),
            ResNet50DownBlock(1024, outs=[256, 256, 1024], kernel_size=[1, 3, 1], stride=[1, 1, 1, 1],
                              padding=[0, 1, 0])
        )

        self.layer4 = nn.Sequential(
            ResNet50DownBlock(1024, outs=[512, 512, 2048], kernel_size=[1, 3, 1], stride=[1, 2, 1, 2],
                              padding=[0, 1, 0]),
            ResNet50DownBlock(2048, outs=[512, 512, 2048], kernel_size=[1, 3, 1], stride=[1, 1, 1, 1],
                              padding=[0, 1, 0]),
            ResNet50DownBlock(2048, outs=[512, 512, 2048], kernel_size=[1, 3, 1], stride=[1, 1, 1, 1],
                              padding=[0, 1, 0])
        )

        self.avgpool = nn.AdaptiveAvgPool2d(output_size=(1, 1))

        self.fc = nn.Linear(2048, 10)

    def forward(self, x):
        out = self.conv1(x)
        out = self.maxpool(out)
        out = self.layer1(out)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.layer4(out)
        out = self.avgpool(out)
        out = out.reshape(x.shape[0], -1)
        out = self.fc(out)
        return out


if __name__ == '__main__':
    x = torch.randn(2, 3, 224, 224)
    net = ResNet50()
    out = net(x)
    print('out.shape: ', out.shape)
    print(out)


main.py

import torch
from torch import nn, optim
import torchvision.transforms as transforms
from torchvision import datasets
from torch.utils.data import DataLoader
from resnet50 import ResNet50


#  用CIFAR-10 数据集进行实验

def main():
    batchsz = 128

    cifar_train = datasets.CIFAR10('cifar', True, transform=transforms.Compose([
        transforms.Resize((32, 32)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                             std=[0.229, 0.224, 0.225])
    ]), download=True)
    cifar_train = DataLoader(cifar_train, batch_size=batchsz, shuffle=True)

    cifar_test = datasets.CIFAR10('cifar', False, transform=transforms.Compose([
        transforms.Resize((32, 32)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                             std=[0.229, 0.224, 0.225])
    ]), download=True)
    cifar_test = DataLoader(cifar_test, batch_size=batchsz, shuffle=True)

    x, label = iter(cifar_train).next()
    print('x:', x.shape, 'label:', label.shape)

    device = torch.device('cuda')
    # model = Lenet5().to(device)
    model = ResNet50().to(device)

    criteon = nn.CrossEntropyLoss().to(device)
    optimizer = optim.Adam(model.parameters(), lr=1e-3)
    # print(model)

    for epoch in range(1000):

        model.train()
        for batchidx, (x, label) in enumerate(cifar_train):
            # [b, 3, 32, 32]
            # [b]
            x, label = x.to(device), label.to(device)

            logits = model(x)
            # logits: [b, 10]
            # label:  [b]
            # loss: tensor scalar
            loss = criteon(logits, label)

            # backprop
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

        print(epoch, 'loss:', loss.item())

        model.eval()
        with torch.no_grad():
            # test
            total_correct = 0
            total_num = 0
            for x, label in cifar_test:
                # [b, 3, 32, 32]
                # [b]
                x, label = x.to(device), label.to(device)

                # [b, 10]
                logits = model(x)
                # [b]
                pred = logits.argmax(dim=1)
                # [b] vs [b] => scalar tensor
                correct = torch.eq(pred, label).float().sum().item()
                total_correct += correct
                total_num += x.size(0)
                # print(correct)

            acc = total_correct / total_num
            print(epoch, 'test acc:', acc)


if __name__ == '__main__':
    main()


结果展示

跑了100个Epoch,标号从0-99.最后的AC结果为0.7841

  • 3
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Multi-scale-1D-ResNet是一种用于信号处理和时间序列分析的深度学习模型。它基于ResNet(残差网络)的架构,并通过引入多尺度特征来改进模型的性能。 在传统的ResNet中,每个块都具有相同的尺度,这可能会限制模型对不同频率的信号特征的捕捉。因此,Multi-scale-1D-ResNet通过添加具有不同滤波器长度的并行卷积层来引入多尺度,从而使模型能够更好地学习不同频率的特征。 具体来说,Multi-scale-1D-ResNet包括一系列块,每个块内部包含了一定数目的相同尺度的卷积层。但与传统ResNet不同的是,在每个块的最后,Multi-scale-1D-ResNet还引入了一组具有不同滤波器长度的卷积层。这些卷积层使得模型能够在多个尺度上建模,从而能够更好地捕捉信号中的关键特征。 在实际应用中,Multi-scale-1D-ResNet被广泛用于诊断和预测方面,例如医疗领域中的心电图(ECG)分析,智能交通领域中的交通流预测和自然语言处理领域中的文本分类等。 ### 回答2: multi-scale-1d-resnet是一种深度学习模型。它结合了多尺度信息和残差网络来处理1D信号(比如音频,生物医学信号等)。该模型包括了多个1D卷积层和池化层,以提取输入信号的不同尺度(比如音频信号的基频和谐波等)。同时,残差网络的加入可以有效地防止梯度消失问题,使得该模型能够训练更深的神经网络。 multi-scale-1d-resnet模型在许多应用领域都有广泛的应用,比如语音识别、心电图诊断等。因为1D信号具有时域关系,而且大多数情况下其与其他数据(如图像)没有直接的对应关系,所以需要一种特殊的模型来处理。multi-scale-1d-resnet模型的出现大大提高了这类问题的解决效率,具有很好的性能表现。 总之,multi-scale-1d-resnet是一种处理1D信号的深度学习模型,它集成了多尺度信息和残差网络,可以有效地提取1D信号的特征,以实现不同领域的应用。 ### 回答3: Multi-scale-1D-ResNet是一种深度学习模型,可以处理一维序列数据。该模型是在ResNet的基础上,加入了多尺度特征融合的机制。在传统的ResNet中,深度网络的信息流只有一个固定的尺度,而多尺度特征融合将不同尺度的特征进行融合,可以提高网络对不同尺度的信号的处理能力,提高模型的表达能力和泛化能力。 Multi-scale-1D-ResNet模型中,输入的一维时间序列数据首先通过多个卷积层提取特征,然后使用残差块将特征进行深层次的挖掘。在多尺度特征融合中,通过在不同的卷积层之间增加shortcut连接,将不同尺度的特征进行融合。同时,在全局池化层中,对不同尺度特征进行平均池化,得到融合后的特征表示。最后,通过全连接层将特征映射到输出维度,完成任务的预测。 Multi-scale-1D-ResNet适用于处理一维时间序列数据,如语音、信号、股票等数据。由于多尺度特征融合的机制,使得模型能够更好地处理不同尺度的信号分布,具有很强的泛化能力和适配性。同时,由于ResNet的残差块结构,可避免梯度消失等问题,能够训练更深层次的网络。因此,Multi-scale-1D-ResNet成为处理时间序列数据上的重要方法之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值