【分类与检测训练需要注意的点】

分类与检测训练需要注意的点

分类模型数据集搜集

  • 最好是下载线上的封面数据,这些数据随机性比较强;
    • 最开始是下的视频–> 后来换成了封面数据
  • 可以先用几百张小的数据集训练一个小模型专门做清洗用,但是数据清洗完后要质检;
    • 因为没有质检,发现还是清洗的不干净,峡谷里面很多死亡、赛事模式等图片,导致分类器效果一直不佳
  • 在数据搜集完准备训练时,可以将数据集的10%提前保存,做训练完后的测试集使用;
    • 上一版本的测试集和训练集混合使用了,导致这一次要重新整理测试集,增多了工作量
  • 测试集对整体模型的结果评估影响很大,如果有问题会直接影响结果,要确保测试集没有问题再测试;
    • 测试集没有质检,里面有些类别标签是错误的,例如有的是失败,但是标签为成功
  • 测试时,尽量不要全用一个视频来测,要覆盖全面,否则测试结果不具有代表性;
    • 云顶类别的测试集是一个视频,云顶模式比较多,用一个视频不能体现整体效果
  • 训练之前可以将 1920 * 1080 的大图进行批量缩放成 227*227 的小图,但是原图需要保存备份;
    • 因为原图没有备份,导致在测试sdk的时候又要重新整理,因为sdk输入统一是1920*1080大小的

检测模型数据集搜集

  • 将数据集的10%提前保存,做训练完后的测试集使用,测试模型的效果;
  • 训练集分来自两个部分:1. 线上下载的封面截图给打标组打标(约1w张)、2. 自己造一批数据(通过脚本贴图);
  • 训练数据准备好后,要抽样质检,确保标签的正确性;

模型训练

分类模型训练

在这里插入图片描述

  • 分类模型训练的时候把每个类别都单独建一个文件夹存放数据集,不要都放到一起,质检的时候不方便
    • 之前都是放到一个文件夹中,所以质检起来只能根据文件名来看,不方便
  • 分类训练时,最好把标签都打乱,因为神经网络的拟合能力太强了,如果不乱序的话,同一个组合的batch反复出现,模型有可能会“记住”这些样本的次序,从而影响泛化能力。
    • 之前训练的标签没有打乱,训练时一个batchsize里面的图片都是同一个类别的
# shell命令shuf标签
shuf train.txt > train_.txt
shuf val.txt > val_.txt

检测模型训练

在这里插入图片描述

  • train.py 训练模型,detect.py测试模型效果,val.py统计模型的准确率和召回率,使用val.py统计模型效果时,需要把测试集的标签处理成与验证集标签相同的模式,才能测出效果(需要把.xml标签文件处理成.txt文件格式);
  • 检测模型训练完了后,可以通过python端用detect.py脚本来测试大批量的数据集,只保存有识别结果的即可,可以快速统计模型的准确率;

效果测试

召回率统计
  • 召回率效果测试统计,验证集和测试集都要统计,先测试验证集是否满足效果,后测测试集;
    • 之前没有测试验证集,直接在测试集上测试的;
  • 把误识别的类别保存下来看看,看看是模型效果不好还是测试集标签打错,这个对测试效果影响很大;
    • 模型效果不好的时候没有及时检测数据,以为数据都是正确的,导致训练了很多次模型效果都不是很好;
  • 需要先把baseline的结果统计出来,然后再在测试集上与自己的模型进行对比,计算每个类别的召回提升了或者下降了多少;
  • 单个模块的召回测完后,再把全流程的召回率测一下,以确保每个功能都能正常运行;
准确率统计
  • 准备大批量的数据测试准确率,比较baseline与自己的模型在大批量数据上的误推率;
  • 如果推出图片较多,可以采用随机抽样的方法来统计准确率,需要保证随机;
  • 通过调整阈值提升准确率的同时,召回率也要重新再测一下,确保召回没有降低;
  • 准确率很低的情况下先与baseline进行对比,结合误推率一起看效果;

性能测试

进程数据量统计
  • 启1个handle,进程数据量为1000,那么启4个handle的时候,单进程数据量为250,总进程量为1000;
    • 之前我的测试方式是 启1个handle,进程数据量为1000,那么启4个handle的时候,进程数据量为4000,测试方式最好与上一版本的测试方式保持一致;

在这里插入图片描述

CPU消耗计算
  • cpu核数 = Core(s) per socket * Thread(s) per core,通过lscpu命令可以查看
  • cpu消耗通过性能基础监控来计算,cpu消耗 = cpu利用率 * cpu总核数

在这里插入图片描述

内存消耗计算
  • 单个模型在不同的机器上,消耗的内存基本一致
  • 内存消耗计算方法:KiB Mem total * %MEM
    • 之前我是直接看used栏消耗的内存,但是这里消耗的内存是表示所有进程消耗的,不指我的进程;
      在这里插入图片描述
QPS计算
  • QPS:(Queries Per Second)每秒执行的查询总数(每秒有多少的请求响应)
  • QPS = 图片数量 / 处理时间
  • 多线程处理时,qps在sdk内部测试时,需要记录线程启动的最早开始时间及最晚结束时间,才能确保qps的准确性
    • 之前我的计算方法是在sdk内部测试平均耗时,然后再用1000ms除以平均耗时,得到qps,但是在多线程处理的时候,该方法容易出错,因为每个线程开始的时间和结束的时间不知道,不好计算多线程的时候的平均耗时;
      在这里插入图片描述

sdk逻辑代码

  1. 分类模型对输入图片进行分类
  2. 判断图片类别是否为8,如果类别为8就过检查模型;如果类别不为8,则返回相应结果;
  3. 分类类别为8的图片通过检测识别;
    1. 是否检测到2个或2个以上标签为1、2、3 的情况;
    2. 取出上面情况的排名最前的2个图标的结果;
    3. 取出这2个图标结果的坐标,判断这2个结果的x点坐标距离是否大于1400;y点坐标距离是否小于100;
    4. 满足上一条件,判断2个图标的宽高是否都小于100;
    5. 结果返回;
检测结果排序

获得检测模型检测到的结果,同一个标签结果置信度从大到小进行排序;

bool compard(const YoloOutput &input_x, const YoloOutput &input_y)
{
	return input_x.confidence > input_y.confidence;
}
std::vector<YoloOutput> det_outs;
Detect(src, det_outs);
sort(det_outs.begin(), det_outs.end(), compard);
申请临时空间

获得检测模型的类别个数,申请一个大小为类别个数的临时空间save_rect_resule,用来存放需要进行逻辑判断的结果;

size_t GetClaaName(){
    return class_names_.size() ;
    }
int detect_nums = ptr_detect_net_->GetClaaName();
std::vector<std::vector<GameBoardRect>> save_rect_resule(detect_nums);
Size_t主要用来计数,如sizeof得到的类型即为size_t。
在32位架构中被普遍定义为:   typedef   unsigned int size_t; (4个字节)
而在64位架构中被定义为:      typedef  unsigned long size_t;(8个字节)
Size_t 是无符号数;int 则无论在32位还是64位架构中,都是4个字节,带符号数。

遍历检测结果,将置信度大于阈值的结果存储到临时空间save_rect_resule中;

        if (det_outs[i].confidence > 0.8) 
        { 
            class_num = det_outs[i].id;
            GameBoardRect det_res_blood;              //云顶之弈的图标位置保存
            det_res_blood.x = det_outs[i].box.x;
            det_res_blood.y = det_outs[i].box.y;
            det_res_blood.w = det_outs[i].box.width;
            det_res_blood.h = det_outs[i].box.height;
            // bboxes_det.push_back(det_res_blood);
            save_rect_resule[class_num].push_back(det_res_blood);
        } 
主逻辑判断

sdk逻辑判断,检测的标签为1、2、3且检测到的个数为2时;

        if(class_num > 0 && class_num < 4 && save_rect_resule[class_num].size() == 2)
        {
            int res_x = abs(save_rect_resule[class_num][0].x - save_rect_resule[class_num][1].x);
            int res_y = abs(save_rect_resule[class_num][0].y - save_rect_resule[class_num][1].y);
            int res_w1 = save_rect_resule[class_num][0].w;
            int res_h1 = save_rect_resule[class_num][0].h;
            int res_w2 = save_rect_resule[class_num][1].w;
            int res_h2 = save_rect_resule[class_num][1].h;
            if(res_x > (int)((src.cols/1920.0)*1400) && res_y<(int)((src.cols/1080.0)*100) && 
                res_w1<(int)((src.cols/1920.0)*100) && res_h1<(int)((src.cols/1080.0)*100) &&
                res_w2 <(int)((src.cols/1920.0)*100) && res_h2 < (int)((src.cols/1080.0)*100) )
            {
                return class_num;
            }
        } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值