关于yolov5训练后权重较大的原因及其解决方案

yolov5在官方预训练权重的基础之上再训练后权重较预训练权重大很多,为了大家更加直观的了解为什么及其解决方案,此篇简单介绍一下。


精度变化
官方给的预训练权重是FP16,而我们训练的时候是使用混合精度训练(支持CUDA才行),半精度训练只能在CUDA下进行,不支持CUDA默认是使用单精度训练,最终我们保存的权重是FP32,较FP16储存空间大了一倍。直接上代码视图:


import argparse

from models.common import *

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', type=str, default='D:/py/test_FP/weights/yolov5s.pt', help='weights path')
    opt = parser.parse_args()

    # Load pytorch model
    model = torch.load(opt.weights, map_location=torch.device('cpu'))['model']

    for name, parameters in model.named_parameters():
        # print(name,':',parameters.size())
        print(parameters.dtype)

原始预训练权重

关于yolov5训练后权重较大的原因及其解决方案_第1张图片
我们自己的训练权重

关于yolov5训练后权重较大的原因及其解决方案_第2张图片
参数储存不同

预训练权重默认epoch=-1,不保存training_results,不保存optimizer,相当于只保存了模型和权重

    ckpt = {'epoch': -1,
            'best_fitness': model['best_fitness'],
            'training_results': None,
            'model': model['model'],
            'optimizer': None}

可以用以下代码测试以下


import argparse

from models.common import *

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', type=str, default='D:/py/test_FP/weights/yolov5s.pt', help='weights path')
    opt = parser.parse_args()

    # Load pytorch model
    model = torch.load(opt.weights, map_location=torch.device('cpu'))
    print(model)

在这里插入图片描述
在这里插入图片描述
我们训练的时候是默认都保存,源码设置的是在最后一个批次不保存optimizer,如果你是正常跑完所有epoch,最后的权重应该是不包含optimizer,否则会自动保存,以下是官方train.py的保存权重的部分代码
关于yolov5训练后权重较大的原因及其解决方案_第3张图片
所以我们自己训练出来的模型权重文件比较大是必然的


那问题来了,如果想让权重文件变小怎么办
[注]小编此处使用的权重是基于yolov5s预训练权重训练后的结果,且未在批次执行完就停止,也就是这个权重默认是包含以下这么多信息,内容较多,暂且用省略号表示

    ckpt = {'epoch': .....,
            'best_fitness': ......,
            'training_results': .......,
            'model': ......,
            'optimizer': ......}

初始大小为:57M
在这里插入图片描述
现在我一步步来让这个权重变小
step1
第一步按照以下内容进行,为什么epoch变成-1,官方权重设置的epoch为-1,作为预训练权重,批次从0开始,如果仅作为inference权重,这个不影响;接着是把training_results变为None

    ckpt = {'epoch': -1,
            'best_fitness': model['best_fitness'],
            'training_results': None,
            'model': model['model'],
            'optimizer': model['optimizer']}

我们按照以上内容把权重文件重新保存以下看看大小变化多少,如下图所示,发现这个training_results占的内存很少,基本可以忽略不计:
在这里插入图片描述
step2
第二步按照以下内容执行,相比第一步,只是把optimizer参数变成None

    ckpt = {'epoch': -1,
            'best_fitness': model['best_fitness'],
            'training_results': None,
            'model': model['model'],
            'optimizer': None}

这次权重又有多大变化呢,如下图所示,发现这个optimizer占的内存很多,大致占了权重文件的一般大小,说明优化器的参数是导致文件较大的主谋:
在这里插入图片描述
step3
可是权重文件还是很大,比原始的yolov3s大了一倍,这是因为目前的权重还是FP32,需要把FP32转为FP16,此处根据个人情况来决定是否转为FP16,小编不才,此处使用暴力方法直接把FP32转FP16(使用half函数),如下图,权重小了一倍,基本和yolov3s大小差不多。
在这里插入图片描述
以下把代码附上,很简单



import argparse
import numpy as np
import torch

from models.common import *

if __name__ == '__main__':

    weights_path = 'D:/py/test_FP/weights/last.pt'
    is_half = True

    # Load pytorch model
    model = torch.load(weights_path, map_location=torch.device('cpu'))

    net = model['model']

    if is_half:
        net.half() # 把FP32转为FP16

    # print(model)

    ckpt = {'epoch': -1,
            'best_fitness': model['best_fitness'],
            'training_results': None,
            'model': net,
            'optimizer': None}

    # Save .pt
    torch.save(ckpt, 'weights/test.pt')
    # for name, parameters in model.named_parameters():
    #     # print(name,':',parameters.size())
    #     print(parameters.dtype)

小编能力有限,在FP32转FP16时暂且使用最暴力的方法解决,以后有新的方法再及时更新,还有很多不足,希望大家多多指教。

你可能感兴趣的:(yolov5,深度学习)