ResNet和ResNeXt

第3周学习:ResNet+ResNeXt

一、ResNet+ResNeXt

  1. ResNet
  • 网络结构
    • 亮点:超深的网络结构,residual模块,使用batchNormalization加速训练;可以解决梯度消失以及退化问题:深层模型反而取得更低的训练和测试误差。
    • 主要使用两种残差结构,左边的残差结构用于层数较少的网络使用,如18-layer、34-layer,右边用于层数较深的网络,如50-layer,101-layer,152-layer。虚线表示需要shortcut需要经过1x1的卷积核进行维度处理,即bottleneck模块。注意,主分支与shortcut的输出矩阵必须相同。
  • conv2每一block的第一层,stride默认为1,经过计算后,表示第一次只改变深度,不改变宽高。
  • 在这里插入图片描述
  • BatchNormalization
    在这里插入图片描述

    • BN操作是为了使一个batch的数据更集中,然后在我们验证以及预测过程中,就使用统计得到的均值和方差进行标准化处理,目的就是使我们的feature map满足均值为0,方差为1的分布规律,加快收敛速度。
      在这里插入图片描述
      其中前两个参数是正向传播得到的,反向传播时利用均值和方差参数不断优化,最后使其满足均值为0,方差为1的分布规律。
      在这里插入图片描述
  • 迁移学习

    • 使用迁移学习能够快速的训练出一个理想的结果,当数据集较小时也能训练出理想的结果。主要是使用预训练模型参数(要注意别人的预处理方式)
      在这里插入图片描述

    • 其他:padding = (kernel_size-1)/2

  1. ResNeXt
    将原ResNet网络中的block替换成由group分组的block,两者得到的feature map一致,只是参数量更少了。并且当block层数≥3时才有意义。经过验证,group数一般设置为32会取得最好的效果,每组卷积核4d,d表示倍数。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、cat vs dog

首先上kaggle官网加载所提供的对应的数据集,可以省去上传本地数据集至云盘的时间,但colab使用达到限额,故转向本地。
在这里插入图片描述
使用ResNet34提供的预训练权重进行3个epoch的训练,由于本地GPU能力不足,训练所需时间过长,只能使用一部分的数据集进行训练,准确率及代码如下所示。
train.py

import os
import torch
import torchvision
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms, datasets, models
from tqdm import tqdm
import numpy as np
from PIL import Image
import torch.nn.functional as F
import matplotlib.pyplot as plt
from Resnet_model import resnet34

data_transforms = {
    'train': transforms.Compose([
        # transforms.RandomResizedCrop(224),
        transforms.Resize([224, 224]),
        transforms.CenterCrop(224),
        #        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),  # range [0, 255] -> [0.0,1.0]
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        # transforms.Resize(256),
        transforms.Resize([224, 224]),
        # transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])
}

data_dir = 'datasets'

image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x])
                  for x in ['train', 'val']}

dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=32, shuffle=True)
               for x in ['train', 'val']}

dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}

class_names = image_datasets['train'].classes

device = torch.device("cuda:0")

inputs, classes = next(iter(dataloaders['train']))

model = resnet34()
model_weight_path = "resnet34-pre.pth"
model.load_state_dict(torch.load(model_weight_path, map_location="cpu"))
in_channel = model.fc.in_features
model.fc = nn.Linear(in_channel, 2)
model.to(device)

criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-5)




# 训练函数
def train(model):
    model.train()
    # 从train_loader里,64个样本一个batch为单位提取样本进行训练
    for batch_idx, (images, labels) in enumerate(dataloaders['train']):
        images, labels = images.to(device), labels.to(device)
        optimizer.zero_grad()

        output = model(images)
        loss = criterion(output, labels)
        loss.backward()
        optimizer.step()
        if batch_idx % 100 == 0:
            print('Train: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                batch_idx * len(images), len(dataloaders['train'].dataset),
                100. * batch_idx / len(dataloaders['train']), loss.item()))


# 测试函数
def val(model):
    model.eval()
    test_loss = 0
    correct = 0
    total = 0
    best_acc = 0
    save_path = 'resNet34.pth'
    with torch.no_grad():  # 不需要梯度,减少计算量
        for images, labels in dataloaders['val']:
            images, labels = images.to(device), labels.to(device)
            output = model(images)
            _, predicted = torch.max(output.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

        accuracy = 100. * correct / total
        if accuracy > best_acc:
            best_acc = acc
            torch.save(model.state_dict(), save_path)
        print('accuracy on test set: %d %% ' % accuracy)
        return accuracy


if __name__ == '__main__':
    accuracy_list = []
    epoch_list = []
    acc = 0
    for epoch in range(1):
        train(model)
        acc = val(model)
        accuracy_list.append(acc)
        epoch_list.append(epoch)

    plt.plot(epoch_list, accuracy_list)
    plt.xlabel(epoch)
    plt.ylabel(accuracy_list)
    plt.show()
# inputs, classes = next(iter(dataloaders['val']))
#
# out = torchvision.utils.make_grid(inputs)

test.py

# coding=utf-8
#test
class Dataset(torch.utils.data.Dataset):
    def __init__(self):
        self.images = []
        self.name = []
        self.test_transform = transforms.Compose([
            # transforms.Resize(256),
            transforms.Resize([224, 224]),
            # transforms.CenterCrop(224),
            transforms.ToTensor(),
            # transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ])
        filepath = '/content/datasets/test'
        for filename in tqdm(os.listdir(filepath)):
            image = Image.open(os.path.join(filepath, filename))
            image = self.test_transform(image)
            self.images.append(image)
            self.name.append(filename)

    def __getitem__(self, item):
        return self.images[item]

    def __len__(self):
        images = np.array(self.images)
        len = images.shape[0]
        return len

test_datasets = Dataset()
device = torch.device("cuda:0")
testloaders = torch.utils.data.DataLoader(test_datasets, shuffle=False)
print(testloaders)
testset_sizes = len(test_datasets)
#加载之前保存的pth
model = resnet34(num_classes=2).to(device)
model_weight_path = "/content/drive/MyDrive/Colab/deep learning/cat_dog/resNet34.pth"
model.load_state_dict(torch.load(model_weight_path, map_location=device))
model.to(device)


dic = {}


def test(model):
    model.eval()
    cnt = 0
    for inputs in tqdm(testloaders):
        inputs = inputs.to(device)
        outputs = model(inputs)
        _, preds = torch.max(outputs.data, 1)
        key = test_datasets.name[cnt].split('.')[0]
        dic[key] = preds[0]
        cnt += 1
        with open("/content/drive/MyDrive/Colab/deep learning/cat_dog/result.csv", 'a+') as f:
            f.write("{},{}\n".format(key, dic[key]))
test(model)


经过测试后,生成csv文件提交审核
在这里插入图片描述

三、Q&A

1、Residual learning
我们设计的深层次网络是有很多网络层为冗余层的。那么我们希望这些冗余层能够完成恒等映射,保证经过该恒等层的输入和输出完全相同。通过学习残差F(x)=0来让该层网络恒等映射上一层。因此可以避免退化问题,通过更深层的网络获取更多的特征。
2、Batch Normailization 的原理
通过正向传播计算一个batch中同一channel的mean和std参数,我们在训练过程中要去不断的计算每个batch的均值和方差,并使用移动平均(moving average)的方法记录统计的均值和方差,在训练完后我们可以近似认为所统计的均值和方差就等于整个训练集的均值和方差,整个训练样本集所对应feature map的数据都要满足正态分布规律,使数据更集中,所以每次卷积操作都要BatchNorm2d。

其中\gamma是用来调整数值分布的方差大小,\beta是用来调节数值均值的位置。这两个参数是在反向传播过程中学习得到的,\gamma的默认值是1,\beta的默认值是0。
在这里插入图片描述

3、为什么分组卷积可以提升准确率?即然分组卷积可以提升准确率,同时还能降低计算量,分数数量尽量多不行吗?
分组卷积常用在轻量型高效网络中,因为它用少量的参数量和运算量就能生成大量的 feature map,大量的 feature map 意味着能够编码更多的信息。
从分组卷积的角度来看,分组数就像一个控制旋钮,最小值是1,此时的卷积就是普通卷积;最大值是输入 feature map 的通道数,此时的卷积就是 depthwise sepereable convolution,即深度分离卷积。DW卷积 完成后的 Feature map 数量与输入层的通道数相同,无法扩展 Feature map。而且这种运算对输入层的每个通道独立进行卷积运算,没有有效的利用不同通道在相同空间位置上的feature信息。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值