zl程序教程

您现在的位置是:首页 >  其它

当前栏目

图像分类MMClassification

图像 分类
2023-09-27 14:26:26 时间

一、前提环境

  • 我连接的GPU环境,下面几个环境是需要先下载whl然后进行安装

    GPU选择的AtuoDL,够个人学习使用,价格亲民,不用配置cuda环境,已经配置好

    在这里插入图片描述

  • CPU环境的话直接用pip install 环境包==版本号安装即可

1.1、安装版本

版本号
pytorch1.11.0+cu113
torchvision0.12.0+cu113
mmcv-full1.5.0

其余包直接pip install 安装即可

1.2、安装库

  • pytorch和torchvision版本对应
    最新版请看这里 链接
    下面是截止2022.10.30号对应截图
    版本对应

  • pytorchtorchvision
    链接
    在这里插入图片描述

  • mmcv-full
    链接
    在这里插入图片描述

二、安装下载项目

2.1、github项目 mmclassification

在这里插入图片描述

2.2、mmclassification 安装文档

在这里插入图片描述

三、项目解析

3.1、项目结构

在这里插入图片描述

3.2、分类模型构成

1000种
在这里插入图片描述

3.3、分类模型构建

说明

在这里插入图片描述

代码目录

对应代码(以resnet18_8xb32_in1k模型为例)

  • configs->resne->resnet18_8xb32_in1k.py中可以看到restnet18.py文件目录
    在这里插入图片描述
  • 找到restnet18.py目录可以看到对应代码
    在这里插入图片描述
    • 对应的模型可以在mmcls->models里面相应的目录里面找到相应的类
      在这里插入图片描述
      举例
      在这里插入图片描述

3.4、数据集构建

说明

在这里插入图片描述

代码目录

对应代码(以resnet18_8xb32_in1k模型为例)

  • configs->resne->resnet18_8xb32_in1k.py中可以看到restnet18.py文件目录
    在这里插入图片描述
  • 找到imagenet_bs32.py目录可以看到对应代码
    在这里插入图片描述
  • 对应的模型可以在mmcls->datasets里面相应的目录里面找到相应的类
    图中蓝紫色:data中存放数据,之后自己定义的数据集也放到这里
    图中红色代表模型的位置
    在这里插入图片描述

3.5、数据加载流水线

说明

在这里插入图片描述

代码目录

对应代码(以resnet18_8xb32_in1k模型为例)

  • 和上面的数据集构建在同一个文件imagenet_bs32.py
    在这里插入图片描述
  • 对应的模型可以在mmcls->datasets->pipelines里面相应的目录里面找到相应的类
    在这里插入图片描述

3.6、配置学习策略

说明

在这里插入图片描述

代码目录

对应代码(以resnet18_8xb32_in1k模型为例)

  • configs->resne->resnet18_8xb32_in1k.py中可以看到imagenet_bs256.py文件目录
    在这里插入图片描述
  • 找到imagenet_bs256.py目录可以看到对应代码
    在这里插入图片描述
  • 对应的模型可以在mmcls->core里面相应的目录里面找到相应的类
    在这里插入图片描述

四、训练自己的数据集模型

4.1、执行train.py

执行tools->train.py

  • 配置执行环境
    在这里插入图片描述
    Parameters中可以直接写路径,也可以--config 路径
    (以resnet18_8xb32_in1k.py模型为例)
    在这里插入图片描述

    在这里插入图片描述

  • 执行结果报错不用管(相应的目录文件找不到)
    在这里插入图片描述

4.2、修改生成文件

4.2.1、找到生成文件

tools->work_dirs中会生成一个文件夹,点开会看到生成的resnet18_8xb32_in1k.py文件
在这里插入图片描述
生成的代码将上面几个模型混到一个文件中,如果想分离可以按照上述目录分离,这里就不在分离

# 模型
model = dict(
    type='ImageClassifier',
    backbone=dict(
        type='ResNet',
        depth=18,
        num_stages=4,
        out_indices=(3, ),
        style='pytorch'),
    neck=dict(type='GlobalAveragePooling'),
    head=dict(
        type='LinearClsHead',
        num_classes=1000,
        in_channels=512,
        loss=dict(type='CrossEntropyLoss', loss_weight=1.0),
        topk=(1, 5)))
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
# 数据加载流水线
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='RandomResizedCrop', size=224),
    dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),
    dict(
        type='Normalize',
        mean=[123.675, 116.28, 103.53],
        std=[58.395, 57.12, 57.375],
        to_rgb=True),
    dict(type='ImageToTensor', keys=['img']),
    dict(type='ToTensor', keys=['gt_label']),
    dict(type='Collect', keys=['img', 'gt_label'])
]
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='Resize', size=(256, -1)),
    dict(type='CenterCrop', crop_size=224),
    dict(
        type='Normalize',
        mean=[123.675, 116.28, 103.53],
        std=[58.395, 57.12, 57.375],
        to_rgb=True),
    dict(type='ImageToTensor', keys=['img']),
    dict(type='Collect', keys=['img'])
]
# 数据
dataset_type = 'ImageNet'
data = dict(
    samples_per_gpu=32,
    workers_per_gpu=2,
    train=dict(
        type='ImageNet',
        data_prefix='data/imagenet/train',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(type='RandomResizedCrop', size=224),
            dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),
            dict(
                type='Normalize',
                mean=[123.675, 116.28, 103.53],
                std=[58.395, 57.12, 57.375],
                to_rgb=True),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='ToTensor', keys=['gt_label']),
            dict(type='Collect', keys=['img', 'gt_label'])
        ]),
    val=dict(
        type='ImageNet',
        data_prefix='data/imagenet/val',
        ann_file='data/imagenet/meta/val.txt',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(type='Resize', size=(256, -1)),
            dict(type='CenterCrop', crop_size=224),
            dict(
                type='Normalize',
                mean=[123.675, 116.28, 103.53],
                std=[58.395, 57.12, 57.375],
                to_rgb=True),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='Collect', keys=['img'])
        ]),
    test=dict(
        type='ImageNet',
        data_prefix='data/imagenet/val',
        ann_file='data/imagenet/meta/val.txt',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(type='Resize', size=(256, -1)),
            dict(type='CenterCrop', crop_size=224),
            dict(
                type='Normalize',
                mean=[123.675, 116.28, 103.53],
                std=[58.395, 57.12, 57.375],
                to_rgb=True),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='Collect', keys=['img'])
        ]))
# 策略
evaluation = dict(interval=1, metric='accuracy')
optimizer = dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.0001)
optimizer_config = dict(grad_clip=None)
lr_config = dict(policy='step', step=[30, 60, 90])
runner = dict(type='EpochBasedRunner', max_epochs=100)
checkpoint_config = dict(interval=1)
log_config = dict(interval=100, hooks=[dict(type='TextLoggerHook')])
dist_params = dict(backend='nccl')
log_level = 'INFO'
load_from = None
resume_from = None
workflow = [('train', 1)]
work_dir = './work_dirs/resnet18_8xb32_in1k'
gpu_ids = [0]

将生成文件resnet18_8xb32_in1k.py 放入configs->resnet 中并修改名称(today20221029_resnet18_8xb32_in1k.py
在这里插入图片描述

4.2.2、修改生成文件

  • 在目录mmcls->data中存放自己的数据集(flower_data数据集没有标签,以文件夹名称为标签)
    在这里插入图片描述

    • 修改文件today20221029_resnet18_8xb32_in1k.py中的数据集路径
      在这里插入图片描述
  • 修改标签总类别数目在这里插入图片描述

  • 修改模型mmcls->datasets->imagenetimagenet2,改变里面的总类别1000->102

    复制一份,然后修改文件名字和类的名字
    在这里插入图片描述
    修改里面的内容CLASSE列表为102类型
    在这里插入图片描述
    注册模型:在同目录下面的_init_.py文件中完成注册,具体操作如下
    在这里插入图片描述
    注意:将目录文件设置为根目录文件,否则会报错
    KeyError: ‘ImageNet2 is not in the dataset registry’

    在这里插入图片描述

4.2.3、数据集修改

将当前数据集flower_data修改成有标签的格式,这一步可以忽略

执行filelist.py,生成相应的目录结构
在这里插入图片描述
将文件today20221029_resnet18_8xb32_in1k.py复制一份文件改名为today_resnet18_8xb32_in1k.py,数据集路径替换,并且添加数据集标签路径
在这里插入图片描述

filelist.py的代码

import numpy as np
import os
import shutil

train_path = './train'
train_out = './train.txt'
val_path = './valid'
val_out = './val.txt'

data_train_out = './train_filelist'
data_val_out = './val_filelist'

def get_filelist(input_path,output_path):
    with open(output_path,'w') as f:
        for dir_path,dir_names,file_names in os.walk(input_path):
            if dir_path != input_path:
                label = int(dir_path.split('/')[-1]) -1
            #print(label)
            for filename in file_names:
                f.write(filename +' '+str(label)+"\n")

def move_imgs(input_path,output_path):
    for dir_path, dir_names, file_names in os.walk(input_path):
        for filename in file_names:
            #print(os.path.join(dir_path,filename))
            source_path = os.path.join(dir_path,filename)

            shutil.copyfile(source_path, os.path.join(output_path,filename))

get_filelist(train_path,train_out)
get_filelist(val_path,val_out)
move_imgs(train_path,data_train_out)
move_imgs(val_path,data_val_out)

4.3、再次执行train.py文件

  • 将Parameters中的路径文件更改为上面更改的名字today20221029_resnet18_8xb32_in1k.py

    在这里插入图片描述
    运行结果

    • 损失 loss 在下降
    • 准确率 accuracy 在提升
      在这里插入图片描述
  • 将Parameters中的路径文件更改为上面更改的名字today_resnet18_8xb32_in1k.py
    在这里插入图片描述
    运行结果(截图没有跑完)
    在这里插入图片描述
    在路径tools->work_dirs->resnet18_8xb32_in1k下回生成 epoch_50.pth,epoch_100.pth,latest.pth模型
    在这里插入图片描述

五、训练结果测试与验证

5.1测试demo效果

  • 找到demo下面的image_demo.py文件
    在这里插入图片描述
  • 相关参数配置
    在这里插入图片描述
  • 运行结果
    预测结果正确 1 分类 (下标从0开始的)
    在这里插入图片描述

5.2 测试评估模型效果

  • 找到tools->test.py文件,并新建存放测试结果的目录val_result
    在这里插入图片描述
  • 相关参数配置
    在这里插入图片描述
  • 训练结果展示
    在这里插入图片描述

六、训练模型参数替换及改进

预训练模型

  • 下载
    github项目中选取对应的模型
    在这里插入图片描述

    找到自己训练的模型,下载
    在这里插入图片描述

  • 下载完之后放到相应的目录,在代码中写入相关的加载路径
    在这里插入图片描述

七、数据增强流程可视化

在这里插入图片描述

数据处理可视化

不需要训练好的模型,处理过程的可视化

数据处理流程(旋转平移等操作)可视化(vis_pipeline.py

  • 配置参数
    ../../configs/resnet/today_resnet18_8xb32_in1k.py --output-dir ../work_dirs/resnet18_8xb32_in1k/vis/vis_pipeline --phase train --number 10 --mode pipeline在这里插入图片描述
  • 输出结果
    在这里插入图片描述
  • 切换参数,将上面的pipeline切换成concat
    在这里插入图片描述
  • 输出结果
    在这里插入图片描述

数据核心区域可视化

整体流程

  • 需要训练好的模型

  • 使用GradCAM实现,详见github源代码GradCAM论文
    在这里插入图片描述

  • 使用命令 pip install "grad-cam>=1.3.6" 实现,注意版本要求

  • 配置文件(如果linux是系统运行会报错,不能展示图片,请点击链接image_05094.jpg ../../configs/resnet/today_resnet18_8xb32_in1k.py ../work_dirs/resnet18_8xb32_in1k/epoch_101.pth
    在这里插入图片描述

  • 输出结果
    在这里插入图片描述
    在这里插入图片描述

参数调节

  • 输出结果为最后一层
    在这里插入图片描述
  • 调节层数
    281类别为猫在这里插入图片描述
    238类别为狗在这里插入图片描述
  • 输出结果
    281猫的输出
    在这里插入图片描述
    238狗的输出
    在这里插入图片描述

模型输出

输入参数 --preview-model可以打印模型参考
在这里插入图片描述
打印出模型的原因
在这里插入图片描述
输出结果

ImageClassifier(
  (backbone): ResNet(
    (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
    (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace=True)
    (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
    (layer1): ResLayer(
      (0): BasicBlock(
        (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (drop_path): Identity()
      )
      (1): BasicBlock(
        (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (drop_path): Identity()
      )
    )
    (layer2): ResLayer(
      (0): BasicBlock(
        (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (downsample): Sequential(
          (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
          (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        )
        (drop_path): Identity()
      )
      (1): BasicBlock(
        (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (drop_path): Identity()
      )
    )
    (layer3): ResLayer(
      (0): BasicBlock(
        (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (downsample): Sequential(
          (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
          (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        )
        (drop_path): Identity()
      )
      (1): BasicBlock(
        (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (drop_path): Identity()
      )
    )
    (layer4): ResLayer(
      (0): BasicBlock(
        (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (downsample): Sequential(
          (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
          (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        )
        (drop_path): Identity()
      )
      (1): BasicBlock(
        (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (drop_path): Identity()
      )
    )
  )
  init_cfg=[{'type': 'Kaiming', 'layer': ['Conv2d']}, {'type': 'Constant', 'val': 1, 'layer': ['_BatchNorm', 'GroupNorm']}]
  (neck): GlobalAveragePooling(
    (gap): AdaptiveAvgPool2d(output_size=(1, 1))
  )
  (head): LinearClsHead(
    (compute_loss): CrossEntropyLoss()
    (compute_accuracy): Accuracy()
    (fc): Linear(in_features=512, out_features=1000, bias=True)
  )
  init_cfg={'type': 'Normal', 'layer': 'Linear', 'std': 0.01}
)

 Please remove `--preview-model` to get the CAM.

Process finished with exit code 0

重新选择层数配置参数
在这里插入图片描述

在这里插入图片描述
输出结果
在这里插入图片描述

数据集分享

flower_data数据集

链接:https://pan.baidu.com/s/10NdA6nJZC5xK5ozq5ADaPA
提取码:wuts