当前位置: 代码迷 >> 综合 >> GLSL层卷积
  详细解决方案

GLSL层卷积

热度:75   发布时间:2024-02-13 14:45:49.0

前面一次GLSL计算只能完成了一个卷积,应该可以加速。

先了解下网络卷积层的过程:

如果输入30个图(通道)要输出12个图(通道)的话,

1。分别对30图卷积,结果相加得到1图
2。重复12次这个过程,得到12图(共 30 X 12  = 360 个卷积)

相当于: 一个月30日,12个月(年)360日。

一个纹理可以完成一个卷积。多个纹理就可以完成多个卷积。


先检测 显卡支持纹理单元个数

	//检查显卡支持纹理单元个数GLint iUnits;glGetIntegerv(GL_MAX_TEXTURE_UNITS,&iUnits);printf("显卡支持纹理单元个数:%d\n\n",iUnits);

我的笔记本只有8个可用,有点少。


这次接口以层为单位:

//初始化
// main的参数 和 层高,宽
void conv_init(int argc, char* argv[],int h,int w);//层卷积
//核数据,核宽,输入维度,输出维度,偏置数据,输入数据,输出数据,是否激活
//核大小:kw * kw * 输入维度 * 输出维度。
//输入数据大小:wh * 输入维度。 输出数据大小:wh * 输出维度。
void conv_GLSL_层(float* kernel,int kw,int inNum,int outNum,float *bias,float *inData, float * &outData,bool active=true);

用于SRCNN 是这样的:

void SRCNN(int argc, char* argv[],IMAGE *jpg,int up_scale)
{// 先将低分辨率图像使用双三次插值放大至目标尺寸(如放大至2倍、3倍、4倍)IMAGE im_h=*jpg;//双三次放大ResizeGrayscaleImage(&im_h,up_scale ) ;SRCNN模型 sr;// 加载 CNN 模型参数loadModel(&sr);int wid=im_h.getwidth();int hei=im_h.getheight();int wh=wid*hei;//初始化GLSLconv_init(argc,  argv,hei, wid);//图像转化为卷积矩阵卷积矩阵 im_b(wid,hei);//即Y通道卷积矩阵 U(wid,hei),V(wid,hei);//RGB转换为YUVRGB2YUV(&im_h,&im_b,&U,&V);// 第一层卷积:卷积核尺寸9×9(f1×f1),卷积核数目64(n1),输出64张特征图;cout<<"第一层卷积..."<<endl;float * _res ;//引用 conv_GLSL_层(sr.权重_conv1_数据,9,1,64,sr.偏移_conv1_数据,&im_b.data[0], _res,true);// 第二层卷积:卷积核尺寸1×1(),卷积核数目32,输出32张特征图;cout<<"第二层卷积..."<<endl;float *_res2;conv_GLSL_层(sr.权重_conv2_数据,1,64,32,sr.偏移_conv2_数据,_res, _res2);//删除第一层数据delete []_res;  _res=NULL; // 第三层卷积:卷积核尺寸5×5,卷积核数目1,输出1张特征图即为最终重建高分辨率图像。cout<<"第三层卷积..."<<endl;卷积矩阵 conv3_data (wid,hei);float *out;conv_GLSL_层(sr.权重_conv3_数据,5,32,1,NULL,_res2, out, false);memcpy(&conv3_data.data[0], out, wh*sizeof(float));cout<<"卷积完成"<<endl;//彩色//YUV转回RGBYUV2RGB(&conv3_data,&U,& V,&im_h);saveimage("SRCNN 重建.jpg",	&im_h);
}

这个看上去就比较简约了。

这里已经没有“转换卷积核”了,我已一次性转好。

片元着色器(一次完成8个卷积,加偏置也在其中):

//片元着色器
const char *fShader = {"#version 400 compatibility \n"//层数据 8纹理"uniform sampler2DRect  Texture0;         \n""uniform sampler2DRect  Texture1;         \n""uniform sampler2DRect  Texture2;         \n""uniform sampler2DRect  Texture3;         \n""uniform sampler2DRect  Texture4;         \n""uniform sampler2DRect  Texture5;         \n""uniform sampler2DRect  Texture6;         \n""uniform sampler2DRect  Texture7;         \n"//核宽"uniform int kw;                              \n"//核数量"uniform int kNum;                              \n"//9x9的核大小 , 5x5则只使用前面部分//"uniform float kernel[81];                              \n"//8x9x9"uniform float kernel[648];                              \n"//偏置"uniform float bias;                              \n""void main()""{""	vec2 pos = gl_TexCoord[0].st;\n"//坐标"	vec4 fSum = vec4(0.0,0.0,0.0,0.0);\n"//卷积值"	ivec2 vecSize = textureSize(Texture0);\n"//层数据宽高"	int index = 0;""		int coreSize2=kw/2;"//半核宽"		for (float i = pos.x - coreSize2; i < pos.x + coreSize2 + 1.0; i += 1.0)" //对准核心"			for (float j = pos.y - coreSize2; j < pos.y + coreSize2 + 1.0; j += 1.0)""			{""				if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)"//相当于边界以 0 填充"				{""					vec4 currentColor = texture2DRect(Texture0,vec2(i,j));\n""					fSum += currentColor*kernel[index];\n" //积和"				}""				index++;\n"//遍历核"		}""		if (kNum>1)""		{""			for (float i = pos.x - coreSize2; i < pos.x + coreSize2 + 1.0; i += 1.0)" //对准核心"				for (float j = pos.y - coreSize2; j < pos.y + coreSize2 + 1.0; j += 1.0)""				{""					if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)"//相当于边界以 0 填充"					{""						vec4 currentColor = texture2DRect(Texture1,vec2(i,j));\n""						fSum += currentColor*kernel[index];\n" //积和"					}""					index++;\n"//遍历核"			}""		}""		if (kNum>2)""		{""			for (float i = pos.x - coreSize2; i < pos.x + coreSize2 + 1.0; i += 1.0)" //对准核心"				for (float j = pos.y - coreSize2; j < pos.y + coreSize2 + 1.0; j += 1.0)""				{""					if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)"//相当于边界以 0 填充"					{""						vec4 currentColor = texture2DRect(Texture2,vec2(i,j));\n""						fSum += currentColor*kernel[index];\n" //积和"					}""					index++;\n"//遍历核"			}""		}""		if (kNum>3)""		{""			for (float i = pos.x - coreSize2; i < pos.x + coreSize2 + 1.0; i += 1.0)" //对准核心"				for (float j = pos.y - coreSize2; j < pos.y + coreSize2 + 1.0; j += 1.0)""				{""					if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)"//相当于边界以 0 填充"					{""						vec4 currentColor = texture2DRect(Texture3,vec2(i,j));\n""						fSum += currentColor*kernel[index];\n" //积和"					}""					index++;\n"//遍历核"			}""		}""		if (kNum>4)""		{""			for (float i = pos.x - coreSize2; i < pos.x + coreSize2 + 1.0; i += 1.0)" //对准核心"				for (float j = pos.y - coreSize2; j < pos.y + coreSize2 + 1.0; j += 1.0)""				{""					if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)"//相当于边界以 0 填充"					{""						vec4 currentColor = texture2DRect(Texture4,vec2(i,j));\n""						fSum += currentColor*kernel[index];\n" //积和"					}""					index++;\n"//遍历核"			}""		}""		if (kNum>5)""		{""			for (float i = pos.x - coreSize2; i < pos.x + coreSize2 + 1.0; i += 1.0)" //对准核心"				for (float j = pos.y - coreSize2; j < pos.y + coreSize2 + 1.0; j += 1.0)""				{""					if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)"//相当于边界以 0 填充"					{""						vec4 currentColor = texture2DRect(Texture5,vec2(i,j));\n""						fSum += currentColor*kernel[index];\n" //积和"					}""					index++;\n"//遍历核"			}""		}""		if (kNum>6)""		{""			for (float i = pos.x - coreSize2; i < pos.x + coreSize2 + 1.0; i += 1.0)" //对准核心"				for (float j = pos.y - coreSize2; j < pos.y + coreSize2 + 1.0; j += 1.0)""				{""					if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)"//相当于边界以 0 填充"					{""						vec4 currentColor = texture2DRect(Texture6,vec2(i,j));\n""						fSum += currentColor*kernel[index];\n" //积和"					}""					index++;\n"//遍历核"			}""		}""		if (kNum>7)""		{""			for (float i = pos.x - coreSize2; i < pos.x + coreSize2 + 1.0; i += 1.0)" //对准核心"				for (float j = pos.y - coreSize2; j < pos.y + coreSize2 + 1.0; j += 1.0)""				{""					if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)"//相当于边界以 0 填充"					{""						vec4 currentColor = texture2DRect(Texture7,vec2(i,j));\n""						fSum += currentColor*kernel[index];\n" //积和"					}""					index++;\n"//遍历核"			}""		}""	fSum  += bias;\n"//加偏置"	gl_FragColor = fSum;\n""}"

一次生成一层的所有通道为多纹理(分别为1 或 64 或 32):

int LoadGLTextures(float *pTexData,int num)
{glGenTextures( num, textureN );for(int i=0;i<num;++i){glBindTexture(GL_TEXTURE_RECTANGLE_ARB,textureN[i]);//当卷积内核超过了图像边界时使用图像边缘的像素值glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,GL_CLAMP);glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,GL_CLAMP);//纹理过滤的方式不应该设置为线性插值glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);//glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, imgWidth, imgHeight, 0,GL_RGB,GL_UNSIGNED_BYTE,pTexData );//glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, imgWidth, imgHeight, 0,GL_LUMINANCE, GL_FLOAT,pTexData );glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_R32F, imgWidth, imgHeight, 0,GL_RED, GL_FLOAT,pTexData+i* imgHeight * imgWidth );glTexEnvi( GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE );//printf("纹理:%d\n",textureN[i]);}return 0;
}

 

conv_GLSL_层 (1。64:一次传送8个分8 次完成。2。64x32:分256次完成。3。32:分4次完成):

//核数据,核宽,输入维度,输出维度,偏置数据,输入数据,输出数据,是否激活
//核大小:kw * kw * 输入维度 * 输出维度。
//输入数据大小:wh * 输入维度。 输出数据大小:wh * 输出维度。
void conv_GLSL_层(float* kernel,int kw,int inNum,int outNum,float *bias,float *inData, float * &outData,bool active=true)
{printf("核宽:%d,输入维度:%d,输出维度:%d\n",kw,inNum,outNum);//加载全部输入通道到多纹理init(inData,inNum);//最大 8个9x9 核float kernel648[648]={0.0f};clock_t start_t, end_t;//计算时间double total_t;start_t = clock();int wh=imgHeight * imgWidth;outData=new float[wh*outNum];memset(outData, 0, wh*outNum*sizeof(float));//清零float *out=outData;float *in=inData;float * kernel_s=kernel;//当前核//一个实现8个卷积int kNum=(inNum<8)?inNum:8;for(int k=0;k<outNum;++k){for(int i=0;i<inNum;i+=8){//最多8核memcpy(kernel648, kernel_s, kNum*kw*kw*sizeof(float));kernel_s+=kw*kw*kNum;if ( progHandle <= 0 )printf("Failed to run shader.\n");else{char txt[255];//传送纹理 Texture0--- Texture8for(int j=0;j<kNum;++j){sprintf_s(txt,255,"Texture%d\0",j);glActiveTexture( GL_TEXTURE0 +j);glBindTexture(GL_TEXTURE_RECTANGLE_ARB,textureN[i+j]);glUniform1i( glGetUniformLocation( progHandle, txt ),  j);  }glUniform1i( glGetUniformLocation( progHandle, "kw" ), kw );   //核宽glUniform1i( glGetUniformLocation( progHandle, "kNum" ), kNum );   //核1--8个//glUniform1fv( glGetUniformLocation( progHandle, "kernel"),81,kernel81);//核数据glUniform1fv( glGetUniformLocation( progHandle, "kernel"),kw*kw*kNum,kernel648);//核数据//加偏置if(i+8>=inNum && bias!=NULL){glUniform1f( glGetUniformLocation( progHandle, "bias"),bias[k]);//偏置数据}else{glUniform1f( glGetUniformLocation( progHandle, "bias"),0.0f);//无偏置 }}display();readFromTexture( outPutFb );//相加for(int j=0;j<wh;++j){out[j]+=outPutFb[j];}end_t = clock();total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC;if(total_t>1.0){printf("%d/%d\n",k,outNum);start_t = clock();}}out+=wh;}if(active)//激活relu(outData,wh*outNum);//清理for(int i=0;i<64;++i){if(	textureN[i] !=0){//删除纹理glDeleteTextures(1,textureN+i);textureN[i]=0;}}
}

详细过程看代码。

 

结束。