C++实现超分辨率 IDN (2)(4分组卷积)

这里实现《IDN-tensorflow-master》中的IDN,一些不同之处见上章。

 

先说明一下,由于IDN中要用到'组卷积',vl_nnconv在用到这里时会出错,所以前面矩阵乘法中要修改一下:

		filters_getHeight=	filters_getWidth=  filters_biases->核宽;

		//filters_getSize=filters_biases->输出维度;
		filters_getSize=filters_biases->偏移长度;

		//filters_getDepth=filters_biases->输入维度;
		filters_getDepth=filters_biases->权重长度/(filters_getHeight*filters_getHeight*filters_getSize);//组卷积时 != 输入维度

有兴趣的同学可以看 《matconvnet》源代码原文,我这里只是凑合着用。

上章中的“组卷积4分”是按IDN-tensorflow-master 中的GroupConv2d函数改编来的(python 代码):

            inputGroups = tf.split(axis=3, num_or_size_splits=n_group, value=x)
            weightsGroups = tf.split(axis=3, num_or_size_splits=n_group, value=We)
            convGroups = [groupConv(i, k) for i, k in zip(inputGroups, weightsGroups)]

            outputs = tf.concat(axis=3, values=convGroups)

大意是:把当前层输入数据和权重权重数据都分成4份(按通道分割),然后组卷积(这里的权重还是只有数据量的1/4),最后组合在一起。

C++实现(重新命名为“_4分组卷积”):

void _4分组卷积(	卷积层 & si,卷积层 & di,层数据 * 层 )
{
	int wid = si.width;
	int hei = si.height;
	int wh= wid * hei;

	if(层->输出维度 != di.depth || di.width != si.width || di.height != si.height)
		Resize卷积层(di,si.width ,si.height,层->输出维度);
	int pad=层->核宽/2;

	//4分
	卷积层 源(si.width ,si.height,si.depth/4);
	源.data=si.data;
	卷积层 目标(di.width ,di.height,di.depth/4);
	目标.data=di.data;


	层数据   层4分;
	层4分.偏移长度=层->偏移长度/4;
	层4分.权重长度=层->权重长度/4;
	层4分.输入维度 =层->输入维度 /4;
	层4分.输出维度 =层->输出维度 /4;
	层4分.偏移_数据 =层->偏移_数据;
	层4分.权重_数据 =层->权重_数据;
	层4分.核宽 =层->核宽;

	for(int i=0;i<4;i++)
	{
		vl_nnconv(&源,&目标,&层4分 ,1,1,pad,pad,pad,pad);

		//下一份
		源.data+= wh*源.depth;
		目标.data+=wh* (目标.depth);
		层4分.偏移_数据+=层4分.偏移长度;
		层4分.权重_数据+=层4分.权重长度;

	}
	vl_nnrelu(&di,0.05f);
}

正文开始,定义数据池:

struct IDN模型
{
    //特征提取
	层数据 * conv1;//3->64
	层数据 * conv2;//64->64

	//信息蒸馏块
	int 蒸馏块数量;//4块
	蒸馏块 * 块;

	//重建(upsample)
	层数据 * up1;//64->64 卷积
	层数据 * up2;//64->48 卷积
	//亚像素卷积 48->3
	
	
	//输入 和 输入双三次放大的 相加 即重建

	
	//构造函数
	IDN模型();

};

IDN模型::IDN模型()
{

	int size;
	层数据 * 层;

	//用于一层(宏)
	/*输入维度,输出维度,核宽*/
	/*输入维度,输出维度,核宽*/
	#define 初始化ONE层(IN,OUT,KW) \
	\
	层->输入维度=IN;\
	层->输出维度=OUT;\
	层->核宽=KW;\
	层->权重长度=层->输出维度*层->输入维度*层->核宽*层->核宽;\
	层->权重_数据=(float*)malloc(sizeof(float) * 层->权重长度);\
	层->偏移长度=层->输出维度;\
	层->偏移_数据=(float*)malloc(sizeof(float) * 层->偏移长度);\


	#define 初始化层(ConvX,IN,OUT,KW) \
	size = sizeof(层数据);\
\
	层=ConvX =(层数据 *)malloc(size);\
	初始化ONE层(IN,OUT,KW)\


	#define 初始化组卷积层(ConvX,IN,OUT,KW) \
\
	初始化层(ConvX,IN,OUT,KW) \
	层->输入维度*=4;\

	//用于一组(宏)
	/*组名称,输入维度,输出维度,核宽,组中层数*/

	//Conv1: 1层
	/*名称,输入维度,输出维度,核宽,组中层数*/
		初始化层(conv1,3,64,3);
		初始化层(conv2,64,64,3);

		蒸馏块数量=4;
		size = sizeof(蒸馏块)*蒸馏块数量;
		块=(蒸馏块*)malloc(size);
		蒸馏块 * 蒸馏块0=块;
		for (int k = 0;k<蒸馏块数量;k++)
		{

			初始化层(蒸馏块0->conv1_上,64,48,3);
			初始化组卷积层(蒸馏块0->conv2_上,12,32,3);
			初始化层(蒸馏块0->conv3_上,32,64,3);

			初始化层(蒸馏块0->conv1_下,48,64,3);
			初始化组卷积层(蒸馏块0->conv2_下,16,48,3);
			初始化层(蒸馏块0->conv3_下,48,80,3);

			初始化层(蒸馏块0->down,80,64,1);

			蒸馏块0++;
		}

		初始化层(up1,64,64,3);
		初始化层(up2,64,48,3);

}

主函数:

void IDN(char * savefilename,IDN模型 & sr)
{

//		
	int wid=bmp.width;
	int hei=bmp.height;
		cout<<"输入图像宽度:"<<wid<<endl;
		cout<<"        高度:"<<hei<<endl;
//
	卷积层 rgb(wid,hei,3);
	rgb.data=new float[wid * hei * 3 ]; 

	//jpg转换为RGB卷积层
	bmp2RGB(rgb);

	卷积层 rgb备份(wid,hei,3);
	rgb备份.data=new float[wid * hei * 3 ]; 

	//备份
	卷积层复制(&rgb,&rgb备份);



	//---------------------------------------------->
	层数据 * 层;

	//两个卷积层 交替前传(源,目标)
			
	//用这个传回
	卷积层 * di=(卷积层 *)malloc(sizeof(卷积层));
		di->width=1;
		di->height=1;
		di->depth=1;
		di->data=new float[1 ]; 

	卷积层 *源,*目标;
	源 = &rgb;
	
	目标 = di;

	int pad;

		

	//定义一个宏
	//用于各个层
	#define 卷积前传(ConvX,步长)/* 上采样、下采样 */ \
	\
	层=ConvX;/* Conv2 层 */ \
	if(层->输出维度 != 目标->depth || 目标->width != wid || 目标->height != hei)\
		Resize卷积层(*目标,wid,hei,层->输出维度);\
	pad=层->核宽/2;\
	vl_nnconv(源,目标,层 ,步长,步长,pad,pad,pad,pad);\
	vl_nnrelu(目标,0.05f);\
\
	std::swap (源,目标);\


	cout<<"输入层..."<<endl;
	卷积前传(sr.conv1,1);
	卷积前传(sr.conv2,1);


	//----------------------------------------------<

	    
	    

	//第二部分  16残差层
	卷积层 convfea5(wid,hei,源->depth);
	convfea5.data=new float[wid * hei * 源->depth ]; 

	卷积层 *源备份=&convfea5;


	if(源->depth != 目标->depth || 目标->width != wid || 目标->height != hei)
		Resize卷积层(*目标,wid,hei,源->depth);

	蒸馏块 * 蒸馏块0=sr.块;
	cout<<sr.蒸馏块数量<<"个蒸馏块... 包括 2 组卷积"<<endl;

		
	卷积层 割1(wid,hei,16);
	割1.data=new float[wid * hei * 16 ]; 
	卷积层 割2(wid,hei,48);
	割2.data=new float[wid * hei * 48 ]; 

	卷积层 加(wid,hei,80);
	加.data=new float[wid * hei * 80 ]; 

	for (int k = 0;k<sr.蒸馏块数量;k++)
	{
		cout<<"\r"<<k;


		//备份 (split)
		卷积层复制(源,源备份);


		卷积前传(蒸馏块0->conv1_上,1);
		//卷积前传(蒸馏块0->conv2_上,1);//4组 组卷积?
		_4分组卷积(*源,*目标,蒸馏块0->conv2_上);
		std::swap (源,目标);

		卷积前传(蒸馏块0->conv3_上,1);

		//通道分割 (slice) 64->16,48
		通道分割(*源,割1,割2);
		//通道分割(*源,割2,割1);
		

		Resize卷积层(*源,wid,hei,割2.depth);
		卷积层复制(&割2,源);


		卷积前传(蒸馏块0->conv1_下,1);
		//卷积前传(蒸馏块0->conv2_下,1);4组 组卷积?
		_4分组卷积(*源,*目标,蒸馏块0->conv2_下);
		std::swap (源,目标);

		卷积前传(蒸馏块0->conv3_下,1);
						
		//concat
		通道连接(*源备份,割1,加);//16+64=80
		//通道连接(割1,*源备份,加);//16+64=80

		//数据增强 (Eltwise sum)
		卷积层相加(&加,源);

		//数据压缩
		卷积前传(蒸馏块0->down,1);

		蒸馏块0++;//到下蒸馏块
	}
	cout<<endl;
	del卷积层(*源备份);

	//load_mat2卷积层("me/up0.txt",源);
	        
	//放大4倍
		
	cout<<"放大4倍... "<<endl;


	层=sr.up1;/* Conv2 层 */ 
	if(层->输出维度 != 目标->depth || 目标->width != wid || 目标->height != hei)
		Resize卷积层(*目标,wid,hei,层->输出维度);
	pad=层->核宽/2;
	vl_nnconv(源,目标,层 ,1,1,pad,pad,pad,pad);
	//vl_nnrelu(目标);

	std::swap (源,目标);

	层=sr.up2;/* Conv2 层 */ 
	if(层->输出维度 != 目标->depth || 目标->width != wid || 目标->height != hei)
		Resize卷积层(*目标,wid,hei,层->输出维度);
	pad=层->核宽/2;
	vl_nnconv(源,目标,层 ,1,1,pad,pad,pad,pad);
	//vl_nnrelu(目标);

	std::swap (源,目标);
	
	//load_mat2卷积层("me/PS.txt",源);

	//亚像素卷积
	wid *= 4;hei *= 4;
	Resize卷积层(*目标,wid,hei,3);

	像素混组放大(源,目标);

	std::swap (源,目标);

		//save_卷积层2jpg(源,"up");
	//load_mat2卷积层("me/upsample.txt",源);

	cout<<"生成宽,高:"<<wid<<","<<hei<<endl;
	卷积层 urgb(wid,hei,3);
	urgb.data=new float[wid * hei * 3 ]; 

	//1。原图放大4倍--------------------------
	ResizeGrayscaleImage(4.0);
	

	//jpg转换为RGB卷积层
	bmp2RGB(urgb);
	//load_mat2卷积层("me/b.txt",&urgb);
		
	//2。卷积层放大---------------------------

	//卷积层双三次插值(rgb备份,urgb);


	

	//输入加上残差
	卷积层相加(源,&urgb);
		//save_卷积层2jpg(&urgb,"urgb");


	RGB2bmp(urgb);
						
	
	del卷积层(*源);
	del卷积层(*目标);
	


	cout<<"图像转换成jpg格式... "<<endl;


	savejpg(savefilename);

	cout<<"转换文件已经保存为:    "<<savefilename<<endl;

}

 

效果图:

小图

听说亚像素卷积比反卷积效果更好,是否比上一个更好?我也没仔细比过,我想可能需要更少的内存吧。

下载:

win32超分辩重建IDN实用程序(2)

快速超分辨率重建IDN(4倍)的win32程序,由IDN-tensorflow-master中的模型改编而来

https://download.csdn.net/download/juebai123/11130567

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值