接上一篇:DNS-动态外科手术关键细节理解(结合caffe源码)
从git上也下载了一份关于Keras下将INQ(增量网络量化)与DNS结合的仓库,https://github.com/yaysummeriscoming/DNS_and_INQ
服务器下简单跑了下:
数据集是mnist,网络结构为:
15个epoches,从第三个epoch后开始剪枝,剪枝结果(卷积层--共五层):
计划初步实现方案参照该版本下的代码,这里先做简单分析:
主要功能是创建4个路径变量,同时创建对应的目录(若没有的话)
以及开始DNS的轮次,gamma值、crate取值(具体的含义见之前对论文的分析)
这里有一个参数的意义不是很理解:batch_scale_factor(批缩放因子)为什么定义这个?
首先定义输入的张量,接着判断模型的类型定义是否是DNS(源代码下还有一种关于INQ的操作),接着函数DNSConvBNReluLayer重命名给变量layerType,将DNS的三个参数存放在字典中。
该函数是对自己重构的DNSConv2D和激活、BN的组合,核心还是自己重构的类DNSConv2D了:
从layers下Convolution2D基类中继承的DNSConv2D:
看一下init方法,几个关于论文中关键参数,以及convolution2D的传入参数
DNSConv2D:该类是自己重定义的一个层,参考以下链接学习如何定义自己的层类【https://blog.csdn.net/DawnRanger/article/details/78307244】
build函数目的是对重构的层权重进行创建,一般使用add_weight进行设定,这里设定了迭代数cur_iter值=-1和Mask矩阵(暂时设定为全1)
接着定义了回调函数call,该函数定义重构层的主要功能,首先是卷积的计算,mask矩阵和原来的权重矩阵进行复合,通过调用tf的conv2d函数实现卷积计算,同时判断是否加偏置、加激活层。
此外,最重要的一点:更新mask矩阵,以及更新迭代次数cur_iter。(每做一次卷积计算)此处的K.update(x,New_x)当然指的是使用New_x更新x。
配合之前对DNS分析的论文看,上面代码主要工作有:第一句probThreshold是以概率设定掩码矩阵跟新与否的阈值,该阈值随迭代次数推移逐渐变为0(停止更新),第二句代码构建更新T的随机矩阵,注意这里random_num的shape,这里仅和滤波器个数相关,即有多少个filter。
第四句计算均值和标准差,这两个值决定阈值的选取。第9句对mask矩阵进行更新,最后两句表明只有针对DNS迭代次数变化和满足训练阶段才进行。
其他几个方法,start_DNS将迭代计数值定为0,on_batch_end、on_epoch_begin和on_epoch_end则是自定义的回调函数:回调函数(callback)是在调用 fit 时传入模型的一个对象(即实现特定方法
的类实例),它在训练过程中的不同时间点都会被模型调用。它可以访问关于模型状态与性能的所有可用数据,还可以采取行动:中断训练、保存模型、加载一组不同的权重或改变模型的状态。
回到主代码中,根据定义的DNSConvBNReluLayer函数(函数式API)将整个网络串联起来。
手写字符训练集,构建的网络较为简单,5层2*2的卷积核堆叠,每层输出通道个数都为16,窄卷积后加入一个softmax分类器。
模型构建完成后,对模型进行编译损失函数为分类交叉熵、优化器使用的是Adam、优化指标选择精度-acc,ModelCheckpoint监控val_loss,每轮过后保存当前权重,后一句始终保存验证集最佳模型。