一、介绍
这里主要介绍卷积相关函数用c语言实现,如卷积、池化、全零填充等等
二、单核单通道卷积
//单卷积
#define IMG_SIZE 5
#define W_SIZE 3
#define OUT_SIZE 3
int conv(float img[IMG_SIZE][IMG_SIZE], float w[W_SIZE][W_SIZE], float out[OUT_SIZE][OUT_SIZE])
{
int i,j,k,r,m,n;
float tmp;
//单张图片卷积
for(k = 0; k <= (IMG_SIZE - W_SIZE); k++)//行卷积
{
for(r = 0; r <= (IMG_SIZE - W_SIZE); r++)//列
{
//单次卷积
//点对点相乘,然后结果相加
tmp = 0.0;
for(i = 0; i < W_SIZE; i++)//行
{
for(j = 0; j < W_SIZE; j++)//列
{
//单点计算
tmp = tmp + img[i+k][j+r]*w[i][j];
}
}
out[k][r] = tmp;
}
}
}
int conv_test()
{
float x[IMG_SIZE][IMG_SIZE] = { 1,1,1,0,0,
0,1,1,1,0,
0,0,1,1,1,
0,0,1,1,0,
0,1,1,0,0};
float conv_w[W_SIZE][W_SIZE] = {1,0,1,
0,1,0,
1,0,1};
float img_out[OUT_SIZE][OUT_SIZE] = {0};
int i,j,k,r,m,n;
conv(x, conv_w, img_out);
printf("输入图片\n");
for(i = 0; i < 5; i++)
{
for(j = 0; j < 5; j++)
printf("%.1f ", x[i][j]);
printf("\n ");
}
printf("输出图片\n");
for(i = 0; i < 3; i++)
{
for(j = 0; j < 3; j++)
printf("%.1f ", img_out[i][j]);
printf("\n ");
}
}
三、单通道池化
最大值池化和平均值池化
//池化
#define IN_SIEZE 4
#define OUT_SIEZE 2
int pool(float in[IN_SIEZE][IN_SIEZE], float out[OUT_SIEZE][OUT_SIEZE])
{
int i,j;
float tmp1,tmp2,tmp3;
//单张图片池化
for(i = 0; i < IN_SIEZE; i+=2)//行
{
for(j = 0; j < IN_SIEZE; j+=2)//列
{
//单次池化 最大值池化
tmp1 = in[i][j] > in[i][j+1] ? in[i][j] : in[i][j+1];
tmp2 = in[i+1][j] > in[i+1][j+1] ? in[i+1][j] : in[i+1][j+1];
tmp3 = tmp1 > tmp2 ? tmp1 : tmp2;
out[i/2][j/2] = tmp3;
}
}
}
int pool1(float in[IN_SIEZE][IN_SIEZE], float out[OUT_SIEZE][OUT_SIEZE])
{
int i,j;
float tmp1,tmp2,tmp3;
//单张图片池化
for(i = 0; i < IN_SIEZE; i+=2)//行
{
for(j = 0; j < IN_SIEZE; j+=2)//列
{
//单次池化 平均值池化
tmp1 = in[i][j] + in[i][j+1];
tmp2 = in[i+1][j] + in[i+1][j+1];
tmp3 = (tmp1 + tmp2)/4;
out[i/2][j/2] = tmp3;
}
}
}
int pool_test()
{
float input[IN_SIEZE][IN_SIEZE] = {
1,2,3,4,
5,6,7,8,
9,10,11,12,
2,2,3,4
};
float output[OUT_SIEZE][OUT_SIEZE]= {0};
int i,j;
pool(input, output);
printf("最大值池化\n ");
printf(" 输入图片\n ");
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
printf("%.1f ", input[i][j]);
printf("\n ");
}
printf("输出图片\n ");
for(i = 0; i < 2; i++)
{
for(j = 0; j < 2; j++)
printf("%.1f ", output[i][j]);
printf("\n ");
}
pool1(input, output);
printf("平均值池化\n ");
printf(" 输入图片\n ");
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
printf("%.1f ", input[i][j]);
printf("\n ");
}
printf("输出图片\n ");
for(i = 0; i < 2; i++)
{
for(j = 0; j < 2; j++)
printf("%.1f ", output[i][j]);
printf("\n ");
}
}
四、padding全零填充
#define P_IN_SIZE 4
#define P_OUT_SIZE 6
int padding_1(float in[P_IN_SIZE][P_IN_SIZE], float out[P_OUT_SIZE][P_OUT_SIZE])
{
int i,j;
//清零输出
for(i = 0; i < P_OUT_SIZE; i++)
for(j = 0; j < P_OUT_SIZE; j++)
out[i][j] = 0.0;
//填充输入
for(i = 1; i < (P_OUT_SIZE - 1); i++)
for(j = 1; j < (P_OUT_SIZE - 1); j++)
out[i][j] = in[i-1][j-1];
}
int padding_test()
{
int i,j;
float input[P_IN_SIZE][P_IN_SIZE] = {
1,2,3,4,
5,6,7,8,
9,10,11,12,
2,2,3,4
};
float output[P_OUT_SIZE][P_OUT_SIZE];
padding_1(input, output);
printf(" 输入图片\n ");
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
printf("%.1f ", input[i][j]);
printf("\n ");
}
printf("输出图片\n ");
for(i = 0; i < 6; i++)
{
for(j = 0; j < 6; j++)
printf("%.1f ", output[i][j]);
printf("\n ");
}
}
五、多核多通道卷积
#define IMG_SIZE 7
#define IMG_CH 3
#define CONV_W_SIZE 3
#define CONV_W_CH 3
#define CONV_W_NUM 2
#define CONV_O_SIZE 5
int conv(float img[IMG_SIZE][IMG_SIZE][IMG_CH],
float conv_w[CONV_W_SIZE][CONV_W_SIZE][CONV_W_CH][CONV_W_NUM],
float out[CONV_O_SIZE][CONV_O_SIZE][CONV_W_NUM])
{
int i,j,k,r,m,n;
float tmp1,tmp2;
//多核多通道卷积
//多核卷积
for(r = 0; r < CONV_W_NUM; r++)
{
//多特征平面卷卷积
for(m = 0; m <= (IMG_SIZE-CONV_W_SIZE); m++)//特征平面行
{
for(n = 0; n <= (IMG_SIZE-CONV_W_SIZE); n++)//特征平面的列
{
tmp2 = 0.0;//清零多通道单次卷积结果
//多通道
for(k = 0; k < IMG_CH; k++)
{
tmp1 = 0.0;//清零单次卷积结果
//单次卷积
for(i = 0; i < CONV_W_SIZE; i++)//卷积核行
{
for(j = 0; j < CONV_W_SIZE; j++)//卷积核列
{
//单点计算
tmp1 = tmp1 + img[i+m][j+n][k]*conv_w[i][j][k][r];
}
}
//累加多个特征平面的卷积结果
tmp2 = tmp2 + tmp1;
}
//偏置
//激活
out[m][n][r] = tmp2;
}
}
}
}
int conv_test()
{
float input[IMG_CH][IMG_SIZE][IMG_SIZE] = {
0,0,0,0,0,0,0,
0,1,1,2,2,1,0,
0,1,1,1,2,1,0,
0,2,1,1,0,2,0,
0,2,1,0,1,2,0,
0,2,1,2,2,2,0,
0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0,0,1,2,0,1,0,
0,2,2,1,1,0,0,
0,2,1,0,0,2,0,
0,1,0,0,0,2,0,
0,0,1,0,1,2,0,
0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0,2,2,0,1,2,0,
0,0,0,2,1,2,0,
0,2,1,0,2,1,0,
0,1,1,0,0,0,0,
0,0,0,1,1,1,0,
0,0,0,0,0,0,0,};
float conv_w[CONV_W_NUM][CONV_W_CH][CONV_W_SIZE][CONV_W_SIZE] = {
1,1,1,
-1,-1,0,
-1,1,0,
-1,-1,1,
-1,1,0,
-1,1,0,
1,0,-1,
0,0,0,
1,-1,-1,
0,0,-1,
-1,1,1,
0,0,0,
0,0,1,
1,0,1,
0,-1,-1,
-1,1,1,
0,1,1,
1,-1,1};
float input1[IMG_SIZE][IMG_SIZE][IMG_CH] = {0};
float conv1_w[CONV_W_SIZE][CONV_W_SIZE][CONV_W_CH][CONV_W_NUM] = {0};
float output[CONV_O_SIZE][CONV_O_SIZE][CONV_W_NUM] = {0};
int i,j,k,r,m,n;
printf("imge data \n");
for(i = 0; i < IMG_CH; i++)
{
for(j = 0; j < IMG_SIZE; j++)
{
for(k = 0; k < IMG_SIZE; k++)
{
input1[j][k][i] = input[i][j][k];
printf("%.1f ", input1[j][k][i]);
}
printf("\n");
}
printf("\n");
}
printf("\n");
printf("conv w \n");
for(i = 0; i < CONV_W_NUM; i++)
{
for(j = 0; j < CONV_W_CH; j++)
{
for(k = 0; k < CONV_W_SIZE; k++)
{
for(r = 0; r < CONV_W_SIZE; r++)
{
conv1_w[k][r][j][i] = conv_w[i][j][k][r];
printf("%.1f ", conv1_w[k][r][j][i]);
}
printf("\n");
}
printf("\n");
}
printf("\n");
}
printf("\n");
conv(input1, conv1_w, output);
printf("result data \n");
for(i = 0; i < CONV_W_NUM; i++)
{
for(j = 0; j < CONV_O_SIZE; j++)
{
for(k = 0; k < CONV_O_SIZE; k++)
{
printf("%.1f ", output[j][k][i]);
}
printf("\n");
}
printf("\n");
}
}
六、多维转一维
#define SW_IN_SIZE 3
#define SW_IN_CH 3
#define SW_OUT_LEN (SW_IN_SIZE*SW_IN_SIZE*SW_IN_CH)
int Narry_1(float in[SW_IN_SIZE][SW_IN_SIZE][SW_IN_CH], float out[SW_OUT_LEN])
{
int i,j,k;
float *p = out;
for(i = 0; i < SW_IN_CH; i++)
{
for(j = 0; j < SW_IN_SIZE; j++)
{
for(k = 0; k < SW_IN_SIZE; k++)
{
#if 1
*p = in[j][k][i];
p++;
#else
out[(i*SW_IN_SIZE*SW_IN_SIZE + j*SW_IN_SIZE + k)] = in[j][k][i];
#endif
}
}
}
}
int Narry_1_test()
{
float input[SW_IN_CH][SW_IN_SIZE][SW_IN_SIZE] = {
1,1,1,
-1,-1,0,
-1,1,0,
-1,-1,1,
-1,1,0,
-1,1,0,
1,0,-1,
0,0,0,
1,-1,-1,
};
float input1[SW_IN_SIZE][SW_IN_SIZE][SW_IN_CH];
float output[SW_IN_SIZE*SW_IN_SIZE*SW_IN_CH] = {0};
int i,j,k;
float *p = output;
//转换输入
for(i = 0; i < SW_IN_CH; i++)
{
for(j = 0; j < SW_IN_SIZE; j++)
{
for(k = 0; k < SW_IN_SIZE; k++)
{
input1[j][k][i] = input[i][j][k];
printf("%.1f ", input1[j][k][i]);
}
printf("\n");
}
printf("\n");
}
Narry_1(input1, output);
printf("input data \n");
for(i = 0; i < SW_IN_CH; i++)
{
for(j = 0; j < SW_IN_SIZE; j++)
{
for(k = 0; k < SW_IN_SIZE; k++)
{
printf("%.1f ", input1[j][k][i]);
}
printf("\n");
}
printf("\n");
}
printf("output data \n");
for(i = 0; i < SW_IN_CH; i++)
{
for(j = 0; j < SW_IN_SIZE; j++)
{
for(k = 0; k < SW_IN_SIZE; k++)
{
printf("%.1f ", *p);
p++;
}
printf(" ");
}
printf(" ");
}
}