cnn突破八中最后说明白了,但没给出结果,我们今天算出结果:
在四层中:=.....ds(hocnn[1])*x[17];
这个公式实际对应14*14(x【】)-》5*5(hocnn【】)
同样在5层中:=......ds(hxo[])*x[i=?]
这个公式实际对应28*28(x【】)-》12*12(hox【】),
所以我们通过hox【】求x【】的方法和四层网络是一样的。
14*14(x【】)-》5*5(hocnn【】)被12*12(hox【】)-》4*4(hocnn【】)替代,就形成:
28*28-》12*12-》4*4-》80-》10
因为hox就相当于四层中的原图像x【】,我们已经能求出来,也就是说hxo【】我们能求出来,我们在五层网络中再走一遍:
hxi【】来自temphicnn【】2*2最大池化:
temphicnn[0]+=x[i=0,j=0,5*5方阵]*w784[0-24],
hxi[]与hxo【】是12*12的,temphicnn是【】24*24的,x是【】28*28的。
hxi【1】来自temphicnn【2】【3】【26】【27】,一一对应池化中的位置(0,0)(0,1)(1,0)(1,1),假定(1,1)最大,即27=(第二行=1,第四列=3),即temphicnn【27=1*24+3】最大,对应x【31=1*28+3】
所以,一个hxi对应一个hxo,一个hxo【1】对应25个w784更新:显然:
=.....ds(hxo[1])*x[31];
=.....ds(hxo[1])*x[32];
......
从上面看出来:hxo显然是12*12的,每一个hxo:w784【】有25个就对应25个x【】取值。
下面我们看实现代码:前向网络forward代码(前面四个卷积核,后头16个卷积核):
public void cnnforward()//202409180943使用4层网络,抄过来(这里还是三层网络),14*14->5*5->15->10
{
hIcnntemp = new double[576];
hIcnntemp1 = new double[576]; hIcnntemp2 = new double[576]; hIcnntemp3 = new double[576];
hIcnn1na = new double[144]; hIcnn2na = new double[144]; hIcnn3na = new double[144];
hIcnnna = new double[144];//每一幅图片都要重置
jilumnna.Clear();//forwardcnn执行一次,就是换一张图片
jilumn1na.Clear();
jilumn2na.Clear(); jilumn3na.Clear();
for (int i = 0; i < 24; i++)
for (int j = 0; j < 24; j++)//
{
int l = (i) * 24 + j;
for (int m = 0; m < 5; m++)
for (int n = 0; n < 5; n++)
{
int k = (i + m) * 28 + j + n;
hIcnntemp[l] += xI[k] * w576cnn[m * 5 + n, 0];//始终用零组,其他三个组不用
//为了方便,如此设计202409181006
hIcnntemp1[l] += xI[k] * w576cnn[m * 5 + n, 1];
hIcnntemp2[l] += xI[k] * w576cnn[m * 5 + n, 2];
hIcnntemp3[l] += xI[k] * w576cnn[m * 5 + n, 3];
}
}
//第二步,10*10-》5*5
//第二步,24*24》12*12
for (int i = 0; i < 12; i++)
for (int j = 0; j < 12; j++)//
{
int l = (i) * 12 + j;
double tempb = 0;
Point tempPt = new Point();
for (int m = 0; m < 2; m++)
for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
{
int k = (i * 2 + m) * 24 + j * 2 + n;
// tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
if (hIcnntemp[k] > tempb)
{
tempb = hIcnntemp[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
tempPt = new Point(n, m);//m是h,n是w,这个要小心用错
}
}
// C1[l] = (byte)(tempb/4f);
jilumnna.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
hIcnnna[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
}
// showbuffer2pictmod4(B1, 5, 5, pictureBox17);
for (int i = 0; i <12; i++)
for (int j = 0; j < 12; j++)//
{
int l = (i) * 12 + j;
double tempb = 0;
Point tempPt = new Point();
for (int m = 0; m < 2; m++)
for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
{
int k = (i * 2 + m) * 24 + j * 2 + n;
// tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
if (hIcnntemp1[k] > tempb)
{
tempb = hIcnntemp1[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
tempPt = new Point(n, m);//m是h,n是w,这个要小心用错
}
}
// C1[l] = (byte)(tempb/4f);
jilumn1na.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
hIcnn1na[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
}
for (int i = 0; i < 12; i++)
for (int j = 0; j < 12; j++)//
{
int l = (i) * 12 + j;
double tempb = 0;
Point tempPt = new Point();
for (int m = 0; m < 2; m++)
for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
{
int k = (i * 2 + m) * 24 + j * 2 + n;
// tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
if (hIcnntemp2[k] > tempb)
{
tempb = hIcnntemp2[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
tempPt = new Point(n, m);//m是h,n是w,这个要小心用错
}
}
// C1[l] = (byte)(tempb/4f);
jilumn2na.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
hIcnn2na[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
}
for (int i = 0; i < 12; i++)
for (int j = 0; j < 12; j++)//
{
int l = (i) * 12+ j;
double tempb = 0;
Point tempPt = new Point();
for (int m = 0; m < 2; m++)
for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
{
int k = (i * 2 + m) * 24 + j * 2 + n;
// tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
if (hIcnntemp3[k] > tempb)
{
tempb = hIcnntemp3[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
tempPt = new Point(n, m);//m是h,n是w,这个要小心用错
}
}
// C1[l] = (byte)(tempb/4f);
jilumn3na.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
hIcnn3na[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
}
/
// 上面已经达成12*12的四张特征图202409211852,下面每张特征图再卷积成8*8,下采样,生成4张4*4
// List<double[]>
hebingbackImg = new List<double[]>();
// List<List<Point>>
hebingpos = new List<List<Point>>();
// for (int i = 0; i < 4; i++)
{
List<double[] >tempbackImg=new List<double[]>();
List<List<Point>>
temp=chongfu(hIcnnna, w1cnn, tempbackImg);//重复一次,生成4张4*4特征图和16个位置记录要返回,4次就是,16张图,64个位置记录
for (int i = 0; i < 4; i++)
{
hebingpos.Add(temp[i]);
hebingbackImg.Add(tempbackImg[i]);
}
tempbackImg.Clear();
temp.Clear();
temp = chongfu(hIcnn1na, w1cnn2, tempbackImg);//重复一次,生成4张4*4特征图和16个位置记录要返回,4次就是,16张图,64个位置记录
for (int i = 0; i < 4; i++)
{
hebingpos.Add(temp[i]);
hebingbackImg.Add(tempbackImg[i]);
}
tempbackImg.Clear();
temp.Clear();
temp = chongfu(hIcnn2na, w1cnn3, tempbackImg);//重复一次,生成4张4*4特征图和16个位置记录要返回,4次就是,16张图,64个位置记录
for (int i = 0; i < 4; i++)
{
hebingpos.Add(temp[i]);
hebingbackImg.Add(tempbackImg[i]);
}
tempbackImg.Clear();
temp.Clear();
temp = chongfu(hIcnn3na, w1cnn4, tempbackImg);//重复一次,生成4张4*4特征图和16个位置记录要返回,4次就是,16张图,64个位置记录
for (int i = 0; i < 4; i++)
{
hebingpos.Add(temp[i]);
hebingbackImg.Add(tempbackImg[i]);
}
}
hocnnhebing = new double[16*16];
for(int i=0;i<16;i++)
for (int j = 0; j < 16; j++)
{
hocnnhebing[i*16+j] = sigmoid(hebingbackImg[i][j]);//i代表16服图像,j代表pixel4*4
}
//
hocnnhebing=new double[75];
//hocnnhebing = new double[100];
//for (int i = 0; i < 25; i++)
//{
// //hO[i] = sigmoid(hI[i]+bh[i]);
// hocnnhebing[i] = hocnn[i] = sigmoid(hIcnn[i]);
// hocnnhebing[i + 25] = hocnn1na[i] = sigmoid(hIcnn1na[i]);
// hocnnhebing[i + 50] = sigmoid(hIcnn2na[i]);
// hocnnhebing[i + 75] = sigmoid(hIcnn3na[i]);
//}
//下面开始全连接202409181044
hI2cnn = new double[50];//15gai 25
for (int i = 0; i < 16*16; i++)//128
for (int j = 0; j < 50; j++)//60
hI2cnn[j] += (hocnnhebing[i]) * w12cnn[i, j];//75,25
//通过激活函数对隐藏层进行计算
for (int i = 0; i < 50; i++)
hO2cnn[i] = sigmoid(hI2cnn[i]);
yicnn = new double[10];
//通过w2计算隐藏层-输出层
for (int i = 0; i < 50; i++)
for (int j = 0; j < 10; j++)
yicnn[j] += hO2cnn[i] * w2cnn[i, j];
//通过激活函数求yo
for (int i = 0; i < 10; i++)
//yO[i] = sigmoid(yi[i]+by[i]);
yOcnn[i] = sigmoid(yicnn[i]);
}
调用函数:
public List<List<Point>> chongfu(double []输入图像,double [,] 卷积核,List<double[]>fanhuituxiang)
{
List<List<Point>> templlp = new List<List<Point>>();
// 上面已经达成12*12的四张特征图202409211852,下面每张特征图再卷积成8*8,下采样,生成4张4*4
ThIcnntemp = new double[64];
ThIcnntemp1 = new double[64]; ThIcnntemp2 = new double[64]; ThIcnntemp3 = new double[64];
ThIcnn1na = new double[16]; ThIcnn2na = new double[16]; ThIcnn3na = new double[16];
ThIcnnna = new double[16];//每一幅图片都要重置
Tjilumnna.Clear();//forwardcnn执行一次,就是换一张图片
Tjilumn1na.Clear();
Tjilumn2na.Clear(); Tjilumn3na.Clear();
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)//
{
int l = (i) * 8 + j;
for (int m = 0; m < 5; m++)
for (int n = 0; n < 5; n++)
{
int k = (i + m) * 12 + j + n;
ThIcnntemp[l] += 输入图像[k] * 卷积核[m * 5 + n, 0];//始终用零组,其他三个组不用
//为了方便,如此设计202409181006
ThIcnntemp1[l] += 输入图像[k] * 卷积核[m * 5 + n, 1];
ThIcnntemp2[l] += 输入图像[k] * 卷积核[m * 5 + n, 2];
ThIcnntemp3[l] += 输入图像[k] * 卷积核[m * 5 + n, 3];//一个图像用四个卷积核生成4个特征图*8*8
//ThIcnntemp[l] += hIcnnna[k] * w1cnn[m * 5 + n, 0];//始终用零组,其他三个组不用
为了方便,如此设计202409181006
//ThIcnntemp1[l] += hIcnnna[k] * w1cnn[m * 5 + n, 1];
//ThIcnntemp2[l] += hIcnnna[k] * w1cnn[m * 5 + n, 2];
//ThIcnntemp3[l] += hIcnnna[k] * w1cnn[m * 5 + n, 3];//一个图像用四个卷积核生成4个特征图*8*8
}
}
//第二步,8*8-》4*4
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)//
{
int l = (i) * 4 + j;
double tempb = 0;
Point tempPt = new Point();
for (int m = 0; m < 2; m++)
for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
{
int k = (i * 2 + m) * 8 + j * 2 + n;
// tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
if (ThIcnntemp[k] > tempb)
{
tempb = ThIcnntemp[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
tempPt = new Point(n, m);//m是h,n是w,这个要小心用错
}
}
// C1[l] = (byte)(tempb/4f);
Tjilumnna.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
ThIcnnna[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
}
templlp.Add(Tjilumnna); fanhuituxiang.Add(ThIcnnna);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)//
{
int l = (i) * 4 + j;
double tempb = 0;
Point tempPt = new Point();
for (int m = 0; m < 2; m++)
for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
{
int k = (i * 2 + m) * 8 + j * 2 + n;
// tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
if (ThIcnntemp1[k] > tempb)
{
tempb = ThIcnntemp1[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
tempPt = new Point(n, m);//m是h,n是w,这个要小心用错
}
}
// C1[l] = (byte)(tempb/4f);
Tjilumn1na.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
ThIcnn1na[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
}
templlp.Add(Tjilumn1na); fanhuituxiang.Add(ThIcnn1na);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)//
{
int l = (i) * 4 + j;
double tempb = 0;
Point tempPt = new Point();
for (int m = 0; m < 2; m++)
for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
{
int k = (i * 2 + m) * 4 + j * 2 + n;
// tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
if (ThIcnntemp2[k] > tempb)
{
tempb = ThIcnntemp2[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
tempPt = new Point(n, m);//m是h,n是w,这个要小心用错
}
}
// C1[l] = (byte)(tempb/4f);
Tjilumn2na.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
ThIcnn2na[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
}
templlp.Add(Tjilumn2na); fanhuituxiang.Add(ThIcnn2na);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)//
{
int l = (i) * 4 + j;
double tempb = 0;
Point tempPt = new Point();
for (int m = 0; m < 2; m++)
for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
{
int k = (i * 2 + m) * 8 + j * 2 + n;
// tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
if (ThIcnntemp3[k] > tempb)
{
tempb = ThIcnntemp3[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
tempPt = new Point(n, m);//m是h,n是w,这个要小心用错
}
}
// C1[l] = (byte)(tempb/4f);
Tjilumn3na.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
ThIcnn3na[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
}
templlp.Add(Tjilumn3na); fanhuituxiang.Add(ThIcnn3na);
return templlp;
}
下面是backward函数:
//反向传播函数
void backcnn()//应该引入结局b的更新,这样可以加快收敛速度202409140818
{
for (int i = 0; i < 50; i++)//15
for (int j = 0; j < 10; j++)//10
{//q=10
double delta = (yOcnn[j] - d[j]) * dsigmoid(yOcnn[j]) * hO2cnn[i];//图像28*28是ling,则标签是0,d[]={1,0,0,0,0,0,0,0,0,0};图像28*28是wu,则标签是5,d[]={0,0,0,0,0,1,0,0,0,0}
w2cnn[i, j] -= delta * learnRate;
}
double[] W3 = new double[50];//
for (int j = 0; j < 50; j++)//15
for (int k = 0; k < 10; k++)//10
W3[j] += (yOcnn[k] - d[k]) * dsigmoid(yOcnn[k]) * w2cnn[j, k];
for (int i = 0; i < 16*16; i++)//256
for (int j = 0; j < 50; j++)//15
{
double delta = dsigmoid(hO2cnn[j]) * (hocnnhebing[i]) * W3[j];//这里要的是系数
w12cnn[i, j] -= delta * learnRate;
}
//double[] deltacnn = new double[25];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核
//for (int i = 0; i < 25; i++)//25
double[] deltacnn = new double[16];
for (int i = 0; i < 16; i++)//25
for (int j = 0; j < 50; j++)//15
{
//这里处理的对不对?直觉对不对?回头验算一下202409191114
deltacnn[i] = dsigmoid(hO2cnn[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);
}//全连接还是好处理202409200708
for (int i = 0; i <16; i++)
{//hebingpos
Point temppt = 求二维(i, hebingpos[0][i].Y, hebingpos[0][i].X);
//Point temppt = 求二维(i, jilumn[i].Y, jilumn[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{
// temp = chongfu(hIcnnna, w1cnn, tempbackImg);//相当于原图像12*12
// hebingbackImg[i][j],8*8
int newIndex = (temppt.Y + k) * 12 + (temppt.X + z);
double delta = hIcnnna[newIndex] * deltacnn[i];//一共25个
w1cnn[k * 5 + z, 0] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
//另一个卷积核202409191112
double[] deltacnn1 = new double[16];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核
for (int i = 16; i <32; i++)//25
for (int j = 0; j < 50; j++)//15
{
deltacnn1[i - 16] = dsigmoid(hO2cnn[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);
}
for (int i = 0; i < 16; i++)
{
//Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
Point temppt = 求二维(i, hebingpos[1][i].Y, hebingpos[1][i].X);//1代表第二波16个
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{
int newIndex = (temppt.Y + k) * 12 + (temppt.X + z);
double delta = hIcnnna[newIndex] * deltacnn1[i];//一共25个
w1cnn[k * 5 + z, 1] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
//第三个卷积核202409191112
double[] deltacnn2 = new double[16];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核
for (int i = 32; i < 48; i++)//25
//for (int j = 0; j < 15; j++)//15
for (int j = 0; j < 50; j++)//15
{
//deltacnn1[i-25] = dsigmoid(hO2[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnn1na[i]);
deltacnn2[i - 32] = dsigmoid(hO2cnn[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);
}
for (int i = 0; i < 16; i++)
{
// Point temppt = 求二维(i, jilumn2na[i].Y, jilumn2na[i].X);
Point temppt = 求二维(i, hebingpos[2][i].Y, hebingpos[2][i].X);//2代表第san波16个
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{
int newIndex = (temppt.Y + k) * 12 + (temppt.X + z);
double delta = hIcnnna[newIndex] * deltacnn2[i];//一共25个
w1cnn[k * 5 + z, 2] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
//第四个卷积核202409191112
double[] deltacnn3 = new double[16];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核
for (int i = 48; i < 64; i++)//25
//for (int j = 0; j < 15; j++)//15
for (int j = 0; j < 50; j++)//15
{
//deltacnn1[i-25] = dsigmoid(hO2[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnn1na[i]);
deltacnn3[i -48] = dsigmoid(hO2cnn[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);
}
for (int i = 0; i < 16; i++)
{
// Point temppt = 求二维(i, jilumn3na[i].Y, jilumn3na[i].X);
Point temppt = 求二维(i, hebingpos[3][i].Y, hebingpos[3][i].X);//3代表第si波16个
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{
int newIndex = (temppt.Y + k) * 12 + (temppt.X + z);
double delta = hIcnnna[newIndex] * deltacnn3[i];//一共25个
w1cnn[k * 5 + z, 3] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
//4个卷积核已经更新完,下面第5个到16
double[] deltacnn5 = 更新卷积核(W3, 5, hIcnn1na, w1cnn2);//5->0,w1cnn2[25,(5 - 1) % 4]->w1cnn2[25,(6 - 1) % 4]->w1cnn2[25,(7 - 1) % 4]->w1cnn2[25,(8 - 1) % 4]
double[] deltacnn6= 更新卷积核(W3, 6, hIcnn1na, w1cnn2);
double[] deltacnn7 = 更新卷积核(W3, 7, hIcnn1na, w1cnn2);
double[] deltacnn8 = 更新卷积核(W3, 8, hIcnn1na, w1cnn2);
double[] deltacnn9 = 更新卷积核(W3, 9, hIcnn2na, w1cnn3);//9->0,w1cnn3[25,(9- 1) % 4]->w1cnn3[25,(10 - 1) % 4]->w1cnn3[25,(11- 1) % 4]->w1cnn3[25,(12 - 1) % 4]
double[] deltacnn10 = 更新卷积核(W3, 10, hIcnn2na, w1cnn3);
double[] deltacnn11 = 更新卷积核(W3, 11, hIcnn2na, w1cnn3);
double[] deltacnn12 = 更新卷积核(W3, 12, hIcnn2na, w1cnn3);
double[] deltacnn13 = 更新卷积核(W3, 13, hIcnn3na, w1cnn4);//卷积核w1cnn4[25,0],5*5的卷积核
double[] deltacnn14 = 更新卷积核(W3, 14, hIcnn3na, w1cnn4);//卷积核w1cnn4[25,1]
double[] deltacnn15 = 更新卷积核(W3, 15, hIcnn3na, w1cnn4);//卷积核w1cnn4[25,2]
double[] deltacnn16 = 更新卷积核(W3, 16, hIcnn3na, w1cnn4);//卷积核w1cnn4[25,3]//hIcnn3na是12*12的图像《-8**《-4*4,backup
//继续向上,四个卷积核刚好对应一副原始图像,即四个卷积核向上对应一个卷积核28*28-》24*24-》12*12
//卷积核w1cnn[25,4]对应xI[k] * w576cnn[m * 5 + n, 0]
//卷积核w1cnn1[25,4]对应xI[k] * w576cnn[m * 5 + n, 1]
double[] deltacnnX = new double[16];//每一个deltacnnx,都对应25个28*28中的数据元素,以及一个5*5的卷积核
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
// int newIndex = (temppt.Y + k) * 12 + (temppt.X + z);
//deltacnnX[i] = deltacnn[i] * w1cnn[k * 5 + z, 0] * dsigmoid(hocnnhebing[i]);hIcnnna[newIndex]
deltacnnX[i] = deltacnn[i] * w1cnn[j, 0];//* dsigmoid(hocnnhebing[i]);hIcnnna[newIndex]
}//全连接还是好处理202409200708
for (int i = 0; i < 16; i++)
{//jilumnna
Point temppt = 求二维(i, jilumnna[i].Y, jilumnna[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28+ (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnnna[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 0] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn1[i] * w1cnn[j, 1];//*
}
for (int i = 0; i < 16; i++)
{//jilumnna
Point temppt = 求二维(i, jilumnna[i].Y, jilumnna[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnnna[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 0] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn2[i] * w1cnn[j, 2];//*
}
for (int i = 0; i < 16; i++)
{//jilumnna
Point temppt = 求二维(i, jilumnna[i].Y, jilumnna[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnnna[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 0] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn3[i] * w1cnn[j, 3];//*
}
for (int i = 0; i < 16; i++)
{//jilumnna
Point temppt = 求二维(i, jilumnna[i].Y, jilumnna[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnnna[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 0] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
//第二轮开始
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn5[i] * w1cnn2[j, 0];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn1na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 1] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn6[i] * w1cnn2[j, 1];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn1na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 1] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn7[i] * w1cnn2[j, 2];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn1na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 1] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn8[i] * w1cnn2[j, 3];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn1na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 1] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
//第san轮开始
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn9[i] * w1cnn3[j, 0];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn2na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 2] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn10[i] * w1cnn3[j, 1];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn2na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 2] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn11[i] * w1cnn3[j, 2];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn2na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 2] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn12[i] * w1cnn3[j, 3];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn2na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 2] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
//最后yilun
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn13[i] * w1cnn4[j, 0];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn3na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 3] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn14[i] * w1cnn4[j, 1];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn3na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 3] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn15[i] * w1cnn4[j, 2];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn3na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 3] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
for (int i = 0; i < 16; i++)//16
for (int j = 0; j < 25; j++)//25
{
deltacnnX[i] = deltacnn16[i] * w1cnn4[j, 3];//*
}//jilumn1na
for (int i = 0; i < 16; i++)
{//jilumn1na
Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{ // int k = (i * 2 + m) * 24 + j * 2 + n;
int newIndex = (temppt.Y + k) * 28 + (temppt.X + z);
double delta = xI[newIndex] * deltacnnX[i] * dsigmoid(hIcnn3na[(temppt.Y / 2 + k) * 12 + temppt.X / 2 + z]);//一共25个
w576cnn[k * 5 + z, 3] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
}
}
}
public double[] 更新卷积核(double[] 中间值, int 卷积核序号, double[] 图像, double[,] 卷积核)//=4,=5,卷积核序号从1开始
{
//第四个卷积核202409191112
double[] deltacnn3 = new double[16];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核
int kk = 0;
int temp=(卷积核序号-1) * 16;
for (int i = temp; i < temp+ 16; i++)
{
for (int j = 0; j < 50; j++)//15
{
deltacnn3[kk] = dsigmoid(hO2cnn[j]) * 中间值[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);
}
kk++;
}
for (int i = 0; i < 16; i++)
{
Point temppt = 求二维(i, hebingpos[卷积核序号 - 1][i].Y, hebingpos[卷积核序号 - 1][i].X);//3代表第si波16个
for (int k = 0; k < 5; k++)
for (int z = 0; z < 5; z++)
{
int newIndex = (temppt.Y + k) * 12 + (temppt.X + z);
//double delta = hIcnnna[newIndex] * deltacnn3[i];//一共25个
//w1cnn[k * 5 + z, 卷积核序号 - 1] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
//5,6,7,8
double delta = 图像[newIndex] * deltacnn3[i];//一共25个
// w1cnn1[k * 5 + z, 卷积核序号 - 1] -= delta * learnRate;
卷积核[k * 5 + z, (卷积核序号 - 1) % 4] -= delta * learnRate;
}
}
return deltacnn3;
}
public Point 求二维(int index, int mm, int nn)
{
Point rePt = new Point();
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
{
int n = i * 5 + j;
if (index == n)
{
int h = i * 2 + mm;
int w = j * 2 + nn;
rePt.X = w;
rePt.Y = h;
i = 5;
j = 5;//end 2 for loop;
}
}
return rePt;
}
代码虽然复杂,但原理不复杂!编程大多数是注意细节和找bug!