mmclassification
一、MMCLS项目
0.下载链接
- CPU : pip install torch -i https://download.pytorch.org/whl/torch_stable.html # 指定清华源
- GPU : CUDA和对应的torch版本
- https://download.pytorch.org/whl/torch_stable.html
- https://developer.nvidia.com/cuda-toolkit-archive
-
mmcv
这里有一个官方出的版本对应表,https://github.com/open-mmlab/mmcv#installation
1.配置好mmcv后,从GitHub上下载mmclassification的项目。
2.针对configs/resnet/resnet18_8xb16_cifar10.py
文件进行说明,8xb16
表示8个卡,每个卡的batch_size的大小是16,cifar10
表示预训练模型使用的数据集。
configs\resnet\resnet50_8xb32-mixup_in1k.py
mixup表示数据增强的策略。
3.configs/resnet/resnet18_8xb16_cifar10.py
配置文件的解释
_base_ = [
'../_base_/models/resnet18.py', '../_base_/datasets/imagenet_bs32.py',
'../_base_/schedules/imagenet_bs256.py', '../_base_/default_runtime.py'
]
# 网络结构的定义、数据集的定义、学习的策略(学习率的衰减、学习轮数)、模型保存位置 训练过程的一些
(1)查看../_base_/models/resnet18.py
# model settings
model = dict(
type='ImageClassifier', # 类名
backbone=dict(
type='ResNet', # 选取的backbone,在models/backbones下选择
depth=18, # 网络层数.
num_stages=4, # stage的数量
out_indices=(3, ), # 输出特征层的索引,从0开始
style='pytorch'), # pytorch和caffee
neck=dict(type='GlobalAveragePooling'), # 对backbone提取到的特征做一些融合策略
head=dict( # 输出
type='LinearClsHead', # FC
num_classes=1000, # 分类数
in_channels=512, # 根据backbone和neck来,需要修改
loss=dict(type='CrossEntropyLoss', loss_weight=1.0), # 损失函数
topk=(1, 5), # 评估标准
))
type指定源码等会到哪去走,对应一个一个类名,不是瞎写的。比如ImageClassifier
去下图中位置寻找
比如ResNet
到下图中位置寻找
之后可以在neck层中进行修改
(2)查看../_base_/datasets/imagenet_bs32.py
# dataset settings
dataset_type = 'ImageNet' # 后续这里修改成自己的
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'), # 读图像数据,这些方法在datase_type中有
dict(type='RandomResizedCrop', size=224), # 随机裁剪
dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'), # 翻转操作
dict(type='Normalize', **img_norm_cfg), # 归一化
dict(type='ImageToTensor', keys=['img']), # 转化成Tensor,需要做. keys表示对谁做操作,后面的值在dataset_type 中有
dict(type='ToTensor', keys=['gt_label']), # 标签转化成Tensor
dict(type='Collect', keys=['img', 'gt_label']) # 遍历dataloader,返回一个图像和标签
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='Resize', size=(256, -1)),
dict(type='CenterCrop', crop_size=224),
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img'])
]
data = dict(
samples_per_gpu=32, # 单卡的batchsize;多卡每张卡的batchsize
workers_per_gpu=2,
train=dict(
type=dataset_type, # 指定dataset_type,可以自己写之后介绍
data_prefix='data/imagenet/train', # 读数据。自己数据的路径。不指定标签,拿文件夹的名字当作标签
pipeline=train_pipeline),
val=dict(
type=dataset_type,
data_prefix='data/imagenet/val', # 读数据
ann_file='data/imagenet/meta/val.txt', # 读标签
pipeline=test_pipeline),
test=dict(
# replace `data/val` with `data/test` for standard test
type=dataset_type,
data_prefix='data/imagenet/val',
ann_file='data/imagenet/meta/val.txt',
pipeline=test_pipeline))
evaluation = dict(interval=1, metric='accuracy') # 经过多少epoch,走一遍验证集,metric评估标准
dataset_type = 'ImageNet'
数据的格式,不一定是ImageNet
,根据自己的数据选择合适的格式。此处指定ImageNet
,就按照mmcls/datasets/imagenet.py
中定义的进行读取。
samples_per_gpu=32
, 单卡的batchsize;多卡每张卡的batchsize,如果训练过程中怎么调都会报显存,那就把以下代码中size的值调小。
train_pipeline = [
dict(type='LoadImageFromFile'), # 读图像数据,这些方法在datase_type中有
dict(type='RandomResizedCrop', size=224),
(3)查看../_base_/schedules/imagenet_bs256.py
# optimizer
optimizer = dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.0001)
optimizer_config = dict(grad_clip=None) # 这个值不改
# learning policy 学习率衰减
lr_config = dict(policy='step', step=[30, 60, 90]) # 迭代多少次(step指定)之后开始衰减
runner = dict(type='EpochBasedRunner', max_epochs=100) # 迭代epoch的次数
(4)查看../_base_/default_runtime.py
# checkpoint saving
checkpoint_config = dict(interval=1) # 修改,此处是1个epoch进行保存
# yapf:disable
log_config = dict(
interval=100, # 迭代多少次数,保存日志的信息
hooks=[
dict(type='TextLoggerHook'),
# dict(type='TensorboardLoggerHook')
])
# yapf:enable
dist_params = dict(backend='nccl')
log_level = 'INFO'
load_from = None # 从哪加载模型
resume_from = None # 从上一个epoch中保存的checkpoint继续训练
workflow = [('train', 1)] # 默认值,单卡
二、生成完整的配置文件
指定所选模型的路径,在mmclassification的目录下,如D:\E\mmlab\mmclassification-master\tools\train.py
,指定train.py中参数的路径,比如D:\E\mmlab\mmclassification-master\configs\resnet\resnet18_8xb32_in1k.py
,运行一下train.py,执行之后会在此处D:\E\mmlab\mmclassification-master\tools\work_dirs\resnet18_b32x8_imagenet\resnet18_b32x8_imagenet.py
生成配置文件。复制到D:\E\mmlab\mmclassification-master\configs\resnet
路径下,并将其命名为my_resnet18_b32x8_imagenet.py
。
三、根据文件夹定义数据集
方法一:根据文件夹定义数据集,此方法适用于flower_data这类型的数据
(1)首先,修改上面生成的配置文件中的num_classes
,此处以flower_data数据集进行说明,一共有102个种类,所以num_classes=102
。并把mmcls/datasets/imagenet.py
中CLASSES =[]
进行修改。
(2)修改data
中data_prefix字段,读数据的路径,如果省略掉ann_file
,就直接把文件夹的名字当作标签的类别
(3)修改checkpoint_config的值,checkpoint_config = dict(interval=50)
, 隔50个保存一次
方法二:构建自己的数据集
(1)所有的训练数据集都在一个文件夹下,训练集在train文件夹下。
(2)mmcls/datasets
下自己写一个文件,仿照imagenet进行写,看人家怎么写,自己怎么写。
import numpy as np
from .builder import DATASETS
from .base_dataset import BaseDataset
@DATASETS.register_module()
class MyFilelist(BaseDataset): # 继承BaseDataset,所以下面用到的self.ann_file和self.data_prefix就是从这来的
CLASSES = [
'我懒得写名字了,有102个。。。',
'我懒得写名字了,有102个。。。',
………,
'我懒得写名字了,有102个。。。',
'我懒得写名字了,有102个。。。'
]
def load_annotations(self):
assert isinstance(self.ann_file, str)
data_infos = []
with open(self.ann_file) as f:
samples = [x.strip().split(' ') for x in f.readlines()]
for filename, gt_label in samples:
info = {'img_prefix': self.data_prefix}
info['img_info'] = {'filename': filename}
info['gt_label'] = np.array(gt_label, dtype=np.int64)
data_infos.append(info)
return data_infos
(3)在mmcls/datasets\__init__
中把自己定义的数据集处理进行加载,操作如下。
(4)在生成的完整配置文件中进行修改,数据部分要修改成以下格式,train、valid、test
type='MyFilelist',
data_prefix='D:\\eclipse-workspace\\PyTorch4\\mmclassification-master\\mmcls\\data\\flower_data\\train_filelist',
ann_file='D:\\eclipse-workspace\\PyTorch4\\mmclassification-master\\mmcls\\data\\flower_data\\train.txt',
四、测试demo的效果
(1)demo/image_demo.py
下进行简单的测试
image_05094.jpg ../configs/resnet/today_resnet18_8xb32_in1k.py ../tools/work_dirs/resnet18_8xb32_in1k/epoch_100.pth
通过命令行分别指定img、config、checkpoint,通过这样进行单张图片的测试。
(2)测试评估模型效果:在tools/test.py
文件下进行
#../configs/resnet/today_resnet18_8xb32_in1k.py ../tools/work_dirs/resnet18_8xb32_in1k/epoch_100.pth --show
#--show-dir ../tools/work_dirs/resnet18_8xb32_in1k/val_result
#--metrics accuracy recall
通过指定以上参数,进行批量数据的测试。
五、MMCLS中增加一个新的模块
在生成的完整配置文件中进行修改。
backbone一般是替换。
1.修改Neck层
有哪些可以换呢?在mmcls/models/necks
地方寻找。
2.head层中的损失函数
如果自己想加一个损失函数,示例如下:
然后在__init__中添加
最后在配置文件中进行修改
3.添加数据增强
mmcls/datasets/pipelines/transforms.py
中有一些数据增强的操作。添加一个数据处理的操作,如下:
4.可以指定预训练模型,通过load_from参数
5.添加mixup操作
在configs/resnet/resnet50_b32x8_mixup_imagenet.py
文件中看到
_base_ = 'resnet50_8xb32-mixup_in1k.py'
_deprecation_ = dict(
expected='resnet50_8xb32-mixup_in1k.py',
reference='https://github.com/open-mmlab/mmclassification/pull/508',
)
然后去_base_指定的文件中,把train_cfg
复制到自己的配置文件中head层中,并修改num_classes参数
六、数据增强流程可视化展示
在tools/visualizations
文件夹下,有一个可视化的模块。有3个文件,vis_cam.py
、vis_lr.py
、vis_pipeline.py
。vis_cam.py
是哪里是图像中关注的区域、vis_lr.py
学习率的可视化变化、vis_pipeline.py
图像由输入经过旋转、平移、缩放操作,最终放到模型当中,可视化这一系列操作是怎么做的,经历哪些阶段。(在输入模型之前都经历了哪些操作)
(1)vis_pipeline.py
的介绍
常用参数的介绍:
config
:配置文件的指定
--output-dir
:输出图像的设置路径
--phase
:选择可视化的数据集train、test、val
--number
:选择可视化图像的数量
--mode
:展示的模式,展示原始图像original,……
"original" means show images load from disk'
'; "transformed" means to show images after transformed; "concat" '
'means show images stitched by "original" and "output" images. '
'"pipeline" means show all the intermediate images. Default concat.'
--show
:whether to display images in pop-up window. Default False.
--mode
指定pipeline
结果示例:
--mode
指定transformed
结果示例:转化完之后的结果示例
--mode
指定concat
结果示例:
(2)vis_cam.py
的介绍,Grad-Cam可视化方法,可视化细节与效果分析
- 首先需要安装
pip install "grad-cam>=1.3.6"
- 指定参数
img
、config
、checkpoint
、--target-category
表示The target category to get CAM、--target-layers
可以指定查看哪一层特征图的CAM,默认是最后一层–the norm layer in the last block、--preview-model
添加这个参数,会打印出模型的结构,其余参数不起作用了
- 指定参数的示例
cat-dog.png ../../configs/resnet/resnet18_8xb32_in1k.py D:\\E\\mmlab\\mmclassification-master\\mmcls\\data\\resnet18_8xb32_in1k_20210831-fbbb1da6.pth
--target-category 238 --target-category 281
cat-dog.png ../../configs/resnet/resnet18_8xb32_in1k.py D:\\E\\mmlab\\mmclassification-master\\mmcls\\data\\resnet18_8xb32_in1k_20210831-fbbb1da6.pth
--target-layers backbone.layer2.1.conv2
七、模型分析脚本使用
tools/analysis_tools
中绘制的图还不是很好看:analysis_logs
log中有一些指标,打印出的,可以画出来get_flops.py
所需的参数量和计算量
1.绘制评估结果,loss的结果图。
此目录下有日志文件
参数设置示例:
plot_curve ../work_dirs/resnet18_b32x8_imagenet/20220601_112055.log.json --keys loss accuracy_top-1
2.计算迭代时间
参数设置示例
cal_train_time ../work_dirs/resnet18_b32x8_imagenet/20220601_112055.log.json
平均一次迭代所需花的时间
3.get_flops.py
所需的参数量和计算量
参数设置示例:
../../configs/resnet/today_resnet18_b32x8_imagenet.py --shape 224 224
参数量和训不训练没关系。和模型以及输入图像的大小有关。