2019中兴捧月·总决赛心得

article/2025/10/13 8:13:20

2019中兴捧月·总决赛心得

原文链接:https://hey-yahei.cn/2019/05/25/zte_challenge_final/

赛题背景

与初赛类似,不过初赛更多关注的是加速,而总决赛更关注的是压缩
原始模型是一个简单的3x112x112输入大小的resnet18,人脸识别项目,主办方提供了两万张无标签的校准数据集,和两千张带标签的本地验证数据集,同时主办方保留两千张私有、不公开的测试数据集。
评分规则如下:
s c o r e = ( ( M − m M ) × 20 + ( S − s s ) × 80 ) × A ( z ) × B ( z ) score = \left( \left( \frac { M - m } { M } \right) \times 20 + \left( \frac { S - s } { s } \right) \times 80 \right) \times A ( z ) \times B ( z ) score=((MMm)×20+(sSs)×80)×A(z)×B(z)
A ( z ) = { 1 , z ≥ 0.97 0.9 , 0.965 ≤ z &lt; 0.97 0 , z &lt; 0.965 A ( z ) = \left\{ \begin{array} { l l } { 1 , } &amp; { z \geq 0.97 } \\ { 0.9 , } &amp; { 0.965 \leq z &lt; 0.97 } \\ { 0 , } &amp; { z &lt; 0.965 } \end{array} \right. A(z)=1,0.9,0,z0.970.965z<0.97z<0.965
B ( z ) = { 1 , s ≤ 40 M B 0.9 , 40 M B &lt; s ≤ 50 M B 0.8 , 50 M B &lt; s ≤ 63 M B 0 , s &gt; 63 M B B ( z ) = \left\{ \begin{array} { l l } { 1 , } &amp; { s \leq 40 M B } \\ { 0.9 , } &amp; { 40 M B &lt; s \leq 50 M B } \\ { 0.8 , } &amp; { 50 M B &lt; s \leq 63 M B } \\ { 0 , } &amp; { s &gt; 63 M B } \end{array} \right. B(z)=1,0.9,0.8,0,s40MB40MB<s50MB50MB<s63MBs>63MB

其中, M M M S S S分别为原始模型的内存占用大小、模型文件大小, m m m s s s z z z分别是压缩后的内存占用大小、模型文件大小、万分之一误检率下的正检率。主要参照本地验证数据集(一千个人,每人两张图片)的z值,私有测试集只用于模型泛化能力的参考(防止选手故意过拟合于验证集)。

压缩方案

总体思路参考论文《Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman Coding(2016)》,采用剪枝-量化-哈夫曼编码三步走的压缩策略。
在这里插入图片描述

剪枝

粒度

按照论文《Exploring the Regularity of Sparse Structure in Convolutional Neural Networks(2017)》,剪枝的粒度按不规则(非结构)到规则(结构)可以分为fine-grained(精细的神经元层面的剪枝,也称为netron)、vector(向量,以卷积核的某一行或列为单位)、kernel(核,以输入通道为单位)、filter(滤波器,以输出通道为单位),除此之外其实还有以layer或block为单位进行裁剪,但相对比较暴力,实用中比较少见。
在这里插入图片描述

在上述粒度中,最为常见的是fine-grained(netron)filter,前者因为采用精细化的裁剪,往往可以取得更高的压缩率,但需要搭配稀疏存储、稀疏计算技术使用;后者有比较高的结构性,往往配合以kernel为单位的裁剪(前一层裁掉filter后,后一层可以相应的裁剪kernel),不依赖于额外的存储和计算技术,而且有直接、明显的速度提升,适合加速网络。
本次赛题以压缩为主,故自然而然地采用**fine-grained(netron)**的剪枝方案。

剪枝标准

在**fine-grained(netron)级别的剪枝中通常采用某个阈值作为剪枝标准,最简单的阈值可以通过人为设置,也可以设置一个剪枝的百分比。而论文《Learning both Weights and Connections for Efficient Neural Networks(2015)》则采用敏感度(sensitivity)**作为剪枝的标准——
s e n s i t i v i t y = s t d ( weight ) ∗ s sensitivity = std ( \text {weight} ) * s sensitivity=std(weight)s

计算十分简单,直接统计一个层里权重的标准差,然后乘以一个人为设定的系数 s s s作为剪枝的阈值。

在这里插入图片描述

众所周知,

  1. 神经网络的第一层卷积比较敏感;
  2. 全连接层的冗余性远高于卷积层

所以我简单的分了三档系数,以普通的卷积层的剪枝系数为 s s s,分别设定第一层卷积、最后的全连接层为 0 0 0 2 s 2s 2s
事实上,第一层卷积主要是对量化比较敏感,还是可以轻裁的,只不过我后续把稀疏存储和哈弗曼编码写在了一起,如果只裁剪不量化就需要拆解代码,加上第一层卷积只有1728个参数(相比之下全连接层可是有足足8,388,608个参数),剪枝的压缩空间非常小,所以这里索性不对第一层卷积进行裁剪。

恢复训练

如果能对剪枝后的模型进行简单的训练,模型可以有效的恢复精度。而本次比赛只给了两万张无标签的校准数据,常规的训练是行不通的,但既然有原始模型,我们不妨采用知识蒸馏的策略对剪枝后的模型进行恢复训练。

向原始模型依次投喂这两万张数据,并保存其输出作为恢复训练的标签;
loss可以采用简单的距离度量,比如L2、cosine,还可以采用KL散度(又称为相对熵)——实践表明,KL散度的效果略优于L2和cosine。决赛时也有大佬融合了L2和cosine作为loss,我自己尚未做过测试,不知道相比之下效果如何。

恢复训练通常有两种形式,

  1. 直接一刀剪枝,然后一次性fine-tune到最佳效果;
  2. 逐层剪枝,每次剪枝后都进行fine-tune到最佳效果再进行下一次剪枝;

在这里插入图片描述

前一种方式简单粗暴,但无疑第二种方式往往可以取得比较好的结果。可第二种方式往往也是最费时的,比赛时间有限,所以我采取了论文《To prune, or not to prune: exploring the efficacy of pruning for model compression(2017)》用的折中方案——每次多剪一点点,然后简单的fine-tune(但不fine-tune到最佳效果),最后达到目标剪枝结果后再进行彻底的fine-tune。

稀疏存储

netron级别的剪枝往往需要搭配稀疏存储和稀疏运算来实现,比如对于密集的矩阵数据存储方式,每个非零数值可以改为**(行序, 列序, 数值)的三元组进行存储,甚至可以展平后按(索引, 数值)的二元组进行存储,只要稀疏度足够高,这种存储方式就能获得收益。
论文《Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman Coding(2016)》甚至对该方式进行了简单的改进,采用二元组存储,但使用
相对索引而不是绝对索引**——

在这里插入图片描述

当非零元素之间的距离超过最大值时,通过补0值的方式来保证相对索引的正常工作。

量化

按量化后数值的分布进行简单地划分,量化可以分为均匀分布的量化非均匀分布的量化,前者因为可以将浮点运算转换为整型运算而大幅提高模型推理速度,所以更为常见;后者不得不依赖查表运算,对推理速度的提升毫无帮助,但由于量化过程中聚类中心(可以把量化看成一种权重共享,聚集成 2 n 2^n 2n类)不再需要“均匀分布”这一约束,往往能对量化后的模型造成更小的损失,也意味着可以采用更低位数的量化方式。
在这里插入图片描述

与剪枝类似,在训练过程中融入模拟量化有助于减少量化造成的模型精度损失,也即论文《Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference(2018)》提到的Quantization-Aware Training,先前在《MXNet上的重训练量化 | Hey~YaHei!》一文中有所提及,这里就不再赘述。

非均匀分布的量化的训练过程则有些不同,如论文《Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman Coding(2016)》采用KMEANS进行聚类,训练过程中用量化后的权重前向传播,反向传播时则将所有梯度按类别分组求和,最后乘以学习率(也即SGD方式)来更新聚类中心。

在这里插入图片描述

原本在参加比赛前已经写好了训练代码,在有硬标签的ImageNet上工作正常,但到了决赛现场换成知识蒸馏的方式后训练就不断出现问题,最后比赛时间有限也没来得及解决,所以量化这一块由于没用上重训练,也没有做出很好的效果。

哈夫曼编码

哈夫曼编码是根据数值出现的频次分配不等长的位数进行表示的压缩编码方式,与量化乃是天然的技术组合,也广泛应用在各类文件压缩技术当中。
在这里插入图片描述

以数值0、1、2为例,假设0值的出现频率远高于1、2,那么如果构建如下图所示的哈夫曼树:

将0编码为0b0,将1编码为0b10,将2编码为0b11;此时0值只需要一个bit就能表示,当0值出现频率足够高时,则整体的数据串具有压缩的效果,如——
在这里插入图片描述

压缩效果

应用剪枝、量化、哈夫曼编码后,模型大小从74.5MB减少到6.9MB,验证集上精度(万分之一误检率下的正检率)仅从97.3%下降为97.2%,各层剪枝情况、量化位数、哈夫曼编码后的平均位数、整体压缩率如下表所示:

LayerSparsityWeight BitsWeight Bits(H)Index BitsIndex Bits(H)Rate(P+Q)Rate(P+Q+H)
conv1
res2a_177.56%78.2153.3591.59%91.89%
res2a_2a82.18%76.6952.6593.32%94.79%
res2a_2b67.48%76.1852.3687.81%91.32%
res2b_2a55.63%76.2352.1383.36%88.40%
res2b_2b53.96%76.1851.9682.73%88.28%
res3a_158.36%76.8352.4084.39%87.99%
res3a_2a48.08%75.9751.9180.53%87.21%
res3a_2b52.51%75.8052.0482.19%88.35%
res3b_2a52.68%75.8552.0782.25%88.28%
res3b_2b56.35%75.7652.0483.63%89.37%
res4a_154.75%76.1752.2183.03%88.14%
res4a_2a47.52%75.5351.9080.32%87.82%
res4a_2b52.11%76.0152.0682.04%87.92%
res4b_2a48.99%75.7051.9680.87%87.80%
res4b_2b51.80%75.4951.9981.93%88.73%
res5a_153.95%75.9252.1482.73%88.41%
res5a_2a48.01%75.7551.9280.51%87.54%
res5a_2b46.93%75.6451.8880.10%87.51%
res5b_2a48.41%75.6751.9480.65%87.73%
res5b_2b49.19%75.5751.9480.95%88.08%
fc573.97%43.3353.1992.68%94.69%
total59.79%85.97%90.81%

注意到res2a_1Weigths Bits(H),其哈夫曼编码后占用的空间反而比直接的紧凑存储(七位紧凑存储,而非按字节存储)高,这是因为其编码前的数值出现频次相对均衡造成的(构建的哈夫曼树会是一棵平衡树或相对平衡的树)。

关于内存

起初一听说决赛会考量运行时的内存占用大小,立马就想起了直接卷积——天下没有免费的午餐,任何加速算法都需要额外的代价,而这个代价往往就是额外的占用空间,卷积也是如此——还有什么比最朴素的for循环卷积更省空间的吗?
在这里插入图片描述

再加上KMEANS的量化方式不得不采用查表法实现推理,在比赛前我就用纯C++写好了一个神经网络……甚至越陷越深,试图取巧地用紧凑存储的方式把权重存储在内存上(本来想做稀疏存储的,但时间来不及)。

最后评委也没认可我这种查表法的处理方式(摊手.jpg),而且只看“加载权重后的内存占用”而不看“前向推理的内存占用”,所以决赛时内存部分也没拿到几分……唉~

后记

答辩PPT:点击下载

一直都是一个人瞎捣鼓着模型压缩的东西,碰巧看到有这么一个比赛所以想去试试,起初也没想过能拿奖,摸着摸着初赛竟然拿到第一,决赛虽然有些遗憾 但也已经远远超出最初的预期,而且在比赛过程中学习效率极高,又认识了非常多可爱的人儿,专家组、HR、还有所有的选手都相当棒!!还认识了非常优秀的一等奖大佬(我大三那会儿可啥都不会,jh真是太强了!),——已经十分满足了哈~(๑¯∀¯๑)

这里的6.9MB也不是最优的结果——首先决赛疏忽大意,剪枝前忘记做一下SVD;此外,剪枝部分给量化预留了太多的空间,事实上还能多裁几刀;按照经验,即使是用上均匀分布的量化,通过重训练应该也能用更少的bit位数(而不是7bits和4bits)来进一步压缩——个人估计压缩到5MB以内应该也没啥问题。

应主办方要求,总决赛这部分只能公开一下文档,代码就不便开源啦。
DeepCompression的实现可以稍微参考一下Deep-Compression-PyTorch | Github, mightydeveloper,但他有些部分做的不够完美(比如稀疏存储部分没有使用论文的相对索引导致最终的模型偏大,而且也没实现量化的重训练)。


http://chatgpt.dhexx.cn/article/MjEZhsj7.shtml

相关文章

2020年中兴捧月傅里叶派决赛题目

目录 题目&#xff1a; 模型建立 题目分析 注意的小问题 计算结果 代码 模型改进和精细预测 写在最后 题目&#xff1a; 假设&#xff1a; 病毒正在一个居民总数为N100,000, 的城市里扩散。在我们研究的时间段内&#xff08;300天&#xff09;&#xff0c;没有新生儿…

2022中兴捧月算法挑战赛(RAW图像去噪)——初赛到决赛总结与反思

文章目录 1. 初赛经历&炼丹详情1.1 初赛经历1.2 炼丹详情 2、复赛经历&反思与总结2.1 复赛经历2.2 复赛反思 3、决赛经历&反思与总结3.1 决赛题目3.2 决赛思路总结3.3 冠军方案记录3.4 决赛经历3.5 决赛反思 1. 初赛经历&炼丹详情 1.1 初赛经历 最后分数57.2…

2020中兴捧月算法大赛迪杰斯特拉赛道初赛题解

目录 摘要1 程序中使用的数据结构1.1 几个基本数据类型1.2 车道(Lane)1.3 道路(Road)1.4 站点(Station)1.5 货物(Goods)1.6 系统资源(SystemResource)1.7 物流系统(LogisticsSystem) 2 算法思路2.1 初赛初版&#xff1a;路由表、深度优先搜索、路径惩罚2.1.1 搜索策略2.1.2 路径…

中兴捧月营销精英挑战赛回顾

先上图 为期四天的比赛结束了&#xff0c;把这次比赛的收获做一个总结和分享。希望能帮上后面有需要的同学吧。 主要内容分为比赛流程、决赛内容和心得体会三部分。 一.比赛流程 比赛流程分为三部分&#xff0c;初赛、复赛和决赛。初赛开始需要每位同学从瑞伊、加勒斯和奥格…

2023中兴捧月图像赛道-任意尺度盲超分初赛第三方案

任意尺度盲超分-初赛第三方案 吐槽篇方案篇一、左脚踩右脚二、梯度攻击 建议篇 吐槽篇 正文内容.正式讲述方案之前&#xff0c;容我先吐槽两句&#xff0c;真tm的是比赛&#xff0c;纯纯ex人。学历厂就别打着以赛招聘的口号&#xff0c;要985计算机的直接去他们学校里宣讲嘛&am…

中兴捧月之旅

上个月底&#xff0c;我怀着激动的心情来到古都西安参加了第十一届中兴捧月算法大赛的全国总决赛&#xff0c;因为这是我第一次参加的线下封闭开发的现场竞赛&#xff0c;特以此文记录这趟快乐的西安之旅。 中兴捧月是中兴通讯公司举办的大型算法比赛&#xff0c;今年共有6大赛…

2020中兴捧月算法大赛——傅里叶赛道 第1名方案

大家好&#xff0c;我是轶扬。 最近我在总结研究生阶段参与的一些项目和比赛&#xff0c;翻到了2020年参加的中兴捧月算法大赛&#xff0c;题目很有意思&#xff0c;解法上也有一些有趣的创新&#xff0c;所以拿出来特别记录一下。 中兴捧月算法大赛是中兴通讯公司主办的算法赛…

2023 中兴捧月算法挑战赛-自智网络-参赛总结

“中兴捧月”是由中兴通讯面向在校大学生举办的全球性系列赛事活动&#xff0c;致力于培养学生建模编程、创新、方案策划和团队合作能力。今年是在学校的宣传下了解到比赛&#xff0c;最初抱着学习的态度报名了比赛&#xff0c;最终进入了决赛&#xff0c;完成了封闭的开发与赛…

谈谈中兴捧月大赛决赛以及总结

前言 四月份&#xff0c;在师兄的推荐下&#xff0c;报名参加了中兴捧月大赛。一开始只是为了混一个面笔试的资格&#xff08;因为提交有效成绩即可免笔试&#xff09;&#xff0c;然后为了找一个简单的赛道&#xff0c;注册了几个号看了两三个赛道的题目。发现自己每个都不熟…

我得重新集结部队(模拟)

思路&#xff1a;感觉问题不大&#xff0c;不知道为啥一直WA WA代码&#xff1a; package 练习; import java.util.*; import java.io.*; import java.lang.*; public class Main{public static void main(String[] args) {Scanner scnew Scanner (System.in);int nsc.nextInt…

攻防演习紫队第一篇之介绍和组织

文章目录 0x01 什么是紫队0x02 如何组织攻防实战攻防演习一、实战攻防演习组织要素二、实战攻防演习组织形式三、实战攻防演习组织关键 摘抄 0x01 什么是紫队 ● 紫队&#xff0c;一般是指网络实战攻防演习中的组织方。 ● 紫队是在实战攻防演习中&#xff0c;以组织方角色&am…

java毕业设计民兵管理系统(附源码、数据库)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven Vue 等等组成&#xff0c;B/…

哨兵数据的介绍

转载&#xff1a;[哨兵数据的介绍(http://www.spacemagazines.org/h-nd-193.html) “哨兵”卫星家族概览 据欧洲航天局网站2014年5月28日的报道&#xff0c;欧洲哨兵&#xff0d;1A&#xff08;Sentinel&#xff0d;1A&#xff09;卫星尽管还没有正式工作&#xff0c;但已为波…

创建Dota游戏中的兵营类(Barrack),创建3个兵营,通过控制台为每个兵营定义兵营名称,并指定该兵营需要创建的士兵人数。

上面图标里的这个类是创建的兵营类,下面的代码是兵营类的测试类: package com.xjc; /任务一&#xff0c; 1.创建Dota游戏中的兵营类&#xff08;Barrack&#xff09;&#xff0c;该类中有一个类成员变量count&#xff08;类属性&#xff09;、一个实例变量name和另一个实例变…

敌兵布阵问题

一 问题描述 A 国在海岸线沿直线部署了 N 个工兵营地&#xff0c;C 国通过先进的监测手段&#xff0c;对 A 国的每个工兵营里的人数都掌握的一清二楚&#xff0c;每个工兵营的人数都可能发生变动&#xff0c;可能增加或减少若干人数。 二 输入和输出 1 输入 第 1 行包含一个…

红蓝对抗-红队打点的那些事

红蓝对抗-红队打点的那些事 攻防演练中作为攻击方&#xff0c;效率很重要&#xff0c;例如2019 BCS红队行动议题&#xff1a; RedTeam-BCS 半自动化的资产收集 域名/IP/需要交互的系统 当拿到目标的时候&#xff0c;首先需要利用天眼查获取目标企业结构&#xff0c;有子公司…

如何快速搭建红队练习靶场

使用项目:Vulhub Vulhub是一个基于docker和docker-compose的漏洞环境集合,进入对应目录并执行一条语句即可启动一个全新的漏洞环境,让漏洞复现变得更加简单,让安全研究者更加专注于漏洞原理本身。 前期准备 安装docker curl -s https://get.docker.com/ | sh

UGC、PGC、OGC比较详解

UGC、OGC 和 PGC &#xff0c;是网络平台上三种常见的内容生产模式&#xff0c;本文主要对其差别进行比较。 UGC模式 UGC&#xff08;全称为 User Generated Content&#xff0c;即用户输出内容&#xff09; 主要是通过激励用户生产内容&#xff0c;形成社区氛围。 UGC模式…

【学习心得】OGC城市地理标记语言(CityGML)编码标准_CityGML一般性特征

CityGML概述 CityGML是一种基于XML格式的、用于存储和交换虚拟3D城市模型的开放数据模型。它是地理标记语言3.1.1版 本(GML3)的一个应用模式&#xff0c;是由OGC和ISO TC211发布的用于空间数据交换的可扩展国际标准 开发CityGML的目标是为了对三维城市模型的基本实体、属性和…